diff --git a/CMakeLists.txt b/CMakeLists.txt index de808e2..d6b0536 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,13 +35,13 @@ include_directories(SYSTEM ${MASON_PACKAGE_benchmark_INCLUDE_DIRS}) mason_use(variant VERSION 1.1.5 HEADER_ONLY) include_directories(SYSTEM ${MASON_PACKAGE_variant_INCLUDE_DIRS}) -mason_use(vtzero VERSION 7adde32 HEADER_ONLY) +mason_use(vtzero VERSION 1b89523 HEADER_ONLY) include_directories(SYSTEM ${MASON_PACKAGE_vtzero_INCLUDE_DIRS}) mason_use(geometry VERSION 1.0.0 HEADER_ONLY) include_directories(SYSTEM ${MASON_PACKAGE_geometry_INCLUDE_DIRS}) -mason_use(protozero VERSION 1.6.0 HEADER_ONLY) +mason_use(protozero VERSION 1.6.5 HEADER_ONLY) include_directories(SYSTEM ${MASON_PACKAGE_protozero_INCLUDE_DIRS}) include_directories("${PROJECT_SOURCE_DIR}/include") diff --git a/bench/run.cpp b/bench/run.cpp index 12216d8..6c98f35 100644 --- a/bench/run.cpp +++ b/bench/run.cpp @@ -29,12 +29,12 @@ static void BM_decode_polygon_fixture(benchmark::State& state) // NOLINT google- { std::string buffer = open_tile("test/mvt-fixtures/fixtures/019/tile.mvt"); vtzero::vector_tile tile(buffer); - auto layer = tile.next_layer(); - auto feature = layer.next_feature(); + auto layer = tile.begin(); + auto feature = (*layer).begin(); while (state.KeepRunning()) { - benchmark::DoNotOptimize(mapbox::vector_tile::extract_geometry(feature)); + benchmark::DoNotOptimize(mapbox::vector_tile::extract_geometry(*feature)); } } @@ -47,12 +47,12 @@ static void BM_decode_multipolygon_fixture(benchmark::State& state) // NOLINT go { std::string buffer = open_tile("test/mvt-fixtures/fixtures/022/tile.mvt"); vtzero::vector_tile tile(buffer); - auto layer = tile.next_layer(); - auto feature = layer.next_feature(); + auto layer = tile.begin(); + auto feature = (*layer).begin(); while (state.KeepRunning()) { - benchmark::DoNotOptimize(mapbox::vector_tile::extract_geometry(feature)); + benchmark::DoNotOptimize(mapbox::vector_tile::extract_geometry(*feature)); } } @@ -65,12 +65,12 @@ static void BM_decode_multilinestring_fixture(benchmark::State& state) // NOLINT { std::string buffer = open_tile("test/mvt-fixtures/fixtures/021/tile.mvt"); vtzero::vector_tile tile(buffer); - auto layer = tile.next_layer(); - auto feature = layer.next_feature(); + auto layer = tile.begin(); + auto feature = (*layer).begin(); while (state.KeepRunning()) { - benchmark::DoNotOptimize(mapbox::vector_tile::extract_geometry(feature)); + benchmark::DoNotOptimize(mapbox::vector_tile::extract_geometry(*feature)); } } @@ -83,12 +83,12 @@ static void BM_decode_linestring_fixture(benchmark::State& state) // NOLINT goog { std::string buffer = open_tile("test/mvt-fixtures/fixtures/018/tile.mvt"); vtzero::vector_tile tile(buffer); - auto layer = tile.next_layer(); - auto feature = layer.next_feature(); + auto layer = tile.begin(); + auto feature = (*layer).begin(); while (state.KeepRunning()) { - benchmark::DoNotOptimize(mapbox::vector_tile::extract_geometry(feature)); + benchmark::DoNotOptimize(mapbox::vector_tile::extract_geometry(*feature)); } } @@ -101,12 +101,12 @@ static void BM_decode_multipoint_fixture(benchmark::State& state) // NOLINT goog { std::string buffer = open_tile("test/mvt-fixtures/fixtures/020/tile.mvt"); vtzero::vector_tile tile(buffer); - auto layer = tile.next_layer(); - auto feature = layer.next_feature(); + auto layer = tile.begin(); + auto feature = (*layer).begin(); while (state.KeepRunning()) { - benchmark::DoNotOptimize(mapbox::vector_tile::extract_geometry(feature)); + benchmark::DoNotOptimize(mapbox::vector_tile::extract_geometry(*feature)); } } @@ -119,12 +119,12 @@ static void BM_decode_point_fixture(benchmark::State& state) // NOLINT google-ru { std::string buffer = open_tile("test/mvt-fixtures/fixtures/017/tile.mvt"); vtzero::vector_tile tile(buffer); - auto layer = tile.next_layer(); - auto feature = layer.next_feature(); + auto layer = tile.begin(); + auto feature = (*layer).begin(); while (state.KeepRunning()) { - benchmark::DoNotOptimize(mapbox::vector_tile::extract_geometry(feature)); + benchmark::DoNotOptimize(mapbox::vector_tile::extract_geometry(*feature)); } } @@ -186,12 +186,12 @@ static void BM_decode_polygon(benchmark::State& state) // NOLINT google-runtime- } vtzero::vector_tile tile(buffer); - auto layer = tile.next_layer(); - auto feature = layer.next_feature(); + auto layer = tile.begin(); + auto feature = (*layer).begin(); while (state.KeepRunning()) { - benchmark::DoNotOptimize(mapbox::vector_tile::extract_geometry(feature)); + benchmark::DoNotOptimize(mapbox::vector_tile::extract_geometry(*feature)); } // sets a simple counter state.counters["Points"] = num_points; diff --git a/include/mapbox/vector_tile.hpp b/include/mapbox/vector_tile.hpp index 298fa1a..4f436b1 100644 --- a/include/mapbox/vector_tile.hpp +++ b/include/mapbox/vector_tile.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -29,19 +30,19 @@ mapbox::geometry::geometry extract_geometry(vtzero::feature cons inline mapbox::feature::property_map extract_properties(vtzero::feature const& f) { - mapbox::feature::property_map map; - f.for_each_property([&](vtzero::property&& p) { - map.emplace(std::string(p.key()), vtzero::convert_property_value(p.value())); - return true; - }); - return map; + detail::AttributeHandler handler(f); + return f.decode_attributes(handler); } inline mapbox::feature::identifier extract_id(vtzero::feature const& f) { - if (f.has_id()) + if (f.has_string_id()) { - return mapbox::feature::identifier(f.id()); + return mapbox::feature::identifier(std::string(f.string_id())); + } + else if (f.has_integer_id()) + { + return mapbox::feature::identifier(f.integer_id()); } else { @@ -63,10 +64,10 @@ layer_map decode_tile(std::string const& buffer) { layer_map m; vtzero::vector_tile tile(buffer); - while (auto layer = tile.next_layer()) + for (auto layer : tile) { mapbox::feature::feature_collection fc; - while (auto feature = layer.next_feature()) + for (auto feature : layer) { auto f = extract_feature(feature); if (!f.geometry.template is()) diff --git a/include/mapbox/vector_tile/attribute_handler.hpp b/include/mapbox/vector_tile/attribute_handler.hpp new file mode 100644 index 0000000..31324b6 --- /dev/null +++ b/include/mapbox/vector_tile/attribute_handler.hpp @@ -0,0 +1,234 @@ +#pragma once + +#include +#include +#include + +namespace mapbox { +namespace vector_tile { +namespace detail { + +struct AttributeHandler +{ + + using map_type = mapbox::feature::property_map; + using vec_type = std::vector; + + struct handler_store + { + std::unique_ptr map; + std::unique_ptr vec; + vtzero::data_view last_key; + vtzero::scaling const* scaling; + bool is_map; + }; + + std::vector stack; + vtzero::layer const& layer; + handler_store* active; + + AttributeHandler(vtzero::feature const& feature) + : stack(), + layer(feature.get_layer()), + active() + { + stack.push_back({std::make_unique(), nullptr, {}, nullptr, true}); + active = &(stack.back()); + } + + map_type result() + { + return std::move(*(active->map)); + } + + vec_type vec_result() + { + return std::move(*(active->vec)); + } + + bool attribute_key(vtzero::data_view key, std::size_t /*depth*/) + { + active->last_key = key; + return true; + } + + bool attribute_value(vtzero::data_view value, std::size_t /*depth*/) + { + if (active->is_map) + { + active->map->emplace(std::string(active->last_key), mapbox::feature::value(std::string(value))); + } + else + { + active->vec->push_back(mapbox::feature::value(std::string(value))); + } + return true; + } + + bool attribute_value(vtzero::null_type /*value*/, std::size_t /*depth*/) + { + if (active->is_map) + { + active->map->emplace(std::string(active->last_key), mapbox::feature::value(mapbox::feature::null_value_t())); + } + else + { + active->vec->push_back(mapbox::feature::value(mapbox::feature::null_value_t())); + } + return true; + } + + bool attribute_value(int64_t value, std::size_t /*depth*/) + { + if (active->is_map) + { + active->map->emplace(std::string(active->last_key), mapbox::feature::value(value)); + } + else + { + active->vec->push_back(mapbox::feature::value(value)); + } + return true; + } + + bool attribute_value(uint64_t value, std::size_t /*depth*/) + { + if (active->is_map) + { + active->map->emplace(std::string(active->last_key), mapbox::feature::value(value)); + } + else + { + active->vec->push_back(mapbox::feature::value(value)); + } + return true; + } + + bool attribute_value(double value, std::size_t /*depth*/) + { + if (active->is_map) + { + active->map->emplace(std::string(active->last_key), mapbox::feature::value(value)); + } + else + { + active->vec->push_back(mapbox::feature::value(value)); + } + return true; + } + + bool attribute_value(float value, std::size_t /*depth*/) + { + if (active->is_map) + { + active->map->emplace(std::string(active->last_key), mapbox::feature::value(static_cast(value))); + } + else + { + active->vec->push_back(mapbox::feature::value(static_cast(value))); + } + return true; + } + + bool attribute_value(bool value, std::size_t /*depth*/) + { + if (active->is_map) + { + active->map->emplace(std::string(active->last_key), mapbox::feature::value(value)); + } + else + { + active->vec->push_back(mapbox::feature::value(value)); + } + return true; + } + + bool start_list_attribute(std::size_t size, std::size_t /*depth*/) + { + stack.push_back({nullptr, std::make_unique(), {}, nullptr, false}); + active = &(stack.back()); + active->vec->reserve(size); + return true; + } + + bool end_list_attribute(std::size_t /*depth*/) + { + auto* prev_active = &*(++(stack.rbegin())); + if (prev_active->is_map) + { + prev_active->map->emplace(std::string(prev_active->last_key), mapbox::feature::value(vec_result())); + } + else + { + prev_active->vec->push_back(mapbox::feature::value(vec_result())); + } + stack.pop_back(); + active = prev_active; + return true; + } + + bool start_map_attribute(std::size_t size, std::size_t /*depth*/) + { + stack.push_back({std::make_unique(), nullptr, {}, nullptr, true}); + active = &(stack.back()); + active->map->reserve(size); + return true; + } + + bool end_map_attribute(std::size_t /*depth*/) + { + auto* prev_active = &*(++(stack.rbegin())); + if (prev_active->is_map) + { + prev_active->map->emplace(std::string(prev_active->last_key), mapbox::feature::value(result())); + } + else + { + prev_active->vec->push_back(mapbox::feature::value(result())); + } + stack.pop_back(); + active = prev_active; + return true; + } + + bool start_number_list(std::size_t size, vtzero::index_value index, std::size_t /*depth*/) + { + auto const& scaling = layer.attribute_scaling(index); + stack.push_back({nullptr, std::make_unique(), {}, &scaling, false}); + active = &(stack.back()); + active->vec->reserve(size); + return true; + } + + bool number_list_null_value(std::size_t /*depth*/) + { + active->vec->push_back(mapbox::feature::value(mapbox::feature::null_value_t())); + return true; + } + + bool number_list_value(int64_t value, std::size_t /*depth*/) + { + active->vec->push_back(mapbox::feature::value(active->scaling->decode(value))); + return true; + } + + bool end_number_list(std::size_t /*depth*/) + { + auto* prev_active = &*(++(stack.rbegin())); + if (prev_active->is_map) + { + prev_active->map->emplace(std::string(prev_active->last_key), mapbox::feature::value(vec_result())); + } + else + { + prev_active->vec->push_back(mapbox::feature::value(vec_result())); + } + stack.pop_back(); + active = prev_active; + return true; + } +}; + +} // end ns detail +} +} diff --git a/include/mapbox/vector_tile/builder.hpp b/include/mapbox/vector_tile/builder.hpp index fa8055d..092b119 100644 --- a/include/mapbox/vector_tile/builder.hpp +++ b/include/mapbox/vector_tile/builder.hpp @@ -8,6 +8,12 @@ namespace mapbox { namespace vector_tile { +template +vtzero::point_2d convert(mapbox::geometry::point pt) +{ + return {static_cast(pt.x), static_cast(pt.y)}; +} + template struct id_visitor { @@ -18,15 +24,12 @@ struct id_visitor void operator()(std::uint64_t val) { - fbuilder.set_id(val); + fbuilder.set_integer_id(val); } void operator()(std::int64_t val) { - if (0 <= val) - { - fbuilder.set_id(static_cast(val)); - } + fbuilder.set_integer_id(static_cast(val)); } template @@ -128,10 +131,10 @@ struct feature_builder_visitor template void operator()(mapbox::geometry::point const& pt) { - using builder_type = vtzero::point_feature_builder; + using builder_type = vtzero::point_feature_builder<2>; builder_type fbuilder{lbuilder}; mapbox::util::apply_visitor(id_visitor(fbuilder), id); - fbuilder.add_point(pt); + fbuilder.add_point(convert(pt)); set_properties(fbuilder, prop); fbuilder.commit(); } @@ -139,14 +142,18 @@ struct feature_builder_visitor template void operator()(mapbox::geometry::multi_point const& mp) { - using builder_type = vtzero::point_feature_builder; + using builder_type = vtzero::point_feature_builder<2>; if (mp.empty()) { return; } builder_type fbuilder{lbuilder}; mapbox::util::apply_visitor(id_visitor(fbuilder), id); - fbuilder.add_points_from_container(mp); + fbuilder.add_points(static_cast(mp.size())); + for (auto const& pt : mp) + { + fbuilder.set_point(convert(pt)); + } set_properties(fbuilder, prop); fbuilder.commit(); } @@ -154,7 +161,7 @@ struct feature_builder_visitor template void operator()(mapbox::geometry::line_string const& ls) { - using builder_type = vtzero::linestring_feature_builder; + using builder_type = vtzero::linestring_feature_builder<2>; std::uint32_t s = size_no_repeats(ls); if (s < 2) { @@ -163,12 +170,12 @@ struct feature_builder_visitor builder_type fbuilder{lbuilder}; mapbox::util::apply_visitor(id_visitor(fbuilder), id); fbuilder.add_linestring(s); - fbuilder.set_point(ls.front()); + fbuilder.set_point(convert(ls.front())); for (std::size_t i = 1; i < ls.size(); ++i) { if (ls[i] != ls[i - 1]) { - fbuilder.set_point(ls[i]); + fbuilder.set_point(convert(ls[i])); } } set_properties(fbuilder, prop); @@ -178,7 +185,7 @@ struct feature_builder_visitor template void operator()(mapbox::geometry::multi_line_string const& mls) { - using builder_type = vtzero::linestring_feature_builder; + using builder_type = vtzero::linestring_feature_builder<2>; if (mls.empty()) { return; @@ -194,12 +201,12 @@ struct feature_builder_visitor continue; } fbuilder.add_linestring(s); - fbuilder.set_point(ls.front()); + fbuilder.set_point(convert(ls.front())); for (std::size_t i = 1; i < ls.size(); ++i) { if (ls[i] != ls[i - 1]) { - fbuilder.set_point(ls[i]); + fbuilder.set_point(convert(ls[i])); } } empty = false; @@ -218,7 +225,7 @@ struct feature_builder_visitor template void operator()(mapbox::geometry::polygon const& poly) { - using builder_type = vtzero::polygon_feature_builder; + using builder_type = vtzero::polygon_feature_builder<2>; if (poly.empty()) { return; @@ -237,12 +244,12 @@ struct feature_builder_visitor else if (s >= 4) { fbuilder.add_ring(s); - fbuilder.set_point(ring.front()); + fbuilder.set_point(convert(ring.front())); for (std::size_t i = 1; i < ring.size(); ++i) { if (ring[i] != ring[i - 1]) { - fbuilder.set_point(ring[i]); + fbuilder.set_point(convert(ring[i])); } } } @@ -255,7 +262,7 @@ struct feature_builder_visitor template void operator()(mapbox::geometry::multi_polygon const& mp) { - using builder_type = vtzero::polygon_feature_builder; + using builder_type = vtzero::polygon_feature_builder<2>; builder_type fbuilder{lbuilder}; mapbox::util::apply_visitor(id_visitor(fbuilder), id); for (auto const& poly : mp) @@ -272,12 +279,12 @@ struct feature_builder_visitor else if (s >= 4) { fbuilder.add_ring(s); - fbuilder.set_point(ring.front()); + fbuilder.set_point(convert(ring.front())); for (std::size_t i = 1; i < ring.size(); ++i) { if (ring[i] != ring[i - 1]) { - fbuilder.set_point(ring[i]); + fbuilder.set_point(convert(ring[i])); } } } diff --git a/include/mapbox/vector_tile/handlers.hpp b/include/mapbox/vector_tile/handlers.hpp index ab51a83..0ad0ed0 100644 --- a/include/mapbox/vector_tile/handlers.hpp +++ b/include/mapbox/vector_tile/handlers.hpp @@ -10,6 +10,8 @@ namespace detail { template struct point_geometry_handler { + constexpr static const int dimensions = 2; + constexpr static const unsigned int max_geometric_attributes = 0; using geom_type = mapbox::geometry::multi_point; @@ -24,7 +26,7 @@ struct point_geometry_handler geom_.reserve(count); } - void points_point(const vtzero::point pt) + void points_point(const vtzero::point_2d pt) { geom_.emplace_back(pt.x, pt.y); } @@ -39,7 +41,7 @@ mapbox::geometry::geometry extract_geometry_point(vtzero::featur { mapbox::geometry::multi_point mp; - vtzero::decode_point_geometry(f.geometry(), detail::point_geometry_handler(mp)); + f.decode_point_geometry(detail::point_geometry_handler(mp)); if (mp.empty()) { return mapbox::geometry::geometry(); @@ -58,6 +60,8 @@ mapbox::geometry::geometry extract_geometry_point(vtzero::featur template struct line_string_geometry_handler { + constexpr static const int dimensions = 2; + constexpr static const unsigned int max_geometric_attributes = 0; using geom_type = mapbox::geometry::multi_line_string; @@ -73,7 +77,7 @@ struct line_string_geometry_handler geom_.back().reserve(count); } - void linestring_point(const vtzero::point pt) + void linestring_point(const vtzero::point_2d pt) { geom_.back().emplace_back(pt.x, pt.y); } @@ -98,6 +102,8 @@ struct polygon_ring template struct polygon_geometry_handler { + constexpr static const int dimensions = 2; + constexpr static const unsigned int max_geometric_attributes = 0; using geom_type = std::vector>; @@ -113,7 +119,7 @@ struct polygon_geometry_handler geom_.back().ring.reserve(count); } - void ring_point(const vtzero::point pt) + void ring_point(const vtzero::point_2d pt) { geom_.back().ring.emplace_back(pt.x, pt.y); } @@ -129,7 +135,7 @@ mapbox::geometry::geometry extract_geometry_polygon(vtzero::feat { std::vector> rings; - vtzero::decode_polygon_geometry(f.geometry(), detail::polygon_geometry_handler(rings)); + f.decode_polygon_geometry(detail::polygon_geometry_handler(rings)); if (rings.empty()) { return mapbox::geometry::geometry(); @@ -169,7 +175,7 @@ mapbox::geometry::geometry extract_geometry_line_string(vtzero:: { mapbox::geometry::multi_line_string mls; - vtzero::decode_linestring_geometry(f.geometry(), detail::line_string_geometry_handler(mls)); + f.decode_linestring_geometry(detail::line_string_geometry_handler(mls)); if (mls.empty()) { return mapbox::geometry::geometry(); diff --git a/include/mapbox/vector_tile/version.hpp b/include/mapbox/vector_tile/version.hpp index 2bb268a..c52178d 100644 --- a/include/mapbox/vector_tile/version.hpp +++ b/include/mapbox/vector_tile/version.hpp @@ -4,7 +4,7 @@ #define VECTOR_TILE_VERSION_MAJOR 2 /// The minor version number -#define VECTOR_TILE_VERSION_MINOR 0 +#define VECTOR_TILE_VERSION_MINOR 1 /// The patch number #define VECTOR_TILE_VERSION_PATCH 0 @@ -13,4 +13,4 @@ #define VECTOR_TILE_VERSION_CODE (VECTOR_TILE_VERSION_MAJOR * 10000 + VECTOR_TILE_VERSION_MINOR * 100 + VECTOR_TILE_VERSION_PATCH) /// Version number as string -#define VECTOR_TILE_VERSION_STRING "2.0.0" +#define VECTOR_TILE_VERSION_STRING "2.1.0" diff --git a/test/unit/builder.test.cpp b/test/unit/builder.test.cpp index 166915e..0d2702a 100644 --- a/test/unit/builder.test.cpp +++ b/test/unit/builder.test.cpp @@ -61,7 +61,8 @@ TEST_CASE("Encode feature") REQUIRE(l.second.size() == 1); for (auto const& f : l.second) { - REQUIRE(f.id.is()); + REQUIRE(f.id.is()); + CHECK(f.id.get() == 18446744073709551606ULL); REQUIRE(f.geometry.is>()); prop_out = f.properties; pt_out = f.geometry.get>();