This is an automated email from the git hooks/post-receive script. sebastic pushed a commit to branch master in repository libosmium.
commit e7709959e84dda3dca58cb628c84baa082a6a422 Author: Bas Couwenberg <[email protected]> Date: Thu Feb 25 09:25:04 2016 +0100 Imported Upstream version 2.6.1 --- CHANGELOG.md | 19 ++- CMakeLists.txt | 9 +- examples/osmium_area_test.cpp | 12 +- include/osmium/area/assembler.hpp | 30 ++-- include/osmium/area/detail/proto_ring.hpp | 8 + include/osmium/area/detail/segment_list.hpp | 27 +++- include/osmium/io/detail/pbf_output_format.hpp | 55 +++---- include/osmium/io/detail/protobuf_tags.hpp | 2 +- include/osmium/relations/collector.hpp | 95 ++++++----- include/osmium/relations/detail/member_meta.hpp | 15 -- include/osmium/util/iterator.hpp | 74 +++++++++ include/osmium/util/memory.hpp | 6 +- include/protozero/config.hpp | 4 +- include/protozero/exception.hpp | 8 +- include/protozero/pbf_builder.hpp | 14 +- include/protozero/pbf_message.hpp | 2 +- include/protozero/pbf_reader.hpp | 40 +++-- include/protozero/pbf_writer.hpp | 202 ++++++++++++++++++++++-- include/protozero/{pbf_types.hpp => types.hpp} | 8 +- include/protozero/varint.hpp | 4 +- include/protozero/version.hpp | 6 +- test/t/basic/test_node_ref.cpp | 52 ++++++ 22 files changed, 517 insertions(+), 175 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ca6518..3946448 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,22 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed +## [2.6.1] - 2016-02-22 + +### Added + +- Add `WITH_PROFILING` option to CMake config. When enabled, this sets the + `-fno-omit-frame-pointer` compiler option. + +### Changed + +- Massive speed improvements when building multipolygons. +- Uses (and includes) new version 1.3.0 of protozero library. +- Removed dependency on Boost Iterator for PBF writer. +- Example program `osmium_area_test` now uses `cerr` instead of `cout` for + debug output. + + ## [2.6.0] - 2016-02-04 ### Added @@ -260,7 +276,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). Doxygen (up to version 1.8.8). This version contains a workaround to fix this. -[unreleased]: https://github.com/osmcode/libosmium/compare/v2.6.0...HEAD +[unreleased]: https://github.com/osmcode/libosmium/compare/v2.6.1...HEAD +[2.6.1]: https://github.com/osmcode/libosmium/compare/v2.6.0...v2.6.1 [2.6.0]: https://github.com/osmcode/libosmium/compare/v2.5.4...v2.6.0 [2.5.4]: https://github.com/osmcode/libosmium/compare/v2.5.3...v2.5.4 [2.5.3]: https://github.com/osmcode/libosmium/compare/v2.5.2...v2.5.3 diff --git a/CMakeLists.txt b/CMakeLists.txt index 7339467..bc9b12e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ project(libosmium) set(LIBOSMIUM_VERSION_MAJOR 2) set(LIBOSMIUM_VERSION_MINOR 6) -set(LIBOSMIUM_VERSION_PATCH 0) +set(LIBOSMIUM_VERSION_PATCH 1) set(LIBOSMIUM_VERSION "${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH}") @@ -58,6 +58,8 @@ option(INSTALL_GDALCPP "also install gdalcpp headers" OFF) option(INSTALL_PROTOZERO "also install protozero headers" OFF) option(INSTALL_UTFCPP "also install utfcpp headers" OFF) +option(WITH_PROFILING "add flags needed for profiling" OFF) + #----------------------------------------------------------------------------- # @@ -205,12 +207,17 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${USUAL_COMPILE_OPTIONS}" CACHE STRING "Flags used by the compiler during RELWITHDEBINFO builds." FORCE) +if(WITH_PROFILING) + add_definitions(-fno-omit-frame-pointer) +endif() + #----------------------------------------------------------------------------- # # Build Type # #----------------------------------------------------------------------------- + # In 'Dev' mode: compile with very strict warnings and turn them into errors. if(CMAKE_BUILD_TYPE STREQUAL "Dev") if(NOT MSVC) diff --git a/examples/osmium_area_test.cpp b/examples/osmium_area_test.cpp index f072c5e..e9b7a18 100644 --- a/examples/osmium_area_test.cpp +++ b/examples/osmium_area_test.cpp @@ -99,13 +99,13 @@ int main(int argc, char* argv[]) { osmium::area::Assembler::config_type assembler_config; osmium::area::MultipolygonCollector<osmium::area::Assembler> collector(assembler_config); - std::cout << "Pass 1...\n"; + std::cerr << "Pass 1...\n"; osmium::io::Reader reader1(infile, osmium::osm_entity_bits::relation); collector.read_relations(reader1); reader1.close(); - std::cout << "Pass 1 done\n"; + std::cerr << "Pass 1 done\n"; - std::cout << "Memory:\n"; + std::cerr << "Memory:\n"; collector.used_memory(); index_pos_type index_pos; @@ -113,15 +113,15 @@ int main(int argc, char* argv[]) { location_handler_type location_handler(index_pos, index_neg); location_handler.ignore_errors(); // XXX - std::cout << "Pass 2...\n"; + std::cerr << "Pass 2...\n"; osmium::io::Reader reader2(infile); osmium::apply(reader2, location_handler, collector.handler([&handler](osmium::memory::Buffer&& buffer) { osmium::apply(buffer, handler); })); reader2.close(); - std::cout << "Pass 2 done\n"; + std::cerr << "Pass 2 done\n"; - std::cout << "Memory:\n"; + std::cerr << "Memory:\n"; collector.used_memory(); std::vector<const osmium::Relation*> incomplete_relations = collector.get_incomplete_relations(); diff --git a/include/osmium/area/assembler.hpp b/include/osmium/area/assembler.hpp index 1d9b0df..a2d1c8e 100644 --- a/include/osmium/area/assembler.hpp +++ b/include/osmium/area/assembler.hpp @@ -232,7 +232,7 @@ namespace osmium { if (!ring.closed()) { open_rings = true; if (m_config.problem_reporter) { - m_config.problem_reporter->report_ring_not_closed(ring.get_segment_front().first().location(), ring.get_segment_back().second().location()); + m_config.problem_reporter->report_ring_not_closed(ring.get_node_ref_front().location(), ring.get_node_ref_back().location()); } } } @@ -248,14 +248,14 @@ namespace osmium { * true. */ bool possibly_combine_rings_back(ProtoRing& ring) { - const osmium::NodeRef& nr = ring.get_segment_back().second(); + const osmium::NodeRef& nr = ring.get_node_ref_back(); if (debug()) { std::cerr << " possibly_combine_rings_back()\n"; } for (auto it = m_rings.begin(); it != m_rings.end(); ++it) { if (&*it != &ring && !it->closed()) { - if (has_same_location(nr, it->get_segment_front().first())) { + if (has_same_location(nr, it->get_node_ref_front())) { if (debug()) { std::cerr << " ring.last=it->first\n"; } @@ -263,7 +263,7 @@ namespace osmium { m_rings.erase(it); return true; } - if (has_same_location(nr, it->get_segment_back().second())) { + if (has_same_location(nr, it->get_node_ref_back())) { if (debug()) { std::cerr << " ring.last=it->last\n"; } @@ -284,14 +284,14 @@ namespace osmium { * true. */ bool possibly_combine_rings_front(ProtoRing& ring) { - const osmium::NodeRef& nr = ring.get_segment_front().first(); + const osmium::NodeRef& nr = ring.get_node_ref_front(); if (debug()) { std::cerr << " possibly_combine_rings_front()\n"; } for (auto it = m_rings.begin(); it != m_rings.end(); ++it) { if (&*it != &ring && !it->closed()) { - if (has_same_location(nr, it->get_segment_back().second())) { + if (has_same_location(nr, it->get_node_ref_back())) { if (debug()) { std::cerr << " ring.first=it->last\n"; } @@ -300,7 +300,7 @@ namespace osmium { m_rings.erase(it); return true; } - if (has_same_location(nr, it->get_segment_front().first())) { + if (has_same_location(nr, it->get_node_ref_front())) { if (debug()) { std::cerr << " ring.first=it->first\n"; } @@ -368,7 +368,7 @@ namespace osmium { } osmium::area::detail::ProtoRing::segments_type segments(ring.segments().size()); - std::copy(ring.segments().begin(), ring.segments().end(), segments.begin()); + std::copy(ring.segments().cbegin(), ring.segments().cend(), segments.begin()); std::sort(segments.begin(), segments.end()); const auto it = std::adjacent_find(segments.begin(), segments.end(), [this](const osmium::area::detail::NodeRefSegment& s1, const osmium::area::detail::NodeRefSegment& s2) { return has_same_location(s1.first(), s2.first()); @@ -433,14 +433,14 @@ namespace osmium { } { osmium::builder::OuterRingBuilder ring_builder(builder.buffer(), &builder); - ring_builder.add_node_ref(ring->get_segment_front().first()); + ring_builder.add_node_ref(ring->get_node_ref_front()); for (const auto& segment : ring->segments()) { ring_builder.add_node_ref(segment.second()); } } for (ProtoRing* inner : ring->inner_rings()) { osmium::builder::InnerRingBuilder ring_builder(builder.buffer(), &builder); - ring_builder.add_node_ref(inner->get_segment_front().first()); + ring_builder.add_node_ref(inner->get_node_ref_front()); for (const auto& segment : inner->segments()) { ring_builder.add_node_ref(segment.second()); } @@ -459,21 +459,21 @@ namespace osmium { std::cerr << " => ring CLOSED\n"; } } else { - if (has_same_location(ring.get_segment_back().second(), segment.first())) { + if (has_same_location(ring.get_node_ref_back(), segment.first())) { combine_rings_back(segment, ring); return true; } - if (has_same_location(ring.get_segment_back().second(), segment.second())) { + if (has_same_location(ring.get_node_ref_back(), segment.second())) { segment.swap_locations(); combine_rings_back(segment, ring); return true; } - if (has_same_location(ring.get_segment_front().first(), segment.first())) { + if (has_same_location(ring.get_node_ref_front(), segment.first())) { segment.swap_locations(); combine_rings_front(segment, ring); return true; } - if (has_same_location(ring.get_segment_front().first(), segment.second())) { + if (has_same_location(ring.get_node_ref_front(), segment.second())) { combine_rings_front(segment, ring); return true; } @@ -696,7 +696,7 @@ namespace osmium { } // Now create the Area object and add the attributes and tags - // from the relation. + // from the way. { osmium::builder::AreaBuilder builder(out_buffer); builder.initialize_from_object(way); diff --git a/include/osmium/area/detail/proto_ring.hpp b/include/osmium/area/detail/proto_ring.hpp index 59478dc..c4edf40 100644 --- a/include/osmium/area/detail/proto_ring.hpp +++ b/include/osmium/area/detail/proto_ring.hpp @@ -118,6 +118,10 @@ namespace osmium { return m_segments.front(); } + const NodeRef& get_node_ref_front() const { + return get_segment_front().first(); + } + const NodeRefSegment& get_segment_back() const { return m_segments.back(); } @@ -126,6 +130,10 @@ namespace osmium { return m_segments.back(); } + const NodeRef& get_node_ref_back() const { + return get_segment_back().second(); + } + bool closed() const { return m_segments.front().first().location() == m_segments.back().second().location(); } diff --git a/include/osmium/area/detail/segment_list.hpp b/include/osmium/area/detail/segment_list.hpp index 29eec58..05e0cd8 100644 --- a/include/osmium/area/detail/segment_list.hpp +++ b/include/osmium/area/detail/segment_list.hpp @@ -58,7 +58,7 @@ namespace osmium { */ class SegmentList { - typedef std::vector<NodeRefSegment> slist_type; + using slist_type = std::vector<NodeRefSegment>; slist_type m_segments; @@ -67,10 +67,11 @@ namespace osmium { public: explicit SegmentList(bool debug) noexcept : + m_segments(), m_debug(debug) { } - ~SegmentList() = default; + ~SegmentList() noexcept = default; SegmentList(const SegmentList&) = delete; SegmentList(SegmentList&&) = delete; @@ -88,6 +89,15 @@ namespace osmium { } typedef slist_type::const_iterator const_iterator; + typedef slist_type::iterator iterator; + + iterator begin() noexcept { + return m_segments.begin(); + } + + iterator end() noexcept { + return m_segments.end(); + } const_iterator begin() const noexcept { return m_segments.begin(); @@ -98,8 +108,8 @@ namespace osmium { } /** - * Enable or disable debug output to stderr. This is for Osmium - * developers only. + * Enable or disable debug output to stderr. This is used + * for debugging libosmium itself. */ void enable_debug_output(bool debug = true) noexcept { m_debug = debug; @@ -148,9 +158,9 @@ namespace osmium { /** * Find duplicate segments (ie same start and end point) in the - * list and remove them. This will always remove pairs of the same - * segment. So if there are three, for instance, two will be - * removed and one will be left. + * list and remove them. This will always remove pairs of the + * same segment. So if there are three, for instance, two will + * be removed and one will be left. */ void erase_duplicate_segments() { while (true) { @@ -168,7 +178,8 @@ namespace osmium { /** * Find intersection between segments. * - * @param problem_reporter Any intersections found are reported to this object. + * @param problem_reporter Any intersections found are + * reported to this object. * @returns true if there are intersections. */ bool find_intersections(osmium::area::ProblemReporter* problem_reporter) const { diff --git a/include/osmium/io/detail/pbf_output_format.hpp b/include/osmium/io/detail/pbf_output_format.hpp index 02b543f..878d7b4 100644 --- a/include/osmium/io/detail/pbf_output_format.hpp +++ b/include/osmium/io/detail/pbf_output_format.hpp @@ -44,10 +44,6 @@ DEALINGS IN THE SOFTWARE. #include <time.h> #include <utility> -// needed for older boost libraries -#define BOOST_RESULT_OF_USE_DECLTYPE -#include <boost/iterator/transform_iterator.hpp> - #include <protozero/pbf_builder.hpp> #include <osmium/handler.hpp> @@ -441,22 +437,19 @@ namespace osmium { template <typename T> void add_meta(const osmium::OSMObject& object, T& pbf_object) { - const osmium::TagList& tags = object.tags(); - - auto map_tag_key = [this](const osmium::Tag& tag) -> uint32_t { - return m_primitive_block.store_in_stringtable(tag.key()); - }; - auto map_tag_value = [this](const osmium::Tag& tag) -> uint32_t { - return m_primitive_block.store_in_stringtable(tag.value()); - }; - - pbf_object.add_packed_uint32(T::enum_type::packed_uint32_keys, - boost::make_transform_iterator(tags.begin(), map_tag_key), - boost::make_transform_iterator(tags.end(), map_tag_key)); + { + protozero::packed_field_uint32 field{pbf_object, protozero::pbf_tag_type(T::enum_type::packed_uint32_keys)}; + for (const auto& tag : object.tags()) { + field.add_element(m_primitive_block.store_in_stringtable(tag.key())); + } + } - pbf_object.add_packed_uint32(T::enum_type::packed_uint32_vals, - boost::make_transform_iterator(tags.begin(), map_tag_value), - boost::make_transform_iterator(tags.end(), map_tag_value)); + { + protozero::packed_field_uint32 field{pbf_object, protozero::pbf_tag_type(T::enum_type::packed_uint32_vals)}; + for (const auto& tag : object.tags()) { + field.add_element(m_primitive_block.store_in_stringtable(tag.value())); + } + } if (m_options.add_metadata) { protozero::pbf_builder<OSMFormat::Info> pbf_info(pbf_object, T::enum_type::optional_Info_info); @@ -596,12 +589,12 @@ namespace osmium { pbf_relation.add_int64(OSMFormat::Relation::required_int64_id, relation.id()); add_meta(relation, pbf_relation); - auto map_member_role = [this](const osmium::RelationMember& member) -> uint32_t { - return m_primitive_block.store_in_stringtable(member.role()); - }; - pbf_relation.add_packed_int32(OSMFormat::Relation::packed_int32_roles_sid, - boost::make_transform_iterator(relation.members().begin(), map_member_role), - boost::make_transform_iterator(relation.members().end(), map_member_role)); + { + protozero::packed_field_int32 field{pbf_relation, protozero::pbf_tag_type(OSMFormat::Relation::packed_int32_roles_sid)}; + for (const auto& member : relation.members()) { + field.add_element(m_primitive_block.store_in_stringtable(member.role())); + } + } static auto map_member_ref = [](osmium::RelationMemberList::const_iterator member) noexcept -> osmium::object_id_type { return member->ref(); @@ -612,12 +605,12 @@ namespace osmium { it_type last { members.cend(), members.cend(), map_member_ref }; pbf_relation.add_packed_sint64(OSMFormat::Relation::packed_sint64_memids, first, last); - static auto map_member_type = [](const osmium::RelationMember& member) noexcept -> int32_t { - return int32_t(osmium::item_type_to_nwr_index(member.type())); - }; - pbf_relation.add_packed_int32(OSMFormat::Relation::packed_MemberType_types, - boost::make_transform_iterator(relation.members().begin(), map_member_type), - boost::make_transform_iterator(relation.members().end(), map_member_type)); + { + protozero::packed_field_int32 field{pbf_relation, protozero::pbf_tag_type(OSMFormat::Relation::packed_MemberType_types)}; + for (const auto& member : relation.members()) { + field.add_element(int32_t(osmium::item_type_to_nwr_index(member.type()))); + } + } } }; // class PBFOutputFormat diff --git a/include/osmium/io/detail/protobuf_tags.hpp b/include/osmium/io/detail/protobuf_tags.hpp index 1106f03..bdaabba 100644 --- a/include/osmium/io/detail/protobuf_tags.hpp +++ b/include/osmium/io/detail/protobuf_tags.hpp @@ -33,7 +33,7 @@ DEALINGS IN THE SOFTWARE. */ -#include <protozero/pbf_types.hpp> +#include <protozero/types.hpp> namespace osmium { diff --git a/include/osmium/relations/collector.hpp b/include/osmium/relations/collector.hpp index af9d63c..7d7d14d 100644 --- a/include/osmium/relations/collector.hpp +++ b/include/osmium/relations/collector.hpp @@ -49,6 +49,7 @@ DEALINGS IN THE SOFTWARE. #include <osmium/osm/types.hpp> #include <osmium/handler.hpp> #include <osmium/memory/buffer.hpp> +#include <osmium/util/iterator.hpp> #include <osmium/visitor.hpp> #include <osmium/relations/detail/relation_meta.hpp> @@ -61,6 +62,17 @@ namespace osmium { */ namespace relations { + namespace detail { + + template <typename R> + inline typename std::iterator_traits<typename R::iterator>::difference_type count_not_removed(const R& range) { + return std::count_if(range.begin(), range.end(), [](MemberMeta& mm) { + return !mm.removed(); + }); + } + + } // namespace detail + /** * The Collector class collects members of a relation. This is a generic * base class that can be used to assemble all kinds of relations. It has numerous @@ -175,7 +187,9 @@ namespace osmium { * One vector each for nodes, ways, and relations containing all * mappings from member ids to their relations. */ - std::vector<MemberMeta> m_member_meta[3]; + using mm_vector_type = std::vector<MemberMeta>; + using mm_iterator = mm_vector_type::iterator; + mm_vector_type m_member_meta[3]; int m_count_complete = 0; @@ -184,6 +198,11 @@ namespace osmium { static constexpr size_t initial_buffer_size = 1024 * 1024; + iterator_range<mm_iterator> find_member_meta(osmium::item_type type, osmium::object_id_type id) { + auto& mmv = member_meta(type); + return iterator_range<mm_iterator>{std::equal_range(mmv.begin(), mmv.end(), MemberMeta(id))}; + } + public: /** @@ -367,10 +386,9 @@ namespace osmium { * relation and false otherwise */ bool find_and_add_object(const osmium::OSMObject& object) { - auto& mmv = member_meta(object.type()); - auto range = std::equal_range(mmv.begin(), mmv.end(), MemberMeta(object.id())); + auto range = find_member_meta(object.type(), object.id()); - if (osmium::relations::count_not_removed(range.first, range.second) == 0) { + if (detail::count_not_removed(range) == 0) { // nothing found return false; } @@ -379,13 +397,12 @@ namespace osmium { members_buffer().add_item(object); const size_t member_offset = members_buffer().commit(); - for (auto it = range.first; it != range.second; ++it) { - it->set_buffer_offset(member_offset); + for (auto& member_meta : range) { + member_meta.set_buffer_offset(member_offset); } } - for (auto it = range.first; it != range.second; ++it) { - MemberMeta& member_meta = *it; + for (auto& member_meta : range) { if (member_meta.removed()) { break; } @@ -405,11 +422,6 @@ namespace osmium { } } - // Remove MemberMetas that were marked as removed. - mmv.erase(std::remove_if(mmv.begin(), mmv.end(), [](MemberMeta& mm) { - return mm.removed(); - }), mmv.end()); - return true; } @@ -417,19 +429,18 @@ namespace osmium { const osmium::Relation& relation = get_relation(relation_meta); for (const auto& member : relation.members()) { if (member.ref() != 0) { - auto& mmv = member_meta(member.type()); - auto range = std::equal_range(mmv.begin(), mmv.end(), MemberMeta(member.ref())); - assert(range.first != range.second); + auto range = find_member_meta(member.type(), member.ref()); + assert(!range.empty()); // if this is the last time this object was needed // then mark it as removed - if (osmium::relations::count_not_removed(range.first, range.second) == 1) { - get_member(range.first->buffer_offset()).set_removed(true); + if (detail::count_not_removed(range) == 1) { + get_member(range.begin()->buffer_offset()).set_removed(true); } - for (auto it = range.first; it != range.second; ++it) { - if (!it->removed() && relation.id() == get_relation(it->relation_pos()).id()) { - it->remove(); + for (auto& member_meta : range) { + if (!member_meta.removed() && relation.id() == get_relation(member_meta.relation_pos()).id()) { + member_meta.remove(); break; } } @@ -446,24 +457,24 @@ namespace osmium { const uint64_t relations_buffer_capacity = m_relations_buffer.capacity(); const uint64_t members_buffer_capacity = m_members_buffer.capacity(); - std::cout << " nR = m_relations.capacity() ........... = " << std::setw(12) << m_relations.capacity() << "\n"; - std::cout << " nMN = m_member_meta[NODE].capacity() ... = " << std::setw(12) << m_member_meta[0].capacity() << "\n"; - std::cout << " nMW = m_member_meta[WAY].capacity() .... = " << std::setw(12) << m_member_meta[1].capacity() << "\n"; - std::cout << " nMR = m_member_meta[RELATION].capacity() = " << std::setw(12) << m_member_meta[2].capacity() << "\n"; - std::cout << " nM = m_member_meta[*].capacity() ...... = " << std::setw(12) << nmembers << "\n"; + std::cerr << " nR = m_relations.capacity() ........... = " << std::setw(12) << m_relations.capacity() << "\n"; + std::cerr << " nMN = m_member_meta[NODE].capacity() ... = " << std::setw(12) << m_member_meta[0].capacity() << "\n"; + std::cerr << " nMW = m_member_meta[WAY].capacity() .... = " << std::setw(12) << m_member_meta[1].capacity() << "\n"; + std::cerr << " nMR = m_member_meta[RELATION].capacity() = " << std::setw(12) << m_member_meta[2].capacity() << "\n"; + std::cerr << " nM = m_member_meta[*].capacity() ...... = " << std::setw(12) << nmembers << "\n"; - std::cout << " sRM = sizeof(RelationMeta) ............. = " << std::setw(12) << sizeof(RelationMeta) << "\n"; - std::cout << " sMM = sizeof(MemberMeta) ............... = " << std::setw(12) << sizeof(MemberMeta) << "\n\n"; + std::cerr << " sRM = sizeof(RelationMeta) ............. = " << std::setw(12) << sizeof(RelationMeta) << "\n"; + std::cerr << " sMM = sizeof(MemberMeta) ............... = " << std::setw(12) << sizeof(MemberMeta) << "\n\n"; - std::cout << " nR * sRM ............................... = " << std::setw(12) << relations << "\n"; - std::cout << " nM * sMM ............................... = " << std::setw(12) << members << "\n"; - std::cout << " relations_buffer_capacity .............. = " << std::setw(12) << relations_buffer_capacity << "\n"; - std::cout << " members_buffer_capacity ................ = " << std::setw(12) << members_buffer_capacity << "\n"; + std::cerr << " nR * sRM ............................... = " << std::setw(12) << relations << "\n"; + std::cerr << " nM * sMM ............................... = " << std::setw(12) << members << "\n"; + std::cerr << " relations_buffer_capacity .............. = " << std::setw(12) << relations_buffer_capacity << "\n"; + std::cerr << " members_buffer_capacity ................ = " << std::setw(12) << members_buffer_capacity << "\n"; const uint64_t total = relations + members + relations_buffer_capacity + members_buffer_capacity; - std::cout << " total .................................. = " << std::setw(12) << total << "\n"; - std::cout << " =======================================================\n"; + std::cerr << " total .................................. = " << std::setw(12) << total << "\n"; + std::cerr << " =======================================================\n"; return relations_buffer_capacity + members_buffer_capacity + relations + members; } @@ -481,10 +492,9 @@ namespace osmium { } size_t get_offset(osmium::item_type type, osmium::object_id_type id) { - const auto& mmv = member_meta(type); - const auto range = std::equal_range(mmv.cbegin(), mmv.cend(), MemberMeta(id)); - assert(range.first != range.second); - return range.first->buffer_offset(); + const auto range = find_member_meta(type, id); + assert(!range.empty()); + return range.begin()->buffer_offset(); } template <typename TIter> @@ -502,11 +512,10 @@ namespace osmium { void moving_in_buffer(size_t old_offset, size_t new_offset) { const osmium::OSMObject& object = m_members_buffer.get<osmium::OSMObject>(old_offset); - auto& mmv = member_meta(object.type()); - auto range = std::equal_range(mmv.begin(), mmv.end(), MemberMeta(object.id())); - for (auto it = range.first; it != range.second; ++it) { - assert(it->buffer_offset() == old_offset); - it->set_buffer_offset(new_offset); + auto range = find_member_meta(object.type(), object.id()); + for (auto& member_meta : range) { + assert(member_meta.buffer_offset() == old_offset); + member_meta.set_buffer_offset(new_offset); } } diff --git a/include/osmium/relations/detail/member_meta.hpp b/include/osmium/relations/detail/member_meta.hpp index a540f43..f0e9c36 100644 --- a/include/osmium/relations/detail/member_meta.hpp +++ b/include/osmium/relations/detail/member_meta.hpp @@ -136,21 +136,6 @@ namespace osmium { return out; } - /** - * Count the number of MemberMeta objects in the iterator range - * that are not marked as removed. - * - * @tparam TIter Iterator that dereferences to a MemberMeta - * @param begin Begin of iterator range - * @param end End of iterator range - */ - template <typename TIter> - inline typename std::iterator_traits<TIter>::difference_type count_not_removed(TIter begin, TIter end) { - return std::count_if(begin, end, [](MemberMeta& mm) { - return !mm.removed(); - }); - } - } // namespace relations } // namespace osmium diff --git a/include/osmium/util/iterator.hpp b/include/osmium/util/iterator.hpp new file mode 100644 index 0000000..4cef519 --- /dev/null +++ b/include/osmium/util/iterator.hpp @@ -0,0 +1,74 @@ +#ifndef OSMIUM_UTIL_ITERATOR_HPP +#define OSMIUM_UTIL_ITERATOR_HPP + +/* + +This file is part of Osmium (http://osmcode.org/libosmium). + +Copyright 2013-2016 Jochen Topf <[email protected]> and others (see README). + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +*/ + +#include <cstddef> +#include <utility> + +namespace osmium { + + template <typename It, typename P = std::pair<It, It>> + struct iterator_range : public P { + + using iterator = It; + + iterator_range(P&& p) : + P(std::forward<P>(p)) { + } + + It begin() { + return this->first; + } + + It end() { + return this->second; + } + + It begin() const { + return this->first; + } + + It end() const { + return this->second; + } + + size_t empty() const { + return begin() == end(); + } + + }; + +} // namespace osmium + +#endif // OSMIUM_UTIL_ITERATOR_HPP diff --git a/include/osmium/util/memory.hpp b/include/osmium/util/memory.hpp index 7ef445b..777a6e0 100644 --- a/include/osmium/util/memory.hpp +++ b/include/osmium/util/memory.hpp @@ -45,9 +45,9 @@ namespace osmium { int m_peak = 0; #ifdef __linux__ - int parse_number(const std::string& line) { - int f = line.find_first_of("0123456789"); - int l = line.find_last_of("0123456789"); + static int parse_number(const std::string& line) { + const auto f = line.find_first_of("0123456789"); + const auto l = line.find_last_of("0123456789"); return std::atoi(line.substr(f, l-f+1).c_str()); } #endif diff --git a/include/protozero/config.hpp b/include/protozero/config.hpp index 4086994..8465c96 100644 --- a/include/protozero/config.hpp +++ b/include/protozero/config.hpp @@ -40,7 +40,9 @@ documentation. // in this case. #if PROTOZERO_BYTE_ORDER == PROTOZERO_LITTLE_ENDIAN # if !defined(__arm__) && !defined(_M_ARM) -# define PROTOZERO_USE_BARE_POINTER_FOR_PACKED_FIXED +# ifndef PROTOZERO_DO_NOT_USE_BARE_POINTER +# define PROTOZERO_USE_BARE_POINTER_FOR_PACKED_FIXED +# endif # endif #endif diff --git a/include/protozero/exception.hpp b/include/protozero/exception.hpp index 1229f7d..5c7ab54 100644 --- a/include/protozero/exception.hpp +++ b/include/protozero/exception.hpp @@ -29,7 +29,7 @@ namespace protozero { */ struct exception : std::exception { /// Returns the explanatory string. - const char *what() const noexcept { return "pbf exception"; } + const char *what() const noexcept override { return "pbf exception"; } }; /** @@ -38,7 +38,7 @@ struct exception : std::exception { */ struct varint_too_long_exception : exception { /// Returns the explanatory string. - const char *what() const noexcept { return "varint too long exception"; } + const char *what() const noexcept override { return "varint too long exception"; } }; /** @@ -47,7 +47,7 @@ struct varint_too_long_exception : exception { */ struct unknown_pbf_wire_type_exception : exception { /// Returns the explanatory string. - const char *what() const noexcept { return "unknown pbf field type exception"; } + const char *what() const noexcept override { return "unknown pbf field type exception"; } }; /** @@ -60,7 +60,7 @@ struct unknown_pbf_wire_type_exception : exception { */ struct end_of_buffer_exception : exception { /// Returns the explanatory string. - const char *what() const noexcept { return "end of buffer exception"; } + const char *what() const noexcept override { return "end of buffer exception"; } }; } // end namespace protozero diff --git a/include/protozero/pbf_builder.hpp b/include/protozero/pbf_builder.hpp index 063fa9c..548f4ce 100644 --- a/include/protozero/pbf_builder.hpp +++ b/include/protozero/pbf_builder.hpp @@ -18,7 +18,7 @@ documentation. #include <type_traits> -#include <protozero/pbf_types.hpp> +#include <protozero/types.hpp> #include <protozero/pbf_writer.hpp> namespace protozero { @@ -26,8 +26,10 @@ namespace protozero { /** * The pbf_builder is used to write PBF formatted messages into a buffer. It * is based on the pbf_writer class and has all the same methods. The - * difference is that whereever the pbf_writer class takes an integer tag, - * this template class takes a tag of the template type T. + * difference is that while the pbf_writer class takes an integer tag, + * this template class takes a tag of the template type T. The idea is that + * T will be an enumeration value and this helps reduce the possibility of + * programming errors. * * Almost all methods in this class can throw an std::bad_alloc exception if * the std::string used as a buffer wants to resize. @@ -77,7 +79,7 @@ public: #undef PROTOZERO_WRITER_WRAP_ADD_SCALAR /// @endcond - inline void add_bytes(T tag, const char* value, size_t size) { + inline void add_bytes(T tag, const char* value, std::size_t size) { pbf_writer::add_bytes(pbf_tag_type(tag), value, size); } @@ -85,7 +87,7 @@ public: pbf_writer::add_bytes(pbf_tag_type(tag), value); } - inline void add_string(T tag, const char* value, size_t size) { + inline void add_string(T tag, const char* value, std::size_t size) { pbf_writer::add_string(pbf_tag_type(tag), value, size); } @@ -97,7 +99,7 @@ public: pbf_writer::add_string(pbf_tag_type(tag), value); } - inline void add_message(T tag, const char* value, size_t size) { + inline void add_message(T tag, const char* value, std::size_t size) { pbf_writer::add_message(pbf_tag_type(tag), value, size); } diff --git a/include/protozero/pbf_message.hpp b/include/protozero/pbf_message.hpp index 7fef06f..45f01c1 100644 --- a/include/protozero/pbf_message.hpp +++ b/include/protozero/pbf_message.hpp @@ -19,7 +19,7 @@ documentation. #include <type_traits> #include <protozero/pbf_reader.hpp> -#include <protozero/pbf_types.hpp> +#include <protozero/types.hpp> namespace protozero { diff --git a/include/protozero/pbf_reader.hpp b/include/protozero/pbf_reader.hpp index aced901..58b3884 100644 --- a/include/protozero/pbf_reader.hpp +++ b/include/protozero/pbf_reader.hpp @@ -25,7 +25,7 @@ documentation. #include <protozero/config.hpp> #include <protozero/exception.hpp> -#include <protozero/pbf_types.hpp> +#include <protozero/types.hpp> #include <protozero/varint.hpp> #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN @@ -94,11 +94,12 @@ class pbf_reader { #ifdef PROTOZERO_USE_BARE_POINTER_FOR_PACKED_FIXED template <typename T> - inline std::pair<const T*, const T*> packed_fixed() { - protozero_assert(tag() != 0 && "call next() before accessing field value"); - auto len = get_len_and_skip(); - protozero_assert(len % sizeof(T) == 0); - return std::make_pair(reinterpret_cast<const T*>(m_data-len), reinterpret_cast<const T*>(m_data)); + using const_fixed_iterator = const T*; + + template <typename T> + inline std::pair<const_fixed_iterator<T>, const_fixed_iterator<T>> create_fixed_iterator_pair(const char* first, const char* last) { + return std::make_pair(reinterpret_cast<const T*>(first), + reinterpret_cast<const T*>(last)); } #else @@ -157,16 +158,21 @@ class pbf_reader { }; // class const_fixed_iterator template <typename T> + inline std::pair<const_fixed_iterator<T>, const_fixed_iterator<T>> create_fixed_iterator_pair(const char* first, const char* last) { + return std::make_pair(const_fixed_iterator<T>(first, last), + const_fixed_iterator<T>(last, last)); + } + +#endif + + template <typename T> inline std::pair<const_fixed_iterator<T>, const_fixed_iterator<T>> packed_fixed() { protozero_assert(tag() != 0 && "call next() before accessing field value"); auto len = get_len_and_skip(); protozero_assert(len % sizeof(T) == 0); - return std::make_pair(const_fixed_iterator<T>(m_data-len, m_data), - const_fixed_iterator<T>(m_data, m_data)); + return create_fixed_iterator_pair<T>(m_data-len, m_data); } -#endif - template <typename T> inline T get_varint(); template <typename T> inline T get_svarint(); @@ -187,7 +193,7 @@ public: * * @post There is no current field. */ - inline pbf_reader(const char *data, size_t length) noexcept; + inline pbf_reader(const char *data, std::size_t length) noexcept; /** * Construct a pbf_reader message from a data pointer and a length. The pointer @@ -198,7 +204,7 @@ public: * * @post There is no current field. */ - inline pbf_reader(std::pair<const char *, size_t> data) noexcept; + inline pbf_reader(std::pair<const char *, std::size_t> data) noexcept; /** * Construct a pbf_reader message from a std::string. A pointer to the string @@ -247,8 +253,8 @@ public: * buffer. Of course you have to know reasonably well what data to expect * and how it is encoded for this number to have any meaning. */ - size_t length() const noexcept { - return size_t(m_end - m_data); + std::size_t length() const noexcept { + return std::size_t(m_end - m_data); } /** @@ -832,14 +838,14 @@ public: }; // class pbf_reader -pbf_reader::pbf_reader(const char *data, size_t length) noexcept +pbf_reader::pbf_reader(const char *data, std::size_t length) noexcept : m_data(data), m_end(data + length), m_wire_type(pbf_wire_type::unknown), m_tag(0) { } -pbf_reader::pbf_reader(std::pair<const char *, size_t> data) noexcept +pbf_reader::pbf_reader(std::pair<const char *, std::size_t> data) noexcept : m_data(data.first), m_end(data.first + data.second), m_wire_type(pbf_wire_type::unknown), @@ -935,7 +941,7 @@ void pbf_reader::skip() { skip_bytes(4); break; default: - throw unknown_pbf_wire_type_exception(); + protozero_assert(false && "can not be here because next() should have thrown already"); } } diff --git a/include/protozero/pbf_writer.hpp b/include/protozero/pbf_writer.hpp index 2b78cb8..422e147 100644 --- a/include/protozero/pbf_writer.hpp +++ b/include/protozero/pbf_writer.hpp @@ -24,7 +24,7 @@ documentation. #include <string> #include <protozero/config.hpp> -#include <protozero/pbf_types.hpp> +#include <protozero/types.hpp> #include <protozero/varint.hpp> #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN @@ -33,6 +33,14 @@ documentation. namespace protozero { +namespace detail { + + template <typename T> class packed_field_varint; + template <typename T> class packed_field_svarint; + template <typename T> class packed_field_fixed; + +} // end namespace detail + /** * The pbf_writer is used to write PBF formatted messages into a buffer. * @@ -41,9 +49,24 @@ namespace protozero { */ class pbf_writer { + // A pointer to a string buffer holding the data already written to the + // PBF message. For default constructed writers or writers that have been + // rolled back, this is a nullptr. std::string* m_data; + + // A pointer to a parent writer object if this is a submessage. If this + // is a top-level writer, it is a nullptr. pbf_writer* m_parent_writer; - size_t m_pos = 0; + + // This is usually 0. If there is an open submessage, this is set in the + // parent to the rollback position, ie. the last position before the + // submessage was started. This is the position where the header of the + // submessage starts. + std::size_t m_rollback_pos = 0; + + // This is usually 0. If there is an open submessage, this is set in the + // parent to the position where the data of the submessage is written to. + std::size_t m_pos = 0; inline void add_varint(uint64_t value) { protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage"); @@ -94,7 +117,9 @@ class pbf_writer { return; } - add_length_varint(tag, sizeof(T) * pbf_length_type(std::distance(first, last))); + auto length = std::distance(first, last); + add_length_varint(tag, sizeof(T) * pbf_length_type(length)); + reserve(sizeof(T) * std::size_t(length)); while (first != last) { add_fixed<T>(*first++); @@ -132,16 +157,37 @@ class pbf_writer { // and a varint needs 8 bit for every 7 bit. static const int reserve_bytes = sizeof(pbf_length_type) * 8 / 7 + 1; - inline void open_submessage(pbf_tag_type tag) { + // If m_rollpack_pos is set to this special value, it means that when + // the submessage is closed, nothing needs to be done, because the length + // of the submessage has already been written correctly. + static const std::size_t size_is_known = std::numeric_limits<std::size_t>::max(); + + inline void open_submessage(pbf_tag_type tag, std::size_t size) { protozero_assert(m_pos == 0); protozero_assert(m_data); - add_field(tag, pbf_wire_type::length_delimited); - m_data->append(size_t(reserve_bytes), '\0'); + if (size == 0) { + m_rollback_pos = m_data->size(); + add_field(tag, pbf_wire_type::length_delimited); + m_data->append(std::size_t(reserve_bytes), '\0'); + } else { + m_rollback_pos = size_is_known; + add_length_varint(tag, pbf_length_type(size)); + reserve(size); + } m_pos = m_data->size(); } - inline void close_submessage() { + inline void rollback_submessage() { protozero_assert(m_pos != 0); + protozero_assert(m_rollback_pos != size_is_known); + protozero_assert(m_data); + m_data->resize(m_rollback_pos); + m_pos = 0; + } + + inline void commit_submessage() { + protozero_assert(m_pos != 0); + protozero_assert(m_rollback_pos != size_is_known); protozero_assert(m_data); auto length = pbf_length_type(m_data->size() - m_pos); @@ -152,6 +198,18 @@ class pbf_writer { m_pos = 0; } + inline void close_submessage() { + protozero_assert(m_data); + if (m_pos == 0 || m_rollback_pos == size_is_known) { + return; + } + if (m_data->size() - m_pos == 0) { + rollback_submessage(); + } else { + commit_submessage(); + } + } + inline void add_length_varint(pbf_tag_type tag, pbf_length_type length) { add_field(tag, pbf_wire_type::length_delimited); add_varint(length); @@ -161,7 +219,8 @@ public: /** * Create a writer using the given string as a data store. The pbf_writer - * stores a reference to that string and adds all data to it. + * stores a reference to that string and adds all data to it. The string + * doesn't have to be empty. The pbf_writer will just append data. */ inline explicit pbf_writer(std::string& data) noexcept : m_data(&data), @@ -185,12 +244,15 @@ public: * * @param parent_writer The pbf_writer * @param tag Tag (field number) of the field that will be written + * @param size Optional size of the submessage in bytes (use 0 for unknown). + * Setting this allows some optimizations but is only possible in + * a few very specific cases. */ - inline pbf_writer(pbf_writer& parent_writer, pbf_tag_type tag) : + inline pbf_writer(pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size=0) : m_data(parent_writer.m_data), m_parent_writer(&parent_writer), m_pos(0) { - m_parent_writer->open_submessage(tag); + m_parent_writer->open_submessage(tag, size); } /// A pbf_writer object can be copied @@ -211,6 +273,26 @@ public: } } + /** + * Reserve size bytes in the underlying message store in addition to + * whatever the message store already holds. So unlike + * the `std::string::reserve()` method this is not an absolute size, + * but additional memory that should be reserved. + * + * @param size Number of bytes to reserve in underlying message store. + */ + void reserve(std::size_t size) { + protozero_assert(m_data); + m_data->reserve(m_data->size() + size); + } + + inline void rollback() { + protozero_assert(m_parent_writer && "you can't call rollback() on a pbf_writer without a parent"); + protozero_assert(m_pos == 0 && "you can't call rollback() on a pbf_writer that has an open nested submessage"); + m_parent_writer->rollback_submessage(); + m_data = nullptr; + } + ///@{ /** * @name Scalar field writer functions @@ -372,7 +454,7 @@ public: * @param value Pointer to value to be written * @param size Number of bytes to be written */ - inline void add_bytes(pbf_tag_type tag, const char* value, size_t size) { + inline void add_bytes(pbf_tag_type tag, const char* value, std::size_t size) { protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage"); protozero_assert(m_data); protozero_assert(size <= std::numeric_limits<pbf_length_type>::max()); @@ -397,7 +479,7 @@ public: * @param value Pointer to value to be written * @param size Number of bytes to be written */ - inline void add_string(pbf_tag_type tag, const char* value, size_t size) { + inline void add_string(pbf_tag_type tag, const char* value, std::size_t size) { add_bytes(tag, value, size); } @@ -429,7 +511,7 @@ public: * @param value Pointer to message to be written * @param size Length of the message */ - inline void add_message(pbf_tag_type tag, const char* value, size_t size) { + inline void add_message(pbf_tag_type tag, const char* value, std::size_t size) { add_bytes(tag, value, size); } @@ -654,8 +736,102 @@ public: ///@} + template <typename T> friend class detail::packed_field_varint; + template <typename T> friend class detail::packed_field_svarint; + template <typename T> friend class detail::packed_field_fixed; + }; // class pbf_writer +namespace detail { + + class packed_field { + + protected: + + pbf_writer m_writer; + + public: + + packed_field(pbf_writer& parent_writer, pbf_tag_type tag) : + m_writer(parent_writer, tag) { + } + + packed_field(pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size) : + m_writer(parent_writer, tag, size) { + } + + void rollback() { + m_writer.rollback(); + } + + }; // class packed_field + + template <typename T> + class packed_field_fixed : public packed_field { + + public: + + packed_field_fixed(pbf_writer& parent_writer, pbf_tag_type tag) : + packed_field(parent_writer, tag) { + } + + packed_field_fixed(pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size) : + packed_field(parent_writer, tag, size * sizeof(T)) { + } + + void add_element(T value) { + m_writer.add_fixed<T>(value); + } + + }; // class packed_field_fixed + + template <typename T> + class packed_field_varint : public packed_field { + + public: + + packed_field_varint(pbf_writer& parent_writer, pbf_tag_type tag) : + packed_field(parent_writer, tag) { + } + + void add_element(T value) { + m_writer.add_varint(uint64_t(value)); + } + + }; // class packed_field_varint + + template <typename T> + class packed_field_svarint : public packed_field { + + public: + + packed_field_svarint(pbf_writer& parent_writer, pbf_tag_type tag) : + packed_field(parent_writer, tag) { + } + + void add_element(T value) { + m_writer.add_varint(encode_zigzag64(value)); + } + + }; // class packed_field_svarint + +} // end namespace detail + +using packed_field_bool = detail::packed_field_varint<bool>; +using packed_field_enum = detail::packed_field_varint<int32_t>; +using packed_field_int32 = detail::packed_field_varint<int32_t>; +using packed_field_sint32 = detail::packed_field_svarint<int32_t>; +using packed_field_uint32 = detail::packed_field_varint<uint32_t>; +using packed_field_int64 = detail::packed_field_varint<int64_t>; +using packed_field_sint64 = detail::packed_field_svarint<int64_t>; +using packed_field_uint64 = detail::packed_field_varint<uint64_t>; +using packed_field_fixed32 = detail::packed_field_fixed<uint32_t>; +using packed_field_sfixed32 = detail::packed_field_fixed<int32_t>; +using packed_field_fixed64 = detail::packed_field_fixed<uint64_t>; +using packed_field_sfixed64 = detail::packed_field_fixed<int64_t>; +using packed_field_float = detail::packed_field_fixed<float>; +using packed_field_double = detail::packed_field_fixed<double>; + } // end namespace protozero #endif // PROTOZERO_PBF_WRITER_HPP diff --git a/include/protozero/pbf_types.hpp b/include/protozero/types.hpp similarity index 91% rename from include/protozero/pbf_types.hpp rename to include/protozero/types.hpp index 9f38584..6856b3d 100644 --- a/include/protozero/pbf_types.hpp +++ b/include/protozero/types.hpp @@ -1,5 +1,5 @@ -#ifndef PROTOZERO_PBF_TYPES_HPP -#define PROTOZERO_PBF_TYPES_HPP +#ifndef PROTOZERO_TYPES_HPP +#define PROTOZERO_TYPES_HPP /***************************************************************************** @@ -11,7 +11,7 @@ documentation. *****************************************************************************/ /** - * @file pbf_types.hpp + * @file types.hpp * * @brief Contains the declaration of low-level types used in the pbf format. */ @@ -46,4 +46,4 @@ namespace protozero { } // end namespace protozero -#endif // PROTOZERO_PBF_TYPES_HPP +#endif // PROTOZERO_TYPES_HPP diff --git a/include/protozero/varint.hpp b/include/protozero/varint.hpp index 27536fd..4242df9 100644 --- a/include/protozero/varint.hpp +++ b/include/protozero/varint.hpp @@ -25,13 +25,13 @@ namespace protozero { /** * The maximum length of a 64bit varint. */ -const int8_t max_varint_length = sizeof(uint64_t) * 8 / 7 + 1; +constexpr const int8_t max_varint_length = sizeof(uint64_t) * 8 / 7 + 1; // from https://github.com/facebook/folly/blob/master/folly/Varint.h /** * Decode a 64bit varint. * - * String exception guarantee: if there is an exception the data pointer will + * Strong exception guarantee: if there is an exception the data pointer will * not be changed. * * @param[in,out] data Pointer to pointer to the input data. After the function diff --git a/include/protozero/version.hpp b/include/protozero/version.hpp index 4f129ac..7b60e2e 100644 --- a/include/protozero/version.hpp +++ b/include/protozero/version.hpp @@ -11,12 +11,12 @@ documentation. *****************************************************************************/ #define PROTOZERO_VERSION_MAJOR 1 -#define PROTOZERO_VERSION_MINOR 2 -#define PROTOZERO_VERSION_PATCH 3 +#define PROTOZERO_VERSION_MINOR 3 +#define PROTOZERO_VERSION_PATCH 0 #define PROTOZERO_VERSION_CODE (PROTOZERO_VERSION_MAJOR * 10000 + PROTOZERO_VERSION_MINOR * 100 + PROTOZERO_VERSION_PATCH) -#define PROTOZERO_VERSION_STRING "1.2.3" +#define PROTOZERO_VERSION_STRING "1.3.0" #endif // PROTOZERO_VERSION_HPP diff --git a/test/t/basic/test_node_ref.cpp b/test/t/basic/test_node_ref.cpp index ac7ccbf..9932ff5 100644 --- a/test/t/basic/test_node_ref.cpp +++ b/test/t/basic/test_node_ref.cpp @@ -1,6 +1,9 @@ #include "catch.hpp" +#include <osmium/builder/attr.hpp> +#include <osmium/memory/buffer.hpp> #include <osmium/osm/node_ref.hpp> +#include <osmium/osm/node_ref_list.hpp> TEST_CASE("NodeRef") { @@ -55,3 +58,52 @@ TEST_CASE("NodeRef") { } +TEST_CASE("WayNodeList") { + osmium::memory::Buffer buffer(1024); + + SECTION("Empty list") { + { + osmium::builder::WayNodeListBuilder builder(buffer); + } + REQUIRE(buffer.commit() == 0); + REQUIRE(buffer.committed( )> 0); + + const osmium::WayNodeList& nrl = buffer.get<osmium::WayNodeList>(0); + REQUIRE(nrl.empty()); + REQUIRE(nrl.size() == 0); + } + + SECTION("Small area") { + osmium::builder::add_way_node_list(buffer, osmium::builder::attr::_nodes({ + { 1, {0, 0}}, + { 2, {0, 1}}, + { 3, {1, 1}}, + { 4, {1, 0}}, + { 1, {0, 0}}, + })); + + const osmium::WayNodeList& nrl = buffer.get<osmium::WayNodeList>(0); + REQUIRE_FALSE(nrl.empty()); + REQUIRE(nrl.size() == 5); + REQUIRE(nrl.is_closed()); + REQUIRE(nrl.ends_have_same_id()); + REQUIRE(nrl.ends_have_same_location()); + } + + SECTION("Not an area") { + osmium::builder::add_way_node_list(buffer, osmium::builder::attr::_nodes({ + { 1, {0, 0}}, + { 2, {1, 0}}, + { 1, {0, 0}}, + })); + + const osmium::WayNodeList& nrl = buffer.get<osmium::WayNodeList>(0); + REQUIRE_FALSE(nrl.empty()); + REQUIRE(nrl.size() == 3); + REQUIRE(nrl.is_closed()); + REQUIRE(nrl.ends_have_same_id()); + REQUIRE(nrl.ends_have_same_location()); + } + +} + -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/libosmium.git _______________________________________________ Pkg-grass-devel mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel

