[libosmium] 01/04: Imported Upstream version 2.6.1
Sebastiaan Couwenberg
sebastic at moszumanska.debian.org
Thu Feb 25 19:28:57 UTC 2016
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 <sebastic at xs4all.nl>
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 <jochen at topf.org> 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
More information about the Pkg-grass-devel
mailing list