Skip to content

Commit 2d97601

Browse files
authored
Merge pull request #2339 from joto/hex-refactor
Refactor hex en/decoding
2 parents 771baaa + fb631b0 commit 2d97601

File tree

15 files changed

+227
-127
lines changed

15 files changed

+227
-127
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ target_sources(osm2pgsql_lib PRIVATE
3232
geom-functions.cpp
3333
geom-pole-of-inaccessibility.cpp
3434
geom.cpp
35+
hex.cpp
3536
idlist.cpp
3637
input.cpp
3738
locator.cpp

src/db-copy-mgr.hpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#include <string>
1616

1717
#include "db-copy.hpp"
18-
#include "util.hpp"
18+
#include "hex.hpp"
1919

2020
/**
2121
* Management class that fills and manages copy buffers.
@@ -237,13 +237,7 @@ class db_copy_mgr_t
237237
*/
238238
void add_hex_geom(std::string const &wkb)
239239
{
240-
char const *const lookup_hex = "0123456789ABCDEF";
241-
242-
for (auto c : wkb) {
243-
unsigned int const num = static_cast<unsigned char>(c);
244-
m_current.buffer += lookup_hex[(num >> 4U) & 0xfU];
245-
m_current.buffer += lookup_hex[num & 0xfU];
246-
}
240+
util::encode_hex(wkb, &m_current.buffer);
247241
m_current.buffer += '\t';
248242
}
249243

src/gen/canvas.cpp

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "canvas.hpp"
1111

12+
#include "hex.hpp"
1213
#include "raster.hpp"
1314
#include "tile.hpp"
1415

@@ -139,19 +140,3 @@ void canvas_t::merge(canvas_t const &other)
139140
{
140141
cv::bitwise_or(m_rast, other.m_rast, m_rast);
141142
}
142-
143-
std::string to_hex(std::string const &in)
144-
{
145-
std::string result;
146-
result.reserve(in.size() * 2);
147-
148-
char const *const lookup_hex = "0123456789ABCDEF";
149-
150-
for (const auto c : in) {
151-
unsigned int const num = static_cast<unsigned char>(c);
152-
result += lookup_hex[(num >> 4U) & 0xfU];
153-
result += lookup_hex[num & 0xfU];
154-
}
155-
156-
return result;
157-
}

src/gen/canvas.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,4 @@ class canvas_t
7777
image_type m_rast;
7878
}; // class canvas_t
7979

80-
std::string to_hex(std::string const &in);
81-
8280
#endif // OSM2PGSQL_CANVAS_HPP

src/gen/gen-rivers.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "gen-rivers.hpp"
1111

1212
#include "geom-functions.hpp"
13+
#include "hex.hpp"
1314
#include "logging.hpp"
1415
#include "params.hpp"
1516
#include "pgsql.hpp"
@@ -264,7 +265,7 @@ SELECT "{id_column}", "{width_column}", "{name_column}", "{geom_column}"
264265
if (!name.empty()) {
265266
names.emplace(id, name);
266267
}
267-
auto const geom = ewkb_to_geom(decode_hex(result.get(i, 3)));
268+
auto const geom = ewkb_to_geom(util::decode_hex(result.get(i, 3)));
268269

269270
if (geom.is_linestring()) {
270271
auto const &ls = geom.get<geom::linestring_t>();

src/gen/gen-tile-builtup.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "canvas.hpp"
1313
#include "geom-functions.hpp"
14+
#include "hex.hpp"
1415
#include "logging.hpp"
1516
#include "params.hpp"
1617
#include "pgsql.hpp"
@@ -33,7 +34,7 @@ void save_image_to_table(pg_conn_t *connection, canvas_t const &canvas,
3334
std::string const &table, char const *variant,
3435
std::string const &table_prefix)
3536
{
36-
auto const wkb = to_hex(canvas.to_wkb(tile, margin));
37+
auto const wkb = util::encode_hex(canvas.to_wkb(tile, margin));
3738

3839
connection->exec("INSERT INTO \"{}_{}_{}\" (zoom, x, y, rast)"
3940
" VALUES ({}, {}, {}, '{}')",
@@ -61,7 +62,7 @@ void draw_from_db(double margin, canvas_list_t *canvas_list, pg_conn_t *conn,
6162
box.max_x(), box.max_y());
6263

6364
for (int n = 0; n < result.num_tuples(); ++n) {
64-
auto const geom = ewkb_to_geom(decode_hex(result.get(n, 0)));
65+
auto const geom = ewkb_to_geom(util::decode_hex(result.get(n, 0)));
6566
cc.canvas.draw(geom, tile);
6667
}
6768
}
@@ -251,7 +252,7 @@ void gen_tile_builtup_t::process(tile_t const &tile)
251252
log_gen("Write geometries to destination table...");
252253
timer(m_timer_write).start();
253254
for (auto const &geom : geometries) {
254-
auto const wkb = to_hex(geom_to_ewkb(geom));
255+
auto const wkb = util::encode_hex(geom_to_ewkb(geom));
255256
if (m_has_area_column) {
256257
connection().exec_prepared("insert_geoms", wkb, tile.x(), tile.y(),
257258
geom::area(geom));

src/gen/gen-tile-raster.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "gen-tile-raster.hpp"
1111

1212
#include "canvas.hpp"
13+
#include "hex.hpp"
1314
#include "logging.hpp"
1415
#include "params.hpp"
1516
#include "pgsql.hpp"
@@ -49,7 +50,7 @@ void draw_from_db(double margin, unsigned int image_extent,
4950

5051
for (int n = 0; n < result.num_tuples(); ++n) {
5152
std::string param = result.get_value(n, 1);
52-
auto const geom = ewkb_to_geom(decode_hex(result.get(n, 0)));
53+
auto const geom = ewkb_to_geom(util::decode_hex(result.get(n, 0)));
5354

5455
auto const [it, success] = canvas_list->try_emplace(
5556
std::move(param), image_extent, image_buffer);
@@ -63,7 +64,7 @@ void save_image_to_table(pg_conn_t *connection, canvas_t const &canvas,
6364
std::string const &param, char const *variant,
6465
std::string const &table_prefix)
6566
{
66-
auto const wkb = to_hex(canvas.to_wkb(tile, margin));
67+
auto const wkb = util::encode_hex(canvas.to_wkb(tile, margin));
6768

6869
connection->exec("INSERT INTO \"{}_{}\" (type, zoom, x, y, rast)"
6970
" VALUES ('{}', {}, {}, {}, '{}')",

src/hex.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* SPDX-License-Identifier: GPL-2.0-or-later
3+
*
4+
* This file is part of osm2pgsql (https://osm2pgsql.org/).
5+
*
6+
* Copyright (C) 2006-2025 by the osm2pgsql developer community.
7+
* For a full list of authors see the git log.
8+
*/
9+
10+
#include "hex.hpp"
11+
12+
#include <array>
13+
#include <cassert>
14+
#include <stdexcept>
15+
16+
namespace util {
17+
18+
void encode_hex(std::string const &in, std::string *out)
19+
{
20+
assert(out);
21+
22+
constexpr char const *const LOOKUP_HEX = "0123456789ABCDEF";
23+
24+
for (auto const c : in) {
25+
unsigned int const num = static_cast<unsigned char>(c);
26+
(*out) += LOOKUP_HEX[(num >> 4U) & 0xfU];
27+
(*out) += LOOKUP_HEX[num & 0xfU];
28+
}
29+
}
30+
31+
std::string encode_hex(std::string const &in)
32+
{
33+
std::string result;
34+
result.reserve(in.size() * 2);
35+
encode_hex(in, &result);
36+
return result;
37+
}
38+
39+
namespace {
40+
41+
constexpr std::array<char, 256> const HEX_TABLE = {
42+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
43+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
44+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
45+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
46+
47+
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
48+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
49+
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50+
};
51+
52+
} // anonymous namespace
53+
54+
unsigned char decode_hex_char(char c) noexcept
55+
{
56+
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
57+
return HEX_TABLE[static_cast<std::size_t>(static_cast<unsigned char>(c))];
58+
}
59+
60+
std::string decode_hex(std::string_view hex_string)
61+
{
62+
if (hex_string.size() % 2 != 0) {
63+
throw std::runtime_error{"Invalid wkb: Not a valid hex string"};
64+
}
65+
66+
std::string wkb;
67+
wkb.reserve(hex_string.size() / 2);
68+
69+
// NOLINTNEXTLINE(llvm-qualified-auto, readability-qualified-auto)
70+
for (auto hex = hex_string.begin(); hex != hex_string.end();) {
71+
unsigned int const c = decode_hex_char(*hex++);
72+
wkb += static_cast<char>((c << 4U) | decode_hex_char(*hex++));
73+
}
74+
75+
return wkb;
76+
}
77+
78+
} // namespace util

src/hex.hpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#ifndef OSM2PGSQL_HEX_HPP
2+
#define OSM2PGSQL_HEX_HPP
3+
4+
/**
5+
* SPDX-License-Identifier: GPL-2.0-or-later
6+
*
7+
* This file is part of osm2pgsql (https://osm2pgsql.org/).
8+
*
9+
* Copyright (C) 2006-2025 by the osm2pgsql developer community.
10+
* For a full list of authors see the git log.
11+
*/
12+
13+
#include <string>
14+
15+
namespace util {
16+
17+
/**
18+
* Convert content of input string to hex and append to output.
19+
*
20+
* \param in The input data.
21+
* \param out Pointer to output string.
22+
*/
23+
void encode_hex(std::string const &in, std::string *out);
24+
25+
/**
26+
* Convert content of input string to hex and return it.
27+
*
28+
* \param in The input data.
29+
* \returns Hex encoded string.
30+
*/
31+
[[nodiscard]] std::string encode_hex(std::string const &in);
32+
33+
/**
34+
* Decode one hex character (0-9A-F or 0-9a-f) and return its value.
35+
* Returns 0 for characters that are not hex characters.
36+
*/
37+
[[nodiscard]] unsigned char decode_hex_char(char c) noexcept;
38+
39+
/**
40+
* Decode a string of hex characters. Throws an exception if the input is not
41+
* a valid hex encoding.
42+
*/
43+
[[nodiscard]] std::string decode_hex(std::string_view hex);
44+
45+
} // namespace util
46+
47+
#endif // OSM2PGSQL_HEX_HPP

src/locator.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "geom-boost-adaptor.hpp"
1313
#include "geom-box.hpp"
1414
#include "geom-functions.hpp"
15+
#include "hex.hpp"
1516
#include "overloaded.hpp"
1617
#include "pgsql-capabilities.hpp"
1718
#include "pgsql.hpp"
@@ -60,7 +61,7 @@ void locator_t::add_regions(pg_conn_t const &db_connection,
6061

6162
for (int n = 0; n < result.num_tuples(); ++n) {
6263
std::string const name = result.get_value(n, 0);
63-
auto geometry = ewkb_to_geom(decode_hex(result.get(n, 1)));
64+
auto geometry = ewkb_to_geom(util::decode_hex(result.get(n, 1)));
6465

6566
if (geometry.srid() == 4326) {
6667
add_region(name, geometry);

0 commit comments

Comments
 (0)