libosmium version bump

This commit is contained in:
Dennis Luxen 2014-10-29 16:27:48 -04:00
parent 0249bed53a
commit 710e74219a
91 changed files with 7244 additions and 6417 deletions

View File

@ -152,15 +152,26 @@ namespace osmium {
} }
} }
struct MPFilter : public osmium::tags::KeyFilter {
MPFilter() : osmium::tags::KeyFilter(true) {
add(false, "type");
add(false, "created_by");
add(false, "source");
add(false, "note");
add(false, "test:id");
add(false, "test:section");
}
}; // struct MPFilter
static MPFilter& filter() {
static MPFilter filter;
return filter;
}
void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Relation& relation) const { void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Relation& relation) const {
osmium::tags::KeyFilter filter(true); auto count = std::count_if(relation.tags().begin(), relation.tags().end(), filter());
filter.add(false, "type").add(false, "created_by").add(false, "source").add(false, "note");
filter.add(false, "test:id").add(false, "test:section");
osmium::tags::KeyFilter::iterator fi_begin(filter, relation.tags().begin(), relation.tags().end());
osmium::tags::KeyFilter::iterator fi_end(filter, relation.tags().end(), relation.tags().end());
auto count = std::distance(fi_begin, fi_end);
if (debug()) { if (debug()) {
std::cerr << " found " << count << " tags on relation (without ignored ones)\n"; std::cerr << " found " << count << " tags on relation (without ignored ones)\n";
@ -728,27 +739,26 @@ namespace osmium {
const osmium::TagList& area_tags = out_buffer.get<osmium::Area>(area_offset).tags(); // tags of the area we just built const osmium::TagList& area_tags = out_buffer.get<osmium::Area>(area_offset).tags(); // tags of the area we just built
// Find all closed ways that are inner rings and check their
// tags. If they are not the same as the tags of the area we
// just built, add them to a list and later build areas for
// them, too.
std::vector<const osmium::Way*> ways_that_should_be_areas;
if (m_inner_outer_mismatches == 0) { if (m_inner_outer_mismatches == 0) {
auto memit = relation.members().begin(); auto memit = relation.members().begin();
for (size_t offset : members) { for (size_t offset : members) {
if (!std::strcmp(memit->role(), "inner")) { if (!std::strcmp(memit->role(), "inner")) {
const osmium::Way& way = in_buffer.get<const osmium::Way>(offset); const osmium::Way& way = in_buffer.get<const osmium::Way>(offset);
if (way.is_closed() && way.tags().size() > 0) { if (way.is_closed() && way.tags().size() > 0) {
osmium::tags::KeyFilter filter(true); auto d = std::count_if(way.tags().begin(), way.tags().end(), filter());
filter.add(false, "created_by").add(false, "source").add(false, "note");
filter.add(false, "test:id").add(false, "test:section");
osmium::tags::KeyFilter::iterator fi_begin(filter, way.tags().begin(), way.tags().end());
osmium::tags::KeyFilter::iterator fi_end(filter, way.tags().end(), way.tags().end());
auto d = std::distance(fi_begin, fi_end);
if (d > 0) { if (d > 0) {
osmium::tags::KeyFilter::iterator area_fi_begin(filter, area_tags.begin(), area_tags.end()); osmium::tags::KeyFilter::iterator way_fi_begin(filter(), way.tags().begin(), way.tags().end());
osmium::tags::KeyFilter::iterator area_fi_end(filter, area_tags.end(), area_tags.end()); osmium::tags::KeyFilter::iterator way_fi_end(filter(), way.tags().end(), way.tags().end());
osmium::tags::KeyFilter::iterator area_fi_begin(filter(), area_tags.begin(), area_tags.end());
osmium::tags::KeyFilter::iterator area_fi_end(filter(), area_tags.end(), area_tags.end());
if (!std::equal(fi_begin, fi_end, area_fi_begin) || d != std::distance(area_fi_begin, area_fi_end)) { if (!std::equal(way_fi_begin, way_fi_end, area_fi_begin) || d != std::distance(area_fi_begin, area_fi_end)) {
Assembler assembler(m_config); ways_that_should_be_areas.push_back(&way);
assembler(way, out_buffer);
} }
} }
} }
@ -756,6 +766,12 @@ namespace osmium {
++memit; ++memit;
} }
} }
// Now build areas for all ways found in the last step.
for (const osmium::Way* way : ways_that_should_be_areas) {
Assembler assembler(m_config);
assembler(*way, out_buffer);
}
} }
}; // class Assembler }; // class Assembler

View File

@ -78,7 +78,7 @@ namespace osmium {
swap(m_first, m_second); swap(m_first, m_second);
} }
explicit NodeRefSegment() : explicit NodeRefSegment() noexcept :
m_first(), m_first(),
m_second(), m_second(),
m_role(nullptr), m_role(nullptr),
@ -104,12 +104,12 @@ namespace osmium {
~NodeRefSegment() = default; ~NodeRefSegment() = default;
/// Return first NodeRef of Segment according to sorting order (bottom left to top right). /// Return first NodeRef of Segment according to sorting order (bottom left to top right).
const osmium::NodeRef& first() const { const osmium::NodeRef& first() const noexcept {
return m_first; return m_first;
} }
/// Return second NodeRef of Segment according to sorting order (bottom left to top right). /// Return second NodeRef of Segment according to sorting order (bottom left to top right).
const osmium::NodeRef& second() const { const osmium::NodeRef& second() const noexcept {
return m_second; return m_second;
} }
@ -138,26 +138,26 @@ namespace osmium {
return ((bx - ax)*(ly - ay) - (by - ay)*(lx - ax)) <= 0; return ((bx - ax)*(ly - ay) - (by - ay)*(lx - ax)) <= 0;
} }
bool role_outer() const { bool role_outer() const noexcept {
return !strcmp(m_role, "outer"); return !strcmp(m_role, "outer");
} }
bool role_inner() const { bool role_inner() const noexcept {
return !strcmp(m_role, "inner"); return !strcmp(m_role, "inner");
} }
const osmium::Way* way() const { const osmium::Way* way() const noexcept {
return m_way; return m_way;
} }
}; // class NodeRefSegment }; // class NodeRefSegment
/// NodeRefSegments are equal if both their locations are equal /// NodeRefSegments are equal if both their locations are equal
inline bool operator==(const NodeRefSegment& lhs, const NodeRefSegment& rhs) { inline bool operator==(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
return lhs.first().location() == rhs.first().location() && lhs.second().location() == rhs.second().location(); return lhs.first().location() == rhs.first().location() && lhs.second().location() == rhs.second().location();
} }
inline bool operator!=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) { inline bool operator!=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
return ! (lhs == rhs); return ! (lhs == rhs);
} }
@ -166,19 +166,19 @@ namespace osmium {
* segment. The first() location is checked first() and only if they have the * segment. The first() location is checked first() and only if they have the
* same first() location the second() location is taken into account. * same first() location the second() location is taken into account.
*/ */
inline bool operator<(const NodeRefSegment& lhs, const NodeRefSegment& rhs) { inline bool operator<(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
return (lhs.first().location() == rhs.first().location() && lhs.second().location() < rhs.second().location()) || lhs.first().location() < rhs.first().location(); return (lhs.first().location() == rhs.first().location() && lhs.second().location() < rhs.second().location()) || lhs.first().location() < rhs.first().location();
} }
inline bool operator>(const NodeRefSegment& lhs, const NodeRefSegment& rhs) { inline bool operator>(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
return rhs < lhs; return rhs < lhs;
} }
inline bool operator<=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) { inline bool operator<=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
return ! (rhs < lhs); return ! (rhs < lhs);
} }
inline bool operator>=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) { inline bool operator>=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
return ! (lhs < rhs); return ! (lhs < rhs);
} }
@ -187,7 +187,7 @@ namespace osmium {
return out << segment.first() << "--" << segment.second(); return out << segment.first() << "--" << segment.second();
} }
inline bool outside_x_range(const NodeRefSegment& s1, const NodeRefSegment& s2) { inline bool outside_x_range(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
if (s1.first().location().x() > s2.second().location().x()) { if (s1.first().location().x() > s2.second().location().x()) {
return true; return true;
} }
@ -204,20 +204,20 @@ namespace osmium {
} }
/** /**
* Calculate the intersection between to NodeRefSegments. The result is returned * Calculate the intersection between to NodeRefSegments. The result is returned
* as a Location. Note that because the Location uses integers with limited * as a Location. Note that because the Location uses integers with limited
* precision internally, the result might be slightly different than the * precision internally, the result might be slightly different than the
* numerically correct location. * numerically correct location.
* *
* If the segments touch in one of their endpoints, it doesn't count as an * If the segments touch in one of their endpoints, it doesn't count as an
* intersection. * intersection.
* *
* If the segments intersect not in a single point but in multiple points, ie * If the segments intersect not in a single point but in multiple points, ie
* if they overlap, this is NOT detected. * if they overlap, this is NOT detected.
* *
* @returns Undefined osmium::Location if there is no intersection or a defined * @returns Undefined osmium::Location if there is no intersection or a defined
* Location if the segments intersect. * Location if the segments intersect.
*/ */
inline osmium::Location calculate_intersection(const NodeRefSegment& s1, const NodeRefSegment& s2) { inline osmium::Location calculate_intersection(const NodeRefSegment& s1, const NodeRefSegment& s2) {
if (s1.first().location() == s2.first().location() || if (s1.first().location() == s2.first().location() ||
s1.first().location() == s2.second().location() || s1.first().location() == s2.second().location() ||
@ -226,10 +226,15 @@ namespace osmium {
return osmium::Location(); return osmium::Location();
} }
double denom = ((s2.second().lat() - s2.first().lat())*(s1.second().lon() - s1.first().lon())) - auto d = (static_cast<int64_t>(s2.second().y()) - static_cast<int64_t>(s2.first().y())) *
((s2.second().lon() - s2.first().lon())*(s1.second().lat() - s1.first().lat())); (static_cast<int64_t>(s1.second().x()) - static_cast<int64_t>(s1.first().x())) -
(static_cast<int64_t>(s2.second().x()) - static_cast<int64_t>(s2.first().x())) *
(static_cast<int64_t>(s1.second().y()) - static_cast<int64_t>(s1.first().y()));
if (d != 0) {
double denom = ((s2.second().lat() - s2.first().lat())*(s1.second().lon() - s1.first().lon())) -
((s2.second().lon() - s2.first().lon())*(s1.second().lat() - s1.first().lat()));
if (denom != 0) {
double nume_a = ((s2.second().lon() - s2.first().lon())*(s1.first().lat() - s2.first().lat())) - double nume_a = ((s2.second().lon() - s2.first().lon())*(s1.first().lat() - s2.first().lat())) -
((s2.second().lat() - s2.first().lat())*(s1.first().lon() - s2.first().lon())); ((s2.second().lat() - s2.first().lat())*(s1.first().lon() - s2.first().lon()));

View File

@ -70,7 +70,7 @@ namespace osmium {
public: public:
explicit ProtoRing(const NodeRefSegment& segment) : explicit ProtoRing(const NodeRefSegment& segment) noexcept :
m_segments() { m_segments() {
add_segment_back(segment); add_segment_back(segment);
} }
@ -80,19 +80,19 @@ namespace osmium {
std::copy(sbegin, send, m_segments.begin()); std::copy(sbegin, send, m_segments.begin());
} }
bool outer() const { bool outer() const noexcept {
return m_outer; return m_outer;
} }
void set_inner() { void set_inner() noexcept {
m_outer = false; m_outer = false;
} }
segments_type& segments() { segments_type& segments() noexcept {
return m_segments; return m_segments;
} }
const segments_type& segments() const { const segments_type& segments() const noexcept {
return m_segments; return m_segments;
} }

View File

@ -64,7 +64,7 @@ namespace osmium {
public: public:
explicit SegmentList(bool debug) : explicit SegmentList(bool debug) noexcept :
m_debug(debug) { m_debug(debug) {
} }
@ -77,21 +77,21 @@ namespace osmium {
SegmentList& operator=(SegmentList&& other) = delete; SegmentList& operator=(SegmentList&& other) = delete;
/// The number of segments in the list. /// The number of segments in the list.
size_t size() const { size_t size() const noexcept {
return m_segments.size(); return m_segments.size();
} }
bool empty() const { bool empty() const noexcept {
return m_segments.empty(); return m_segments.empty();
} }
typedef slist_type::const_iterator const_iterator; typedef slist_type::const_iterator const_iterator;
const_iterator begin() const { const_iterator begin() const noexcept {
return m_segments.begin(); return m_segments.begin();
} }
const_iterator end() const { const_iterator end() const noexcept {
return m_segments.end(); return m_segments.end();
} }
@ -99,7 +99,7 @@ namespace osmium {
* Enable or disable debug output to stderr. This is for Osmium * Enable or disable debug output to stderr. This is for Osmium
* developers only. * developers only.
*/ */
void enable_debug_output(bool debug=true) { void enable_debug_output(bool debug=true) noexcept {
m_debug = debug; m_debug = debug;
} }

View File

@ -1,211 +1,211 @@
#ifndef OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP #ifndef OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
#define OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP #define OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <cstring> #include <cstring>
#include <vector> #include <vector>
#include <osmium/memory/buffer.hpp> #include <osmium/memory/buffer.hpp>
#include <osmium/osm/item_type.hpp> #include <osmium/osm/item_type.hpp>
#include <osmium/osm/relation.hpp> #include <osmium/osm/relation.hpp>
#include <osmium/osm/tag.hpp> #include <osmium/osm/tag.hpp>
#include <osmium/osm/way.hpp> #include <osmium/osm/way.hpp>
#include <osmium/relations/collector.hpp> #include <osmium/relations/collector.hpp>
#include <osmium/relations/detail/member_meta.hpp> #include <osmium/relations/detail/member_meta.hpp>
namespace osmium { namespace osmium {
struct invalid_location; struct invalid_location;
namespace relations { namespace relations {
class RelationMeta; class RelationMeta;
} }
/** /**
* @brief Code related to the building of areas (multipolygons) from relations. * @brief Code related to the building of areas (multipolygons) from relations.
*/ */
namespace area { namespace area {
/** /**
* This class collects all data needed for creating areas from * This class collects all data needed for creating areas from
* relations tagged with type=multipolygon or type=boundary. * relations tagged with type=multipolygon or type=boundary.
* Most of its functionality is derived from the parent class * Most of its functionality is derived from the parent class
* osmium::relations::Collector. * osmium::relations::Collector.
* *
* The actual assembling of the areas is done by the assembler * The actual assembling of the areas is done by the assembler
* class given as template argument. * class given as template argument.
* *
* @tparam TAssembler Multipolygon Assembler class. * @tparam TAssembler Multipolygon Assembler class.
*/ */
template <class TAssembler> template <class TAssembler>
class MultipolygonCollector : public osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> { class MultipolygonCollector : public osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> {
typedef typename osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> collector_type; typedef typename osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> collector_type;
typedef typename TAssembler::config_type assembler_config_type; typedef typename TAssembler::config_type assembler_config_type;
const assembler_config_type m_assembler_config; const assembler_config_type m_assembler_config;
osmium::memory::Buffer m_output_buffer; osmium::memory::Buffer m_output_buffer;
static constexpr size_t initial_output_buffer_size = 1024 * 1024; static constexpr size_t initial_output_buffer_size = 1024 * 1024;
static constexpr size_t max_buffer_size_for_flush = 100 * 1024; static constexpr size_t max_buffer_size_for_flush = 100 * 1024;
void flush_output_buffer() { void flush_output_buffer() {
if (this->callback()) { if (this->callback()) {
this->callback()(m_output_buffer); this->callback()(m_output_buffer);
m_output_buffer.clear(); m_output_buffer.clear();
} }
} }
void possibly_flush_output_buffer() { void possibly_flush_output_buffer() {
if (m_output_buffer.committed() > max_buffer_size_for_flush) { if (m_output_buffer.committed() > max_buffer_size_for_flush) {
flush_output_buffer(); flush_output_buffer();
} }
} }
public: public:
explicit MultipolygonCollector(const assembler_config_type& assembler_config) : explicit MultipolygonCollector(const assembler_config_type& assembler_config) :
collector_type(), collector_type(),
m_assembler_config(assembler_config), m_assembler_config(assembler_config),
m_output_buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes) { m_output_buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes) {
} }
/** /**
* We are interested in all relations tagged with type=multipolygon or * We are interested in all relations tagged with type=multipolygon or
* type=boundary. * type=boundary.
* *
* Overwritten from the base class. * Overwritten from the base class.
*/ */
bool keep_relation(const osmium::Relation& relation) const { bool keep_relation(const osmium::Relation& relation) const {
const char* type = relation.tags().get_value_by_key("type"); const char* type = relation.tags().get_value_by_key("type");
// ignore relations without "type" tag // ignore relations without "type" tag
if (!type) { if (!type) {
return false; return false;
} }
if ((!strcmp(type, "multipolygon")) || (!strcmp(type, "boundary"))) { if ((!strcmp(type, "multipolygon")) || (!strcmp(type, "boundary"))) {
return true; return true;
} }
return false; return false;
} }
/** /**
* Overwritten from the base class. * Overwritten from the base class.
*/ */
bool keep_member(const osmium::relations::RelationMeta& /*relation_meta*/, const osmium::RelationMember& member) const { bool keep_member(const osmium::relations::RelationMeta& /*relation_meta*/, const osmium::RelationMember& member) const {
// We are only interested in members of type way. // We are only interested in members of type way.
return member.type() == osmium::item_type::way; return member.type() == osmium::item_type::way;
} }
/** /**
* This is called when a way is not in any multipolygon * This is called when a way is not in any multipolygon
* relation. * relation.
* *
* Overwritten from the base class. * Overwritten from the base class.
*/ */
void way_not_in_any_relation(const osmium::Way& way) { void way_not_in_any_relation(const osmium::Way& way) {
if (way.ends_have_same_location() && way.nodes().size() > 3) { if (way.ends_have_same_location() && way.nodes().size() > 3) {
// way is closed and has enough nodes, build simple multipolygon // way is closed and has enough nodes, build simple multipolygon
try { try {
TAssembler assembler(m_assembler_config); TAssembler assembler(m_assembler_config);
assembler(way, m_output_buffer); assembler(way, m_output_buffer);
possibly_flush_output_buffer(); possibly_flush_output_buffer();
} catch (osmium::invalid_location&) { } catch (osmium::invalid_location&) {
// XXX ignore // XXX ignore
} }
} }
} }
void complete_relation(osmium::relations::RelationMeta& relation_meta) { void complete_relation(osmium::relations::RelationMeta& relation_meta) {
const osmium::Relation& relation = this->get_relation(relation_meta); const osmium::Relation& relation = this->get_relation(relation_meta);
std::vector<size_t> offsets; std::vector<size_t> offsets;
for (const auto& member : relation.members()) { for (const auto& member : relation.members()) {
if (member.ref() != 0) { if (member.ref() != 0) {
offsets.push_back(this->get_offset(member.type(), member.ref())); offsets.push_back(this->get_offset(member.type(), member.ref()));
} }
} }
try { try {
TAssembler assembler(m_assembler_config); TAssembler assembler(m_assembler_config);
assembler(relation, offsets, this->members_buffer(), m_output_buffer); assembler(relation, offsets, this->members_buffer(), m_output_buffer);
possibly_flush_output_buffer(); possibly_flush_output_buffer();
} catch (osmium::invalid_location&) { } catch (osmium::invalid_location&) {
// XXX ignore // XXX ignore
} }
// clear member metas // clear member metas
for (const auto& member : relation.members()) { for (const auto& member : relation.members()) {
if (member.ref() != 0) { if (member.ref() != 0) {
auto& mmv = this->member_meta(member.type()); auto& mmv = this->member_meta(member.type());
auto range = std::equal_range(mmv.begin(), mmv.end(), osmium::relations::MemberMeta(member.ref())); auto range = std::equal_range(mmv.begin(), mmv.end(), osmium::relations::MemberMeta(member.ref()));
assert(range.first != range.second); assert(range.first != range.second);
// if this is the last time this object was needed // if this is the last time this object was needed
// then mark it as removed // then mark it as removed
if (range.first + 1 == range.second) { if (osmium::relations::count_not_removed(range.first, range.second) == 1) {
this->get_member(range.first->buffer_offset()).removed(true); this->get_member(range.first->buffer_offset()).set_removed(true);
} }
for (auto it = range.first; it != range.second; ++it) { for (auto it = range.first; it != range.second; ++it) {
if (relation.id() == this->get_relation(it->relation_pos()).id()) { if (!it->removed() && relation.id() == this->get_relation(it->relation_pos()).id()) {
mmv.erase(it); it->remove();
break; break;
} }
} }
} }
} }
} }
void flush() { void flush() {
flush_output_buffer(); flush_output_buffer();
} }
osmium::memory::Buffer read() { osmium::memory::Buffer read() {
osmium::memory::Buffer buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes); osmium::memory::Buffer buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes);
std::swap(buffer, m_output_buffer); std::swap(buffer, m_output_buffer);
return buffer; return buffer;
} }
}; // class MultipolygonCollector }; // class MultipolygonCollector
} // namespace area } // namespace area
} // namespace osmium } // namespace osmium
#endif // OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP #endif // OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP

View File

@ -1,149 +1,149 @@
#ifndef OSMIUM_AREA_PROBLEM_REPORTER_HPP #ifndef OSMIUM_AREA_PROBLEM_REPORTER_HPP
#define OSMIUM_AREA_PROBLEM_REPORTER_HPP #define OSMIUM_AREA_PROBLEM_REPORTER_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <osmium/osm/item_type.hpp> #include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp> #include <osmium/osm/location.hpp>
#include <osmium/osm/types.hpp> #include <osmium/osm/types.hpp>
namespace osmium { namespace osmium {
namespace area { namespace area {
/** /**
* When assembling a multipolygon/area from a multipolygon relation * When assembling a multipolygon/area from a multipolygon relation
* or a closed way several problems can be detected. This includes * or a closed way several problems can be detected. This includes
* intersections between lines, wrong role attributes on relation * intersections between lines, wrong role attributes on relation
* members etc. These problems are reported by the area::Assembler * members etc. These problems are reported by the area::Assembler
* class to the ProblemReporter class or one of its child classes. * class to the ProblemReporter class or one of its child classes.
* *
* This is the parent class which does nothing with the reports. * This is the parent class which does nothing with the reports.
* Child classes are expected to implement different ways of * Child classes are expected to implement different ways of
* reporting the problems. * reporting the problems.
*/ */
class ProblemReporter { class ProblemReporter {
protected: protected:
// Type of object we are currently working on // Type of object we are currently working on
osmium::item_type m_object_type; osmium::item_type m_object_type;
// ID of the relation/way we are currently working on // ID of the relation/way we are currently working on
osmium::object_id_type m_object_id; osmium::object_id_type m_object_id;
public: public:
ProblemReporter() = default; ProblemReporter() = default;
virtual ~ProblemReporter() = default; virtual ~ProblemReporter() = default;
/** /**
* Set the object the next problem reports will be on. * Set the object the next problem reports will be on.
* *
* @param object_type The type of the object. * @param object_type The type of the object.
* @param object_id The ID of the object. * @param object_id The ID of the object.
*/ */
void set_object(osmium::item_type object_type, osmium::object_id_type object_id) { void set_object(osmium::item_type object_type, osmium::object_id_type object_id) noexcept {
m_object_type = object_type; m_object_type = object_type;
m_object_id = object_id; m_object_id = object_id;
} }
// Disable "unused-parameter" warning, so that the compiler will not complain. // Disable "unused-parameter" warning, so that the compiler will not complain.
// We can't remove the parameter names, because then doxygen will complain. // We can't remove the parameter names, because then doxygen will complain.
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-parameter"
/** /**
* Report a duplicate node, ie. two nodes with the same location. * Report a duplicate node, ie. two nodes with the same location.
* *
* @param node_id1 ID of the first node. * @param node_id1 ID of the first node.
* @param node_id2 ID of the second node. * @param node_id2 ID of the second node.
* @param location Location of both nodes. * @param location Location of both nodes.
*/ */
virtual void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) { virtual void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) {
} }
/** /**
* Report an intersection between two segments. * Report an intersection between two segments.
* *
* @param way1_id ID of the first involved way. * @param way1_id ID of the first involved way.
* @param way1_seg_start Location where the segment of the first way with the intersection starts * @param way1_seg_start Location where the segment of the first way with the intersection starts
* @param way1_seg_end Location where the segment of the first way with the intersection ends * @param way1_seg_end Location where the segment of the first way with the intersection ends
* @param way2_id ID of the second involved way. * @param way2_id ID of the second involved way.
* @param way2_seg_start Location where the segment of the second way with the intersection starts * @param way2_seg_start Location where the segment of the second way with the intersection starts
* @param way2_seg_end Location where the segment of the second way with the intersection ends * @param way2_seg_end Location where the segment of the second way with the intersection ends
* @param intersection Location of the intersection. This might be slightly off the correct location due to rounding. * @param intersection Location of the intersection. This might be slightly off the correct location due to rounding.
*/ */
virtual void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end, virtual void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) { osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) {
} }
/** /**
* Report an open ring. * Report an open ring.
* *
* @param end1 Location of the first open end. * @param end1 Location of the first open end.
* @param end2 Location of the second open end. * @param end2 Location of the second open end.
*/ */
virtual void report_ring_not_closed(osmium::Location end1, osmium::Location end2) { virtual void report_ring_not_closed(osmium::Location end1, osmium::Location end2) {
} }
/** /**
* Report a segment that should have role "outer", but has a different role. * Report a segment that should have role "outer", but has a different role.
* *
* @param way_id ID of the way this segment is in. * @param way_id ID of the way this segment is in.
* @param seg_start Start of the segment with the wrong role. * @param seg_start Start of the segment with the wrong role.
* @param seg_end End of the segment with the wrong role. * @param seg_end End of the segment with the wrong role.
*/ */
virtual void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) { virtual void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) {
} }
/** /**
* Report a segment that should have role "inner", but has a different role. * Report a segment that should have role "inner", but has a different role.
* *
* @param way_id ID of the way this segment is in. * @param way_id ID of the way this segment is in.
* @param seg_start Start of the segment with the wrong role. * @param seg_start Start of the segment with the wrong role.
* @param seg_end End of the segment with the wrong role. * @param seg_end End of the segment with the wrong role.
*/ */
virtual void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) { virtual void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) {
} }
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
}; // class ProblemReporter }; // class ProblemReporter
} // namespace area } // namespace area
} // namespace osmium } // namespace osmium
#endif // OSMIUM_AREA_PROBLEM_REPORTER_HPP #endif // OSMIUM_AREA_PROBLEM_REPORTER_HPP

View File

@ -37,10 +37,14 @@ DEALINGS IN THE SOFTWARE.
#define OSMIUM_LINK_WITH_LIBS_OGR `gdal-config --libs` #define OSMIUM_LINK_WITH_LIBS_OGR `gdal-config --libs`
#pragma GCC diagnostic push #pragma GCC diagnostic push
#ifdef __clang__
# pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
#endif
#pragma GCC diagnostic ignored "-Wfloat-equal"
#pragma GCC diagnostic ignored "-Wold-style-cast" #pragma GCC diagnostic ignored "-Wold-style-cast"
#pragma GCC diagnostic ignored "-Wpadded"
#pragma GCC diagnostic ignored "-Wredundant-decls" #pragma GCC diagnostic ignored "-Wredundant-decls"
#pragma GCC diagnostic ignored "-Wshadow" #pragma GCC diagnostic ignored "-Wshadow"
#pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
# include <ogr_api.h> # include <ogr_api.h>
# include <ogrsf_frmts.h> # include <ogrsf_frmts.h>
#pragma GCC diagnostic pop #pragma GCC diagnostic pop

View File

@ -1,96 +1,96 @@
#ifndef OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP #ifndef OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP
#define OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP #define OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <ostream> #include <ostream>
#include <osmium/area/problem_reporter.hpp> #include <osmium/area/problem_reporter.hpp>
#include <osmium/osm/item_type.hpp> #include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp> #include <osmium/osm/location.hpp>
#include <osmium/osm/types.hpp> #include <osmium/osm/types.hpp>
namespace osmium { namespace osmium {
namespace area { namespace area {
class ProblemReporterStream : public ProblemReporter { class ProblemReporterStream : public ProblemReporter {
std::ostream& m_out; std::ostream* m_out;
public: public:
explicit ProblemReporterStream(std::ostream& out) : explicit ProblemReporterStream(std::ostream& out) :
m_out(out) { m_out(&out) {
} }
virtual ~ProblemReporterStream() = default; virtual ~ProblemReporterStream() = default;
void header(const char* msg) { void header(const char* msg) {
m_out << "DATA PROBLEM: " << msg << " on " << item_type_to_char(m_object_type) << m_object_id << ": "; *m_out << "DATA PROBLEM: " << msg << " on " << item_type_to_char(m_object_type) << m_object_id << ": ";
} }
void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override { void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
header("duplicate node"); header("duplicate node");
m_out << "node_id1=" << node_id1 << " node_id2=" << node_id2 << " location=" << location << "\n"; *m_out << "node_id1=" << node_id1 << " node_id2=" << node_id2 << " location=" << location << "\n";
} }
void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end, void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override { osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
header("intersection"); header("intersection");
m_out << "way1_id=" << way1_id << " way1_seg_start=" << way1_seg_start << " way1_seg_end=" << way1_seg_end *m_out << "way1_id=" << way1_id << " way1_seg_start=" << way1_seg_start << " way1_seg_end=" << way1_seg_end
<< " way2_id=" << way2_id << " way2_seg_start=" << way2_seg_start << " way2_seg_end=" << way2_seg_end << " intersection=" << intersection << "\n"; << " way2_id=" << way2_id << " way2_seg_start=" << way2_seg_start << " way2_seg_end=" << way2_seg_end << " intersection=" << intersection << "\n";
} }
void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override { void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
header("ring not closed"); header("ring not closed");
m_out << "end1=" << end1 << " end2=" << end2 << "\n"; *m_out << "end1=" << end1 << " end2=" << end2 << "\n";
} }
void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override { void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
header("role should be outer"); header("role should be outer");
m_out << "way_id=" << way_id << " seg_start=" << seg_start << " seg_end=" << seg_end << "\n"; *m_out << "way_id=" << way_id << " seg_start=" << seg_start << " seg_end=" << seg_end << "\n";
} }
void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override { void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
header("role should be inner"); header("role should be inner");
m_out << "way_id=" << way_id << " seg_start=" << seg_start << " seg_end=" << seg_end << "\n"; *m_out << "way_id=" << way_id << " seg_start=" << seg_start << " seg_end=" << seg_end << "\n";
} }
}; // class ProblemReporterStream }; // class ProblemReporterStream
} // namespace area } // namespace area
} // namespace osmium } // namespace osmium
#endif // OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP #endif // OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP

View File

@ -1,179 +1,220 @@
#ifndef OSMIUM_BUILDER_BUILDER_HPP #ifndef OSMIUM_BUILDER_BUILDER_HPP
#define OSMIUM_BUILDER_BUILDER_HPP #define OSMIUM_BUILDER_BUILDER_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <new> #include <new>
#include <type_traits>
#include <osmium/memory/buffer.hpp>
#include <osmium/memory/item.hpp> #include <osmium/memory/buffer.hpp>
#include <osmium/memory/item.hpp>
namespace osmium { #include <osmium/osm/types.hpp>
#include <osmium/util/cast.hpp>
/**
* @brief Classes for building OSM objects and other items in buffers namespace osmium {
*/
namespace builder { /**
* @brief Classes for building OSM objects and other items in buffers
class Builder { */
namespace builder {
osmium::memory::Buffer& m_buffer;
Builder* m_parent; class Builder {
size_t m_item_offset;
osmium::memory::Buffer& m_buffer;
Builder(const Builder&) = delete; Builder* m_parent;
Builder(Builder&&) = delete; size_t m_item_offset;
Builder& operator=(const Builder&) = delete; Builder(const Builder&) = delete;
Builder& operator=(Builder&&) = delete; Builder(Builder&&) = delete;
protected: Builder& operator=(const Builder&) = delete;
Builder& operator=(Builder&&) = delete;
explicit Builder(osmium::memory::Buffer& buffer, Builder* parent, size_t size) :
m_buffer(buffer), protected:
m_parent(parent),
m_item_offset(buffer.written()) { explicit Builder(osmium::memory::Buffer& buffer, Builder* parent, osmium::memory::item_size_type size) :
m_buffer.reserve_space(size); m_buffer(buffer),
assert(buffer.is_aligned()); m_parent(parent),
if (m_parent) { m_item_offset(buffer.written()) {
m_parent->add_size(size); m_buffer.reserve_space(size);
} assert(buffer.is_aligned());
} if (m_parent) {
m_parent->add_size(size);
~Builder() = default; }
}
osmium::memory::Item& item() const {
return *reinterpret_cast<osmium::memory::Item*>(m_buffer.data() + m_item_offset); ~Builder() = default;
}
osmium::memory::Item& item() const {
public: return *reinterpret_cast<osmium::memory::Item*>(m_buffer.data() + m_item_offset);
}
/**
* Add padding to buffer (if needed) to align data properly. public:
*
* This calculates how many padding bytes are needed and adds /**
* as many zero bytes to the buffer. It also adds this number * Add padding to buffer (if needed) to align data properly.
* to the size of the current item (if the "self" param is *
* true) and recursively to all the parent items. * This calculates how many padding bytes are needed and adds
* * as many zero bytes to the buffer. It also adds this number
* @param self If true add number of padding bytes to size * to the size of the current item (if the "self" param is
* of current item. Size is always added to * true) and recursively to all the parent items.
* parent item (if any). *
* * @param self If true add number of padding bytes to size
*/ * of current item. Size is always added to
void add_padding(bool self=false) { * parent item (if any).
size_t padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes); *
if (padding != osmium::memory::align_bytes) { */
std::memset(m_buffer.reserve_space(padding), 0, padding); void add_padding(bool self=false) {
if (self) { auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
add_size(padding); if (padding != osmium::memory::align_bytes) {
} else if (m_parent) { std::memset(m_buffer.reserve_space(padding), 0, padding);
m_parent->add_size(padding); if (self) {
assert(m_parent->size() % osmium::memory::align_bytes == 0); add_size(padding);
} } else if (m_parent) {
} m_parent->add_size(padding);
} assert(m_parent->size() % osmium::memory::align_bytes == 0);
}
void add_size(uint32_t size) { }
item().add_size(size); }
if (m_parent) {
m_parent->add_size(size); void add_size(uint32_t size) {
} item().add_size(size);
} if (m_parent) {
m_parent->add_size(size);
uint32_t size() const { }
return item().byte_size(); }
}
uint32_t size() const noexcept {
void add_item(const osmium::memory::Item* item) { return item().byte_size();
std::memcpy(m_buffer.reserve_space(item->padded_size()), item, item->padded_size()); }
add_size(item->padded_size());
} void add_item(const osmium::memory::Item* item) {
std::memcpy(m_buffer.reserve_space(item->padded_size()), item, item->padded_size());
/** add_size(item->padded_size());
* Reserve space for an object of class T in buffer and return }
* pointer to it.
*/ /**
template <class T> * Reserve space for an object of class T in buffer and return
T* reserve_space_for() { * pointer to it.
assert(m_buffer.is_aligned()); */
return reinterpret_cast<T*>(m_buffer.reserve_space(sizeof(T))); template <class T>
} T* reserve_space_for() {
assert(m_buffer.is_aligned());
/** return reinterpret_cast<T*>(m_buffer.reserve_space(sizeof(T)));
* Append \0-terminated string to buffer. }
*/
size_t append(const char* str) { /**
size_t length = std::strlen(str) + 1; * Append data to buffer.
std::memcpy(m_buffer.reserve_space(length), str, length); *
return length; * @param data Pointer to data.
} * @param length Length of data in bytes. If data is a
* \0-terminated string, length must contain the
/// Return the buffer this builder is using. * \0 byte.
osmium::memory::Buffer& buffer() { */
return m_buffer; osmium::memory::item_size_type append(const char* data, const osmium::memory::item_size_type length) {
} std::memcpy(m_buffer.reserve_space(length), data, length);
return length;
}; // class Builder }
template <class T> /**
class ObjectBuilder : public Builder { * Append \0-terminated string to buffer.
*/
public: osmium::memory::item_size_type append(const char* str) {
return append(str, static_cast<osmium::memory::item_size_type>(std::strlen(str) + 1));
explicit ObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) : }
Builder(buffer, parent, sizeof(T)) {
new (&item()) T(); /// Return the buffer this builder is using.
} osmium::memory::Buffer& buffer() noexcept {
return m_buffer;
T& object() { }
return static_cast<T&>(item());
} }; // class Builder
void add_user(const char* user) { template <class TItem>
object().user_size(std::strlen(user) + 1); class ObjectBuilder : public Builder {
add_size(append(user));
add_padding(true); static_assert(std::is_base_of<osmium::memory::Item, TItem>::value,
} "ObjectBuilder can only build objects derived from osmium::memory::Item");
}; // class ObjectBuilder public:
} // namespace builder explicit ObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
Builder(buffer, parent, sizeof(TItem)) {
} // namespace osmium new (&item()) TItem();
}
#endif // OSMIUM_BUILDER_BUILDER_HPP
TItem& object() noexcept {
return static_cast<TItem&>(item());
}
/**
* Add user name to buffer.
*
* @param user Pointer to user name.
* @param length Length of user name including \0 byte.
*/
void add_user(const char* user, const string_size_type length) {
object().set_user_size(length);
add_size(append(user, length));
add_padding(true);
}
/**
* Add user name to buffer.
*
* @param user Pointer to \0-terminated user name.
*/
void add_user(const char* user) {
add_user(user, static_cast_with_assert<string_size_type>(std::strlen(user) + 1));
}
/**
* Add user name to buffer.
*
* @param user User name.
*/
void add_user(const std::string& user) {
add_user(user.data(), static_cast_with_assert<string_size_type>(user.size() + 1));
}
}; // class ObjectBuilder
} // namespace builder
} // namespace osmium
#endif // OSMIUM_BUILDER_BUILDER_HPP

View File

@ -46,6 +46,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/object.hpp> #include <osmium/osm/object.hpp>
#include <osmium/osm/tag.hpp> #include <osmium/osm/tag.hpp>
#include <osmium/osm/types.hpp> #include <osmium/osm/types.hpp>
#include <osmium/util/cast.hpp>
namespace osmium { namespace osmium {
@ -67,10 +68,27 @@ namespace osmium {
add_padding(); add_padding();
} }
/**
* Add tag to buffer.
*
* @param key Tag key.
* @param value Tag value.
*/
void add_tag(const char* key, const char* value) { void add_tag(const char* key, const char* value) {
add_size(append(key) + append(value)); add_size(append(key) + append(value));
} }
/**
* Add tag to buffer.
*
* @param key Tag key.
* @param value Tag value.
*/
void add_tag(const std::string& key, const std::string& value) {
add_size(append(key.data(), static_cast_with_assert<string_size_type>(key.size() + 1)) +
append(value.data(), static_cast_with_assert<string_size_type>(value.size() + 1)));
}
}; // class TagListBuilder }; // class TagListBuilder
template <class T> template <class T>
@ -103,14 +121,42 @@ namespace osmium {
class RelationMemberListBuilder : public ObjectBuilder<RelationMemberList> { class RelationMemberListBuilder : public ObjectBuilder<RelationMemberList> {
void add_role(osmium::RelationMember* member, const char* role) { /**
size_t length = std::strlen(role) + 1; * Add role to buffer.
assert(length < std::numeric_limits<string_size_type>::max()); *
member->set_role_size(static_cast<string_size_type>(length)); * @param member Relation member object where the length of the role
add_size(append(role)); * will be set.
* @param role The role.
* @param length Length of role string including \0 termination.
*/
void add_role(osmium::RelationMember& member, const char* role, const string_size_type length) {
member.set_role_size(length);
add_size(append(role, length));
add_padding(true); add_padding(true);
} }
/**
* Add role to buffer.
*
* @param member Relation member object where the length of the role
* will be set.
* @param role \0-terminated role.
*/
void add_role(osmium::RelationMember& member, const char* role) {
add_role(member, role, static_cast_with_assert<string_size_type>(std::strlen(role) + 1));
}
/**
* Add role to buffer.
*
* @param member Relation member object where the length of the role
* will be set.
* @param role Role.
*/
void add_role(osmium::RelationMember& member, const std::string& role) {
add_role(member, role.data(), static_cast_with_assert<string_size_type>(role.size() + 1));
}
public: public:
explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) : explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
@ -121,11 +167,41 @@ namespace osmium {
add_padding(); add_padding();
} }
/**
* Add a member to the relation.
*
* @param type The type (node, way, or relation).
* @param ref The ID of the member.
* @param role The role of the member.
* @param full_member Optional pointer to the member object. If it
* is available a copy will be added to the
* relation.
*/
void add_member(osmium::item_type type, object_id_type ref, const char* role, const osmium::OSMObject* full_member = nullptr) { void add_member(osmium::item_type type, object_id_type ref, const char* role, const osmium::OSMObject* full_member = nullptr) {
osmium::RelationMember* member = reserve_space_for<osmium::RelationMember>(); osmium::RelationMember* member = reserve_space_for<osmium::RelationMember>();
new (member) osmium::RelationMember(ref, type, full_member != nullptr); new (member) osmium::RelationMember(ref, type, full_member != nullptr);
add_size(sizeof(RelationMember)); add_size(sizeof(RelationMember));
add_role(member, role); add_role(*member, role);
if (full_member) {
add_item(full_member);
}
}
/**
* Add a member to the relation.
*
* @param type The type (node, way, or relation).
* @param ref The ID of the member.
* @param role The role of the member.
* @param full_member Optional pointer to the member object. If it
* is available a copy will be added to the
* relation.
*/
void add_member(osmium::item_type type, object_id_type ref, const std::string& role, const osmium::OSMObject* full_member = nullptr) {
osmium::RelationMember* member = reserve_space_for<osmium::RelationMember>();
new (member) osmium::RelationMember(ref, type, full_member != nullptr);
add_size(sizeof(RelationMember));
add_role(*member, role);
if (full_member) { if (full_member) {
add_item(full_member); add_item(full_member);
} }
@ -186,12 +262,12 @@ namespace osmium {
*/ */
void initialize_from_object(const osmium::OSMObject& source) { void initialize_from_object(const osmium::OSMObject& source) {
osmium::Area& area = object(); osmium::Area& area = object();
area.id(osmium::object_id_to_area_id(source.id(), source.type())); area.set_id(osmium::object_id_to_area_id(source.id(), source.type()));
area.version(source.version()); area.set_version(source.version());
area.changeset(source.changeset()); area.set_changeset(source.changeset());
area.timestamp(source.timestamp()); area.set_timestamp(source.timestamp());
area.visible(source.visible()); area.set_visible(source.visible());
area.uid(source.uid()); area.set_uid(source.uid());
add_user(source.user()); add_user(source.user());
} }

View File

@ -1,195 +1,195 @@
#ifndef OSMIUM_DYNAMIC_HANDLER_HPP #ifndef OSMIUM_DYNAMIC_HANDLER_HPP
#define OSMIUM_DYNAMIC_HANDLER_HPP #define OSMIUM_DYNAMIC_HANDLER_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <osmium/handler.hpp> #include <osmium/handler.hpp>
namespace osmium { namespace osmium {
class Node; class Node;
class Way; class Way;
class Relation; class Relation;
class Area; class Area;
class Changeset; class Changeset;
namespace handler { namespace handler {
namespace detail { namespace detail {
class HandlerWrapperBase { class HandlerWrapperBase {
public: public:
virtual ~HandlerWrapperBase() { virtual ~HandlerWrapperBase() {
} }
virtual void node(const osmium::Node&) { virtual void node(const osmium::Node&) {
} }
virtual void way(const osmium::Way&) { virtual void way(const osmium::Way&) {
} }
virtual void relation(const osmium::Relation&) { virtual void relation(const osmium::Relation&) {
} }
virtual void area(const osmium::Area&) { virtual void area(const osmium::Area&) {
} }
virtual void changeset(const osmium::Changeset&) { virtual void changeset(const osmium::Changeset&) {
} }
virtual void flush() { virtual void flush() {
} }
}; // class HandlerWrapperBase }; // class HandlerWrapperBase
// The following uses trick from // The following uses trick from
// http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence // http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence
// to either call handler style functions or visitor style operator(). // to either call handler style functions or visitor style operator().
#define OSMIUM_DYNAMIC_HANDLER_DISPATCH(_name_, _type_) \ #define OSMIUM_DYNAMIC_HANDLER_DISPATCH(_name_, _type_) \
template <class THandler> \ template <class THandler> \
auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, int) -> decltype(handler._name_(object), void()) { \ auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, int) -> decltype(handler._name_(object), void()) { \
handler._name_(object); \ handler._name_(object); \
} \ } \
template <class THandler> \ template <class THandler> \
auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) -> decltype(handler(object), void()) { \ auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) -> decltype(handler(object), void()) { \
handler(object); \ handler(object); \
} }
OSMIUM_DYNAMIC_HANDLER_DISPATCH(node, Node) OSMIUM_DYNAMIC_HANDLER_DISPATCH(node, Node)
OSMIUM_DYNAMIC_HANDLER_DISPATCH(way, Way) OSMIUM_DYNAMIC_HANDLER_DISPATCH(way, Way)
OSMIUM_DYNAMIC_HANDLER_DISPATCH(relation, Relation) OSMIUM_DYNAMIC_HANDLER_DISPATCH(relation, Relation)
OSMIUM_DYNAMIC_HANDLER_DISPATCH(changeset, Changeset) OSMIUM_DYNAMIC_HANDLER_DISPATCH(changeset, Changeset)
OSMIUM_DYNAMIC_HANDLER_DISPATCH(area, Area) OSMIUM_DYNAMIC_HANDLER_DISPATCH(area, Area)
template <class THandler> template <class THandler>
auto flush_dispatch(THandler& handler, int) -> decltype(handler.flush(), void()) { auto flush_dispatch(THandler& handler, int) -> decltype(handler.flush(), void()) {
handler.flush(); handler.flush();
} }
template <class THandler> template <class THandler>
void flush_dispatch(THandler&, long) {} void flush_dispatch(THandler&, long) {}
template <class THandler> template <class THandler>
class HandlerWrapper : public HandlerWrapperBase { class HandlerWrapper : public HandlerWrapperBase {
THandler m_handler; THandler m_handler;
public: public:
template <class... TArgs> template <class... TArgs>
HandlerWrapper(TArgs&&... args) : HandlerWrapper(TArgs&&... args) :
m_handler(std::forward<TArgs>(args)...) { m_handler(std::forward<TArgs>(args)...) {
} }
void node(const osmium::Node& node) override final { void node(const osmium::Node& node) override final {
node_dispatch(m_handler, node, 0); node_dispatch(m_handler, node, 0);
} }
void way(const osmium::Way& way) override final { void way(const osmium::Way& way) override final {
way_dispatch(m_handler, way, 0); way_dispatch(m_handler, way, 0);
} }
void relation(const osmium::Relation& relation) override final { void relation(const osmium::Relation& relation) override final {
relation_dispatch(m_handler, relation, 0); relation_dispatch(m_handler, relation, 0);
} }
void area(const osmium::Area& area) override final { void area(const osmium::Area& area) override final {
area_dispatch(m_handler, area, 0); area_dispatch(m_handler, area, 0);
} }
void changeset(const osmium::Changeset& changeset) override final { void changeset(const osmium::Changeset& changeset) override final {
changeset_dispatch(m_handler, changeset, 0); changeset_dispatch(m_handler, changeset, 0);
} }
void flush() override final { void flush() override final {
flush_dispatch(m_handler, 0); flush_dispatch(m_handler, 0);
} }
}; // HandlerWrapper }; // class HandlerWrapper
} // namespace detail } // namespace detail
class DynamicHandler : public osmium::handler::Handler { class DynamicHandler : public osmium::handler::Handler {
typedef std::unique_ptr<osmium::handler::detail::HandlerWrapperBase> impl_ptr; typedef std::unique_ptr<osmium::handler::detail::HandlerWrapperBase> impl_ptr;
impl_ptr m_impl; impl_ptr m_impl;
public: public:
DynamicHandler() : DynamicHandler() :
m_impl(impl_ptr(new osmium::handler::detail::HandlerWrapperBase)) { m_impl(impl_ptr(new osmium::handler::detail::HandlerWrapperBase)) {
} }
template <class THandler, class... TArgs> template <class THandler, class... TArgs>
void set(TArgs&&... args) { void set(TArgs&&... args) {
m_impl = impl_ptr(new osmium::handler::detail::HandlerWrapper<THandler>(std::forward<TArgs>(args)...)); m_impl = impl_ptr(new osmium::handler::detail::HandlerWrapper<THandler>(std::forward<TArgs>(args)...));
} }
void node(const osmium::Node& node) { void node(const osmium::Node& node) {
m_impl->node(node); m_impl->node(node);
} }
void way(const osmium::Way& way) { void way(const osmium::Way& way) {
m_impl->way(way); m_impl->way(way);
} }
void relation(const osmium::Relation& relation) { void relation(const osmium::Relation& relation) {
m_impl->relation(relation); m_impl->relation(relation);
} }
void area(const osmium::Area& area) { void area(const osmium::Area& area) {
m_impl->area(area); m_impl->area(area);
} }
void changeset(const osmium::Changeset& changeset) { void changeset(const osmium::Changeset& changeset) {
m_impl->changeset(changeset); m_impl->changeset(changeset);
} }
void flush() { void flush() {
m_impl->flush(); m_impl->flush();
} }
}; // DynamicHandler }; // class DynamicHandler
} // namspace handler } // namspace handler
} // namespace osmium } // namespace osmium
#endif // OSMIUM_DYNAMIC_HANDLER_HPP #endif // OSMIUM_DYNAMIC_HANDLER_HPP

View File

@ -38,59 +38,50 @@ DEALINGS IN THE SOFTWARE.
#include <string> #include <string>
#include <osmium/osm/location.hpp> #include <osmium/osm/location.hpp>
#include <osmium/util/double.hpp>
namespace osmium { namespace osmium {
namespace geom { namespace geom {
namespace detail {
/**
* Append double to string, removing superfluous '0' characters at
* the end. The decimal dot will also be removed if necessary.
*/
inline void double2string(std::string& s, double value) {
s += std::to_string(value);
size_t len = s.size()-1;
while (s[len] == '0') --len;
if (s[len] == '.') --len;
s.resize(len+1);
}
} // namespace detail
struct Coordinates { struct Coordinates {
double x; double x;
double y; double y;
explicit Coordinates(double cx, double cy) : x(cx), y(cy) { explicit Coordinates(double cx, double cy) noexcept : x(cx), y(cy) {
} }
Coordinates(const osmium::Location& location) : x(location.lon()), y(location.lat()) { Coordinates(const osmium::Location& location) : x(location.lon()), y(location.lat()) {
} }
void append_to_string(std::string& s, const char infix) const { void append_to_string(std::string& s, const char infix, int precision) const {
osmium::geom::detail::double2string(s, x); osmium::util::double2string(s, x, precision);
s += infix; s += infix;
osmium::geom::detail::double2string(s, y); osmium::util::double2string(s, y, precision);
} }
void append_to_string(std::string& s, const char prefix, const char infix, const char suffix) const { void append_to_string(std::string& s, const char prefix, const char infix, const char suffix, int precision) const {
s += prefix; s += prefix;
append_to_string(s, infix); append_to_string(s, infix, precision);
s += suffix; s += suffix;
} }
}; // struct coordinates }; // struct coordinates
inline bool operator==(const Coordinates& lhs, const Coordinates& rhs) { /**
* Compare whether two Coordinates are identical. Might not give the
* right result if the coordinates have been the result of some
* calculation that introduced rounding errors.
*/
inline bool operator==(const Coordinates& lhs, const Coordinates& rhs) noexcept {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
return lhs.x == rhs.x && lhs.y == rhs.y; return lhs.x == rhs.x && lhs.y == rhs.y;
#pragma GCC diagnostic pop
} }
inline bool operator!=(const Coordinates& lhs, const Coordinates& rhs) { inline bool operator!=(const Coordinates& lhs, const Coordinates& rhs) noexcept {
return ! operator==(lhs, rhs); return ! operator==(lhs, rhs);
} }

View File

@ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <cstddef>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <utility> #include <utility>
@ -49,6 +50,10 @@ DEALINGS IN THE SOFTWARE.
namespace osmium { namespace osmium {
/**
* Exception thrown when an invalid geometry is encountered. An example
* would be a linestring with less than two points.
*/
struct geometry_error : public std::runtime_error { struct geometry_error : public std::runtime_error {
geometry_error(const std::string& what) : geometry_error(const std::string& what) :
@ -72,7 +77,7 @@ namespace osmium {
enum class use_nodes : bool { enum class use_nodes : bool {
unique = true, ///< Remove consecutive nodes with same location. unique = true, ///< Remove consecutive nodes with same location.
all = false ///< Use all nodes. all = false ///< Use all nodes.
}; }; // enum class use_nodes
/** /**
* Which direction the linestring created from a way * Which direction the linestring created from a way
@ -81,7 +86,7 @@ namespace osmium {
enum class direction : bool { enum class direction : bool {
backward = true, ///< Linestring has reverse direction. backward = true, ///< Linestring has reverse direction.
forward = false ///< Linestring has same direction as way. forward = false ///< Linestring has same direction as way.
}; }; // enum class direction
/** /**
* This pseudo projection just returns its WGS84 input unchanged. * This pseudo projection just returns its WGS84 input unchanged.
@ -95,7 +100,7 @@ namespace osmium {
return Coordinates{location.lon(), location.lat()}; return Coordinates{location.lon(), location.lat()};
} }
int epsg() const { int epsg() const noexcept {
return 4326; return 4326;
} }
@ -178,6 +183,10 @@ namespace osmium {
/* LineString */ /* LineString */
void linestring_start() {
m_impl.linestring_start();
}
template <class TIter> template <class TIter>
size_t fill_linestring(TIter it, TIter end) { size_t fill_linestring(TIter it, TIter end) {
size_t num_points = 0; size_t num_points = 0;
@ -201,8 +210,12 @@ namespace osmium {
return num_points; return num_points;
} }
linestring_type linestring_finish(size_t num_points) {
return m_impl.linestring_finish(num_points);
}
linestring_type create_linestring(const osmium::WayNodeList& wnl, use_nodes un=use_nodes::unique, direction dir=direction::forward) { linestring_type create_linestring(const osmium::WayNodeList& wnl, use_nodes un=use_nodes::unique, direction dir=direction::forward) {
m_impl.linestring_start(); linestring_start();
size_t num_points = 0; size_t num_points = 0;
if (un == use_nodes::unique) { if (un == use_nodes::unique) {
@ -227,16 +240,49 @@ namespace osmium {
} }
if (num_points < 2) { if (num_points < 2) {
throw geometry_error("not enough points for linestring"); throw osmium::geometry_error("not enough points for linestring");
} }
return m_impl.linestring_finish(num_points); return linestring_finish(num_points);
} }
linestring_type create_linestring(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir=direction::forward) { linestring_type create_linestring(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir=direction::forward) {
return create_linestring(way.nodes(), un, dir); return create_linestring(way.nodes(), un, dir);
} }
/* Polygon */
void polygon_start() {
m_impl.polygon_start();
}
template <class TIter>
size_t fill_polygon(TIter it, TIter end) {
size_t num_points = 0;
for (; it != end; ++it, ++num_points) {
m_impl.polygon_add_location(m_projection(it->location()));
}
return num_points;
}
template <class TIter>
size_t fill_polygon_unique(TIter it, TIter end) {
size_t num_points = 0;
osmium::Location last_location;
for (; it != end; ++it) {
if (last_location != it->location()) {
last_location = it->location();
m_impl.polygon_add_location(m_projection(last_location));
++num_points;
}
}
return num_points;
}
polygon_type polygon_finish(size_t num_points) {
return m_impl.polygon_finish(num_points);
}
/* MultiPolygon */ /* MultiPolygon */
multipolygon_type create_multipolygon(const osmium::Area& area) { multipolygon_type create_multipolygon(const osmium::Area& area) {
@ -266,7 +312,7 @@ namespace osmium {
// if there are no rings, this area is invalid // if there are no rings, this area is invalid
if (num_rings == 0) { if (num_rings == 0) {
throw geometry_error("invalid area"); throw osmium::geometry_error("invalid area");
} }
m_impl.multipolygon_polygon_finish(); m_impl.multipolygon_polygon_finish();

View File

@ -49,6 +49,7 @@ namespace osmium {
class GeoJSONFactoryImpl { class GeoJSONFactoryImpl {
std::string m_str; std::string m_str;
int m_precision;
public: public:
@ -58,14 +59,16 @@ namespace osmium {
typedef std::string multipolygon_type; typedef std::string multipolygon_type;
typedef std::string ring_type; typedef std::string ring_type;
GeoJSONFactoryImpl() = default; GeoJSONFactoryImpl(int precision = 7) :
m_precision(precision) {
}
/* Point */ /* Point */
// { "type": "Point", "coordinates": [100.0, 0.0] } // { "type": "Point", "coordinates": [100.0, 0.0] }
point_type make_point(const osmium::geom::Coordinates& xy) const { point_type make_point(const osmium::geom::Coordinates& xy) const {
std::string str {"{\"type\":\"Point\",\"coordinates\":"}; std::string str {"{\"type\":\"Point\",\"coordinates\":"};
xy.append_to_string(str, '[', ',', ']'); xy.append_to_string(str, '[', ',', ']', m_precision);
str += "}"; str += "}";
return str; return str;
} }
@ -78,7 +81,7 @@ namespace osmium {
} }
void linestring_add_location(const osmium::geom::Coordinates& xy) { void linestring_add_location(const osmium::geom::Coordinates& xy) {
xy.append_to_string(m_str, '[', ',', ']'); xy.append_to_string(m_str, '[', ',', ']', m_precision);
m_str += ','; m_str += ',';
} }
@ -124,7 +127,7 @@ namespace osmium {
} }
void multipolygon_add_location(const osmium::geom::Coordinates& xy) { void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
xy.append_to_string(m_str, '[', ',', ']'); xy.append_to_string(m_str, '[', ',', ']', m_precision);
m_str += ','; m_str += ',';
} }

View File

@ -1,96 +1,94 @@
#ifndef OSMIUM_GEOM_HAVERSINE_HPP #ifndef OSMIUM_GEOM_HAVERSINE_HPP
#define OSMIUM_GEOM_HAVERSINE_HPP #define OSMIUM_GEOM_HAVERSINE_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <cmath> #include <cmath>
#include <iterator> #include <iterator>
#include <osmium/geom/coordinates.hpp> #include <osmium/geom/coordinates.hpp>
#include <osmium/geom/util.hpp> #include <osmium/geom/util.hpp>
#include <osmium/memory/collection.hpp> #include <osmium/osm/node_ref.hpp>
#include <osmium/osm/location.hpp> #include <osmium/osm/way.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/way.hpp> namespace osmium {
namespace osmium { namespace geom {
namespace geom { /**
* @brief Functions to calculate arc distance on Earth using the haversine formula.
/** *
* @brief Functions to calculate arc distance on Earth using the haversine formula. * See http://en.wikipedia.org/wiki/Haversine_formula
* *
* See http://en.wikipedia.org/wiki/Haversine_formula * Implementation derived from
* * http://blog.julien.cayzac.name/2008/10/arc-and-distance-between-two-points-on.html
* Implementation derived from */
* http://blog.julien.cayzac.name/2008/10/arc-and-distance-between-two-points-on.html namespace haversine {
*/
namespace haversine { /// @brief Earth's quadratic mean radius for WGS84
constexpr double EARTH_RADIUS_IN_METERS = 6372797.560856;
/// @brief Earth's quadratic mean radius for WGS84
constexpr double EARTH_RADIUS_IN_METERS = 6372797.560856; /**
* Calculate distance in meters between two sets of coordinates.
/** */
* Calculate distance in meters between two sets of coordinates. inline double distance(const osmium::geom::Coordinates& c1, const osmium::geom::Coordinates& c2) {
*/ double lonh = sin(deg_to_rad(c1.x - c2.x) * 0.5);
inline double distance(const osmium::geom::Coordinates& c1, const osmium::geom::Coordinates& c2) { lonh *= lonh;
double lonh = sin(deg_to_rad(c1.x - c2.x) * 0.5); double lath = sin(deg_to_rad(c1.y - c2.y) * 0.5);
lonh *= lonh; lath *= lath;
double lath = sin(deg_to_rad(c1.y - c2.y) * 0.5); const double tmp = cos(deg_to_rad(c1.y)) * cos(deg_to_rad(c2.y));
lath *= lath; return 2.0 * EARTH_RADIUS_IN_METERS * asin(sqrt(lath + tmp*lonh));
const double tmp = cos(deg_to_rad(c1.y)) * cos(deg_to_rad(c2.y)); }
return 2.0 * EARTH_RADIUS_IN_METERS * asin(sqrt(lath + tmp*lonh));
} /**
* Calculate length of way.
/** */
* Calculate length of way. inline double distance(const osmium::WayNodeList& wnl) {
*/ double sum_length=0;
inline double distance(const osmium::WayNodeList& wnl) {
double sum_length=0; for (auto it = wnl.begin(); it != wnl.end(); ++it) {
if (std::next(it) != wnl.end()) {
for (auto it = wnl.begin(); it != wnl.end(); ++it) { sum_length += distance(it->location(), std::next(it)->location());
if (std::next(it) != wnl.end()) { }
sum_length += distance(it->location(), std::next(it)->location()); }
}
} return sum_length;
}
return sum_length;
} } // namespace haversine
} // namespace haversine } // namespace geom
} // namespace geom } // namespace osmium
} // namespace osmium #endif // OSMIUM_GEOM_HAVERSINE_HPP
#endif // OSMIUM_GEOM_HAVERSINE_HPP

View File

@ -46,22 +46,22 @@ namespace osmium {
namespace detail { namespace detail {
constexpr double EARTH_RADIUS_FOR_EPSG3857 = 6378137.0; constexpr double earth_radius_for_epsg3857 = 6378137.0;
constexpr inline double lon_to_x(double lon) { constexpr inline double lon_to_x(double lon) {
return EARTH_RADIUS_FOR_EPSG3857 * deg_to_rad(lon); return earth_radius_for_epsg3857 * deg_to_rad(lon);
} }
inline double lat_to_y(double lat) { // not constexpr because math functions aren't inline double lat_to_y(double lat) { // not constexpr because math functions aren't
return EARTH_RADIUS_FOR_EPSG3857 * std::log(std::tan(osmium::geom::PI/4 + deg_to_rad(lat)/2)); return earth_radius_for_epsg3857 * std::log(std::tan(osmium::geom::PI/4 + deg_to_rad(lat)/2));
} }
constexpr inline double x_to_lon(double x) { constexpr inline double x_to_lon(double x) {
return rad_to_deg(x) / EARTH_RADIUS_FOR_EPSG3857; return rad_to_deg(x) / earth_radius_for_epsg3857;
} }
inline double y_to_lat(double y) { // not constexpr because math functions aren't inline double y_to_lat(double y) { // not constexpr because math functions aren't
return rad_to_deg(2 * std::atan(std::exp(y / EARTH_RADIUS_FOR_EPSG3857)) - osmium::geom::PI/2); return rad_to_deg(2 * std::atan(std::exp(y / earth_radius_for_epsg3857)) - osmium::geom::PI/2);
} }
} // namespace detail } // namespace detail
@ -92,7 +92,7 @@ namespace osmium {
return Coordinates {detail::lon_to_x(location.lon()), detail::lat_to_y(location.lat())}; return Coordinates {detail::lon_to_x(location.lon()), detail::lat_to_y(location.lat())};
} }
int epsg() const { int epsg() const noexcept {
return 3857; return 3857;
} }

View File

@ -37,11 +37,16 @@ DEALINGS IN THE SOFTWARE.
#define OSMIUM_LINK_WITH_LIBS_OGR `gdal-config --libs` #define OSMIUM_LINK_WITH_LIBS_OGR `gdal-config --libs`
#include <cassert> #include <cassert>
#include <cstddef>
#include <memory> #include <memory>
#include <utility> #include <utility>
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdocumentation-unknown-command" #ifdef __clang__
# pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
#endif
#pragma GCC diagnostic ignored "-Wfloat-equal"
#pragma GCC diagnostic ignored "-Wpadded"
# include <ogr_geometry.h> # include <ogr_geometry.h>
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
@ -96,6 +101,23 @@ namespace osmium {
return std::move(m_linestring); return std::move(m_linestring);
} }
/* Polygon */
void polygon_start() {
m_ring = std::unique_ptr<OGRLinearRing>(new OGRLinearRing());
}
void polygon_add_location(const osmium::geom::Coordinates& xy) {
assert(!!m_ring);
m_ring->addPoint(xy.x, xy.y);
}
polygon_type polygon_finish(size_t /* num_points */) {
std::unique_ptr<OGRPolygon> polygon = std::unique_ptr<OGRPolygon>(new OGRPolygon());
polygon->addRingDirectly(m_ring.release());
return polygon;
}
/* MultiPolygon */ /* MultiPolygon */
void multipolygon_start() { void multipolygon_start() {

View File

@ -57,7 +57,7 @@ namespace osmium {
void operator()(void* crs) { void operator()(void* crs) {
pj_free(crs); pj_free(crs);
} }
}; }; // struct ProjCRSDeleter
std::unique_ptr<void, ProjCRSDeleter> m_crs; std::unique_ptr<void, ProjCRSDeleter> m_crs;
@ -142,7 +142,7 @@ namespace osmium {
} }
} }
int epsg() const { int epsg() const noexcept {
return m_epsg; return m_epsg;
} }

View File

@ -1,71 +1,75 @@
#ifndef OSMIUM_GEOM_UTIL_HPP #ifndef OSMIUM_GEOM_UTIL_HPP
#define OSMIUM_GEOM_UTIL_HPP #define OSMIUM_GEOM_UTIL_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
namespace osmium { namespace osmium {
struct projection_error : public std::runtime_error { /**
* Exception thrown when a projection object can not be initialized or the
projection_error(const std::string& what) : * projection of some coordinates can not be calculated.
std::runtime_error(what) { */
} struct projection_error : public std::runtime_error {
projection_error(const char* what) : projection_error(const std::string& what) :
std::runtime_error(what) { std::runtime_error(what) {
} }
}; // struct projection_error projection_error(const char* what) :
std::runtime_error(what) {
namespace geom { }
constexpr double PI = 3.14159265358979323846; }; // struct projection_error
/// Convert angle from degrees to radians. namespace geom {
inline constexpr double deg_to_rad(double degree) {
return degree * (PI / 180.0); constexpr double PI = 3.14159265358979323846;
}
/// Convert angle from degrees to radians.
/// Convert angle from radians to degrees. inline constexpr double deg_to_rad(double degree) noexcept {
inline constexpr double rad_to_deg(double radians) { return degree * (PI / 180.0);
return radians * (180.0 / PI); }
}
/// Convert angle from radians to degrees.
} // namespace geom inline constexpr double rad_to_deg(double radians) noexcept {
return radians * (180.0 / PI);
} // namespace osmium }
#endif // OSMIUM_GEOM_UTIL_HPP } // namespace geom
} // namespace osmium
#endif // OSMIUM_GEOM_UTIL_HPP

View File

@ -38,8 +38,18 @@ DEALINGS IN THE SOFTWARE.
#include <cstring> #include <cstring>
#include <string> #include <string>
// Windows is only available for little endian architectures
// http://stackoverflow.com/questions/6449468/can-i-safely-assume-that-windows-installations-will-always-be-little-endian
#if !defined(_WIN32) && !defined(__APPLE__)
# include <endian.h>
#else
# define __LITTLE_ENDIAN 1234
# define __BYTE_ORDER __LITTLE_ENDIAN
#endif
#include <osmium/geom/coordinates.hpp> #include <osmium/geom/coordinates.hpp>
#include <osmium/geom/factory.hpp> #include <osmium/geom/factory.hpp>
#include <osmium/util/cast.hpp>
namespace osmium { namespace osmium {
@ -48,12 +58,12 @@ namespace osmium {
enum class wkb_type : bool { enum class wkb_type : bool {
wkb = false, wkb = false,
ewkb = true ewkb = true
}; }; // enum class wkb_type
enum class out_type : bool { enum class out_type : bool {
binary = false, binary = false,
hex = true hex = true
}; }; // enum class out_type
namespace detail { namespace detail {
@ -99,7 +109,7 @@ namespace osmium {
// SRID-presence flag (EWKB) // SRID-presence flag (EWKB)
wkbSRID = 0x20000000 wkbSRID = 0x20000000
}; }; // enum wkbGeometryType
/** /**
* Byte order marker in WKB geometry. * Byte order marker in WKB geometry.
@ -107,7 +117,7 @@ namespace osmium {
enum class wkb_byte_order_type : uint8_t { enum class wkb_byte_order_type : uint8_t {
XDR = 0, // Big Endian XDR = 0, // Big Endian
NDR = 1 // Little Endian NDR = 1 // Little Endian
}; }; // enum class wkb_byte_order_type
std::string m_data; std::string m_data;
uint32_t m_points {0}; uint32_t m_points {0};
@ -122,7 +132,11 @@ namespace osmium {
size_t m_ring_size_offset = 0; size_t m_ring_size_offset = 0;
size_t header(std::string& str, wkbGeometryType type, bool add_length) const { size_t header(std::string& str, wkbGeometryType type, bool add_length) const {
#if __BYTE_ORDER == __LITTLE_ENDIAN
str_push(str, wkb_byte_order_type::NDR); str_push(str, wkb_byte_order_type::NDR);
#else
str_push(str, wkb_byte_order_type::XDR);
#endif
if (m_wkb_type == wkb_type::ewkb) { if (m_wkb_type == wkb_type::ewkb) {
str_push(str, type | wkbSRID); str_push(str, type | wkbSRID);
str_push(str, srid); str_push(str, srid);
@ -136,8 +150,9 @@ namespace osmium {
return offset; return offset;
} }
void set_size(const size_t offset, const uint32_t size) { void set_size(const size_t offset, const size_t size) {
memcpy(&m_data[offset], &size, sizeof(uint32_t)); const uint32_t s = static_cast_with_assert<uint32_t>(size);
memcpy(&m_data[offset], &s, sizeof(uint32_t));
} }
public: public:

View File

@ -34,6 +34,7 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <cassert> #include <cassert>
#include <cstddef>
#include <string> #include <string>
#include <utility> #include <utility>
@ -49,6 +50,7 @@ namespace osmium {
class WKTFactoryImpl { class WKTFactoryImpl {
std::string m_str; std::string m_str;
int m_precision;
public: public:
@ -58,11 +60,15 @@ namespace osmium {
typedef std::string multipolygon_type; typedef std::string multipolygon_type;
typedef std::string ring_type; typedef std::string ring_type;
WKTFactoryImpl(int precision = 7) :
m_precision(precision) {
}
/* Point */ /* Point */
point_type make_point(const osmium::geom::Coordinates& xy) const { point_type make_point(const osmium::geom::Coordinates& xy) const {
std::string str {"POINT"}; std::string str {"POINT"};
xy.append_to_string(str, '(', ' ', ')'); xy.append_to_string(str, '(', ' ', ')', m_precision);
return str; return str;
} }
@ -73,7 +79,7 @@ namespace osmium {
} }
void linestring_add_location(const osmium::geom::Coordinates& xy) { void linestring_add_location(const osmium::geom::Coordinates& xy) {
xy.append_to_string(m_str, ' '); xy.append_to_string(m_str, ' ', m_precision);
m_str += ','; m_str += ',';
} }
@ -118,7 +124,7 @@ namespace osmium {
} }
void multipolygon_add_location(const osmium::geom::Coordinates& xy) { void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
xy.append_to_string(m_str, ' '); xy.append_to_string(m_str, ' ', m_precision);
m_str += ','; m_str += ',';
} }

View File

@ -1,128 +1,128 @@
#ifndef OSMIUM_HANDLER_CHAIN_HPP #ifndef OSMIUM_HANDLER_CHAIN_HPP
#define OSMIUM_HANDLER_CHAIN_HPP #define OSMIUM_HANDLER_CHAIN_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <tuple> #include <tuple>
#include <osmium/handler.hpp> #include <osmium/handler.hpp>
#define OSMIUM_CHAIN_HANDLER_CALL(_func_, _type_) \ #define OSMIUM_CHAIN_HANDLER_CALL(_func_, _type_) \
template <int N, int SIZE, class THandlers> \ template <int N, int SIZE, class THandlers> \
struct call_ ## _func_ { \ struct call_ ## _func_ { \
void operator()(THandlers& handlers, osmium::_type_& object) { \ void operator()(THandlers& handlers, osmium::_type_& object) { \
std::get<N>(handlers)._func_(object); \ std::get<N>(handlers)._func_(object); \
call_ ## _func_<N+1, SIZE, THandlers>()(handlers, object); \ call_ ## _func_<N+1, SIZE, THandlers>()(handlers, object); \
} \ } \
}; \ }; \
template <int SIZE, class THandlers> \ template <int SIZE, class THandlers> \
struct call_ ## _func_<SIZE, SIZE, THandlers> { \ struct call_ ## _func_<SIZE, SIZE, THandlers> { \
void operator()(THandlers&, osmium::_type_&) {} \ void operator()(THandlers&, osmium::_type_&) {} \
}; };
namespace osmium { namespace osmium {
class Node; class Node;
class Way; class Way;
class Relation; class Relation;
class Area; class Area;
class Changeset; class Changeset;
namespace handler { namespace handler {
/** /**
* This handler allows chaining of any number of handlers into a single * This handler allows chaining of any number of handlers into a single
* handler. * handler.
*/ */
template <class ...THandler> template <class ...THandler>
class ChainHandler : public osmium::handler::Handler { class ChainHandler : public osmium::handler::Handler {
typedef std::tuple<THandler&...> handlers_type; typedef std::tuple<THandler&...> handlers_type;
handlers_type m_handlers; handlers_type m_handlers;
template <int N, int SIZE, class THandlers> template <int N, int SIZE, class THandlers>
struct call_flush { struct call_flush {
void operator()(THandlers& handlers) { void operator()(THandlers& handlers) {
std::get<N>(handlers).flush(); std::get<N>(handlers).flush();
call_flush<N+1, SIZE, THandlers>()(handlers); call_flush<N+1, SIZE, THandlers>()(handlers);
} }
}; }; // struct call_flush
template <int SIZE, class THandlers> template <int SIZE, class THandlers>
struct call_flush<SIZE, SIZE, THandlers> { struct call_flush<SIZE, SIZE, THandlers> {
void operator()(THandlers&) {} void operator()(THandlers&) {}
}; }; // struct call_flush
OSMIUM_CHAIN_HANDLER_CALL(node, Node) OSMIUM_CHAIN_HANDLER_CALL(node, Node)
OSMIUM_CHAIN_HANDLER_CALL(way, Way) OSMIUM_CHAIN_HANDLER_CALL(way, Way)
OSMIUM_CHAIN_HANDLER_CALL(relation, Relation) OSMIUM_CHAIN_HANDLER_CALL(relation, Relation)
OSMIUM_CHAIN_HANDLER_CALL(changeset, Changeset) OSMIUM_CHAIN_HANDLER_CALL(changeset, Changeset)
OSMIUM_CHAIN_HANDLER_CALL(area, Area) OSMIUM_CHAIN_HANDLER_CALL(area, Area)
public: public:
explicit ChainHandler(THandler&... handlers) : explicit ChainHandler(THandler&... handlers) :
m_handlers(handlers...) { m_handlers(handlers...) {
} }
void node(osmium::Node& node) { void node(osmium::Node& node) {
call_node<0, sizeof...(THandler), handlers_type>()(m_handlers, node); call_node<0, sizeof...(THandler), handlers_type>()(m_handlers, node);
} }
void way(osmium::Way& way) { void way(osmium::Way& way) {
call_way<0, sizeof...(THandler), handlers_type>()(m_handlers, way); call_way<0, sizeof...(THandler), handlers_type>()(m_handlers, way);
} }
void relation(osmium::Relation& relation) { void relation(osmium::Relation& relation) {
call_relation<0, sizeof...(THandler), handlers_type>()(m_handlers, relation); call_relation<0, sizeof...(THandler), handlers_type>()(m_handlers, relation);
} }
void changeset( osmium::Changeset& changeset) { void changeset( osmium::Changeset& changeset) {
call_changeset<0, sizeof...(THandler), handlers_type>()(m_handlers, changeset); call_changeset<0, sizeof...(THandler), handlers_type>()(m_handlers, changeset);
} }
void area(osmium::Area& area) { void area(osmium::Area& area) {
call_area<0, sizeof...(THandler), handlers_type>()(m_handlers, area); call_area<0, sizeof...(THandler), handlers_type>()(m_handlers, area);
} }
void flush() { void flush() {
call_flush<0, sizeof...(THandler), handlers_type>()(m_handlers); call_flush<0, sizeof...(THandler), handlers_type>()(m_handlers);
} }
}; // class ChainHandler }; // class ChainHandler
} // namespace handler } // namespace handler
} // namespace osmium } // namespace osmium
#endif // OSMIUM_HANDLER_CHAIN_HPP #endif // OSMIUM_HANDLER_CHAIN_HPP

View File

@ -1,294 +1,294 @@
#ifndef OSMIUM_HANDLER_DUMP_HPP #ifndef OSMIUM_HANDLER_DUMP_HPP
#define OSMIUM_HANDLER_DUMP_HPP #define OSMIUM_HANDLER_DUMP_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <osmium/handler.hpp> #include <osmium/handler.hpp>
#include <osmium/memory/collection.hpp> #include <osmium/memory/collection.hpp>
#include <osmium/memory/item.hpp> #include <osmium/memory/item.hpp>
#include <osmium/osm/area.hpp> #include <osmium/osm/area.hpp>
#include <osmium/osm/box.hpp> #include <osmium/osm/box.hpp>
#include <osmium/osm/changeset.hpp> #include <osmium/osm/changeset.hpp>
#include <osmium/osm/item_type.hpp> #include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp> #include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp> #include <osmium/osm/node.hpp>
#include <osmium/osm/node_ref.hpp> #include <osmium/osm/node_ref.hpp>
#include <osmium/osm/object.hpp> #include <osmium/osm/object.hpp>
#include <osmium/osm/relation.hpp> #include <osmium/osm/relation.hpp>
#include <osmium/osm/tag.hpp> #include <osmium/osm/tag.hpp>
#include <osmium/osm/timestamp.hpp> #include <osmium/osm/timestamp.hpp>
#include <osmium/osm/way.hpp> #include <osmium/osm/way.hpp>
#include <osmium/visitor.hpp> #include <osmium/visitor.hpp>
namespace osmium { namespace osmium {
namespace handler { namespace handler {
class Dump : public osmium::handler::Handler { class Dump : public osmium::handler::Handler {
std::ostream& m_out; std::ostream* m_out;
bool m_with_size; bool m_with_size;
std::string m_prefix; std::string m_prefix;
void print_title(const char* title, const osmium::memory::Item& item) { void print_title(const char* title, const osmium::memory::Item& item) {
m_out << m_prefix *m_out << m_prefix
<< title << title
<< ":"; << ":";
if (m_with_size) { if (m_with_size) {
m_out << " [" *m_out << " ["
<< item.byte_size() << item.byte_size()
<< "]"; << "]";
} }
m_out << "\n"; *m_out << "\n";
} }
void print_meta(const osmium::OSMObject& object) { void print_meta(const osmium::OSMObject& object) {
m_out << m_prefix *m_out << m_prefix
<< " id=" << " id="
<< object.id() << object.id()
<< "\n"; << "\n";
m_out << m_prefix *m_out << m_prefix
<< " version=" << " version="
<< object.version() << object.version()
<< "\n"; << "\n";
m_out << m_prefix *m_out << m_prefix
<< " uid=" << " uid="
<< object.uid() << object.uid()
<< "\n"; << "\n";
m_out << m_prefix *m_out << m_prefix
<< " user=|" << " user=|"
<< object.user() << object.user()
<< "|\n"; << "|\n";
m_out << m_prefix *m_out << m_prefix
<< " changeset=" << " changeset="
<< object.changeset() << object.changeset()
<< "\n"; << "\n";
m_out << m_prefix *m_out << m_prefix
<< " timestamp=" << " timestamp="
<< object.timestamp().to_iso() << object.timestamp().to_iso()
<< "\n"; << "\n";
m_out << m_prefix *m_out << m_prefix
<< " visible=" << " visible="
<< (object.visible() ? "yes" : "no") << (object.visible() ? "yes" : "no")
<< "\n"; << "\n";
Dump dump(m_out, m_with_size, m_prefix + " "); Dump dump(*m_out, m_with_size, m_prefix + " ");
osmium::apply(object.cbegin(), object.cend(), dump); osmium::apply(object.cbegin(), object.cend(), dump);
} }
void print_location(const osmium::Node& node) { void print_location(const osmium::Node& node) {
const osmium::Location& location = node.location(); const osmium::Location& location = node.location();
if (location) { if (location) {
m_out << m_prefix *m_out << m_prefix
<< " lon=" << " lon="
<< std::fixed << std::fixed
<< std::setprecision(7) << std::setprecision(7)
<< location.lon_without_check() << location.lon_without_check()
<< "\n"; << "\n";
m_out << m_prefix *m_out << m_prefix
<< " lat=" << " lat="
<< location.lat_without_check() << location.lat_without_check()
<< "\n"; << "\n";
} else { } else {
m_out << m_prefix *m_out << m_prefix
<< " lon=\n" << " lon=\n"
<< m_prefix << m_prefix
<< " lat=\n"; << " lat=\n";
} }
} }
public: public:
explicit Dump(std::ostream& out, bool with_size=true, const std::string& prefix="") : explicit Dump(std::ostream& out, bool with_size=true, const std::string& prefix="") :
m_out(out), m_out(&out),
m_with_size(with_size), m_with_size(with_size),
m_prefix(prefix) { m_prefix(prefix) {
} }
void tag_list(const osmium::TagList& tags) { void tag_list(const osmium::TagList& tags) {
print_title("TAGS", tags); print_title("TAGS", tags);
for (const auto& tag : tags) { for (const auto& tag : tags) {
m_out << m_prefix *m_out << m_prefix
<< " k=|" << " k=|"
<< tag.key() << tag.key()
<< "| v=|" << "| v=|"
<< tag.value() << tag.value()
<< "|" << "|"
<< "\n"; << "\n";
} }
} }
void way_node_list(const osmium::WayNodeList& wnl) { void way_node_list(const osmium::WayNodeList& wnl) {
print_title("NODES", wnl); print_title("NODES", wnl);
for (const auto& node_ref : wnl) { for (const auto& node_ref : wnl) {
m_out << m_prefix *m_out << m_prefix
<< " ref=" << " ref="
<< node_ref.ref(); << node_ref.ref();
if (node_ref.location()) { if (node_ref.location()) {
m_out << " pos=" *m_out << " pos="
<< node_ref.location(); << node_ref.location();
} }
m_out << "\n"; *m_out << "\n";
} }
} }
void relation_member_list(const osmium::RelationMemberList& rml) { void relation_member_list(const osmium::RelationMemberList& rml) {
print_title("MEMBERS", rml); print_title("MEMBERS", rml);
for (const auto& member : rml) { for (const auto& member : rml) {
m_out << m_prefix *m_out << m_prefix
<< " type=" << " type="
<< item_type_to_name(member.type()) << item_type_to_name(member.type())
<< " ref=" << " ref="
<< member.ref() << member.ref()
<< " role=|" << " role=|"
<< member.role() << member.role()
<< "|\n"; << "|\n";
if (member.full_member()) { if (member.full_member()) {
Dump dump(m_out, m_with_size, m_prefix + " | "); Dump dump(*m_out, m_with_size, m_prefix + " | ");
osmium::apply_item(member.get_object(), dump); osmium::apply_item(member.get_object(), dump);
} }
} }
} }
void outer_ring(const osmium::OuterRing& ring) { void outer_ring(const osmium::OuterRing& ring) {
print_title("OUTER RING", ring); print_title("OUTER RING", ring);
for (const auto& node_ref : ring) { for (const auto& node_ref : ring) {
m_out << m_prefix *m_out << m_prefix
<< " ref=" << " ref="
<< node_ref.ref(); << node_ref.ref();
if (node_ref.location()) { if (node_ref.location()) {
m_out << " pos=" *m_out << " pos="
<< node_ref.location(); << node_ref.location();
} }
m_out << "\n"; *m_out << "\n";
} }
} }
void inner_ring(const osmium::InnerRing& ring) { void inner_ring(const osmium::InnerRing& ring) {
print_title("INNER RING", ring); print_title("INNER RING", ring);
for (const auto& node_ref : ring) { for (const auto& node_ref : ring) {
m_out << m_prefix *m_out << m_prefix
<< " ref=" << " ref="
<< node_ref.ref(); << node_ref.ref();
if (node_ref.location()) { if (node_ref.location()) {
m_out << " pos=" *m_out << " pos="
<< node_ref.location(); << node_ref.location();
} }
m_out << "\n"; *m_out << "\n";
} }
} }
void node(const osmium::Node& node) { void node(const osmium::Node& node) {
print_title("NODE", node); print_title("NODE", node);
print_meta(node); print_meta(node);
print_location(node); print_location(node);
} }
void way(const osmium::Way& way) { void way(const osmium::Way& way) {
print_title("WAY", way); print_title("WAY", way);
print_meta(way); print_meta(way);
} }
void relation(const osmium::Relation& relation) { void relation(const osmium::Relation& relation) {
print_title("RELATION", relation); print_title("RELATION", relation);
print_meta(relation); print_meta(relation);
} }
void area(const osmium::Area& area) { void area(const osmium::Area& area) {
print_title("AREA", area); print_title("AREA", area);
print_meta(area); print_meta(area);
} }
void changeset(const osmium::Changeset& changeset) { void changeset(const osmium::Changeset& changeset) {
print_title("CHANGESET", changeset); print_title("CHANGESET", changeset);
m_out << m_prefix *m_out << m_prefix
<< " id=" << " id="
<< changeset.id() << changeset.id()
<< "\n"; << "\n";
m_out << m_prefix *m_out << m_prefix
<< " num_changes=" << " num_changes="
<< changeset.num_changes() << changeset.num_changes()
<< "\n"; << "\n";
m_out << m_prefix *m_out << m_prefix
<< " uid=" << " uid="
<< changeset.uid() << changeset.uid()
<< "\n"; << "\n";
m_out << m_prefix *m_out << m_prefix
<< " user=|" << " user=|"
<< changeset.user() << changeset.user()
<< "|\n"; << "|\n";
m_out << m_prefix *m_out << m_prefix
<< " created_at=" << " created_at="
<< changeset.created_at().to_iso() << changeset.created_at().to_iso()
<< "\n"; << "\n";
m_out << m_prefix *m_out << m_prefix
<< " closed_at=" << " closed_at="
<< changeset.closed_at().to_iso() << changeset.closed_at().to_iso()
<< "\n"; << "\n";
m_out << m_prefix *m_out << m_prefix
<< " bounds="; << " bounds=";
if (changeset.bounds()) { if (changeset.bounds()) {
m_out << '(' *m_out << '('
<< changeset.bounds().bottom_left().lon_without_check() << changeset.bounds().bottom_left().lon_without_check()
<< ',' << ','
<< changeset.bounds().bottom_left().lat_without_check() << changeset.bounds().bottom_left().lat_without_check()
<< ',' << ','
<< changeset.bounds().top_right().lon_without_check() << changeset.bounds().top_right().lon_without_check()
<< ',' << ','
<< changeset.bounds().top_right().lat_without_check() << changeset.bounds().top_right().lat_without_check()
<< ')'; << ')';
} else { } else {
m_out << "(undefined)"; *m_out << "(undefined)";
} }
m_out << "\n"; *m_out << "\n";
Dump dump(m_out, m_with_size, m_prefix + " "); Dump dump(*m_out, m_with_size, m_prefix + " ");
osmium::apply(changeset.cbegin(), changeset.cend(), dump); osmium::apply(changeset.cbegin(), changeset.cend(), dump);
} }
}; // class Dump }; // class Dump
} // namespace handler } // namespace handler
} // namespace osmium } // namespace osmium
#endif // OSMIUM_HANDLER_DUMP_HPP #endif // OSMIUM_HANDLER_DUMP_HPP

View File

@ -1,148 +1,170 @@
#ifndef OSMIUM_HANDLER_NODE_LOCATIONS_FOR_WAYS_HPP #ifndef OSMIUM_HANDLER_NODE_LOCATIONS_FOR_WAYS_HPP
#define OSMIUM_HANDLER_NODE_LOCATIONS_FOR_WAYS_HPP #define OSMIUM_HANDLER_NODE_LOCATIONS_FOR_WAYS_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <osmium/handler.hpp> #include <type_traits>
#include <osmium/index/index.hpp>
#include <osmium/index/map/dummy.hpp> #include <osmium/handler.hpp>
#include <osmium/osm/location.hpp> #include <osmium/index/index.hpp>
#include <osmium/osm/node.hpp> #include <osmium/index/map/dummy.hpp>
#include <osmium/osm/node_ref.hpp> #include <osmium/osm/location.hpp>
#include <osmium/osm/types.hpp> #include <osmium/osm/node.hpp>
#include <osmium/osm/way.hpp> #include <osmium/osm/node_ref.hpp>
#include <osmium/osm/types.hpp>
namespace osmium { #include <osmium/osm/way.hpp>
namespace handler { namespace osmium {
typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> dummy_type; namespace handler {
/** typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> dummy_type;
* Handler to retrieve locations from nodes and add them to ways.
* /**
* @tparam TStoragePosIDs Class that handles the actual storage of the node locations * Handler to retrieve locations from nodes and add them to ways.
* (for positive IDs). It must support the set(id, value) and *
* get(id) methods. * @tparam TStoragePosIDs Class that handles the actual storage of the node locations
* @tparam TStorageNegIDs Same but for negative IDs. * (for positive IDs). It must support the set(id, value) and
*/ * get(id) methods.
template <class TStoragePosIDs, class TStorageNegIDs = dummy_type> * @tparam TStorageNegIDs Same but for negative IDs.
class NodeLocationsForWays : public osmium::handler::Handler { */
template <class TStoragePosIDs, class TStorageNegIDs = dummy_type>
/// Object that handles the actual storage of the node locations (with positive IDs). class NodeLocationsForWays : public osmium::handler::Handler {
TStoragePosIDs& m_storage_pos;
static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStoragePosIDs>::value,
/// Object that handles the actual storage of the node locations (with negative IDs). "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
TStorageNegIDs& m_storage_neg;
static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStorageNegIDs>::value,
bool m_ignore_errors {false}; "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
bool m_must_sort {false}; /// Object that handles the actual storage of the node locations (with positive IDs).
TStoragePosIDs& m_storage_pos;
// It is okay to have this static dummy instance, even when using several threads,
// because it is read-only. /// Object that handles the actual storage of the node locations (with negative IDs).
static dummy_type& get_dummy() { TStorageNegIDs& m_storage_neg;
static dummy_type instance;
return instance; bool m_ignore_errors {false};
}
bool m_must_sort {false};
public:
// It is okay to have this static dummy instance, even when using several threads,
explicit NodeLocationsForWays(TStoragePosIDs& storage_pos, // because it is read-only.
TStorageNegIDs& storage_neg = get_dummy()) : static dummy_type& get_dummy() {
m_storage_pos(storage_pos), static dummy_type instance;
m_storage_neg(storage_neg) { return instance;
} }
NodeLocationsForWays(const NodeLocationsForWays&) = delete; public:
NodeLocationsForWays& operator=(const NodeLocationsForWays&) = delete;
explicit NodeLocationsForWays(TStoragePosIDs& storage_pos,
~NodeLocationsForWays() noexcept = default; TStorageNegIDs& storage_neg = get_dummy()) :
m_storage_pos(storage_pos),
void ignore_errors() { m_storage_neg(storage_neg) {
m_ignore_errors = true; }
}
NodeLocationsForWays(const NodeLocationsForWays&) = delete;
/** NodeLocationsForWays& operator=(const NodeLocationsForWays&) = delete;
* Store the location of the node in the storage.
*/ ~NodeLocationsForWays() noexcept = default;
void node(const osmium::Node& node) {
m_must_sort = true; void ignore_errors() {
const osmium::object_id_type id = node.id(); m_ignore_errors = true;
if (id >= 0) { }
m_storage_pos.set(id, node.location());
} else { /**
m_storage_neg.set(-id, node.location()); * Store the location of the node in the storage.
} */
} void node(const osmium::Node& node) {
m_must_sort = true;
/** const osmium::object_id_type id = node.id();
* Get location of node with given id. if (id >= 0) {
*/ m_storage_pos.set(static_cast<osmium::unsigned_object_id_type>( id), node.location());
osmium::Location get_node_location(const osmium::object_id_type id) const { } else {
return id >= 0 ? m_storage_pos.get(id) : m_storage_neg.get(-id); m_storage_neg.set(static_cast<osmium::unsigned_object_id_type>(-id), node.location());
} }
}
/**
* Retrieve locations of all nodes in the way from storage and add /**
* them to the way object. * Get location of node with given id.
*/ */
void way(osmium::Way& way) { osmium::Location get_node_location(const osmium::object_id_type id) const {
if (m_must_sort) { if (id >= 0) {
m_storage_pos.sort(); return m_storage_pos.get(static_cast<osmium::unsigned_object_id_type>( id));
m_storage_neg.sort(); } else {
m_must_sort = false; return m_storage_neg.get(static_cast<osmium::unsigned_object_id_type>(-id));
} }
bool error = false; }
for (auto& node_ref : way.nodes()) {
try { /**
node_ref.location(get_node_location(node_ref.ref())); * Retrieve locations of all nodes in the way from storage and add
if (!node_ref.location()) { * them to the way object.
error = true; */
} void way(osmium::Way& way) {
} catch (osmium::not_found&) { if (m_must_sort) {
error = true; m_storage_pos.sort();
} m_storage_neg.sort();
} m_must_sort = false;
if (error && !m_ignore_errors) { }
throw osmium::not_found("not found"); bool error = false;
} for (auto& node_ref : way.nodes()) {
} try {
node_ref.set_location(get_node_location(node_ref.ref()));
}; // class NodeLocationsForWays if (!node_ref.location()) {
error = true;
} // namespace handler }
} catch (osmium::not_found&) {
} // namespace osmium error = true;
}
#endif // OSMIUM_HANDLER_NODE_LOCATIONS_FOR_WAYS_HPP }
if (error && !m_ignore_errors) {
throw osmium::not_found("location for one or more nodes not found in node location index");
}
}
/**
* Call clear on the location indexes. Makes the
* NodeLocationsForWays handler unusable. Used to explicitly free
* memory if thats needed.
*/
void clear() {
m_storage_pos.clear();
m_storage_neg.clear();
}
}; // class NodeLocationsForWays
} // namespace handler
} // namespace osmium
#endif // OSMIUM_HANDLER_NODE_LOCATIONS_FOR_WAYS_HPP

View File

@ -1,183 +1,183 @@
#ifndef OSMIUM_DETAIL_MMAP_VECTOR_BASE_HPP #ifndef OSMIUM_DETAIL_MMAP_VECTOR_BASE_HPP
#define OSMIUM_DETAIL_MMAP_VECTOR_BASE_HPP #define OSMIUM_DETAIL_MMAP_VECTOR_BASE_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <cstddef> #include <cstddef>
#include <new> #include <new>
#include <stdexcept> #include <stdexcept>
#include <osmium/index/detail/typed_mmap.hpp> #include <osmium/index/detail/typed_mmap.hpp>
namespace osmium { namespace osmium {
namespace detail { namespace detail {
constexpr size_t mmap_vector_size_increment = 1024 * 1024; constexpr size_t mmap_vector_size_increment = 1024 * 1024;
/** /**
* This is a base class for implementing classes that look like * This is a base class for implementing classes that look like
* STL vector but use mmap internally. This class can not be used * STL vector but use mmap internally. This class can not be used
* on it's own. Use the derived classes mmap_vector_anon or * on it's own. Use the derived classes mmap_vector_anon or
* mmap_vector_file. * mmap_vector_file.
*/ */
template <typename T, template <typename> class TDerived> template <typename T, template <typename> class TDerived>
class mmap_vector_base { class mmap_vector_base {
protected: protected:
int m_fd; int m_fd;
size_t m_capacity; size_t m_capacity;
size_t m_size; size_t m_size;
T* m_data; T* m_data;
explicit mmap_vector_base(int fd, size_t capacity, size_t size, T* data) : explicit mmap_vector_base(int fd, size_t capacity, size_t size, T* data) noexcept :
m_fd(fd), m_fd(fd),
m_capacity(capacity), m_capacity(capacity),
m_size(size), m_size(size),
m_data(data) { m_data(data) {
} }
explicit mmap_vector_base(int fd, size_t capacity, size_t size) : explicit mmap_vector_base(int fd, size_t capacity, size_t size) :
m_fd(fd), m_fd(fd),
m_capacity(capacity), m_capacity(capacity),
m_size(size), m_size(size),
m_data(osmium::detail::typed_mmap<T>::grow_and_map(capacity, m_fd)) { m_data(osmium::detail::typed_mmap<T>::grow_and_map(capacity, m_fd)) {
} }
void data(T* data) { void data(T* data) {
m_data = data; m_data = data;
} }
public: public:
typedef T value_type; typedef T value_type;
typedef T& reference; typedef T& reference;
typedef const T& const_reference; typedef const T& const_reference;
typedef T* pointer; typedef T* pointer;
typedef const T* const_pointer; typedef const T* const_pointer;
typedef T* iterator; typedef T* iterator;
typedef const T* const_iterator; typedef const T* const_iterator;
~mmap_vector_base() { ~mmap_vector_base() {
osmium::detail::typed_mmap<T>::unmap(m_data, m_capacity); osmium::detail::typed_mmap<T>::unmap(m_data, m_capacity);
} }
size_t capacity() const { size_t capacity() const noexcept {
return m_capacity; return m_capacity;
} }
size_t size() const { size_t size() const noexcept {
return m_size; return m_size;
} }
bool empty() const { bool empty() const noexcept {
return m_size == 0; return m_size == 0;
} }
const T* data() const { const T* data() const noexcept {
return m_data; return m_data;
} }
T* data() { T* data() noexcept {
return m_data; return m_data;
} }
T& operator[](size_t n) { T& operator[](size_t n) {
return m_data[n]; return m_data[n];
} }
T at(size_t n) const { T at(size_t n) const {
if (n >= m_size) { if (n >= m_size) {
throw std::out_of_range("out of range"); throw std::out_of_range("out of range");
} }
return m_data[n]; return m_data[n];
} }
void clear() { void clear() noexcept {
m_size = 0; m_size = 0;
} }
void shrink_to_fit() { void shrink_to_fit() {
// XXX do something here // XXX do something here
} }
void push_back(const T& value) { void push_back(const T& value) {
if (m_size >= m_capacity) { if (m_size >= m_capacity) {
resize(m_size+1); resize(m_size+1);
} }
m_data[m_size] = value; m_data[m_size] = value;
++m_size; ++m_size;
} }
void resize(size_t new_size) { void resize(size_t new_size) {
if (new_size > this->capacity()) { if (new_size > capacity()) {
static_cast<TDerived<T>*>(this)->reserve(new_size + osmium::detail::mmap_vector_size_increment); static_cast<TDerived<T>*>(this)->reserve(new_size + osmium::detail::mmap_vector_size_increment);
} }
if (new_size > this->size()) { if (new_size > size()) {
new (this->data() + this->size()) T[new_size - this->size()]; new (data() + size()) T[new_size - size()];
} }
this->m_size = new_size; m_size = new_size;
} }
iterator begin() { iterator begin() noexcept {
return m_data; return m_data;
} }
iterator end() { iterator end() noexcept {
return m_data + m_size; return m_data + m_size;
} }
const_iterator begin() const { const_iterator begin() const noexcept {
return m_data; return m_data;
} }
const_iterator end() const { const_iterator end() const noexcept {
return m_data + m_size; return m_data + m_size;
} }
const_iterator cbegin() { const_iterator cbegin() noexcept {
return m_data; return m_data;
} }
const_iterator cend() { const_iterator cend() noexcept {
return m_data + m_size; return m_data + m_size;
} }
}; // class mmap_vector_base }; // class mmap_vector_base
} // namespace detail } // namespace detail
} // namespace osmium } // namespace osmium
#endif // OSMIUM_DETAIL_MMAP_VECTOR_BASE_HPP #endif // OSMIUM_DETAIL_MMAP_VECTOR_BASE_HPP

View File

@ -1,83 +1,82 @@
#ifndef OSMIUM_DETAIL_MMAP_VECTOR_FILE_HPP #ifndef OSMIUM_DETAIL_MMAP_VECTOR_FILE_HPP
#define OSMIUM_DETAIL_MMAP_VECTOR_FILE_HPP #define OSMIUM_DETAIL_MMAP_VECTOR_FILE_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <cstddef> #include <cstddef>
#include <osmium/index/detail/typed_mmap.hpp> #include <osmium/index/detail/typed_mmap.hpp>
#include <osmium/index/detail/mmap_vector_base.hpp> #include <osmium/index/detail/mmap_vector_base.hpp>
#include <osmium/index/detail/tmpfile.hpp> #include <osmium/index/detail/tmpfile.hpp>
namespace osmium { namespace osmium {
namespace detail { namespace detail {
/** /**
* This class looks and behaves like STL vector, but mmap's a file internally. * This class looks and behaves like STL vector, but mmap's a file internally.
*/ */
template <typename T> template <typename T>
class mmap_vector_file : public mmap_vector_base<T, mmap_vector_file> { class mmap_vector_file : public mmap_vector_base<T, mmap_vector_file> {
public: public:
explicit mmap_vector_file() : explicit mmap_vector_file() :
mmap_vector_base<T, osmium::detail::mmap_vector_file>( mmap_vector_base<T, osmium::detail::mmap_vector_file>(
osmium::detail::create_tmp_file(), osmium::detail::create_tmp_file(),
osmium::detail::mmap_vector_size_increment, osmium::detail::mmap_vector_size_increment,
0) { 0) {
} }
explicit mmap_vector_file(int fd) : explicit mmap_vector_file(int fd) :
mmap_vector_base<T, osmium::detail::mmap_vector_file>( mmap_vector_base<T, osmium::detail::mmap_vector_file>(
fd, fd,
osmium::detail::typed_mmap<T>::file_size(fd) == 0 ? osmium::detail::mmap_vector_size_increment : osmium::detail::typed_mmap<T>::file_size(fd), osmium::detail::typed_mmap<T>::file_size(fd) == 0 ? osmium::detail::mmap_vector_size_increment : osmium::detail::typed_mmap<T>::file_size(fd),
osmium::detail::typed_mmap<T>::file_size(fd)) { osmium::detail::typed_mmap<T>::file_size(fd)) {
} }
void reserve(size_t new_capacity) { void reserve(size_t new_capacity) {
if (new_capacity > this->capacity()) { if (new_capacity > this->capacity()) {
osmium::detail::typed_mmap<T>::unmap(this->data(), this->capacity()); osmium::detail::typed_mmap<T>::unmap(this->data(), this->capacity());
osmium::detail::typed_mmap<T>::grow_file(new_capacity, this->m_fd); this->data(osmium::detail::typed_mmap<T>::grow_and_map(new_capacity, this->m_fd));
osmium::detail::typed_mmap<T>::map(new_capacity, this->m_fd); this->m_capacity = new_capacity;
this->m_capacity = new_capacity; }
} }
}
}; // class mmap_vector_file
}; // class mmap_vector_file
} // namespace detail
} // namespace detail
} // namespace osmium
} // namespace osmium
#endif // OSMIUM_DETAIL_MMAP_VECTOR_FILE_HPP
#endif // OSMIUM_DETAIL_MMAP_VECTOR_FILE_HPP

View File

@ -44,8 +44,8 @@ namespace osmium {
/** /**
* Create and open a temporary file. It is removed after opening. * Create and open a temporary file. It is removed after opening.
* *
* @return File descriptor of temporary file. * @returns File descriptor of temporary file.
* @exception std::system_error if something went wrong. * @throws std::system_error if something went wrong.
*/ */
inline int create_tmp_file() { inline int create_tmp_file() {
FILE* file = ::tmpfile(); FILE* file = ::tmpfile();

View File

@ -38,18 +38,18 @@ DEALINGS IN THE SOFTWARE.
#include <stdexcept> #include <stdexcept>
#include <system_error> #include <system_error>
#ifndef WIN32 #include <sys/stat.h>
#ifndef _WIN32
# include <sys/mman.h> # include <sys/mman.h>
#else #else
# include <mmap_for_windows.hpp> # include <mmap_for_windows.hpp>
#endif #endif
#include <sys/stat.h> #ifndef _MSC_VER
#ifdef _MSC_VER
# define ftruncate _chsize
#else
# include <unistd.h> # include <unistd.h>
#else
# define ftruncate _chsize
#endif #endif
// for bsd systems // for bsd systems
@ -57,6 +57,8 @@ DEALINGS IN THE SOFTWARE.
# define MAP_ANONYMOUS MAP_ANON # define MAP_ANONYMOUS MAP_ANON
#endif #endif
#include <osmium/util/cast.hpp>
namespace osmium { namespace osmium {
/** /**
@ -89,8 +91,8 @@ namespace osmium {
* Note that no constructor is called for any of the objects in this memory! * Note that no constructor is called for any of the objects in this memory!
* *
* @param size Number of objects of type T that should fit into this memory * @param size Number of objects of type T that should fit into this memory
* @return Pointer to mapped memory * @returns Pointer to mapped memory
* @exception std::system_error If mmap(2) failed * @throws std::system_error If mmap(2) failed
*/ */
static T* map(size_t size) { static T* map(size_t size) {
void* addr = ::mmap(nullptr, sizeof(T) * size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); void* addr = ::mmap(nullptr, sizeof(T) * size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@ -113,8 +115,8 @@ namespace osmium {
* @param size Number of objects of type T that should fit into this memory * @param size Number of objects of type T that should fit into this memory
* @param fd File descriptor * @param fd File descriptor
* @param write True if data should be writable * @param write True if data should be writable
* @return Pointer to mapped memory * @returns Pointer to mapped memory
* @exception std::system_error If mmap(2) failed * @throws std::system_error If mmap(2) failed
*/ */
static T* map(size_t size, int fd, bool write = false) { static T* map(size_t size, int fd, bool write = false) {
int prot = PROT_READ; int prot = PROT_READ;
@ -141,7 +143,7 @@ namespace osmium {
* @param data Pointer to current mapping (as returned by typed_mmap()) * @param data Pointer to current mapping (as returned by typed_mmap())
* @param old_size Number of objects currently stored in this memory * @param old_size Number of objects currently stored in this memory
* @param new_size Number of objects we want to have space for * @param new_size Number of objects we want to have space for
* @exception std::system_error If mremap(2) call failed * @throws std::system_error If mremap(2) call failed
*/ */
static T* remap(T* data, size_t old_size, size_t new_size) { static T* remap(T* data, size_t old_size, size_t new_size) {
void* addr = ::mremap(reinterpret_cast<void*>(data), sizeof(T) * old_size, sizeof(T) * new_size, MREMAP_MAYMOVE); void* addr = ::mremap(reinterpret_cast<void*>(data), sizeof(T) * old_size, sizeof(T) * new_size, MREMAP_MAYMOVE);
@ -162,7 +164,7 @@ namespace osmium {
* *
* @param data Pointer to the data * @param data Pointer to the data
* @param size Number of objects of type T stored * @param size Number of objects of type T stored
* @exception std::system_error If munmap(2) call failed * @throws std::system_error If munmap(2) call failed
*/ */
static void unmap(T* data, size_t size) { static void unmap(T* data, size_t size) {
if (::munmap(reinterpret_cast<void*>(data), sizeof(T) * size) != 0) { if (::munmap(reinterpret_cast<void*>(data), sizeof(T) * size) != 0) {
@ -174,19 +176,19 @@ namespace osmium {
* Get number of objects of type T that would fit into a file. * Get number of objects of type T that would fit into a file.
* *
* @param fd File descriptor * @param fd File descriptor
* @return Number of objects of type T in this file * @returns Number of objects of type T in this file
* @exception std::system_error If fstat(2) call failed * @throws std::system_error If fstat(2) call failed
* @exception std::length_error If size of the file isn't a multiple of sizeof(T) * @throws std::length_error If size of the file isn't a multiple of sizeof(T)
*/ */
static size_t file_size(int fd) { static size_t file_size(int fd) {
struct stat s; struct stat s;
if (fstat(fd, &s) < 0) { if (fstat(fd, &s) < 0) {
throw std::system_error(errno, std::system_category(), "fstat failed"); throw std::system_error(errno, std::system_category(), "fstat failed");
} }
if (s.st_size % sizeof(T) != 0) { if (static_cast<size_t>(s.st_size) % sizeof(T) != 0) {
throw std::length_error("file size has to be multiple of object size"); throw std::length_error("file size has to be multiple of object size");
} }
return s.st_size / sizeof(T); return static_cast<size_t>(s.st_size) / sizeof(T);
} }
/** /**
@ -196,11 +198,11 @@ namespace osmium {
* *
* @param new_size Number of objects of type T that should fit into this file * @param new_size Number of objects of type T that should fit into this file
* @param fd File descriptor * @param fd File descriptor
* @exception std::system_error If ftruncate(2) call failed * @throws std::system_error If ftruncate(2) call failed
*/ */
static void grow_file(size_t new_size, int fd) { static void grow_file(size_t new_size, int fd) {
if (file_size(fd) < new_size) { if (file_size(fd) < new_size) {
if (::ftruncate(fd, sizeof(T) * new_size) < 0) { if (::ftruncate(fd, static_cast_with_assert<off_t>(sizeof(T) * new_size)) < 0) {
throw std::system_error(errno, std::system_category(), "ftruncate failed"); throw std::system_error(errno, std::system_category(), "ftruncate failed");
} }
} }
@ -211,7 +213,7 @@ namespace osmium {
* *
* @param size Number of objects of type T that should fit into this file * @param size Number of objects of type T that should fit into this file
* @param fd File descriptor * @param fd File descriptor
* @exception Errors thrown by grow_file() or map() * @throws Errors thrown by grow_file() or map()
*/ */
static T* grow_and_map(size_t size, int fd) { static T* grow_and_map(size_t size, int fd) {
grow_file(size, fd); grow_file(size, fd);

View File

@ -1,156 +1,155 @@
#ifndef OSMIUM_INDEX_MAP_HPP #ifndef OSMIUM_INDEX_MAP_HPP
#define OSMIUM_INDEX_MAP_HPP #define OSMIUM_INDEX_MAP_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <cstddef> #include <cstddef>
#include <type_traits> #include <type_traits>
#include <osmium/index/index.hpp> // IWYU pragma: export #include <osmium/index/index.hpp> // IWYU pragma: export
namespace osmium { namespace osmium {
namespace index { namespace index {
/** /**
* @brief Key-value containers with unique integer values for a key * @brief Key-value containers with unique integer values for a key
*/ */
namespace map { namespace map {
/** /**
* This abstract class defines an interface to storage classes * This abstract class defines an interface to storage classes
* intended for storing small pieces of data (such as coordinates) * intended for storing small pieces of data (such as coordinates)
* indexed by a positive integer (such as an object ID). The * indexed by a positive integer (such as an object ID). The
* storage must be very space efficient and able to scale to billions * storage must be very space efficient and able to scale to billions
* of objects. * of objects.
* *
* Subclasses have different implementations that store the * Subclasses have different implementations that store the
* data in different ways in memory and/or on disk. Some storage * data in different ways in memory and/or on disk. Some storage
* classes are better suited when working with the whole planet, * classes are better suited when working with the whole planet,
* some are better for data extracts. * some are better for data extracts.
* *
* Note that these classes are not required to track "empty" fields. * Note that these classes are not required to track "empty" fields.
* When reading data you have to be sure you have put something in * When reading data you have to be sure you have put something in
* there before. * there before.
* *
* A typical use for this and derived classes is storage of node * A typical use for this and derived classes is storage of node
* locations indexed by node ID. These indexes will only work * locations indexed by node ID. These indexes will only work
* on 64 bit systems if used in this case. 32 bit systems just * on 64 bit systems if used in this case. 32 bit systems just
* can't address that much memory! * can't address that much memory!
* *
* @tparam TId Id type, usually osmium::unsigned_object_id_type, * @tparam TId Id type, usually osmium::unsigned_object_id_type,
* must be an unsigned integral type. * must be an unsigned integral type.
* @tparam TValue Value type, usually osmium::Location or size_t. * @tparam TValue Value type, usually osmium::Location or size_t.
* Copied by value, so should be "small" type. * Copied by value, so should be "small" type.
*/ */
template <typename TId, typename TValue> template <typename TId, typename TValue>
class Map { class Map {
static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value, static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value,
"TId template parameter for class Map must be unsigned integral type"); "TId template parameter for class Map must be unsigned integral type");
Map(const Map&) = delete; Map(const Map&) = delete;
Map& operator=(const Map&) = delete; Map& operator=(const Map&) = delete;
protected: protected:
Map(Map&&) = default; Map(Map&&) = default;
Map& operator=(Map&&) = default; Map& operator=(Map&&) = default;
public: public:
/// The "key" type, usually osmium::unsigned_object_id_type. /// The "key" type, usually osmium::unsigned_object_id_type.
typedef TId key_type; typedef TId key_type;
/// The "value" type, usually a Location or size_t. /// The "value" type, usually a Location or size_t.
typedef TValue value_type; typedef TValue value_type;
Map() = default; Map() = default;
// workaround for a bug in GCC 4.7 virtual ~Map() = default;
#if __GNUC__ == 4 && __GNUC_MINOR__ < 8
virtual ~Map() {} virtual void reserve(const size_t) {
#else // default implementation is empty
virtual ~Map() = default; }
#endif
/// Set the field with id to value.
virtual void reserve(const size_t) { virtual void set(const TId id, const TValue value) = 0;
// default implementation is empty
} /// Retrieve value by id. Does not check for overflow or empty fields.
virtual const TValue get(const TId id) const = 0;
/// Set the field with id to value.
virtual void set(const TId id, const TValue value) = 0; /**
* Get the approximate number of items in the storage. The storage
/// Retrieve value by id. Does not check for overflow or empty fields. * might allocate memory in blocks, so this size might not be
virtual const TValue get(const TId id) const = 0; * accurate. You can not use this to find out how much memory the
* storage uses. Use used_memory() for that.
/** */
* Get the approximate number of items in the storage. The storage virtual size_t size() const = 0;
* might allocate memory in blocks, so this size might not be
* accurate. You can not use this to find out how much memory the /**
* storage uses. Use used_memory() for that. * Get the memory used for this storage in bytes. Note that this
*/ * is not necessarily entirely accurate but an approximation.
virtual size_t size() const = 0; * For storage classes that store the data in memory, this is
* the main memory used, for storage classes storing data on disk
/** * this is the memory used on disk.
* Get the memory used for this storage in bytes. Note that this */
* is not necessarily entirely accurate but an approximation. virtual size_t used_memory() const = 0;
* For storage classes that store the data in memory, this is
* the main memory used, for storage classes storing data on disk /**
* this is the memory used on disk. * Clear memory used for this storage. After this you can not
*/ * use the storage container any more.
virtual size_t used_memory() const = 0; */
virtual void clear() = 0;
/**
* Clear memory used for this storage. After this you can not /**
* use the storage container any more. * Sort data in map. Call this after writing all data and
*/ * before reading. Not all implementations need this.
virtual void clear() = 0; */
virtual void sort() {
/** // default implementation is empty
* Sort data in map. Call this after writing all data and }
* before reading. Not all implementations need this.
*/ virtual void dump_as_list(int /*fd*/) const {
virtual void sort() { std::runtime_error("can't dump as list");
// default implementation is empty }
}
}; // class Map
}; // class Map
} // namespace map
} // namespace map
} // namespace index
} // namespace index
} // namespace osmium
} // namespace osmium
#endif // OSMIUM_INDEX_MAP_HPP
#endif // OSMIUM_INDEX_MAP_HPP

View File

@ -1,140 +1,140 @@
#ifndef OSMIUM_INDEX_MAP_SPARSE_TABLE_HPP #ifndef OSMIUM_INDEX_MAP_SPARSE_TABLE_HPP
#define OSMIUM_INDEX_MAP_SPARSE_TABLE_HPP #define OSMIUM_INDEX_MAP_SPARSE_TABLE_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <cstddef> #include <cstddef>
#include <stdexcept> #include <stdexcept>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <google/sparsetable> #include <google/sparsetable>
#include <osmium/index/map.hpp> #include <osmium/index/map.hpp>
#include <osmium/io/detail/read_write.hpp> #include <osmium/io/detail/read_write.hpp>
namespace osmium { namespace osmium {
namespace index { namespace index {
namespace map { namespace map {
/** /**
* The SparseTable index stores elements in a Google sparsetable, * The SparseTable index stores elements in a Google sparsetable,
* a data structure that can hold sparsly filled tables in a * a data structure that can hold sparsly filled tables in a
* very space efficient way. It will resize automatically. * very space efficient way. It will resize automatically.
* *
* Use this index if the ID space is only sparsly * Use this index if the ID space is only sparsly
* populated, such as when working with smaller OSM files (like * populated, such as when working with smaller OSM files (like
* country extracts). * country extracts).
* *
* This will only work on 64 bit machines. * This will only work on 64 bit machines.
*/ */
template <typename TId, typename TValue> template <typename TId, typename TValue>
class SparseTable : public osmium::index::map::Map<TId, TValue> { class SparseTable : public osmium::index::map::Map<TId, TValue> {
TId m_grow_size; TId m_grow_size;
google::sparsetable<TValue> m_elements; google::sparsetable<TValue> m_elements;
static_assert(sizeof(typename google::sparsetable<TValue>::size_type) >= 8, "google::sparsetable needs 64bit machine"); static_assert(sizeof(typename google::sparsetable<TValue>::size_type) >= 8, "google::sparsetable needs 64bit machine");
public: public:
/** /**
* Constructor. * Constructor.
* *
* @param grow_size The initial size of the index (ie number of * @param grow_size The initial size of the index (ie number of
* elements that fit into the index). * elements that fit into the index).
* The storage will grow by at least this size * The storage will grow by at least this size
* every time it runs out of space. * every time it runs out of space.
*/ */
explicit SparseTable(const TId grow_size=10000) : explicit SparseTable(const TId grow_size=10000) :
m_grow_size(grow_size), m_grow_size(grow_size),
m_elements(grow_size) { m_elements(grow_size) {
} }
~SparseTable() override final = default; ~SparseTable() override final = default;
void set(const TId id, const TValue value) override final { void set(const TId id, const TValue value) override final {
if (id >= m_elements.size()) { if (id >= m_elements.size()) {
m_elements.resize(id + m_grow_size); m_elements.resize(id + m_grow_size);
} }
m_elements[id] = value; m_elements[id] = value;
} }
const TValue get(const TId id) const override final { const TValue get(const TId id) const override final {
if (id >= m_elements.size()) { if (id >= m_elements.size()) {
not_found_error(id); not_found_error(id);
} }
if (m_elements[id] == osmium::index::empty_value<TValue>()) { if (m_elements[id] == osmium::index::empty_value<TValue>()) {
not_found_error(id); not_found_error(id);
} }
return m_elements[id]; return m_elements[id];
} }
size_t size() const override final { size_t size() const override final {
return m_elements.size(); return m_elements.size();
} }
size_t used_memory() const override final { size_t used_memory() const override final {
// unused elements use 1 bit, used elements sizeof(TValue) bytes // unused elements use 1 bit, used elements sizeof(TValue) bytes
// http://google-sparsehash.googlecode.com/svn/trunk/doc/sparsetable.html // http://google-sparsehash.googlecode.com/svn/trunk/doc/sparsetable.html
return (m_elements.size() / 8) + (m_elements.num_nonempty() * sizeof(TValue)); return (m_elements.size() / 8) + (m_elements.num_nonempty() * sizeof(TValue));
} }
void clear() override final { void clear() override final {
m_elements.clear(); m_elements.clear();
} }
void dump_as_list(const int fd) const { void dump_as_list(const int fd) const override final {
std::vector<std::pair<TId, TValue>> v; std::vector<std::pair<TId, TValue>> v;
int n=0; int n=0;
for (const TValue value : m_elements) { for (const TValue value : m_elements) {
if (value != osmium::index::empty_value<TValue>()) { if (value != osmium::index::empty_value<TValue>()) {
v.emplace_back(n, value); v.emplace_back(n, value);
} }
++n; ++n;
} }
osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(std::pair<TId, TValue>) * v.size()); osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(std::pair<TId, TValue>) * v.size());
} }
}; // class SparseTable }; // class SparseTable
} // namespace map } // namespace map
} // namespace index } // namespace index
} // namespace osmium } // namespace osmium
#endif // OSMIUM_INDEX_BYID_SPARSE_TABLE_HPP #endif // OSMIUM_INDEX_BYID_SPARSE_TABLE_HPP

View File

@ -1,112 +1,112 @@
#ifndef OSMIUM_INDEX_MAP_STL_MAP_HPP #ifndef OSMIUM_INDEX_MAP_STL_MAP_HPP
#define OSMIUM_INDEX_MAP_STL_MAP_HPP #define OSMIUM_INDEX_MAP_STL_MAP_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm> #include <algorithm>
#include <cstddef> #include <cstddef>
#include <iterator> #include <iterator>
#include <map> #include <map>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
#include <osmium/index/map.hpp> #include <osmium/index/map.hpp>
#include <osmium/io/detail/read_write.hpp> #include <osmium/io/detail/read_write.hpp>
namespace osmium { namespace osmium {
namespace index { namespace index {
namespace map { namespace map {
/** /**
* This implementation uses std::map internally. It uses rather a * This implementation uses std::map internally. It uses rather a
* lot of memory, but might make sense for small maps. * lot of memory, but might make sense for small maps.
*/ */
template <typename TId, typename TValue> template <typename TId, typename TValue>
class StlMap : public osmium::index::map::Map<TId, TValue> { class StlMap : public osmium::index::map::Map<TId, TValue> {
// This is a rough estimate for the memory needed for each // This is a rough estimate for the memory needed for each
// element in the map (id + value + pointers to left, right, // element in the map (id + value + pointers to left, right,
// and parent plus some overhead for color of red-black-tree // and parent plus some overhead for color of red-black-tree
// or similar). // or similar).
static constexpr size_t element_size = sizeof(TId) + sizeof(TValue) + sizeof(void*) * 4; static constexpr size_t element_size = sizeof(TId) + sizeof(TValue) + sizeof(void*) * 4;
std::map<TId, TValue> m_elements; std::map<TId, TValue> m_elements;
public: public:
StlMap() = default; StlMap() = default;
~StlMap() override final = default; ~StlMap() override final = default;
void set(const TId id, const TValue value) override final { void set(const TId id, const TValue value) override final {
m_elements[id] = value; m_elements[id] = value;
} }
const TValue get(const TId id) const override final { const TValue get(const TId id) const override final {
try { try {
return m_elements.at(id); return m_elements.at(id);
} catch (std::out_of_range&) { } catch (std::out_of_range&) {
not_found_error(id); not_found_error(id);
} }
} }
size_t size() const override final { size_t size() const override final {
return m_elements.size(); return m_elements.size();
} }
size_t used_memory() const override final { size_t used_memory() const override final {
return element_size * m_elements.size(); return element_size * m_elements.size();
} }
void clear() override final { void clear() override final {
m_elements.clear(); m_elements.clear();
} }
void dump_as_list(const int fd) const { void dump_as_list(const int fd) const override final {
typedef typename std::map<TId, TValue>::value_type t; typedef typename std::map<TId, TValue>::value_type t;
std::vector<t> v; std::vector<t> v;
std::copy(m_elements.begin(), m_elements.end(), std::back_inserter(v)); std::copy(m_elements.begin(), m_elements.end(), std::back_inserter(v));
osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(t) * v.size()); osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(t) * v.size());
} }
}; // class StlMap }; // class StlMap
} // namespace map } // namespace map
} // namespace index } // namespace index
} // namespace osmium } // namespace osmium
#endif // OSMIUM_INDEX_MAP_STL_MAP_HPP #endif // OSMIUM_INDEX_MAP_STL_MAP_HPP

View File

@ -1,208 +1,208 @@
#ifndef OSMIUM_INDEX_MAP_VECTOR_HPP #ifndef OSMIUM_INDEX_MAP_VECTOR_HPP
#define OSMIUM_INDEX_MAP_VECTOR_HPP #define OSMIUM_INDEX_MAP_VECTOR_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm> #include <algorithm>
#include <cstddef> #include <cstddef>
#include <stdexcept> #include <stdexcept>
#include <utility> #include <utility>
#include <osmium/index/map.hpp> #include <osmium/index/map.hpp>
#include <osmium/io/detail/read_write.hpp> #include <osmium/io/detail/read_write.hpp>
namespace osmium { namespace osmium {
namespace index { namespace index {
namespace map { namespace map {
template <class TVector, typename TId, typename TValue> template <class TVector, typename TId, typename TValue>
class VectorBasedDenseMap : public Map<TId, TValue> { class VectorBasedDenseMap : public Map<TId, TValue> {
TVector m_vector; TVector m_vector;
public: public:
VectorBasedDenseMap() : VectorBasedDenseMap() :
m_vector() { m_vector() {
} }
explicit VectorBasedDenseMap(int fd) : explicit VectorBasedDenseMap(int fd) :
m_vector(fd) { m_vector(fd) {
} }
~VectorBasedDenseMap() {} ~VectorBasedDenseMap() {}
void reserve(const size_t size) override final { void reserve(const size_t size) override final {
m_vector.reserve(size); m_vector.reserve(size);
} }
void set(const TId id, const TValue value) override final { void set(const TId id, const TValue value) override final {
if (size() <= id) { if (size() <= id) {
m_vector.resize(id+1); m_vector.resize(id+1);
} }
m_vector[id] = value; m_vector[id] = value;
} }
const TValue get(const TId id) const override final { const TValue get(const TId id) const override final {
try { try {
const TValue& value = m_vector.at(id); const TValue& value = m_vector.at(id);
if (value == osmium::index::empty_value<TValue>()) { if (value == osmium::index::empty_value<TValue>()) {
not_found_error(id); not_found_error(id);
} }
return value; return value;
} catch (std::out_of_range&) { } catch (std::out_of_range&) {
not_found_error(id); not_found_error(id);
} }
} }
size_t size() const override final { size_t size() const override final {
return m_vector.size(); return m_vector.size();
} }
size_t used_memory() const override final { size_t used_memory() const override final {
return sizeof(TValue) * size(); return sizeof(TValue) * size();
} }
void clear() override final { void clear() override final {
m_vector.clear(); m_vector.clear();
m_vector.shrink_to_fit(); m_vector.shrink_to_fit();
} }
}; // class VectorBasedDenseMap }; // class VectorBasedDenseMap
template <typename TId, typename TValue, template<typename...> class TVector> template <typename TId, typename TValue, template<typename...> class TVector>
class VectorBasedSparseMap : public Map<TId, TValue> { class VectorBasedSparseMap : public Map<TId, TValue> {
public: public:
typedef typename std::pair<TId, TValue> element_type; typedef typename std::pair<TId, TValue> element_type;
typedef TVector<element_type> vector_type; typedef TVector<element_type> vector_type;
typedef typename vector_type::iterator iterator; typedef typename vector_type::iterator iterator;
typedef typename vector_type::const_iterator const_iterator; typedef typename vector_type::const_iterator const_iterator;
private: private:
vector_type m_vector; vector_type m_vector;
public: public:
VectorBasedSparseMap() : VectorBasedSparseMap() :
m_vector() { m_vector() {
} }
VectorBasedSparseMap(int fd) : VectorBasedSparseMap(int fd) :
m_vector(fd) { m_vector(fd) {
} }
~VectorBasedSparseMap() override final = default; ~VectorBasedSparseMap() override final = default;
void set(const TId id, const TValue value) override final { void set(const TId id, const TValue value) override final {
m_vector.push_back(element_type(id, value)); m_vector.push_back(element_type(id, value));
} }
const TValue get(const TId id) const override final { const TValue get(const TId id) const override final {
const element_type element { const element_type element {
id, id,
osmium::index::empty_value<TValue>() osmium::index::empty_value<TValue>()
}; };
const auto result = std::lower_bound(m_vector.begin(), m_vector.end(), element, [](const element_type& a, const element_type& b) { const auto result = std::lower_bound(m_vector.begin(), m_vector.end(), element, [](const element_type& a, const element_type& b) {
return a.first < b.first; return a.first < b.first;
}); });
if (result == m_vector.end() || result->first != id) { if (result == m_vector.end() || result->first != id) {
not_found_error(id); not_found_error(id);
} else { } else {
return result->second; return result->second;
} }
} }
size_t size() const override final { size_t size() const override final {
return m_vector.size(); return m_vector.size();
} }
size_t byte_size() const { size_t byte_size() const {
return m_vector.size() * sizeof(element_type); return m_vector.size() * sizeof(element_type);
} }
size_t used_memory() const override final { size_t used_memory() const override final {
return sizeof(element_type) * size(); return sizeof(element_type) * size();
} }
void clear() override final { void clear() override final {
m_vector.clear(); m_vector.clear();
m_vector.shrink_to_fit(); m_vector.shrink_to_fit();
} }
void sort() override final { void sort() override final {
std::sort(m_vector.begin(), m_vector.end()); std::sort(m_vector.begin(), m_vector.end());
} }
void dump_as_list(int fd) const { void dump_as_list(int fd) const override final {
osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size()); osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size());
} }
iterator begin() { iterator begin() {
return m_vector.begin(); return m_vector.begin();
} }
iterator end() { iterator end() {
return m_vector.end(); return m_vector.end();
} }
const_iterator cbegin() const { const_iterator cbegin() const {
return m_vector.cbegin(); return m_vector.cbegin();
} }
const_iterator cend() const { const_iterator cend() const {
return m_vector.cend(); return m_vector.cend();
} }
const_iterator begin() const { const_iterator begin() const {
return m_vector.cbegin(); return m_vector.cbegin();
} }
const_iterator end() const { const_iterator end() const {
return m_vector.cend(); return m_vector.cend();
} }
}; // class VectorBasedSparseMap }; // class VectorBasedSparseMap
} // namespace map } // namespace map
} // namespace index } // namespace index
} // namespace osmium } // namespace osmium
#endif // OSMIUM_INDEX_MAP_VECTOR_HPP #endif // OSMIUM_INDEX_MAP_VECTOR_HPP

View File

@ -1,125 +1,129 @@
#ifndef OSMIUM_INDEX_MULTIMAP_HPP #ifndef OSMIUM_INDEX_MULTIMAP_HPP
#define OSMIUM_INDEX_MULTIMAP_HPP #define OSMIUM_INDEX_MULTIMAP_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <cstddef> #include <cstddef>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <osmium/index/index.hpp> // IWYU pragma: export #include <osmium/index/index.hpp> // IWYU pragma: export
namespace osmium { namespace osmium {
namespace index { namespace index {
/** /**
* @brief Key-value containers with multiple values for an integer key * @brief Key-value containers with multiple values for an integer key
*/ */
namespace multimap { namespace multimap {
template <typename TId, typename TValue> template <typename TId, typename TValue>
class Multimap { class Multimap {
static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value, static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value,
"TId template parameter for class Multimap must be unsigned integral type"); "TId template parameter for class Multimap must be unsigned integral type");
typedef typename std::pair<TId, TValue> element_type; typedef typename std::pair<TId, TValue> element_type;
Multimap(const Multimap&) = delete; Multimap(const Multimap&) = delete;
Multimap& operator=(const Multimap&) = delete; Multimap& operator=(const Multimap&) = delete;
protected: protected:
Multimap(Multimap&&) = default; Multimap(Multimap&&) = default;
Multimap& operator=(Multimap&&) = default; Multimap& operator=(Multimap&&) = default;
public: public:
/// The "key" type, usually osmium::unsigned_object_id_type. /// The "key" type, usually osmium::unsigned_object_id_type.
typedef TId key_type; typedef TId key_type;
/// The "value" type, usually a Location or size_t. /// The "value" type, usually a Location or size_t.
typedef TValue value_type; typedef TValue value_type;
Multimap() = default; Multimap() = default;
virtual ~Multimap() noexcept = default; virtual ~Multimap() noexcept = default;
/// Set the field with id to value. /// Set the field with id to value.
virtual void set(const TId id, const TValue value) = 0; virtual void set(const TId id, const TValue value) = 0;
typedef element_type* iterator; typedef element_type* iterator;
// virtual std::pair<iterator, iterator> get_all(const TId id) const = 0; // virtual std::pair<iterator, iterator> get_all(const TId id) const = 0;
/** /**
* Get the approximate number of items in the storage. The storage * Get the approximate number of items in the storage. The storage
* might allocate memory in blocks, so this size might not be * might allocate memory in blocks, so this size might not be
* accurate. You can not use this to find out how much memory the * accurate. You can not use this to find out how much memory the
* storage uses. Use used_memory() for that. * storage uses. Use used_memory() for that.
*/ */
virtual size_t size() const = 0; virtual size_t size() const = 0;
/** /**
* Get the memory used for this storage in bytes. Note that this * Get the memory used for this storage in bytes. Note that this
* is not necessarily entirely accurate but an approximation. * is not necessarily entirely accurate but an approximation.
* For storage classes that store the data in memory, this is * For storage classes that store the data in memory, this is
* the main memory used, for storage classes storing data on disk * the main memory used, for storage classes storing data on disk
* this is the memory used on disk. * this is the memory used on disk.
*/ */
virtual size_t used_memory() const = 0; virtual size_t used_memory() const = 0;
/** /**
* Clear memory used for this storage. After this you can not * Clear memory used for this storage. After this you can not
* use the storage container any more. * use the storage container any more.
*/ */
virtual void clear() = 0; virtual void clear() = 0;
/** /**
* Sort data in map. Call this after writing all data and * Sort data in map. Call this after writing all data and
* before reading. Not all implementations need this. * before reading. Not all implementations need this.
*/ */
virtual void sort() { virtual void sort() {
// default implementation is empty // default implementation is empty
} }
}; // class Multimap virtual void dump_as_list(int /*fd*/) const {
std::runtime_error("can't dump as list");
} // namespace map }
} // namespace index }; // class Multimap
} // namespace osmium } // namespace map
#endif // OSMIUM_INDEX_MULTIMAP_HPP } // namespace index
} // namespace osmium
#endif // OSMIUM_INDEX_MULTIMAP_HPP

View File

@ -1,199 +1,199 @@
#ifndef OSMIUM_INDEX_MULTIMAP_HYBRID_HPP #ifndef OSMIUM_INDEX_MULTIMAP_HYBRID_HPP
#define OSMIUM_INDEX_MULTIMAP_HYBRID_HPP #define OSMIUM_INDEX_MULTIMAP_HYBRID_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <cstddef> #include <cstddef>
#include <utility> #include <utility>
#include <osmium/index/multimap.hpp> #include <osmium/index/multimap.hpp>
#include <osmium/index/multimap/stl_vector.hpp> #include <osmium/index/multimap/stl_vector.hpp>
#include <osmium/index/multimap/stl_multimap.hpp> #include <osmium/index/multimap/stl_multimap.hpp>
namespace osmium { namespace osmium {
namespace index { namespace index {
namespace multimap { namespace multimap {
template <typename TId, typename TValue> template <typename TId, typename TValue>
class HybridIterator { class HybridIterator {
typedef SparseMultimapMem<TId, TValue> main_map_type; typedef SparseMultimapMem<TId, TValue> main_map_type;
typedef StlMultimap<TId, TValue> extra_map_type; typedef StlMultimap<TId, TValue> extra_map_type;
typedef typename std::pair<TId, TValue> element_type; typedef typename std::pair<TId, TValue> element_type;
typename main_map_type::iterator m_begin_main; typename main_map_type::iterator m_begin_main;
typename main_map_type::iterator m_end_main; typename main_map_type::iterator m_end_main;
typename extra_map_type::iterator m_begin_extra; typename extra_map_type::iterator m_begin_extra;
typename extra_map_type::iterator m_end_extra; typename extra_map_type::iterator m_end_extra;
public: public:
explicit HybridIterator(typename main_map_type::iterator begin_main, explicit HybridIterator(typename main_map_type::iterator begin_main,
typename main_map_type::iterator end_main, typename main_map_type::iterator end_main,
typename extra_map_type::iterator begin_extra, typename extra_map_type::iterator begin_extra,
typename extra_map_type::iterator end_extra) : typename extra_map_type::iterator end_extra) :
m_begin_main(begin_main), m_begin_main(begin_main),
m_end_main(end_main), m_end_main(end_main),
m_begin_extra(begin_extra), m_begin_extra(begin_extra),
m_end_extra(end_extra) { m_end_extra(end_extra) {
} }
HybridIterator& operator++() { HybridIterator& operator++() {
if (m_begin_main == m_end_main) { if (m_begin_main == m_end_main) {
++m_begin_extra; ++m_begin_extra;
} else { } else {
++m_begin_main; ++m_begin_main;
while (m_begin_main != m_end_main && m_begin_main->second == osmium::index::empty_value<TValue>()) { // ignore removed elements while (m_begin_main != m_end_main && m_begin_main->second == osmium::index::empty_value<TValue>()) { // ignore removed elements
++m_begin_main; ++m_begin_main;
} }
} }
return *this; return *this;
} }
HybridIterator<TId, TValue> operator++(int) { HybridIterator<TId, TValue> operator++(int) {
auto tmp(*this); auto tmp(*this);
operator++(); operator++();
return tmp; return tmp;
} }
bool operator==(const HybridIterator& rhs) const { bool operator==(const HybridIterator& rhs) const {
return m_begin_main == rhs.m_begin_main && return m_begin_main == rhs.m_begin_main &&
m_end_main == rhs.m_end_main && m_end_main == rhs.m_end_main &&
m_begin_extra == rhs.m_begin_extra && m_begin_extra == rhs.m_begin_extra &&
m_end_extra == rhs.m_end_extra; m_end_extra == rhs.m_end_extra;
} }
bool operator!=(const HybridIterator& rhs) const { bool operator!=(const HybridIterator& rhs) const {
return ! operator==(rhs); return ! operator==(rhs);
} }
const element_type& operator*() { const element_type& operator*() {
if (m_begin_main == m_end_main) { if (m_begin_main == m_end_main) {
return *m_begin_extra; return *m_begin_extra;
} else { } else {
return *m_begin_main; return *m_begin_main;
} }
} }
const element_type* operator->() { const element_type* operator->() {
return &operator*(); return &operator*();
} }
}; }; // class HybridIterator
template <typename TId, typename TValue> template <typename TId, typename TValue>
class Hybrid : public Multimap<TId, TValue> { class Hybrid : public Multimap<TId, TValue> {
typedef SparseMultimapMem<TId, TValue> main_map_type; typedef SparseMultimapMem<TId, TValue> main_map_type;
typedef StlMultimap<TId, TValue> extra_map_type; typedef StlMultimap<TId, TValue> extra_map_type;
main_map_type m_main; main_map_type m_main;
extra_map_type m_extra; extra_map_type m_extra;
public: public:
typedef HybridIterator<TId, TValue> iterator; typedef HybridIterator<TId, TValue> iterator;
typedef const HybridIterator<TId, TValue> const_iterator; typedef const HybridIterator<TId, TValue> const_iterator;
Hybrid() : Hybrid() :
m_main(), m_main(),
m_extra() { m_extra() {
} }
size_t size() const override final { size_t size() const override final {
return m_main.size() + m_extra.size(); return m_main.size() + m_extra.size();
} }
size_t used_memory() const override final { size_t used_memory() const override final {
return m_main.used_memory() + m_extra.used_memory(); return m_main.used_memory() + m_extra.used_memory();
} }
void reserve(const size_t size) { void reserve(const size_t size) {
m_main.reserve(size); m_main.reserve(size);
} }
void unsorted_set(const TId id, const TValue value) { void unsorted_set(const TId id, const TValue value) {
m_main.set(id, value); m_main.set(id, value);
} }
void set(const TId id, const TValue value) override final { void set(const TId id, const TValue value) override final {
m_extra.set(id, value); m_extra.set(id, value);
} }
std::pair<iterator, iterator> get_all(const TId id) { std::pair<iterator, iterator> get_all(const TId id) {
auto result_main = m_main.get_all(id); auto result_main = m_main.get_all(id);
auto result_extra = m_extra.get_all(id); auto result_extra = m_extra.get_all(id);
return std::make_pair(iterator(result_main.first, result_main.second, result_extra.first, result_extra.second), return std::make_pair(iterator(result_main.first, result_main.second, result_extra.first, result_extra.second),
iterator(result_main.second, result_main.second, result_extra.second, result_extra.second)); iterator(result_main.second, result_main.second, result_extra.second, result_extra.second));
} }
void remove(const TId id, const TValue value) { void remove(const TId id, const TValue value) {
m_main.remove(id, value); m_main.remove(id, value);
m_extra.remove(id, value); m_extra.remove(id, value);
} }
void consolidate() { void consolidate() {
m_main.erase_removed(); m_main.erase_removed();
for (const auto& element : m_extra) { for (const auto& element : m_extra) {
m_main.set(element.first, element.second); m_main.set(element.first, element.second);
} }
m_extra.clear(); m_extra.clear();
m_main.sort(); m_main.sort();
} }
void dump_as_list(int fd) { void dump_as_list(int fd) override final {
consolidate(); consolidate();
m_main.dump_as_list(fd); m_main.dump_as_list(fd);
} }
void clear() override final { void clear() override final {
m_main.clear(); m_main.clear();
m_extra.clear(); m_extra.clear();
} }
void sort() override final { void sort() override final {
m_main.sort(); m_main.sort();
} }
}; // Hybrid }; // class Hybrid
} // namespace multimap } // namespace multimap
} // namespace index } // namespace index
} // namespace osmium } // namespace osmium
#endif // OSMIUM_INDEX_MULTIMAP_HYBRID_HPP #endif // OSMIUM_INDEX_MULTIMAP_HYBRID_HPP

View File

@ -1,151 +1,151 @@
#ifndef OSMIUM_INDEX_MULTIMAP_STL_MULTIMAP_HPP #ifndef OSMIUM_INDEX_MULTIMAP_STL_MULTIMAP_HPP
#define OSMIUM_INDEX_MULTIMAP_STL_MULTIMAP_HPP #define OSMIUM_INDEX_MULTIMAP_STL_MULTIMAP_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm> #include <algorithm>
#include <cstddef> #include <cstddef>
#include <map> #include <map>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <osmium/index/multimap.hpp> #include <osmium/index/multimap.hpp>
#include <osmium/io/detail/read_write.hpp> #include <osmium/io/detail/read_write.hpp>
namespace osmium { namespace osmium {
namespace index { namespace index {
namespace multimap { namespace multimap {
/** /**
* This implementation uses std::multimap internally. It uses rather a * This implementation uses std::multimap internally. It uses rather a
* lot of memory, but might make sense for small maps. * lot of memory, but might make sense for small maps.
*/ */
template <typename TId, typename TValue> template <typename TId, typename TValue>
class StlMultimap : public osmium::index::multimap::Multimap<TId, TValue> { class StlMultimap : public osmium::index::multimap::Multimap<TId, TValue> {
// This is a rough estimate for the memory needed for each // This is a rough estimate for the memory needed for each
// element in the map (id + value + pointers to left, right, // element in the map (id + value + pointers to left, right,
// and parent plus some overhead for color of red-black-tree // and parent plus some overhead for color of red-black-tree
// or similar). // or similar).
static constexpr size_t element_size = sizeof(TId) + sizeof(TValue) + sizeof(void*) * 4; static constexpr size_t element_size = sizeof(TId) + sizeof(TValue) + sizeof(void*) * 4;
public: public:
typedef typename std::multimap<const TId, TValue> collection_type; typedef typename std::multimap<const TId, TValue> collection_type;
typedef typename collection_type::iterator iterator; typedef typename collection_type::iterator iterator;
typedef typename collection_type::const_iterator const_iterator; typedef typename collection_type::const_iterator const_iterator;
typedef typename collection_type::value_type value_type; typedef typename collection_type::value_type value_type;
typedef typename std::pair<TId, TValue> element_type; typedef typename std::pair<TId, TValue> element_type;
private: private:
collection_type m_elements; collection_type m_elements;
public: public:
StlMultimap() = default; StlMultimap() = default;
~StlMultimap() noexcept override final = default; ~StlMultimap() noexcept override final = default;
void unsorted_set(const TId id, const TValue value) { void unsorted_set(const TId id, const TValue value) {
m_elements.emplace(id, value); m_elements.emplace(id, value);
} }
void set(const TId id, const TValue value) override final { void set(const TId id, const TValue value) override final {
m_elements.emplace(id, value); m_elements.emplace(id, value);
} }
std::pair<iterator, iterator> get_all(const TId id) { std::pair<iterator, iterator> get_all(const TId id) {
return m_elements.equal_range(id); return m_elements.equal_range(id);
} }
std::pair<const_iterator, const_iterator> get_all(const TId id) const { std::pair<const_iterator, const_iterator> get_all(const TId id) const {
return m_elements.equal_range(id); return m_elements.equal_range(id);
} }
void remove(const TId id, const TValue value) { void remove(const TId id, const TValue value) {
std::pair<iterator, iterator> r = get_all(id); std::pair<iterator, iterator> r = get_all(id);
for (iterator it = r.first; it != r.second; ++it) { for (iterator it = r.first; it != r.second; ++it) {
if (it->second == value) { if (it->second == value) {
m_elements.erase(it); m_elements.erase(it);
return; return;
} }
} }
} }
iterator begin() { iterator begin() {
return m_elements.begin(); return m_elements.begin();
} }
iterator end() { iterator end() {
return m_elements.end(); return m_elements.end();
} }
size_t size() const override final { size_t size() const override final {
return m_elements.size(); return m_elements.size();
} }
size_t used_memory() const override final { size_t used_memory() const override final {
return element_size * m_elements.size(); return element_size * m_elements.size();
} }
void clear() override final { void clear() override final {
m_elements.clear(); m_elements.clear();
} }
void consolidate() { void consolidate() {
// intentionally left blank // intentionally left blank
} }
void dump_as_list(const int fd) const { void dump_as_list(const int fd) const override final {
std::vector<element_type> v; std::vector<element_type> v;
for (const auto& element : m_elements) { for (const auto& element : m_elements) {
v.emplace_back(element.first, element.second); v.emplace_back(element.first, element.second);
} }
// std::copy(m_elements.cbegin(), m_elements.cend(), std::back_inserter(v)); // std::copy(m_elements.cbegin(), m_elements.cend(), std::back_inserter(v));
std::sort(v.begin(), v.end()); std::sort(v.begin(), v.end());
osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(element_type) * v.size()); osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(element_type) * v.size());
} }
}; // class StlMultimap }; // class StlMultimap
} // namespace multimap } // namespace multimap
} // namespace index } // namespace index
} // namespace osmium } // namespace osmium
#endif // OSMIUM_INDEX_MULTIMAP_STL_MULTIMAP_HPP #endif // OSMIUM_INDEX_MULTIMAP_STL_MULTIMAP_HPP

View File

@ -1,141 +1,151 @@
#ifndef OSMIUM_INDEX_MULTIMAP_VECTOR_HPP #ifndef OSMIUM_INDEX_MULTIMAP_VECTOR_HPP
#define OSMIUM_INDEX_MULTIMAP_VECTOR_HPP #define OSMIUM_INDEX_MULTIMAP_VECTOR_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm> #include <algorithm>
#include <cstddef> #include <cstddef>
#include <utility> #include <utility>
#include <osmium/index/multimap.hpp> #include <osmium/index/multimap.hpp>
#include <osmium/io/detail/read_write.hpp> #include <osmium/io/detail/read_write.hpp>
namespace osmium { namespace osmium {
namespace index { namespace index {
namespace multimap { namespace multimap {
template <typename TId, typename TValue, template<typename...> class TVector> template <typename TId, typename TValue, template<typename...> class TVector>
class VectorBasedSparseMultimap : public Multimap<TId, TValue> { class VectorBasedSparseMultimap : public Multimap<TId, TValue> {
public: public:
typedef typename std::pair<TId, TValue> element_type; typedef typename std::pair<TId, TValue> element_type;
typedef TVector<element_type> vector_type; typedef TVector<element_type> vector_type;
typedef typename vector_type::iterator iterator; typedef typename vector_type::iterator iterator;
typedef typename vector_type::const_iterator const_iterator; typedef typename vector_type::const_iterator const_iterator;
private: private:
vector_type m_vector; vector_type m_vector;
static bool is_removed(element_type& element) { static bool is_removed(element_type& element) {
return element.second == osmium::index::empty_value<TValue>(); return element.second == osmium::index::empty_value<TValue>();
} }
public: public:
void set(const TId id, const TValue value) override final { void set(const TId id, const TValue value) override final {
m_vector.push_back(element_type(id, value)); m_vector.push_back(element_type(id, value));
} }
void unsorted_set(const TId id, const TValue value) { void unsorted_set(const TId id, const TValue value) {
m_vector.push_back(element_type(id, value)); m_vector.push_back(element_type(id, value));
} }
std::pair<iterator, iterator> get_all(const TId id) { std::pair<iterator, iterator> get_all(const TId id) {
const element_type element { const element_type element {
id, id,
osmium::index::empty_value<TValue>() osmium::index::empty_value<TValue>()
}; };
return std::equal_range(m_vector.begin(), m_vector.end(), element, [](const element_type& a, const element_type& b) { return std::equal_range(m_vector.begin(), m_vector.end(), element, [](const element_type& a, const element_type& b) {
return a.first < b.first; return a.first < b.first;
}); });
} }
size_t size() const override final { std::pair<const_iterator, const_iterator> get_all(const TId id) const {
return m_vector.size(); const element_type element {
} id,
osmium::index::empty_value<TValue>()
size_t byte_size() const { };
return m_vector.size() * sizeof(element_type); return std::equal_range(m_vector.cbegin(), m_vector.cend(), element, [](const element_type& a, const element_type& b) {
} return a.first < b.first;
});
size_t used_memory() const override final { }
return sizeof(element_type) * size();
} size_t size() const override final {
return m_vector.size();
void clear() override final { }
m_vector.clear();
m_vector.shrink_to_fit(); size_t byte_size() const {
} return m_vector.size() * sizeof(element_type);
}
void sort() override final {
std::sort(m_vector.begin(), m_vector.end()); size_t used_memory() const override final {
} return sizeof(element_type) * size();
}
void remove(const TId id, const TValue value) {
auto r = get_all(id); void clear() override final {
for (auto it = r.first; it != r.second; ++it) { m_vector.clear();
if (it->second == value) { m_vector.shrink_to_fit();
it->second = 0; }
return;
} void sort() override final {
} std::sort(m_vector.begin(), m_vector.end());
} }
void consolidate() { void remove(const TId id, const TValue value) {
std::sort(m_vector.begin(), m_vector.end()); auto r = get_all(id);
} for (auto it = r.first; it != r.second; ++it) {
if (it->second == value) {
void erase_removed() { it->second = 0;
m_vector.erase( return;
std::remove_if(m_vector.begin(), m_vector.end(), is_removed), }
m_vector.end() }
); }
}
void consolidate() {
void dump_as_list(int fd) const { std::sort(m_vector.begin(), m_vector.end());
osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size()); }
}
void erase_removed() {
}; // class VectorBasedSparseMultimap m_vector.erase(
std::remove_if(m_vector.begin(), m_vector.end(), is_removed),
} // namespace multimap m_vector.end()
);
} // namespace index }
} // namespace osmium void dump_as_list(int fd) const override final {
osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size());
#endif // OSMIUM_INDEX_MULTIMAP_VECTOR_HPP }
}; // class VectorBasedSparseMultimap
} // namespace multimap
} // namespace index
} // namespace osmium
#endif // OSMIUM_INDEX_MULTIMAP_VECTOR_HPP

View File

@ -40,22 +40,50 @@ DEALINGS IN THE SOFTWARE.
#include <string> #include <string>
#include <bzlib.h> #include <bzlib.h>
#ifndef _MSC_VER #ifndef _MSC_VER
# include <unistd.h> # include <unistd.h>
#endif #endif
#include <osmium/io/compression.hpp> #include <osmium/io/compression.hpp>
#include <osmium/io/file_compression.hpp> #include <osmium/io/file_compression.hpp>
#include <osmium/util/cast.hpp>
#include <osmium/util/compatibility.hpp> #include <osmium/util/compatibility.hpp>
namespace osmium { namespace osmium {
/**
* Exception thrown when there are problems compressing or
* decompressing bzip2 files.
*/
struct bzip2_error : public std::runtime_error {
int bzip2_error_code;
int system_errno;
bzip2_error(const std::string& what, int error_code) :
std::runtime_error(what),
bzip2_error_code(error_code),
system_errno(error_code == BZ_IO_ERROR ? errno : 0) {
}
}; // struct bzip2_error
namespace io { namespace io {
namespace detail { namespace detail {
OSMIUM_NORETURN inline void throw_bzip2_error(const std::string& msg, int error) { OSMIUM_NORETURN inline void throw_bzip2_error(BZFILE* bzfile, const char* msg, int bzlib_error=0) {
throw std::runtime_error("bzip2 error: " + msg + ": " + std::to_string(error)); std::string error("bzip2 error: ");
error += msg;
error += ": ";
int errnum = bzlib_error;
if (bzlib_error) {
error += std::to_string(bzlib_error);
} else {
error += ::BZ2_bzerror(bzfile, &errnum);
}
throw osmium::bzip2_error(error, errnum);
} }
} // namespace detail } // namespace detail
@ -74,19 +102,19 @@ namespace osmium {
m_bzerror(BZ_OK), m_bzerror(BZ_OK),
m_bzfile(::BZ2_bzWriteOpen(&m_bzerror, m_file, 6, 0, 0)) { m_bzfile(::BZ2_bzWriteOpen(&m_bzerror, m_file, 6, 0, 0)) {
if (!m_bzfile) { if (!m_bzfile) {
detail::throw_bzip2_error("write open failed", m_bzerror); detail::throw_bzip2_error(m_bzfile, "write open failed", m_bzerror);
} }
} }
~Bzip2Compressor() override final { ~Bzip2Compressor() override final {
this->close(); close();
} }
void write(const std::string& data) override final { void write(const std::string& data) override final {
int error; int error;
::BZ2_bzWrite(&error, m_bzfile, const_cast<char*>(data.data()), data.size()); ::BZ2_bzWrite(&error, m_bzfile, const_cast<char*>(data.data()), static_cast_with_assert<int>(data.size()));
if (error != BZ_OK && error != BZ_STREAM_END) { if (error != BZ_OK && error != BZ_STREAM_END) {
detail::throw_bzip2_error("write failed", error); detail::throw_bzip2_error(m_bzfile, "write failed", error);
} }
} }
@ -99,7 +127,7 @@ namespace osmium {
fclose(m_file); fclose(m_file);
} }
if (error != BZ_OK) { if (error != BZ_OK) {
detail::throw_bzip2_error("write close failed", error); detail::throw_bzip2_error(m_bzfile, "write close failed", error);
} }
} }
} }
@ -121,12 +149,12 @@ namespace osmium {
m_bzerror(BZ_OK), m_bzerror(BZ_OK),
m_bzfile(::BZ2_bzReadOpen(&m_bzerror, m_file, 0, 0, nullptr, 0)) { m_bzfile(::BZ2_bzReadOpen(&m_bzerror, m_file, 0, 0, nullptr, 0)) {
if (!m_bzfile) { if (!m_bzfile) {
detail::throw_bzip2_error("read open failed", m_bzerror); detail::throw_bzip2_error(m_bzfile, "read open failed", m_bzerror);
} }
} }
~Bzip2Decompressor() override final { ~Bzip2Decompressor() override final {
this->close(); close();
} }
std::string read() override final { std::string read() override final {
@ -135,9 +163,9 @@ namespace osmium {
} }
std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0'); std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0');
int error; int error;
int nread = ::BZ2_bzRead(&error, m_bzfile, const_cast<char*>(buffer.data()), buffer.size()); int nread = ::BZ2_bzRead(&error, m_bzfile, const_cast<char*>(buffer.data()), static_cast_with_assert<int>(buffer.size()));
if (error != BZ_OK && error != BZ_STREAM_END) { if (error != BZ_OK && error != BZ_STREAM_END) {
detail::throw_bzip2_error("read failed", error); detail::throw_bzip2_error(m_bzfile, "read failed", error);
} }
if (error == BZ_STREAM_END) { if (error == BZ_STREAM_END) {
void* unused; void* unused;
@ -145,16 +173,16 @@ namespace osmium {
if (! feof(m_file)) { if (! feof(m_file)) {
::BZ2_bzReadGetUnused(&error, m_bzfile, &unused, &nunused); ::BZ2_bzReadGetUnused(&error, m_bzfile, &unused, &nunused);
if (error != BZ_OK) { if (error != BZ_OK) {
detail::throw_bzip2_error("get unused failed", error); detail::throw_bzip2_error(m_bzfile, "get unused failed", error);
} }
std::string unused_data(static_cast<const char*>(unused), static_cast<std::string::size_type>(nunused)); std::string unused_data(static_cast<const char*>(unused), static_cast<std::string::size_type>(nunused));
::BZ2_bzReadClose(&error, m_bzfile); ::BZ2_bzReadClose(&error, m_bzfile);
if (error != BZ_OK) { if (error != BZ_OK) {
detail::throw_bzip2_error("read close failed", error); detail::throw_bzip2_error(m_bzfile, "read close failed", error);
} }
m_bzfile = ::BZ2_bzReadOpen(&error, m_file, 0, 0, const_cast<void*>(static_cast<const void*>(unused_data.data())), unused_data.size()); m_bzfile = ::BZ2_bzReadOpen(&error, m_file, 0, 0, const_cast<void*>(static_cast<const void*>(unused_data.data())), static_cast_with_assert<int>(unused_data.size()));
if (error != BZ_OK) { if (error != BZ_OK) {
detail::throw_bzip2_error("read open failed", error); detail::throw_bzip2_error(m_bzfile, "read open failed", error);
} }
} else { } else {
m_stream_end = true; m_stream_end = true;
@ -173,18 +201,71 @@ namespace osmium {
fclose(m_file); fclose(m_file);
} }
if (error != BZ_OK) { if (error != BZ_OK) {
detail::throw_bzip2_error("read close failed", error); detail::throw_bzip2_error(m_bzfile, "read close failed", error);
} }
} }
} }
}; // class Bzip2Decompressor }; // class Bzip2Decompressor
class Bzip2BufferDecompressor : public Decompressor {
const char* m_buffer;
size_t m_buffer_size;
bz_stream m_bzstream;
public:
Bzip2BufferDecompressor(const char* buffer, size_t size) :
m_buffer(buffer),
m_buffer_size(size),
m_bzstream() {
m_bzstream.next_in = const_cast<char*>(buffer);
m_bzstream.avail_in = static_cast_with_assert<unsigned int>(size);
int result = BZ2_bzDecompressInit(&m_bzstream, 0, 0);
if (result != BZ_OK) {
std::string message("bzip2 error: decompression init failed: ");
throw bzip2_error(message, result);
}
}
~Bzip2BufferDecompressor() override final {
BZ2_bzDecompressEnd(&m_bzstream);
}
std::string read() override final {
if (!m_buffer) {
return std::string();
}
const size_t buffer_size = 10240;
std::string output(buffer_size, '\0');
m_bzstream.next_out = const_cast<char*>(output.data());
m_bzstream.avail_out = buffer_size;
int result = BZ2_bzDecompress(&m_bzstream);
if (result != BZ_OK) {
m_buffer = nullptr;
m_buffer_size = 0;
}
if (result != BZ_OK && result != BZ_STREAM_END) {
std::string message("bzip2 error: decompress failed: ");
throw bzip2_error(message, result);
}
output.resize(static_cast<unsigned long>(m_bzstream.next_out - output.data()));
return output;
}
}; // class Bzip2BufferDecompressor
namespace { namespace {
const bool registered_bzip2_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::bzip2, const bool registered_bzip2_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::bzip2,
[](int fd) { return new osmium::io::Bzip2Compressor(fd); }, [](int fd) { return new osmium::io::Bzip2Compressor(fd); },
[](int fd) { return new osmium::io::Bzip2Decompressor(fd); } [](int fd) { return new osmium::io::Bzip2Decompressor(fd); },
[](const char* buffer, size_t size) { return new osmium::io::Bzip2BufferDecompressor(buffer, size); }
); );
} // anonymous namespace } // anonymous namespace

View File

@ -40,13 +40,14 @@ DEALINGS IN THE SOFTWARE.
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <system_error> #include <system_error>
#ifndef _MSC_VER
#include <unistd.h>
#else
#include <io.h>
#endif
#include <utility> #include <utility>
#ifndef _MSC_VER
# include <unistd.h>
#else
# include <io.h>
#endif
#include <osmium/io/detail/read_write.hpp> #include <osmium/io/detail/read_write.hpp>
#include <osmium/io/file_compression.hpp> #include <osmium/io/file_compression.hpp>
#include <osmium/util/compatibility.hpp> #include <osmium/util/compatibility.hpp>
@ -89,7 +90,8 @@ namespace osmium {
virtual std::string read() = 0; virtual std::string read() = 0;
virtual void close() = 0; virtual void close() {
}
}; // class Decompressor }; // class Decompressor
@ -105,11 +107,12 @@ namespace osmium {
public: public:
typedef std::function<osmium::io::Compressor*(int)> create_compressor_type; typedef std::function<osmium::io::Compressor*(int)> create_compressor_type;
typedef std::function<osmium::io::Decompressor*(int)> create_decompressor_type; typedef std::function<osmium::io::Decompressor*(int)> create_decompressor_type_fd;
typedef std::function<osmium::io::Decompressor*(const char*, size_t)> create_decompressor_type_buffer;
private: private:
typedef std::map<const osmium::io::file_compression, std::pair<create_compressor_type, create_decompressor_type>> compression_map_type; typedef std::map<const osmium::io::file_compression, std::tuple<create_compressor_type, create_decompressor_type_fd, create_decompressor_type_buffer>> compression_map_type;
compression_map_type m_callbacks; compression_map_type m_callbacks;
@ -135,8 +138,13 @@ namespace osmium {
return factory; return factory;
} }
bool register_compression(osmium::io::file_compression compression, create_compressor_type create_compressor, create_decompressor_type create_decompressor) { bool register_compression(
compression_map_type::value_type cc(compression, std::make_pair(create_compressor, create_decompressor)); osmium::io::file_compression compression,
create_compressor_type create_compressor,
create_decompressor_type_fd create_decompressor_fd,
create_decompressor_type_buffer create_decompressor_buffer) {
compression_map_type::value_type cc(compression, std::make_tuple(create_compressor, create_decompressor_fd, create_decompressor_buffer));
return m_callbacks.insert(cc).second; return m_callbacks.insert(cc).second;
} }
@ -144,7 +152,7 @@ namespace osmium {
auto it = m_callbacks.find(compression); auto it = m_callbacks.find(compression);
if (it != m_callbacks.end()) { if (it != m_callbacks.end()) {
return std::unique_ptr<osmium::io::Compressor>((it->second.first)(fd)); return std::unique_ptr<osmium::io::Compressor>(std::get<0>(it->second)(fd));
} }
error(compression); error(compression);
@ -154,7 +162,17 @@ namespace osmium {
auto it = m_callbacks.find(compression); auto it = m_callbacks.find(compression);
if (it != m_callbacks.end()) { if (it != m_callbacks.end()) {
return std::unique_ptr<osmium::io::Decompressor>((it->second.second)(fd)); return std::unique_ptr<osmium::io::Decompressor>(std::get<1>(it->second)(fd));
}
error(compression);
}
std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, const char* buffer, size_t size) {
auto it = m_callbacks.find(compression);
if (it != m_callbacks.end()) {
return std::unique_ptr<osmium::io::Decompressor>(std::get<2>(it->second)(buffer, size));
} }
error(compression); error(compression);
@ -174,7 +192,7 @@ namespace osmium {
} }
~NoCompressor() override final { ~NoCompressor() override final {
this->close(); close();
} }
void write(const std::string& data) override final { void write(const std::string& data) override final {
@ -193,26 +211,46 @@ namespace osmium {
class NoDecompressor : public Decompressor { class NoDecompressor : public Decompressor {
int m_fd; int m_fd;
const char *m_buffer;
size_t m_buffer_size;
public: public:
NoDecompressor(int fd) : NoDecompressor(int fd) :
Decompressor(), Decompressor(),
m_fd(fd) { m_fd(fd),
m_buffer(nullptr),
m_buffer_size(0) {
}
NoDecompressor(const char* buffer, size_t size) :
Decompressor(),
m_fd(-1),
m_buffer(buffer),
m_buffer_size(size) {
} }
~NoDecompressor() override final { ~NoDecompressor() override final {
this->close(); close();
} }
std::string read() override final { std::string read() override final {
std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0'); if (m_buffer) {
ssize_t nread = ::read(m_fd, const_cast<char*>(buffer.data()), buffer.size()); if (m_buffer_size == 0) {
if (nread < 0) { return std::string();
throw std::system_error(errno, std::system_category(), "Read failed"); }
size_t size = m_buffer_size;
m_buffer_size = 0;
return std::string(m_buffer, size);
} else {
std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0');
ssize_t nread = ::read(m_fd, const_cast<char*>(buffer.data()), buffer.size());
if (nread < 0) {
throw std::system_error(errno, std::system_category(), "Read failed");
}
buffer.resize(static_cast<size_t>(nread));
return buffer;
} }
buffer.resize(static_cast<size_t>(nread));
return buffer;
} }
void close() override final { void close() override final {
@ -228,7 +266,8 @@ namespace osmium {
const bool registered_no_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::none, const bool registered_no_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::none,
[](int fd) { return new osmium::io::NoCompressor(fd); }, [](int fd) { return new osmium::io::NoCompressor(fd); },
[](int fd) { return new osmium::io::NoDecompressor(fd); } [](int fd) { return new osmium::io::NoDecompressor(fd); },
[](const char* buffer, size_t size) { return new osmium::io::NoDecompressor(buffer, size); }
); );
} // anonymous namespace } // anonymous namespace

View File

@ -76,7 +76,7 @@ namespace osmium {
m_file(file), m_file(file),
m_read_which_entities(read_which_entities), m_read_which_entities(read_which_entities),
m_input_queue(input_queue) { m_input_queue(input_queue) {
m_header.has_multiple_object_versions(m_file.has_multiple_object_versions()); m_header.set_has_multiple_object_versions(m_file.has_multiple_object_versions());
} }
InputFormat(const InputFormat&) = delete; InputFormat(const InputFormat&) = delete;

View File

@ -48,12 +48,22 @@ DEALINGS IN THE SOFTWARE.
#include <boost/version.hpp> #include <boost/version.hpp>
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wmissing-noreturn"
# pragma clang diagnostic ignored "-Wsign-conversion"
#endif
#if BOOST_VERSION >= 104800 #if BOOST_VERSION >= 104800
# include <boost/regex/pending/unicode_iterator.hpp> # include <boost/regex/pending/unicode_iterator.hpp>
#else #else
# include <boost_unicode_iterator.hpp> # include <boost_unicode_iterator.hpp>
#endif #endif
#ifdef __clang__
# pragma clang diagnostic pop
#endif
#include <osmium/handler.hpp> #include <osmium/handler.hpp>
#include <osmium/io/detail/output_format.hpp> #include <osmium/io/detail/output_format.hpp>
#include <osmium/io/file_format.hpp> #include <osmium/io/file_format.hpp>
@ -95,10 +105,13 @@ namespace osmium {
template <typename... TArgs> template <typename... TArgs>
void output_formatted(const char* format, TArgs&&... args) { void output_formatted(const char* format, TArgs&&... args) {
#ifndef NDEBUG
int len =
#endif
#ifndef _MSC_VER #ifndef _MSC_VER
int len = snprintf(m_tmp_buffer, tmp_buffer_size, format, std::forward<TArgs>(args)...); snprintf(m_tmp_buffer, tmp_buffer_size, format, std::forward<TArgs>(args)...);
#else #else
int len = _snprintf(m_tmp_buffer, tmp_buffer_size, format, std::forward<TArgs>(args)...); _snprintf(m_tmp_buffer, tmp_buffer_size, format, std::forward<TArgs>(args)...);
#endif #endif
assert(len > 0 && static_cast<size_t>(len) < tmp_buffer_size); assert(len > 0 && static_cast<size_t>(len) < tmp_buffer_size);
m_out += m_tmp_buffer; m_out += m_tmp_buffer;
@ -269,7 +282,7 @@ namespace osmium {
} }
void write_buffer(osmium::memory::Buffer&& buffer) override final { void write_buffer(osmium::memory::Buffer&& buffer) override final {
OPLOutputBlock output_block(std::move(buffer)); osmium::thread::SharedPtrWrapper<OPLOutputBlock> output_block(std::move(buffer));
m_output_queue.push(osmium::thread::Pool::instance().submit(std::move(output_block))); m_output_queue.push(osmium::thread::Pool::instance().submit(std::move(output_block)));
while (m_output_queue.size() > 10) { while (m_output_queue.size() > 10) {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // XXX std::this_thread::sleep_for(std::chrono::milliseconds(100)); // XXX
@ -287,10 +300,13 @@ namespace osmium {
namespace { namespace {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
const bool registered_opl_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::opl, const bool registered_opl_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::opl,
[](const osmium::io::File& file, data_queue_type& output_queue) { [](const osmium::io::File& file, data_queue_type& output_queue) {
return new osmium::io::detail::OPLOutputFormat(file, output_queue); return new osmium::io::detail::OPLOutputFormat(file, output_queue);
}); });
#pragma GCC diagnostic pop
} // anonymous namespace } // anonymous namespace

View File

@ -40,7 +40,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmpbf/osmpbf.h> #include <osmpbf/osmpbf.h>
// needed for htonl and ntohl // needed for htonl and ntohl
#ifndef WIN32 #ifndef _WIN32
# include <netinet/in.h> # include <netinet/in.h>
#else #else
# include <winsock2.h> # include <winsock2.h>
@ -50,6 +50,9 @@ DEALINGS IN THE SOFTWARE.
namespace osmium { namespace osmium {
// avoid g++ false positive
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wreturn-type"
inline item_type osmpbf_membertype_to_item_type(const OSMPBF::Relation::MemberType mt) { inline item_type osmpbf_membertype_to_item_type(const OSMPBF::Relation::MemberType mt) {
switch (mt) { switch (mt) {
case OSMPBF::Relation::NODE: case OSMPBF::Relation::NODE:
@ -60,6 +63,7 @@ namespace osmium {
return item_type::relation; return item_type::relation;
} }
} }
#pragma GCC diagnostic pop
inline OSMPBF::Relation::MemberType item_type_to_osmpbf_membertype(const item_type type) { inline OSMPBF::Relation::MemberType item_type_to_osmpbf_membertype(const item_type type) {
switch (type) { switch (type) {

View File

@ -33,7 +33,6 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm> #include <algorithm>
#include <atomic> #include <atomic>
#include <cassert> #include <cassert>
@ -53,6 +52,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/detail/input_format.hpp> #include <osmium/io/detail/input_format.hpp>
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export #include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
#include <osmium/io/detail/zlib.hpp> #include <osmium/io/detail/zlib.hpp>
#include <osmium/io/file.hpp>
#include <osmium/io/file_format.hpp> #include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp> #include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp> #include <osmium/memory/buffer.hpp>
@ -65,9 +65,26 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/thread/name.hpp> #include <osmium/thread/name.hpp>
#include <osmium/thread/pool.hpp> #include <osmium/thread/pool.hpp>
#include <osmium/thread/queue.hpp> #include <osmium/thread/queue.hpp>
#include <osmium/util/cast.hpp>
namespace osmium { namespace osmium {
/**
* Exception thrown when there was a problem with parsing the PBF format of
* a file.
*/
struct pbf_error : public io_error {
pbf_error(const std::string& what) :
io_error(std::string("PBF error: ") + what) {
}
pbf_error(const char* what) :
io_error(std::string("PBF error: ") + what) {
}
}; // struct pbf_error
namespace io { namespace io {
class File; class File;
@ -76,10 +93,10 @@ namespace osmium {
class PBFPrimitiveBlockParser { class PBFPrimitiveBlockParser {
static constexpr size_t initial_buffer_size = 10 * 1024; static constexpr size_t initial_buffer_size = 2 * 1024 * 1024;
const void* m_data; const void* m_data;
const size_t m_size; const int m_size;
const OSMPBF::StringTable* m_stringtable; const OSMPBF::StringTable* m_stringtable;
int64_t m_lon_offset; int64_t m_lon_offset;
@ -99,7 +116,7 @@ namespace osmium {
public: public:
explicit PBFPrimitiveBlockParser(const void* data, const size_t size, osmium::osm_entity_bits::type read_types) : explicit PBFPrimitiveBlockParser(const void* data, const int size, osmium::osm_entity_bits::type read_types) :
m_data(data), m_data(data),
m_size(size), m_size(size),
m_stringtable(nullptr), m_stringtable(nullptr),
@ -116,7 +133,7 @@ namespace osmium {
osmium::memory::Buffer operator()() { osmium::memory::Buffer operator()() {
OSMPBF::PrimitiveBlock pbf_primitive_block; OSMPBF::PrimitiveBlock pbf_primitive_block;
if (!pbf_primitive_block.ParseFromArray(m_data, m_size)) { if (!pbf_primitive_block.ParseFromArray(m_data, m_size)) {
throw std::runtime_error("Failed to parse PrimitiveBlock."); throw osmium::pbf_error("failed to parse PrimitiveBlock");
} }
m_stringtable = &pbf_primitive_block.stringtable(); m_stringtable = &pbf_primitive_block.stringtable();
@ -137,7 +154,7 @@ namespace osmium {
} else if (group.nodes_size() != 0) { } else if (group.nodes_size() != 0) {
if (m_read_types & osmium::osm_entity_bits::node) parse_node_group(group); if (m_read_types & osmium::osm_entity_bits::node) parse_node_group(group);
} else { } else {
throw std::runtime_error("Group of unknown type."); throw osmium::pbf_error("group of unknown type");
} }
} }
@ -150,19 +167,19 @@ namespace osmium {
void parse_attributes(TBuilder& builder, const TPBFObject& pbf_object) { void parse_attributes(TBuilder& builder, const TPBFObject& pbf_object) {
auto& object = builder.object(); auto& object = builder.object();
object.id(pbf_object.id()); object.set_id(pbf_object.id());
if (pbf_object.has_info()) { if (pbf_object.has_info()) {
object.version(pbf_object.info().version()) object.set_version(static_cast_with_assert<object_version_type>(pbf_object.info().version()))
.changeset(pbf_object.info().changeset()) .set_changeset(static_cast_with_assert<changeset_id_type>(pbf_object.info().changeset()))
.timestamp(pbf_object.info().timestamp() * m_date_factor) .set_timestamp(pbf_object.info().timestamp() * m_date_factor)
.uid_from_signed(pbf_object.info().uid()); .set_uid_from_signed(pbf_object.info().uid());
if (pbf_object.info().has_visible()) { if (pbf_object.info().has_visible()) {
object.visible(pbf_object.info().visible()); object.set_visible(pbf_object.info().visible());
} }
builder.add_user(m_stringtable->s(pbf_object.info().user_sid()).data()); builder.add_user(m_stringtable->s(static_cast_with_assert<int>(pbf_object.info().user_sid())));
} else { } else {
builder.add_user(""); builder.add_user("", 1);
} }
} }
@ -173,7 +190,7 @@ namespace osmium {
parse_attributes(builder, pbf_node); parse_attributes(builder, pbf_node);
if (builder.object().visible()) { if (builder.object().visible()) {
builder.object().location(osmium::Location( builder.object().set_location(osmium::Location(
(pbf_node.lon() * m_granularity + m_lon_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision), (pbf_node.lon() * m_granularity + m_lon_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision),
(pbf_node.lat() * m_granularity + m_lat_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision))); (pbf_node.lat() * m_granularity + m_lat_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision)));
} }
@ -181,8 +198,8 @@ namespace osmium {
if (pbf_node.keys_size() > 0) { if (pbf_node.keys_size() > 0) {
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder); osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
for (int tag=0; tag < pbf_node.keys_size(); ++tag) { for (int tag=0; tag < pbf_node.keys_size(); ++tag) {
tl_builder.add_tag(m_stringtable->s(static_cast<int>(pbf_node.keys(tag))).data(), tl_builder.add_tag(m_stringtable->s(static_cast<int>(pbf_node.keys(tag))),
m_stringtable->s(static_cast<int>(pbf_node.vals(tag))).data()); m_stringtable->s(static_cast<int>(pbf_node.vals(tag))));
} }
} }
@ -208,8 +225,8 @@ namespace osmium {
if (pbf_way.keys_size() > 0) { if (pbf_way.keys_size() > 0) {
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder); osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
for (int tag=0; tag < pbf_way.keys_size(); ++tag) { for (int tag=0; tag < pbf_way.keys_size(); ++tag) {
tl_builder.add_tag(m_stringtable->s(static_cast<int>(pbf_way.keys(tag))).data(), tl_builder.add_tag(m_stringtable->s(static_cast<int>(pbf_way.keys(tag))),
m_stringtable->s(static_cast<int>(pbf_way.vals(tag))).data()); m_stringtable->s(static_cast<int>(pbf_way.vals(tag))));
} }
} }
@ -228,15 +245,15 @@ namespace osmium {
int64_t ref = 0; int64_t ref = 0;
for (int n=0; n < pbf_relation.types_size(); ++n) { for (int n=0; n < pbf_relation.types_size(); ++n) {
ref += pbf_relation.memids(n); ref += pbf_relation.memids(n);
rml_builder.add_member(osmpbf_membertype_to_item_type(pbf_relation.types(n)), ref, m_stringtable->s(pbf_relation.roles_sid(n)).data()); rml_builder.add_member(osmpbf_membertype_to_item_type(pbf_relation.types(n)), ref, m_stringtable->s(pbf_relation.roles_sid(n)));
} }
} }
if (pbf_relation.keys_size() > 0) { if (pbf_relation.keys_size() > 0) {
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder); osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
for (int tag=0; tag < pbf_relation.keys_size(); ++tag) { for (int tag=0; tag < pbf_relation.keys_size(); ++tag) {
tl_builder.add_tag(m_stringtable->s(static_cast<int>(pbf_relation.keys(tag))).data(), tl_builder.add_tag(m_stringtable->s(static_cast<int>(pbf_relation.keys(tag))),
m_stringtable->s(static_cast<int>(pbf_relation.vals(tag))).data()); m_stringtable->s(static_cast<int>(pbf_relation.vals(tag))));
} }
} }
@ -262,8 +279,8 @@ namespace osmium {
break; break;
} }
tl_builder.add_tag(m_stringtable->s(tag_key_pos).data(), tl_builder.add_tag(m_stringtable->s(tag_key_pos),
m_stringtable->s(dense.keys_vals(n)).data()); m_stringtable->s(dense.keys_vals(n)));
++n; ++n;
} }
@ -307,23 +324,23 @@ namespace osmium {
osmium::builder::NodeBuilder builder(m_buffer); osmium::builder::NodeBuilder builder(m_buffer);
osmium::Node& node = builder.object(); osmium::Node& node = builder.object();
node.id(last_dense_id); node.set_id(last_dense_id);
if (dense.has_denseinfo()) { if (dense.has_denseinfo()) {
auto v = dense.denseinfo().version(i); auto v = dense.denseinfo().version(i);
assert(v > 0); assert(v > 0);
node.version(static_cast<osmium::object_version_type>(v)); node.set_version(static_cast<osmium::object_version_type>(v));
node.changeset(last_dense_changeset); node.set_changeset(static_cast<osmium::changeset_id_type>(last_dense_changeset));
node.timestamp(last_dense_timestamp * m_date_factor); node.set_timestamp(last_dense_timestamp * m_date_factor);
node.uid_from_signed(last_dense_uid); node.set_uid_from_signed(static_cast<osmium::signed_user_id_type>(last_dense_uid));
node.visible(visible); node.set_visible(visible);
builder.add_user(m_stringtable->s(last_dense_user_sid).data()); builder.add_user(m_stringtable->s(static_cast<int>(last_dense_user_sid)));
} else { } else {
builder.add_user(""); builder.add_user("", 1);
} }
if (visible) { if (visible) {
builder.object().location(osmium::Location( builder.object().set_location(osmium::Location(
(last_dense_longitude * m_granularity + m_lon_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision), (last_dense_longitude * m_granularity + m_lon_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision),
(last_dense_latitude * m_granularity + m_lat_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision))); (last_dense_latitude * m_granularity + m_lat_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision)));
} }
@ -362,7 +379,7 @@ namespace osmium {
return true; return true;
} }
}; }; // class InputQueueReader
template <class TDerived> template <class TDerived>
class BlobParser { class BlobParser {
@ -380,13 +397,10 @@ namespace osmium {
m_blob_num(blob_num), m_blob_num(blob_num),
m_input_queue_reader(input_queue_reader) { m_input_queue_reader(input_queue_reader) {
if (size < 0 || size > OSMPBF::max_uncompressed_blob_size) { if (size < 0 || size > OSMPBF::max_uncompressed_blob_size) {
std::ostringstream errmsg; throw osmium::pbf_error(std::string("invalid blob size: " + std::to_string(size)));
errmsg << "invalid blob size: " << size;
throw std::runtime_error(errmsg.str());
} }
if (! input_queue_reader(m_input_buffer.get(), size)) { if (! input_queue_reader(m_input_buffer.get(), static_cast<size_t>(size))) {
// EOF throw osmium::pbf_error("truncated data (EOF encountered)");
throw std::runtime_error("read error (EOF)");
} }
} }
@ -395,7 +409,7 @@ namespace osmium {
void doit() { void doit() {
OSMPBF::Blob pbf_blob; OSMPBF::Blob pbf_blob;
if (!pbf_blob.ParseFromArray(m_input_buffer.get(), m_size)) { if (!pbf_blob.ParseFromArray(m_input_buffer.get(), m_size)) {
throw std::runtime_error("failed to parse blob"); throw osmium::pbf_error("failed to parse blob");
} }
if (pbf_blob.has_raw()) { if (pbf_blob.has_raw()) {
@ -410,16 +424,16 @@ namespace osmium {
static_cast<TDerived*>(this)->handle_blob(unpack_buffer); static_cast<TDerived*>(this)->handle_blob(unpack_buffer);
return; return;
} else if (pbf_blob.has_lzma_data()) { } else if (pbf_blob.has_lzma_data()) {
throw std::runtime_error("lzma blobs not implemented"); throw osmium::pbf_error("lzma blobs not implemented");
} else { } else {
throw std::runtime_error("Blob contains no data"); throw osmium::pbf_error("blob contains no data");
} }
} }
osmium::memory::Buffer operator()() { osmium::memory::Buffer operator()() {
OSMPBF::Blob pbf_blob; OSMPBF::Blob pbf_blob;
if (!pbf_blob.ParseFromArray(m_input_buffer.get(), m_size)) { if (!pbf_blob.ParseFromArray(m_input_buffer.get(), m_size)) {
throw std::runtime_error("failed to parse blob"); throw osmium::pbf_error("failed to parse blob");
} }
if (pbf_blob.has_raw()) { if (pbf_blob.has_raw()) {
@ -432,9 +446,9 @@ namespace osmium {
std::string unpack_buffer { osmium::io::detail::zlib_uncompress(pbf_blob.zlib_data(), static_cast<unsigned long>(raw_size)) }; std::string unpack_buffer { osmium::io::detail::zlib_uncompress(pbf_blob.zlib_data(), static_cast<unsigned long>(raw_size)) };
return static_cast<TDerived*>(this)->handle_blob(unpack_buffer); return static_cast<TDerived*>(this)->handle_blob(unpack_buffer);
} else if (pbf_blob.has_lzma_data()) { } else if (pbf_blob.has_lzma_data()) {
throw std::runtime_error("lzma blobs not implemented"); throw osmium::pbf_error("lzma blobs not implemented");
} else { } else {
throw std::runtime_error("Blob contains no data"); throw osmium::pbf_error("blob contains no data");
} }
} }
@ -446,8 +460,8 @@ namespace osmium {
void handle_blob(const std::string& data) { void handle_blob(const std::string& data) {
OSMPBF::HeaderBlock pbf_header_block; OSMPBF::HeaderBlock pbf_header_block;
if (!pbf_header_block.ParseFromArray(data.data(), data.size())) { if (!pbf_header_block.ParseFromArray(data.data(), static_cast_with_assert<int>(data.size()))) {
throw std::runtime_error("Failed to parse HeaderBlock."); throw osmium::pbf_error("failed to parse HeaderBlock");
} }
for (int i=0; i < pbf_header_block.required_features_size(); ++i) { for (int i=0; i < pbf_header_block.required_features_size(); ++i) {
@ -459,13 +473,16 @@ namespace osmium {
continue; continue;
} }
if (feature == "HistoricalInformation") { if (feature == "HistoricalInformation") {
m_header.has_multiple_object_versions(true); m_header.set_has_multiple_object_versions(true);
continue; continue;
} }
std::ostringstream errmsg; throw osmium::pbf_error(std::string("required feature not supported: ") + feature);
errmsg << "Required feature not supported: " << feature; }
throw std::runtime_error(errmsg.str());
for (int i=0; i < pbf_header_block.optional_features_size(); ++i) {
const std::string& feature = pbf_header_block.optional_features(i);
m_header.set("pbf_optional_feature_" + std::to_string(i), feature);
} }
if (pbf_header_block.has_writingprogram()) { if (pbf_header_block.has_writingprogram()) {
@ -510,7 +527,7 @@ namespace osmium {
osmium::osm_entity_bits::type m_read_types; osmium::osm_entity_bits::type m_read_types;
osmium::memory::Buffer handle_blob(const std::string& data) { osmium::memory::Buffer handle_blob(const std::string& data) {
PBFPrimitiveBlockParser parser(data.data(), data.size(), m_read_types); PBFPrimitiveBlockParser parser(data.data(), static_cast_with_assert<int>(data.size()), m_read_types);
return std::move(parser()); return std::move(parser());
} }
@ -545,9 +562,9 @@ namespace osmium {
* the expected type) and a size field. * the expected type) and a size field.
* *
* @param expected_type Expected type of data ("OSMHeader" or "OSMData"). * @param expected_type Expected type of data ("OSMHeader" or "OSMData").
* @return Size of the data read from BlobHeader (0 on EOF). * @returns Size of the data read from BlobHeader (0 on EOF).
*/ */
size_t read_blob_header(const char* expected_type) { int read_blob_header(const char* expected_type) {
uint32_t size_in_network_byte_order; uint32_t size_in_network_byte_order;
if (! m_input_queue_reader(reinterpret_cast<unsigned char*>(&size_in_network_byte_order), sizeof(size_in_network_byte_order))) { if (! m_input_queue_reader(reinterpret_cast<unsigned char*>(&size_in_network_byte_order), sizeof(size_in_network_byte_order))) {
@ -556,29 +573,29 @@ namespace osmium {
uint32_t size = ntohl(size_in_network_byte_order); uint32_t size = ntohl(size_in_network_byte_order);
if (size > static_cast<uint32_t>(OSMPBF::max_blob_header_size)) { if (size > static_cast<uint32_t>(OSMPBF::max_blob_header_size)) {
throw std::runtime_error("Invalid BlobHeader size"); throw osmium::pbf_error("invalid BlobHeader size (> max_blob_header_size)");
} }
unsigned char blob_header_buffer[OSMPBF::max_blob_header_size]; unsigned char blob_header_buffer[OSMPBF::max_blob_header_size];
if (! m_input_queue_reader(blob_header_buffer, size)) { if (! m_input_queue_reader(blob_header_buffer, size)) {
throw std::runtime_error("Read error."); throw osmium::pbf_error("read error");
} }
if (!m_blob_header.ParseFromArray(blob_header_buffer, static_cast<int>(size))) { if (!m_blob_header.ParseFromArray(blob_header_buffer, static_cast<int>(size))) {
throw std::runtime_error("Failed to parse BlobHeader."); throw osmium::pbf_error("failed to parse BlobHeader");
} }
if (std::strcmp(m_blob_header.type().c_str(), expected_type)) { if (std::strcmp(m_blob_header.type().c_str(), expected_type)) {
throw std::runtime_error("Blob does not have expected type (OSMHeader in first Blob, OSMData in following Blobs)."); throw osmium::pbf_error("blob does not have expected type (OSMHeader in first blob, OSMData in following blobs)");
} }
return static_cast<size_t>(m_blob_header.datasize()); return m_blob_header.datasize();
} }
void parse_osm_data(osmium::osm_entity_bits::type read_types) { void parse_osm_data(osmium::osm_entity_bits::type read_types) {
osmium::thread::set_thread_name("_osmium_pbf_in"); osmium::thread::set_thread_name("_osmium_pbf_in");
int n=0; int n=0;
while (size_t size = read_blob_header("OSMData")) { while (int size = read_blob_header("OSMData")) {
DataBlobParser data_blob_parser(size, n, m_input_queue_reader, read_types); DataBlobParser data_blob_parser(size, n, m_input_queue_reader, read_types);
if (m_use_thread_pool) { if (m_use_thread_pool) {
@ -627,7 +644,7 @@ namespace osmium {
GOOGLE_PROTOBUF_VERIFY_VERSION; GOOGLE_PROTOBUF_VERIFY_VERSION;
// handle OSMHeader // handle OSMHeader
size_t size = read_blob_header("OSMHeader"); int size = read_blob_header("OSMHeader");
{ {
HeaderBlobParser header_blob_parser(size, m_input_queue_reader, m_header); HeaderBlobParser header_blob_parser(size, m_input_queue_reader, m_header);

View File

@ -128,6 +128,7 @@ More complete outlines of real .osm.pbf files can be created using the osmpbf-ou
#include <osmium/osm/tag.hpp> #include <osmium/osm/tag.hpp>
#include <osmium/osm/timestamp.hpp> #include <osmium/osm/timestamp.hpp>
#include <osmium/osm/way.hpp> #include <osmium/osm/way.hpp>
#include <osmium/util/cast.hpp>
#include <osmium/visitor.hpp> #include <osmium/visitor.hpp>
namespace osmium { namespace osmium {
@ -153,7 +154,7 @@ namespace osmium {
std::string content; std::string content;
msg.SerializeToString(&content); msg.SerializeToString(&content);
pbf_blob.set_raw_size(content.size()); pbf_blob.set_raw_size(static_cast_with_assert<::google::protobuf::int32>(content.size()));
if (use_compression) { if (use_compression) {
pbf_blob.set_zlib_data(osmium::io::detail::zlib_compress(content)); pbf_blob.set_zlib_data(osmium::io::detail::zlib_compress(content));
@ -167,12 +168,12 @@ namespace osmium {
OSMPBF::BlobHeader pbf_blob_header; OSMPBF::BlobHeader pbf_blob_header;
pbf_blob_header.set_type(type); pbf_blob_header.set_type(type);
pbf_blob_header.set_datasize(blob_data.size()); pbf_blob_header.set_datasize(static_cast_with_assert<::google::protobuf::int32>(blob_data.size()));
std::string blob_header_data; std::string blob_header_data;
pbf_blob_header.SerializeToString(&blob_header_data); pbf_blob_header.SerializeToString(&blob_header_data);
uint32_t sz = htonl(blob_header_data.size()); uint32_t sz = htonl(static_cast_with_assert<uint32_t>(blob_header_data.size()));
// write to output: the 4-byte BlobHeader-Size followed by the BlobHeader followed by the Blob // write to output: the 4-byte BlobHeader-Size followed by the BlobHeader followed by the Blob
std::string output; std::string output;
@ -236,7 +237,7 @@ namespace osmium {
* enough space for the string table (which typically * enough space for the string table (which typically
* needs about 0.1 to 0.3% of the block size). * needs about 0.1 to 0.3% of the block size).
*/ */
static constexpr int buffer_fill_percent = 95; static constexpr int64_t buffer_fill_percent = 95;
/** /**
* protobuf-struct of a HeaderBlock * protobuf-struct of a HeaderBlock
@ -313,7 +314,7 @@ namespace osmium {
* called once for each object. * called once for each object.
*/ */
uint16_t primitive_block_contents; uint16_t primitive_block_contents;
uint32_t primitive_block_size; int primitive_block_size;
// StringTable management // StringTable management
StringTable string_table; StringTable string_table;
@ -329,7 +330,7 @@ namespace osmium {
Delta<int64_t> m_delta_timestamp; Delta<int64_t> m_delta_timestamp;
Delta<int64_t> m_delta_changeset; Delta<int64_t> m_delta_changeset;
Delta<int64_t> m_delta_uid; Delta<int64_t> m_delta_uid;
Delta<uint32_t> m_delta_user_sid; Delta<::google::protobuf::int32> m_delta_user_sid;
bool debug; bool debug;
@ -365,10 +366,8 @@ namespace osmium {
for (int i=0, l=dense->keys_vals_size(); i<l; ++i) { for (int i=0, l=dense->keys_vals_size(); i<l; ++i) {
// map interim string-ids > 0 to real string ids // map interim string-ids > 0 to real string ids
auto sid = dense->keys_vals(i); auto sid = dense->keys_vals(i);
assert(sid >= 0);
assert(sid < std::numeric_limits<osmium::io::detail::StringTable::string_id_type>::max());
if (sid > 0) { if (sid > 0) {
dense->set_keys_vals(i, string_table.map_string_id(static_cast<osmium::io::detail::StringTable::string_id_type>(sid))); dense->set_keys_vals(i, string_table.map_string_id(sid));
} }
} }
@ -380,9 +379,7 @@ namespace osmium {
// iterate over all username string-ids // iterate over all username string-ids
for (int i=0, l=denseinfo->user_sid_size(); i<l; ++i) { for (int i=0, l=denseinfo->user_sid_size(); i<l; ++i) {
// map interim string-ids > 0 to real string ids // map interim string-ids > 0 to real string ids
auto usid = denseinfo->user_sid(i); auto user_sid = string_table.map_string_id(denseinfo->user_sid(i));
assert(usid < std::numeric_limits<osmium::io::detail::StringTable::string_id_type>::max());
auto user_sid = string_table.map_string_id(static_cast<osmium::io::detail::StringTable::string_id_type>(usid));
// delta encode the string-id // delta encode the string-id
denseinfo->set_user_sid(i, m_delta_user_sid.update(user_sid)); denseinfo->set_user_sid(i, m_delta_user_sid.update(user_sid));
@ -411,7 +408,7 @@ namespace osmium {
// iterate over all relation members, mapping the interim string-ids // iterate over all relation members, mapping the interim string-ids
// of the role to real string ids // of the role to real string ids
for (int mi=0, ml=relation->roles_sid_size(); mi<ml; ++mi) { for (int mi=0; mi < relation->roles_sid_size(); ++mi) {
relation->set_roles_sid(mi, string_table.map_string_id(relation->roles_sid(mi))); relation->set_roles_sid(mi, string_table.map_string_id(relation->roles_sid(mi)));
} }
} }
@ -447,14 +444,14 @@ namespace osmium {
* convert a double lat or lon value to an int, respecting the current blocks granularity * convert a double lat or lon value to an int, respecting the current blocks granularity
*/ */
int64_t lonlat2int(double lonlat) { int64_t lonlat2int(double lonlat) {
return round(lonlat * OSMPBF::lonlat_resolution / location_granularity()); return static_cast<int64_t>(std::round(lonlat * OSMPBF::lonlat_resolution / location_granularity()));
} }
/** /**
* convert a timestamp to an int, respecting the current blocks granularity * convert a timestamp to an int, respecting the current blocks granularity
*/ */
int64_t timestamp2int(time_t timestamp) { int64_t timestamp2int(time_t timestamp) {
return round(timestamp * (static_cast<double>(1000) / date_granularity())); return static_cast<int64_t>(std::round(timestamp * (1000.0 / date_granularity())));
} }
/** /**
@ -570,7 +567,7 @@ namespace osmium {
void check_block_contents_counter() { void check_block_contents_counter() {
if (primitive_block_contents >= max_block_contents) { if (primitive_block_contents >= max_block_contents) {
store_primitive_block(); store_primitive_block();
} else if (primitive_block_size > (static_cast<uint32_t>(OSMPBF::max_uncompressed_blob_size) * buffer_fill_percent / 100)) { } else if (primitive_block_size > OSMPBF::max_uncompressed_blob_size * buffer_fill_percent / 100) {
if (debug && has_debug_level(1)) { if (debug && has_debug_level(1)) {
std::cerr << "storing primitive_block with only " << primitive_block_contents << " items, because its ByteSize (" << primitive_block_size << ") reached " << std::cerr << "storing primitive_block with only " << primitive_block_contents << " items, because its ByteSize (" << primitive_block_size << ") reached " <<
(static_cast<float>(primitive_block_size) / static_cast<float>(OSMPBF::max_uncompressed_blob_size) * 100.0) << "% of the maximum blob-size" << std::endl; (static_cast<float>(primitive_block_size) / static_cast<float>(OSMPBF::max_uncompressed_blob_size) * 100.0) << "% of the maximum blob-size" << std::endl;
@ -650,7 +647,7 @@ namespace osmium {
denseinfo->add_changeset(m_delta_changeset.update(node.changeset())); denseinfo->add_changeset(m_delta_changeset.update(node.changeset()));
// copy the user id, delta encoded // copy the user id, delta encoded
denseinfo->add_uid(m_delta_uid.update(node.uid())); denseinfo->add_uid(static_cast<::google::protobuf::int32>(m_delta_uid.update(node.uid())));
// record the user-name to the interim stringtable and copy the // record the user-name to the interim stringtable and copy the
// interim string-id to the pbf-object // interim string-id to the pbf-object
@ -808,7 +805,7 @@ namespace osmium {
// when the resulting file will carry history information, add // when the resulting file will carry history information, add
// HistoricalInformation as required feature // HistoricalInformation as required feature
if (this->m_file.has_multiple_object_versions()) { if (m_file.has_multiple_object_versions()) {
pbf_header_block.add_required_features("HistoricalInformation"); pbf_header_block.add_required_features("HistoricalInformation");
} }

View File

@ -34,15 +34,17 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm> #include <algorithm>
#include <cstdint>
#include <iterator> #include <iterator>
#include <map> #include <map>
#include <stdint.h>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <osmpbf/osmpbf.h> #include <osmpbf/osmpbf.h>
#include <osmium/util/cast.hpp>
namespace osmium { namespace osmium {
namespace io { namespace io {
@ -83,12 +85,14 @@ namespace osmium {
* IDs means less used space in the resulting file. * IDs means less used space in the resulting file.
*/ */
struct string_info { struct string_info {
/// number of occurrences of this string /// number of occurrences of this string
uint16_t count; uint16_t count;
/// an intermediate-id /// an intermediate-id
string_id_type interim_id; string_id_type interim_id;
};
}; // struct string_info
/** /**
* Interim StringTable, storing all strings that should be written to * Interim StringTable, storing all strings that should be written to
@ -123,8 +127,7 @@ namespace osmium {
string_info& info = m_strings[string]; string_info& info = m_strings[string];
if (info.interim_id == 0) { if (info.interim_id == 0) {
++m_size; ++m_size;
assert(m_size < std::numeric_limits<string_id_type>::max()); info.interim_id = static_cast_with_assert<string_id_type>(m_size);
info.interim_id = static_cast<string_id_type>(m_size);
} else { } else {
info.count++; info.count++;
} }
@ -176,6 +179,11 @@ namespace osmium {
return m_id2id_map[interim_id]; return m_id2id_map[interim_id];
} }
template <typename T>
string_id_type map_string_id(const T interim_id) const {
return map_string_id(static_cast_with_assert<string_id_type>(interim_id));
}
/** /**
* Clear the stringtable, preparing for the next block. * Clear the stringtable, preparing for the next block.
*/ */

View File

@ -74,10 +74,11 @@ namespace osmium {
while (!m_done) { while (!m_done) {
std::string data {m_decompressor->read()}; std::string data {m_decompressor->read()};
if (data.empty()) { if (data.empty()) {
m_done = true; m_queue.push(std::move(data));
break;
} }
m_queue.push(std::move(data)); m_queue.push(std::move(data));
while (m_queue.size() > 10) { while (m_queue.size() > 10 && !m_done) {
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
} }

View File

@ -37,13 +37,12 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef> #include <cstddef>
#include <fcntl.h> #include <fcntl.h>
#include <string> #include <string>
//#include <sys/stat.h>
//#include <sys/types.h>
#include <system_error> #include <system_error>
#ifndef _MSC_VER #ifndef _MSC_VER
#include <unistd.h> # include <unistd.h>
#else #else
#include <io.h> # include <io.h>
typedef int ssize_t; typedef int ssize_t;
#endif #endif
@ -61,11 +60,11 @@ namespace osmium {
/** /**
* Open file for writing. If the file exists, it is truncated, if * Open file for writing. If the file exists, it is truncated, if
* not, it is created. If the file name is empty or "-", no file * not, it is created. If the file name is empty or "-", no file
* is open and the stdout file descriptor (1) is returned. * is opened and the stdout file descriptor (1) is returned.
* *
* @param filename Name of file to be opened. * @param filename Name of file to be opened.
* @param allow_overwrite If the file exists, should it be overwritten? * @param allow_overwrite If the file exists, should it be overwritten?
* @return File descriptor of open file. * @returns File descriptor of open file.
* @throws system_error if the file can't be opened. * @throws system_error if the file can't be opened.
*/ */
inline int open_for_writing(const std::string& filename, osmium::io::overwrite allow_overwrite = osmium::io::overwrite::no) { inline int open_for_writing(const std::string& filename, osmium::io::overwrite allow_overwrite = osmium::io::overwrite::no) {
@ -78,7 +77,7 @@ namespace osmium {
} else { } else {
flags |= O_EXCL; flags |= O_EXCL;
} }
#ifdef WIN32 #ifdef _WIN32
flags |= O_BINARY; flags |= O_BINARY;
#endif #endif
int fd = ::open(filename.c_str(), flags, 0666); int fd = ::open(filename.c_str(), flags, 0666);
@ -91,9 +90,10 @@ namespace osmium {
/** /**
* Open file for reading. If the file name is empty or "-", no file * Open file for reading. If the file name is empty or "-", no file
* is open and the stdin file descriptor (0) is returned. * is opened and the stdin file descriptor (0) is returned.
* *
* @return File descriptor of open file. * @param filename Name of file to be opened.
* @returns File descriptor of open file.
* @throws system_error if the file can't be opened. * @throws system_error if the file can't be opened.
*/ */
inline int open_for_reading(const std::string& filename) { inline int open_for_reading(const std::string& filename) {
@ -101,7 +101,7 @@ namespace osmium {
return 0; // stdin return 0; // stdin
} else { } else {
int flags = O_RDONLY; int flags = O_RDONLY;
#ifdef WIN32 #ifdef _WIN32
flags |= O_BINARY; flags |= O_BINARY;
#endif #endif
int fd = ::open(filename.c_str(), flags); int fd = ::open(filename.c_str(), flags);
@ -112,39 +112,15 @@ namespace osmium {
} }
} }
/**
* Reads the given number of bytes into the input buffer.
* This is basically just a wrapper around read(2).
*
* @param fd File descriptor.
* @param input_buffer Buffer with data of at least size.
* @param size Number of bytes to be read.
* @return True when read was successful, false on EOF.
* @exception std::system_error On error.
*/
inline bool reliable_read(const int fd, unsigned char* input_buffer, const size_t size) {
size_t offset = 0;
while (offset < size) {
ssize_t length = ::read(fd, input_buffer + offset, size - offset);
if (length < 0) {
throw std::system_error(errno, std::system_category(), "Read failed");
}
if (length == 0) {
return false;
}
offset += static_cast<size_t>(length);
}
return true;
}
/** /**
* Writes the given number of bytes from the output_buffer to the file descriptor. * Writes the given number of bytes from the output_buffer to the file descriptor.
* This is just a wrapper around write(2). * This is just a wrapper around write(2), because write(2) can write less than
* the given number of bytes.
* *
* @param fd File descriptor. * @param fd File descriptor.
* @param output_buffer Buffer where data is written. Must be at least size bytes long. * @param output_buffer Buffer with data to be written. Must be at least size bytes long.
* @param size Number of bytes to be read. * @param size Number of bytes to write.
* @exception std::system_error On error. * @throws std::system_error On error.
*/ */
inline void reliable_write(const int fd, const unsigned char* output_buffer, const size_t size) { inline void reliable_write(const int fd, const unsigned char* output_buffer, const size_t size) {
size_t offset = 0; size_t offset = 0;
@ -157,6 +133,16 @@ namespace osmium {
} while (offset < size); } while (offset < size);
} }
/**
* Writes the given number of bytes from the output_buffer to the file descriptor.
* This is just a wrapper around write(2), because write(2) can write less than
* the given number of bytes.
*
* @param fd File descriptor.
* @param output_buffer Buffer with data to be written. Must be at least size bytes long.
* @param size Number of bytes to write.
* @throws std::system_error On error.
*/
inline void reliable_write(const int fd, const char* output_buffer, const size_t size) { inline void reliable_write(const int fd, const char* output_buffer, const size_t size) {
reliable_write(fd, reinterpret_cast<const unsigned char*>(output_buffer), size); reliable_write(fd, reinterpret_cast<const unsigned char*>(output_buffer), size);
} }

View File

@ -69,9 +69,15 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/types.hpp> #include <osmium/osm/types.hpp>
#include <osmium/thread/queue.hpp> #include <osmium/thread/queue.hpp>
#include <osmium/thread/checked_task.hpp> #include <osmium/thread/checked_task.hpp>
#include <osmium/util/cast.hpp>
namespace osmium { namespace osmium {
/**
* Exception thrown when the XML parser failed. The exception contains
* information about the place where the error happened and the type of
* error.
*/
struct xml_error : public io_error { struct xml_error : public io_error {
unsigned long line; unsigned long line;
@ -120,6 +126,8 @@ namespace osmium {
* Once the header is fully parsed this exception will be thrown if * Once the header is fully parsed this exception will be thrown if
* the caller is not interested in anything else except the header. * the caller is not interested in anything else except the header.
* It will break off the parsing at this point. * It will break off the parsing at this point.
*
* This exception is never seen by user code, it is caught internally.
*/ */
class ParserIsDone : std::exception { class ParserIsDone : std::exception {
}; };
@ -140,7 +148,7 @@ namespace osmium {
ignored_relation, ignored_relation,
ignored_changeset, ignored_changeset,
in_object in_object
}; }; // enum class context
context m_context; context m_context;
context m_last_context; context m_last_context;
@ -168,14 +176,81 @@ namespace osmium {
osmium::thread::Queue<osmium::memory::Buffer>& m_queue; osmium::thread::Queue<osmium::memory::Buffer>& m_queue;
std::promise<osmium::io::Header>& m_header_promise; std::promise<osmium::io::Header>& m_header_promise;
bool m_promise_fulfilled;
osmium::osm_entity_bits::type m_read_types; osmium::osm_entity_bits::type m_read_types;
size_t m_max_queue_size; size_t m_max_queue_size;
std::atomic<bool>& m_done; std::atomic<bool>& m_done;
/**
* A C++ wrapper for the Expat parser that makes sure no memory is leaked.
*/
template <class T>
class ExpatXMLParser {
XML_Parser m_parser;
static void XMLCALL start_element_wrapper(void* data, const XML_Char* element, const XML_Char** attrs) {
static_cast<XMLParser*>(data)->start_element(element, attrs);
}
static void XMLCALL end_element_wrapper(void* data, const XML_Char* element) {
static_cast<XMLParser*>(data)->end_element(element);
}
public:
ExpatXMLParser(T* callback_object) :
m_parser(XML_ParserCreate(nullptr)) {
if (!m_parser) {
throw osmium::io_error("Internal error: Can not create parser");
}
XML_SetUserData(m_parser, callback_object);
XML_SetElementHandler(m_parser, start_element_wrapper, end_element_wrapper);
}
ExpatXMLParser(const ExpatXMLParser&) = delete;
ExpatXMLParser(ExpatXMLParser&&) = delete;
ExpatXMLParser& operator=(const ExpatXMLParser&) = delete;
ExpatXMLParser& operator=(ExpatXMLParser&&) = delete;
~ExpatXMLParser() {
XML_ParserFree(m_parser);
}
void operator()(const std::string& data, bool last) {
if (XML_Parse(m_parser, data.data(), static_cast_with_assert<int>(data.size()), last) == XML_STATUS_ERROR) {
throw osmium::xml_error(m_parser);
}
}
}; // class ExpatXMLParser
/**
* A helper class that makes sure a promise is kept. It stores
* a reference to some piece of data and to a promise and, on
* destruction, sets the value of the promise from the data.
*/
template <class T>
class PromiseKeeper {
T& m_data;
std::promise<T>& m_promise;
public:
PromiseKeeper(T& data, std::promise<T>& promise) :
m_data(data),
m_promise(promise) {
}
~PromiseKeeper() {
m_promise.set_value(m_data);
}
}; // class PromiseKeeper
public: public:
explicit XMLParser(osmium::thread::Queue<std::string>& input_queue, osmium::thread::Queue<osmium::memory::Buffer>& queue, std::promise<osmium::io::Header>& header_promise, osmium::osm_entity_bits::type read_types, std::atomic<bool>& done) : explicit XMLParser(osmium::thread::Queue<std::string>& input_queue, osmium::thread::Queue<osmium::memory::Buffer>& queue, std::promise<osmium::io::Header>& header_promise, osmium::osm_entity_bits::type read_types, std::atomic<bool>& done) :
@ -194,7 +269,6 @@ namespace osmium {
m_input_queue(input_queue), m_input_queue(input_queue),
m_queue(queue), m_queue(queue),
m_header_promise(header_promise), m_header_promise(header_promise),
m_promise_fulfilled(false),
m_read_types(read_types), m_read_types(read_types),
m_max_queue_size(100), m_max_queue_size(100),
m_done(done) { m_done(done) {
@ -222,7 +296,6 @@ namespace osmium {
m_input_queue(other.m_input_queue), m_input_queue(other.m_input_queue),
m_queue(other.m_queue), m_queue(other.m_queue),
m_header_promise(other.m_header_promise), m_header_promise(other.m_header_promise),
m_promise_fulfilled(false),
m_read_types(other.m_read_types), m_read_types(other.m_read_types),
m_max_queue_size(100), m_max_queue_size(100),
m_done(other.m_done) { m_done(other.m_done) {
@ -237,70 +310,45 @@ namespace osmium {
~XMLParser() = default; ~XMLParser() = default;
bool operator()() { bool operator()() {
XML_Parser parser = XML_ParserCreate(nullptr); ExpatXMLParser<XMLParser> parser(this);
if (!parser) { PromiseKeeper<osmium::io::Header> promise_keeper(m_header, m_header_promise);
throw osmium::io_error("Internal error: Can not create parser"); bool last;
} do {
std::string data;
XML_SetUserData(parser, this); m_input_queue.wait_and_pop(data);
last = data.empty();
XML_SetElementHandler(parser, start_element_wrapper, end_element_wrapper); try {
parser(data, last);
try { } catch (ParserIsDone&) {
int done; return true;
do { } catch (...) {
std::string data; m_queue.push(osmium::memory::Buffer()); // empty buffer to signify eof
m_input_queue.wait_and_pop(data); throw;
done = data.empty();
try {
if (XML_Parse(parser, data.data(), data.size(), done) == XML_STATUS_ERROR) {
throw osmium::xml_error(parser);
}
} catch (ParserIsDone&) {
throw;
} catch (...) {
m_queue.push(osmium::memory::Buffer()); // empty buffer to signify eof
if (!m_promise_fulfilled) {
m_promise_fulfilled = true;
m_header_promise.set_value(m_header);
}
throw;
}
} while (!done && !m_done);
header_is_done(); // make sure we'll always fulfill the promise
if (m_buffer.committed() > 0) {
m_queue.push(std::move(m_buffer));
} }
m_queue.push(osmium::memory::Buffer()); // empty buffer to signify eof } while (!last && !m_done);
} catch (ParserIsDone&) { if (m_buffer.committed() > 0) {
// intentionally left blank m_queue.push(std::move(m_buffer));
} }
XML_ParserFree(parser); m_queue.push(osmium::memory::Buffer()); // empty buffer to signify eof
return true; return true;
} }
private: private:
static void XMLCALL start_element_wrapper(void* data, const XML_Char* element, const XML_Char** attrs) {
static_cast<XMLParser*>(data)->start_element(element, attrs);
}
static void XMLCALL end_element_wrapper(void* data, const XML_Char* element) {
static_cast<XMLParser*>(data)->end_element(element);
}
const char* init_object(osmium::OSMObject& object, const XML_Char** attrs) { const char* init_object(osmium::OSMObject& object, const XML_Char** attrs) {
static const char* empty = ""; static const char* empty = "";
const char* user = empty; const char* user = empty;
if (m_in_delete_section) { if (m_in_delete_section) {
object.visible(false); object.set_visible(false);
} }
osmium::Location location;
for (int count = 0; attrs[count]; count += 2) { for (int count = 0; attrs[count]; count += 2) {
if (!strcmp(attrs[count], "lon")) { if (!strcmp(attrs[count], "lon")) {
static_cast<osmium::Node&>(object).location().lon(std::atof(attrs[count+1])); // XXX doesn't detect garbage after the number location.set_lon(std::atof(attrs[count+1])); // XXX doesn't detect garbage after the number
} else if (!strcmp(attrs[count], "lat")) { } else if (!strcmp(attrs[count], "lat")) {
static_cast<osmium::Node&>(object).location().lat(std::atof(attrs[count+1])); // XXX doesn't detect garbage after the number location.set_lat(std::atof(attrs[count+1])); // XXX doesn't detect garbage after the number
} else if (!strcmp(attrs[count], "user")) { } else if (!strcmp(attrs[count], "user")) {
user = attrs[count+1]; user = attrs[count+1];
} else { } else {
@ -308,6 +356,10 @@ namespace osmium {
} }
} }
if (location && object.type() == osmium::item_type::node) {
static_cast<osmium::Node&>(object).set_location(location);
}
return user; return user;
} }
@ -320,13 +372,13 @@ namespace osmium {
osmium::Location max; osmium::Location max;
for (int count = 0; attrs[count]; count += 2) { for (int count = 0; attrs[count]; count += 2) {
if (!strcmp(attrs[count], "min_lon")) { if (!strcmp(attrs[count], "min_lon")) {
min.lon(atof(attrs[count+1])); min.set_lon(atof(attrs[count+1]));
} else if (!strcmp(attrs[count], "min_lat")) { } else if (!strcmp(attrs[count], "min_lat")) {
min.lat(atof(attrs[count+1])); min.set_lat(atof(attrs[count+1]));
} else if (!strcmp(attrs[count], "max_lon")) { } else if (!strcmp(attrs[count], "max_lon")) {
max.lon(atof(attrs[count+1])); max.set_lon(atof(attrs[count+1]));
} else if (!strcmp(attrs[count], "max_lat")) { } else if (!strcmp(attrs[count], "max_lat")) {
max.lat(atof(attrs[count+1])); max.set_lat(atof(attrs[count+1]));
} else if (!strcmp(attrs[count], "user")) { } else if (!strcmp(attrs[count], "user")) {
user = attrs[count+1]; user = attrs[count+1];
} else { } else {
@ -350,8 +402,7 @@ namespace osmium {
for (int count = 0; attrs[count]; count += 2) { for (int count = 0; attrs[count]; count += 2) {
if (attrs[count][0] == 'k' && attrs[count][1] == 0) { if (attrs[count][0] == 'k' && attrs[count][1] == 0) {
key = attrs[count+1]; key = attrs[count+1];
} } else if (attrs[count][0] == 'v' && attrs[count][1] == 0) {
if (attrs[count][0] == 'v' && attrs[count][1] == 0) {
value = attrs[count+1]; value = attrs[count+1];
} }
} }
@ -363,12 +414,8 @@ namespace osmium {
} }
void header_is_done() { void header_is_done() {
if (!m_promise_fulfilled) { if (m_read_types == osmium::osm_entity_bits::nothing) {
m_header_promise.set_value(m_header); throw ParserIsDone();
m_promise_fulfilled = true;
if (m_read_types == osmium::osm_entity_bits::nothing) {
throw ParserIsDone();
}
} }
} }
@ -377,7 +424,7 @@ namespace osmium {
case context::root: case context::root:
if (!strcmp(element, "osm") || !strcmp(element, "osmChange")) { if (!strcmp(element, "osm") || !strcmp(element, "osmChange")) {
if (!strcmp(element, "osmChange")) { if (!strcmp(element, "osmChange")) {
m_header.has_multiple_object_versions(true); m_header.set_has_multiple_object_versions(true);
} }
for (int count = 0; attrs[count]; count += 2) { for (int count = 0; attrs[count]; count += 2) {
if (!strcmp(attrs[count], "version")) { if (!strcmp(attrs[count], "version")) {
@ -438,13 +485,13 @@ namespace osmium {
osmium::Location max; osmium::Location max;
for (int count = 0; attrs[count]; count += 2) { for (int count = 0; attrs[count]; count += 2) {
if (!strcmp(attrs[count], "minlon")) { if (!strcmp(attrs[count], "minlon")) {
min.lon(atof(attrs[count+1])); min.set_lon(atof(attrs[count+1]));
} else if (!strcmp(attrs[count], "minlat")) { } else if (!strcmp(attrs[count], "minlat")) {
min.lat(atof(attrs[count+1])); min.set_lat(atof(attrs[count+1]));
} else if (!strcmp(attrs[count], "maxlon")) { } else if (!strcmp(attrs[count], "maxlon")) {
max.lon(atof(attrs[count+1])); max.set_lon(atof(attrs[count+1]));
} else if (!strcmp(attrs[count], "maxlat")) { } else if (!strcmp(attrs[count], "maxlat")) {
max.lat(atof(attrs[count+1])); max.set_lat(atof(attrs[count+1]));
} }
} }
osmium::Box box; osmium::Box box;
@ -610,7 +657,7 @@ namespace osmium {
} }
} }
}; // XMLParser }; // class XMLParser
class XMLInputFormat : public osmium::io::detail::InputFormat { class XMLInputFormat : public osmium::io::detail::InputFormat {
@ -639,7 +686,11 @@ namespace osmium {
} }
~XMLInputFormat() { ~XMLInputFormat() {
m_done = true; try {
close();
} catch (...) {
// ignore any exceptions at this point because destructor should not throw
}
} }
virtual osmium::io::Header header() override final { virtual osmium::io::Header header() override final {
@ -657,6 +708,11 @@ namespace osmium {
return buffer; return buffer;
} }
void close() {
m_done = true;
m_parser_task.close();
}
}; // class XMLInputFormat }; // class XMLInputFormat
namespace { namespace {

View File

@ -96,10 +96,13 @@ namespace osmium {
void oprintf(std::string& out, const char* format, T value) { void oprintf(std::string& out, const char* format, T value) {
char buffer[tmp_buffer_size+1]; char buffer[tmp_buffer_size+1];
size_t max_size = sizeof(buffer)/sizeof(char); size_t max_size = sizeof(buffer)/sizeof(char);
#ifndef NDEBUG
int len =
#endif
#ifndef _MSC_VER #ifndef _MSC_VER
int len = snprintf(buffer, max_size, format, value); snprintf(buffer, max_size, format, value);
#else #else
int len = _snprintf(buffer, max_size, format, value); _snprintf(buffer, max_size, format, value);
#endif #endif
assert(len > 0 && static_cast<size_t>(len) < max_size); assert(len > 0 && static_cast<size_t>(len) < max_size);
out += buffer; out += buffer;
@ -115,7 +118,7 @@ namespace osmium {
op_create = 1, op_create = 1,
op_modify = 2, op_modify = 2,
op_delete = 3 op_delete = 3
}; }; // enum class operation
osmium::memory::Buffer m_input_buffer; osmium::memory::Buffer m_input_buffer;
@ -257,9 +260,9 @@ namespace osmium {
if (node.location()) { if (node.location()) {
m_out += " lat=\""; m_out += " lat=\"";
osmium::Location::coordinate2string(std::back_inserter(m_out), node.location().lat_without_check()); osmium::util::double2string(std::back_inserter(m_out), node.location().lat_without_check(), 7);
m_out += "\" lon=\""; m_out += "\" lon=\"";
osmium::Location::coordinate2string(std::back_inserter(m_out), node.location().lon_without_check()); osmium::util::double2string(std::back_inserter(m_out), node.location().lon_without_check(), 7);
m_out += "\""; m_out += "\"";
} }
@ -402,7 +405,7 @@ namespace osmium {
} }
void write_buffer(osmium::memory::Buffer&& buffer) override final { void write_buffer(osmium::memory::Buffer&& buffer) override final {
XMLOutputBlock output_block(std::move(buffer), m_write_visible_flag, m_file.is_true("xml_change_format")); osmium::thread::SharedPtrWrapper<XMLOutputBlock> output_block(std::move(buffer), m_write_visible_flag, m_file.is_true("xml_change_format"));
m_output_queue.push(osmium::thread::Pool::instance().submit(std::move(output_block))); m_output_queue.push(osmium::thread::Pool::instance().submit(std::move(output_block)));
while (m_output_queue.size() > 10) { while (m_output_queue.size() > 10) {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // XXX std::this_thread::sleep_for(std::chrono::milliseconds(100)); // XXX

View File

@ -50,7 +50,7 @@ namespace osmium {
* Compress data using zlib. * Compress data using zlib.
* *
* @param input Data to compress. * @param input Data to compress.
* @return Compressed data. * @returns Compressed data.
*/ */
inline std::string zlib_compress(const std::string& input) { inline std::string zlib_compress(const std::string& input) {
unsigned long output_size = ::compressBound(input.size()); unsigned long output_size = ::compressBound(input.size());
@ -74,7 +74,7 @@ namespace osmium {
* *
* @param input Compressed input data. * @param input Compressed input data.
* @param raw_size Size of uncompressed data. * @param raw_size Size of uncompressed data.
* @return Uncompressed data. * @returns Uncompressed data.
*/ */
inline std::string zlib_uncompress(const std::string& input, unsigned long raw_size) { inline std::string zlib_uncompress(const std::string& input, unsigned long raw_size) {
std::string output(raw_size, '\0'); std::string output(raw_size, '\0');

View File

@ -1,319 +1,358 @@
#ifndef OSMIUM_IO_FILE_HPP #ifndef OSMIUM_IO_FILE_HPP
#define OSMIUM_IO_FILE_HPP #define OSMIUM_IO_FILE_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <cstddef> #include <cstddef>
#include <stdexcept> #include <stdexcept>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <osmium/io/file_format.hpp> #include <osmium/io/file_format.hpp>
#include <osmium/io/file_compression.hpp> #include <osmium/io/file_compression.hpp>
#include <osmium/util/options.hpp> #include <osmium/util/options.hpp>
namespace osmium { namespace osmium {
struct io_error : public std::runtime_error { /**
* Exception thrown when some kind of input/output operation failed.
io_error(const std::string& what) : */
std::runtime_error(what) { struct io_error : public std::runtime_error {
}
io_error(const std::string& what) :
io_error(const char* what) : std::runtime_error(what) {
std::runtime_error(what) { }
}
io_error(const char* what) :
}; // struct io_error std::runtime_error(what) {
}
/**
* @brief Everything related to input and output of OSM data. }; // struct io_error
*/
namespace io { /**
* @brief Everything related to input and output of OSM data.
namespace detail { */
namespace io {
inline std::vector<std::string> split(const std::string& in, const char delim) {
std::vector<std::string> result; namespace detail {
std::stringstream ss(in);
std::string item; inline std::vector<std::string> split(const std::string& in, const char delim) {
while (std::getline(ss, item, delim)) { std::vector<std::string> result;
result.push_back(item); std::stringstream ss(in);
} std::string item;
return result; while (std::getline(ss, item, delim)) {
} result.push_back(item);
}
} // namespace detail return result;
}
/**
* This class describes an OSM file in one of several different formats. } // namespace detail
*
* If the filename is empty or "-", this means stdin or stdout is used. /**
*/ * This class describes an OSM file in one of several different formats.
class File : public osmium::util::Options { *
* If the filename is empty or "-", this means stdin or stdout is used.
private: */
class File : public osmium::util::Options {
std::string m_filename;
private:
std::string m_format_string;
std::string m_filename;
file_format m_file_format {file_format::unknown};
const char* m_buffer;
file_compression m_file_compression {file_compression::none}; size_t m_buffer_size;
bool m_has_multiple_object_versions {false}; std::string m_format_string;
public: file_format m_file_format {file_format::unknown};
/** file_compression m_file_compression {file_compression::none};
* Create File using type and encoding from filename or given
* format specification. bool m_has_multiple_object_versions {false};
*
* @param filename Filename including suffix. The type and encoding public:
* of the file will be taken from the suffix.
* An empty filename or "-" means stdin or stdout. /**
* @param format File format as string. See the description of the * Create File using type and encoding from filename or given
* parse_format() function for details. * format specification.
*/ *
explicit File(const std::string& filename = "", const std::string& format = "") : * @param filename Filename including suffix. The type and encoding
Options(), * of the file will be taken from the suffix.
m_filename(filename), * An empty filename or "-" means stdin or stdout.
m_format_string(format) { * @param format File format as string. See the description of the
* parse_format() function for details.
// stdin/stdout */
if (filename == "" || filename == "-") { explicit File(const std::string& filename = "", const std::string& format = "") :
m_filename = ""; Options(),
default_settings_for_stdinout(); m_filename(filename),
} m_buffer(nullptr),
m_buffer_size(0),
// filename is actually a URL m_format_string(format) {
std::string protocol = m_filename.substr(0, m_filename.find_first_of(':'));
if (protocol == "http" || protocol == "https") { // stdin/stdout
default_settings_for_url(); if (filename == "" || filename == "-") {
} m_filename = "";
default_settings_for_stdinout();
detect_format_from_suffix(m_filename); }
if (format != "") { // filename is actually a URL
parse_format(format); std::string protocol = m_filename.substr(0, m_filename.find_first_of(':'));
} if (protocol == "http" || protocol == "https") {
} default_settings_for_url();
}
File(const File& other) = default;
File& operator=(const File& other) = default; detect_format_from_suffix(m_filename);
File(File&& other) = default; if (format != "") {
File& operator=(File&& other) = default; parse_format(format);
}
~File() = default; }
void parse_format(const std::string& format) { /**
std::vector<std::string> options = detail::split(format, ','); * Create File using buffer pointer and size and type and encoding
* from given format specification.
// if the first item in the format list doesn't contain *
// an equals sign, it is a format * @param buffer Pointer to buffer with data.
if (!options.empty() && options[0].find_first_of('=') == std::string::npos) { * @param size Size of buffer.
detect_format_from_suffix(options[0]); * @param format File format as string. See the description of the
options.erase(options.begin()); * parse_format() function for details.
} */
explicit File(const char* buffer, size_t size, const std::string& format = "") :
for (auto& option : options) { Options(),
size_t pos = option.find_first_of('='); m_filename(),
if (pos == std::string::npos) { m_buffer(buffer),
set(option, true); m_buffer_size(size),
} else { m_format_string(format) {
std::string value = option.substr(pos+1);
option.erase(pos); default_settings_for_stdinout();
set(option, value);
} if (format != "") {
} parse_format(format);
}
if (get("history") == "true") { }
m_has_multiple_object_versions = true;
} else if (get("history") == "false") { File(const File& other) = default;
m_has_multiple_object_versions = false; File& operator=(const File& other) = default;
}
} File(File&& other) = default;
File& operator=(File&& other) = default;
void detect_format_from_suffix(const std::string& name) {
std::vector<std::string> suffixes = detail::split(name, '.'); ~File() = default;
if (suffixes.empty()) return; const char* buffer() const noexcept {
return m_buffer;
// if the last suffix is one of a known set of compressions, }
// set that compression
if (suffixes.back() == "gz") { size_t buffer_size() const noexcept {
m_file_compression = file_compression::gzip; return m_buffer_size;
suffixes.pop_back(); }
} else if (suffixes.back() == "bz2") {
m_file_compression = file_compression::bzip2; void parse_format(const std::string& format) {
suffixes.pop_back(); std::vector<std::string> options = detail::split(format, ',');
}
// if the first item in the format list doesn't contain
if (suffixes.empty()) return; // an equals sign, it is a format
if (!options.empty() && options[0].find_first_of('=') == std::string::npos) {
// if the last suffix is one of a known set of formats, detect_format_from_suffix(options[0]);
// set that format options.erase(options.begin());
if (suffixes.back() == "pbf") { }
m_file_format = file_format::pbf;
suffixes.pop_back(); for (auto& option : options) {
} else if (suffixes.back() == "xml") { size_t pos = option.find_first_of('=');
m_file_format = file_format::xml; if (pos == std::string::npos) {
suffixes.pop_back(); set(option, true);
} else if (suffixes.back() == "opl") { } else {
m_file_format = file_format::opl; std::string value = option.substr(pos+1);
suffixes.pop_back(); option.erase(pos);
} set(option, value);
}
if (suffixes.empty()) return; }
if (suffixes.back() == "osm") { if (get("history") == "true") {
if (m_file_format == file_format::unknown) m_file_format = file_format::xml; m_has_multiple_object_versions = true;
suffixes.pop_back(); } else if (get("history") == "false") {
} else if (suffixes.back() == "osh") { m_has_multiple_object_versions = false;
if (m_file_format == file_format::unknown) m_file_format = file_format::xml; }
m_has_multiple_object_versions = true; }
suffixes.pop_back();
} else if (suffixes.back() == "osc") { void detect_format_from_suffix(const std::string& name) {
if (m_file_format == file_format::unknown) m_file_format = file_format::xml; std::vector<std::string> suffixes = detail::split(name, '.');
m_has_multiple_object_versions = true;
set("xml_change_format", true); if (suffixes.empty()) return;
suffixes.pop_back();
} // if the last suffix is one of a known set of compressions,
} // set that compression
if (suffixes.back() == "gz") {
/** m_file_compression = file_compression::gzip;
* Check file format etc. for consistency and throw exception if there suffixes.pop_back();
* is a problem. } else if (suffixes.back() == "bz2") {
* m_file_compression = file_compression::bzip2;
* @throws std::runtime_error suffixes.pop_back();
*/ }
void check() const {
if (m_file_format == file_format::unknown) { if (suffixes.empty()) return;
std::string msg = "Could not detect file format";
if (!m_format_string.empty()) { // if the last suffix is one of a known set of formats,
msg += " from format string '"; // set that format
msg += m_format_string; if (suffixes.back() == "pbf") {
msg += "'"; m_file_format = file_format::pbf;
} suffixes.pop_back();
if (m_filename.empty()) { } else if (suffixes.back() == "xml") {
msg += " for stdin/stdout"; m_file_format = file_format::xml;
} else { suffixes.pop_back();
msg += " for filename '"; } else if (suffixes.back() == "opl") {
msg += m_filename; m_file_format = file_format::opl;
msg += "'"; suffixes.pop_back();
} }
msg += ".";
throw std::runtime_error(msg); if (suffixes.empty()) return;
}
} if (suffixes.back() == "osm") {
if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
/** suffixes.pop_back();
* Set default settings for type and encoding when the filename is } else if (suffixes.back() == "osh") {
* empty or "-". If you want to have a different default setting if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
* override this in a subclass. m_has_multiple_object_versions = true;
*/ suffixes.pop_back();
void default_settings_for_stdinout() { } else if (suffixes.back() == "osc") {
m_file_format = file_format::unknown; if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
m_file_compression = file_compression::none; m_has_multiple_object_versions = true;
} set("xml_change_format", true);
suffixes.pop_back();
/** }
* Set default settings for type and encoding when the filename is }
* a normal file. If you want to have a different default setting
* override this in a subclass. /**
*/ * Check file format etc. for consistency and throw exception if there
void default_settings_for_file() { * is a problem.
m_file_format = file_format::unknown; *
m_file_compression = file_compression::none; * @throws std::runtime_error
} */
void check() const {
/** if (m_file_format == file_format::unknown) {
* Set default settings for type and encoding when the filename is a URL. std::string msg = "Could not detect file format";
* If you want to have a different default setting override this in a if (!m_format_string.empty()) {
* subclass. msg += " from format string '";
*/ msg += m_format_string;
void default_settings_for_url() { msg += "'";
m_file_format = file_format::xml; }
m_file_compression = file_compression::none; if (m_filename.empty()) {
} msg += " for stdin/stdout";
} else {
file_format format() const { msg += " for filename '";
return m_file_format; msg += m_filename;
} msg += "'";
}
File& format(file_format format) { msg += ".";
m_file_format = format; throw std::runtime_error(msg);
return *this; }
} }
file_compression compression() const { /**
return m_file_compression; * Set default settings for type and encoding when the filename is
} * empty or "-". If you want to have a different default setting
* override this in a subclass.
File& compression(file_compression compression) { */
m_file_compression = compression; void default_settings_for_stdinout() {
return *this; m_file_format = file_format::unknown;
} m_file_compression = file_compression::none;
}
bool has_multiple_object_versions() const {
return m_has_multiple_object_versions; /**
} * Set default settings for type and encoding when the filename is
* a normal file. If you want to have a different default setting
File& has_multiple_object_versions(bool value) { * override this in a subclass.
m_has_multiple_object_versions = value; */
return *this; void default_settings_for_file() {
} m_file_format = file_format::unknown;
m_file_compression = file_compression::none;
File& filename(const std::string& filename) { }
if (filename == "-") {
m_filename = ""; /**
} else { * Set default settings for type and encoding when the filename is a URL.
m_filename = filename; * If you want to have a different default setting override this in a
} * subclass.
return *this; */
} void default_settings_for_url() {
m_file_format = file_format::xml;
const std::string& filename() const { m_file_compression = file_compression::none;
return m_filename; }
}
file_format format() const noexcept {
}; // class File return m_file_format;
}
} // namespace io
File& set_format(file_format format) noexcept {
} // namespace osmium m_file_format = format;
return *this;
#endif // OSMIUM_IO_FILE_HPP }
file_compression compression() const noexcept {
return m_file_compression;
}
File& set_compression(file_compression compression) noexcept {
m_file_compression = compression;
return *this;
}
bool has_multiple_object_versions() const noexcept {
return m_has_multiple_object_versions;
}
File& set_has_multiple_object_versions(bool value) noexcept {
m_has_multiple_object_versions = value;
return *this;
}
File& filename(const std::string& filename) {
if (filename == "-") {
m_filename = "";
} else {
m_filename = filename;
}
return *this;
}
const std::string& filename() const noexcept {
return m_filename;
}
}; // class File
} // namespace io
} // namespace osmium
#endif // OSMIUM_IO_FILE_HPP

View File

@ -45,6 +45,9 @@ namespace osmium {
bzip2 = 2 bzip2 = 2
}; };
// avoid g++ false positive
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wreturn-type"
inline const char* as_string(file_compression compression) { inline const char* as_string(file_compression compression) {
switch (compression) { switch (compression) {
case file_compression::none: case file_compression::none:
@ -55,6 +58,7 @@ namespace osmium {
return "bzip2"; return "bzip2";
} }
} }
#pragma GCC diagnostic pop
template <typename TChar, typename TTraits> template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const file_compression compression) { inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const file_compression compression) {

View File

@ -47,6 +47,9 @@ namespace osmium {
json = 4 json = 4
}; };
// avoid g++ false positive
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wreturn-type"
inline const char* as_string(file_format format) { inline const char* as_string(file_format format) {
switch (format) { switch (format) {
case file_format::unknown: case file_format::unknown:
@ -61,6 +64,7 @@ namespace osmium {
return "JSON"; return "JSON";
} }
} }
#pragma GCC diagnostic pop
template <typename TChar, typename TTraits> template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const file_format format) { inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const file_format format) {

View File

@ -38,15 +38,52 @@ DEALINGS IN THE SOFTWARE.
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <errno.h>
#include <zlib.h> #include <zlib.h>
#include <osmium/io/compression.hpp> #include <osmium/io/compression.hpp>
#include <osmium/io/file_compression.hpp> #include <osmium/io/file_compression.hpp>
#include <osmium/util/cast.hpp>
#include <osmium/util/compatibility.hpp>
namespace osmium { namespace osmium {
/**
* Exception thrown when there are problems compressing or
* decompressing gzip files.
*/
struct gzip_error : public std::runtime_error {
int gzip_error_code;
int system_errno;
gzip_error(const std::string& what, int error_code) :
std::runtime_error(what),
gzip_error_code(error_code),
system_errno(error_code == Z_ERRNO ? errno : 0) {
}
}; // struct gzip_error
namespace io { namespace io {
namespace detail {
OSMIUM_NORETURN inline void throw_gzip_error(gzFile gzfile, const char* msg, int zlib_error=0) {
std::string error("gzip error: ");
error += msg;
error += ": ";
int errnum = zlib_error;
if (zlib_error) {
error += std::to_string(zlib_error);
} else {
error += ::gzerror(gzfile, &errnum);
}
throw osmium::gzip_error(error, errnum);
}
} // namespace detail
class GzipCompressor : public Compressor { class GzipCompressor : public Compressor {
gzFile m_gzfile; gzFile m_gzfile;
@ -57,22 +94,30 @@ namespace osmium {
Compressor(), Compressor(),
m_gzfile(::gzdopen(fd, "w")) { m_gzfile(::gzdopen(fd, "w")) {
if (!m_gzfile) { if (!m_gzfile) {
throw std::runtime_error("initialization of gzip compression failed"); detail::throw_gzip_error(m_gzfile, "write initialization failed");
} }
} }
~GzipCompressor() override final { ~GzipCompressor() override final {
this->close(); close();
} }
void write(const std::string& data) override final { void write(const std::string& data) override final {
::gzwrite(m_gzfile, data.data(), data.size()); if (!data.empty()) {
int nwrite = ::gzwrite(m_gzfile, data.data(), static_cast_with_assert<unsigned int>(data.size()));
if (nwrite == 0) {
detail::throw_gzip_error(m_gzfile, "write failed");
}
}
} }
void close() override final { void close() override final {
if (m_gzfile) { if (m_gzfile) {
::gzclose(m_gzfile); int result = ::gzclose(m_gzfile);
m_gzfile = nullptr; m_gzfile = nullptr;
if (result != Z_OK) {
detail::throw_gzip_error(m_gzfile, "write close failed", result);
}
} }
} }
@ -88,20 +133,19 @@ namespace osmium {
Decompressor(), Decompressor(),
m_gzfile(::gzdopen(fd, "r")) { m_gzfile(::gzdopen(fd, "r")) {
if (!m_gzfile) { if (!m_gzfile) {
throw std::runtime_error("initialization of gzip compression failed"); detail::throw_gzip_error(m_gzfile, "read initialization failed");
} }
} }
~GzipDecompressor() override final { ~GzipDecompressor() override final {
this->close(); close();
} }
std::string read() override final { std::string read() override final {
std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0'); std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0');
int nread = ::gzread(m_gzfile, const_cast<char*>(buffer.data()), buffer.size()); int nread = ::gzread(m_gzfile, const_cast<char*>(buffer.data()), static_cast_with_assert<unsigned int>(buffer.size()));
if (nread < 0) { if (nread < 0) {
throw std::runtime_error("gzip read failed"); // XXX better error detection and reporting detail::throw_gzip_error(m_gzfile, "read failed");
// throw std::system_error(errno, std::system_category(), "Read failed");
} }
buffer.resize(static_cast<std::string::size_type>(nread)); buffer.resize(static_cast<std::string::size_type>(nread));
return buffer; return buffer;
@ -109,18 +153,80 @@ namespace osmium {
void close() override final { void close() override final {
if (m_gzfile) { if (m_gzfile) {
::gzclose(m_gzfile); int result = ::gzclose(m_gzfile);
m_gzfile = nullptr; m_gzfile = nullptr;
if (result != Z_OK) {
detail::throw_gzip_error(m_gzfile, "read close failed", result);
}
} }
} }
}; // class GzipDecompressor }; // class GzipDecompressor
class GzipBufferDecompressor : public Decompressor {
const char* m_buffer;
size_t m_buffer_size;
z_stream m_zstream;
public:
GzipBufferDecompressor(const char* buffer, size_t size) :
m_buffer(buffer),
m_buffer_size(size),
m_zstream() {
m_zstream.next_in = reinterpret_cast<unsigned char*>(const_cast<char*>(buffer));
m_zstream.avail_in = static_cast_with_assert<unsigned int>(size);
int result = inflateInit2(&m_zstream, MAX_WBITS | 32);
if (result != Z_OK) {
std::string message("gzip error: decompression init failed: ");
if (m_zstream.msg) {
message.append(m_zstream.msg);
}
throw osmium::gzip_error(message, result);
}
}
~GzipBufferDecompressor() override final {
inflateEnd(&m_zstream);
}
std::string read() override final {
if (!m_buffer) {
return std::string();
}
const size_t buffer_size = 10240;
std::string output(buffer_size, '\0');
m_zstream.next_out = reinterpret_cast<unsigned char*>(const_cast<char*>(output.data()));
m_zstream.avail_out = buffer_size;
int result = inflate(&m_zstream, Z_SYNC_FLUSH);
if (result != Z_OK) {
m_buffer = nullptr;
m_buffer_size = 0;
}
if (result != Z_OK && result != Z_STREAM_END) {
std::string message("gzip error: inflate failed: ");
if (m_zstream.msg) {
message.append(m_zstream.msg);
}
throw osmium::gzip_error(message, result);
}
output.resize(static_cast<unsigned long>(m_zstream.next_out - reinterpret_cast<const unsigned char*>(output.data())));
return output;
}
}; // class GzipBufferDecompressor
namespace { namespace {
const bool registered_gzip_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::gzip, const bool registered_gzip_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::gzip,
[](int fd) { return new osmium::io::GzipCompressor(fd); }, [](int fd) { return new osmium::io::GzipCompressor(fd); },
[](int fd) { return new osmium::io::GzipDecompressor(fd); } [](int fd) { return new osmium::io::GzipDecompressor(fd); },
[](const char* buffer, size_t size) { return new osmium::io::GzipBufferDecompressor(buffer, size); }
); );
} // anonymous namespace } // anonymous namespace

View File

@ -73,15 +73,15 @@ namespace osmium {
~Header() = default; ~Header() = default;
std::vector<osmium::Box>& boxes() { std::vector<osmium::Box>& boxes() noexcept {
return m_boxes; return m_boxes;
} }
const std::vector<osmium::Box>& boxes() const { const std::vector<osmium::Box>& boxes() const noexcept {
return m_boxes; return m_boxes;
} }
Header& boxes(const std::vector<osmium::Box>& boxes) { Header& boxes(const std::vector<osmium::Box>& boxes) noexcept {
m_boxes = boxes; m_boxes = boxes;
return *this; return *this;
} }
@ -104,12 +104,12 @@ namespace osmium {
return *this; return *this;
} }
bool has_multiple_object_versions() const { bool has_multiple_object_versions() const noexcept {
return m_has_multiple_object_versions; return m_has_multiple_object_versions;
} }
Header& has_multiple_object_versions(bool h) { Header& set_has_multiple_object_versions(bool value) noexcept {
m_has_multiple_object_versions = h; m_has_multiple_object_versions = value;
return *this; return *this;
} }

View File

@ -89,7 +89,7 @@ namespace osmium {
} }
// end iterator // end iterator
InputIterator() : InputIterator() noexcept :
m_source(nullptr) { m_source(nullptr) {
} }
@ -110,13 +110,13 @@ namespace osmium {
return tmp; return tmp;
} }
bool operator==(const InputIterator& rhs) const { bool operator==(const InputIterator& rhs) const noexcept {
return m_source == rhs.m_source && return m_source == rhs.m_source &&
m_buffer == rhs.m_buffer && m_buffer == rhs.m_buffer &&
m_iter == rhs.m_iter; m_iter == rhs.m_iter;
} }
bool operator!=(const InputIterator& rhs) const { bool operator!=(const InputIterator& rhs) const noexcept {
return !(*this == rhs); return !(*this == rhs);
} }

View File

@ -1,114 +1,116 @@
#ifndef OSMIUM_IO_OUTPUT_ITERATOR_HPP #ifndef OSMIUM_IO_OUTPUT_ITERATOR_HPP
#define OSMIUM_IO_OUTPUT_ITERATOR_HPP #define OSMIUM_IO_OUTPUT_ITERATOR_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <cstddef> #include <cstddef>
#include <iterator> #include <iterator>
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <osmium/memory/buffer.hpp> #include <osmium/memory/buffer.hpp>
#include <osmium/osm/diff_object.hpp> #include <osmium/osm/diff_object.hpp>
namespace osmium { namespace osmium {
namespace memory { namespace memory {
class Item; class Item;
} // namespace memory } // namespace memory
namespace io { namespace io {
template <class TDest> template <class TDest>
class OutputIterator : public std::iterator<std::output_iterator_tag, osmium::memory::Item> { class OutputIterator : public std::iterator<std::output_iterator_tag, osmium::memory::Item> {
struct buffer_wrapper { struct buffer_wrapper {
osmium::memory::Buffer buffer;
osmium::memory::Buffer buffer;
buffer_wrapper(size_t buffer_size) :
buffer(buffer_size, osmium::memory::Buffer::auto_grow::no) { buffer_wrapper(size_t buffer_size) :
} buffer(buffer_size, osmium::memory::Buffer::auto_grow::no) {
}; }
static constexpr size_t default_buffer_size = 10 * 1024 * 1024; }; // struct buffer_wrapper
TDest& m_destination; static constexpr size_t default_buffer_size = 10 * 1024 * 1024;
std::shared_ptr<buffer_wrapper> m_buffer_wrapper; TDest* m_destination;
public: std::shared_ptr<buffer_wrapper> m_buffer_wrapper;
explicit OutputIterator(TDest& destination, const size_t buffer_size = default_buffer_size) : public:
m_destination(destination),
m_buffer_wrapper(std::make_shared<buffer_wrapper>(buffer_size)) { explicit OutputIterator(TDest& destination, const size_t buffer_size = default_buffer_size) :
} m_destination(&destination),
m_buffer_wrapper(std::make_shared<buffer_wrapper>(buffer_size)) {
void flush() { }
osmium::memory::Buffer buffer(m_buffer_wrapper->buffer.capacity(), osmium::memory::Buffer::auto_grow::no);
std::swap(m_buffer_wrapper->buffer, buffer); void flush() {
m_destination(std::move(buffer)); osmium::memory::Buffer buffer(m_buffer_wrapper->buffer.capacity(), osmium::memory::Buffer::auto_grow::no);
} std::swap(m_buffer_wrapper->buffer, buffer);
(*m_destination)(std::move(buffer));
OutputIterator& operator=(const osmium::memory::Item& item) { }
try {
m_buffer_wrapper->buffer.push_back(item); OutputIterator& operator=(const osmium::memory::Item& item) {
} catch (osmium::memory::BufferIsFull&) { try {
flush(); m_buffer_wrapper->buffer.push_back(item);
m_buffer_wrapper->buffer.push_back(item); } catch (osmium::buffer_is_full&) {
} flush();
return *this; m_buffer_wrapper->buffer.push_back(item);
} }
return *this;
OutputIterator& operator=(const osmium::DiffObject& diff) { }
return this->operator=(diff.curr());
} OutputIterator& operator=(const osmium::DiffObject& diff) {
return this->operator=(diff.curr());
OutputIterator& operator*() { }
return *this;
} OutputIterator& operator*() {
return *this;
OutputIterator& operator++() { }
return *this;
} OutputIterator& operator++() {
return *this;
OutputIterator& operator++(int) { }
return *this;
} OutputIterator& operator++(int) {
return *this;
}; // class OutputIterator }
} // namespace io }; // class OutputIterator
} // namespace osmium } // namespace io
#endif // OSMIUM_IO_OUTPUT_ITERATOR_HPP } // namespace osmium
#endif // OSMIUM_IO_OUTPUT_ITERATOR_HPP

View File

@ -41,15 +41,16 @@ DEALINGS IN THE SOFTWARE.
#include <string> #include <string>
#include <system_error> #include <system_error>
#include <thread> #include <thread>
#ifndef _WIN32
#include <sys/wait.h>
#endif
#ifndef _MSC_VER
#include <unistd.h>
#else
#endif
#include <utility> #include <utility>
#ifndef _WIN32
# include <sys/wait.h>
#endif
#ifndef _MSC_VER
# include <unistd.h>
#endif
#include <osmium/io/compression.hpp> #include <osmium/io/compression.hpp>
#include <osmium/io/detail/input_format.hpp> #include <osmium/io/detail/input_format.hpp>
#include <osmium/io/detail/read_thread.hpp> #include <osmium/io/detail/read_thread.hpp>
@ -95,7 +96,7 @@ namespace osmium {
* *
* @param command Command to execute in the child. * @param command Command to execute in the child.
* @param filename Filename to give to command as argument. * @param filename Filename to give to command as argument.
* @return File descriptor of pipe in the parent. * @returns File descriptor of pipe in the parent.
* @throws std::system_error if a system call fails. * @throws std::system_error if a system call fails.
*/ */
static int execute(const std::string& command, const std::string& filename, int* childpid) { static int execute(const std::string& command, const std::string& filename, int* childpid) {
@ -140,7 +141,7 @@ namespace osmium {
* are opened by executing the "curl" program (which must be installed) * are opened by executing the "curl" program (which must be installed)
* and reading from its output. * and reading from its output.
* *
* @return File descriptor of open file or pipe. * @returns File descriptor of open file or pipe.
* @throws std::system_error if a system call fails. * @throws std::system_error if a system call fails.
*/ */
static int open_input_file_or_url(const std::string& filename, int* childpid) { static int open_input_file_or_url(const std::string& filename, int* childpid) {
@ -173,7 +174,9 @@ namespace osmium {
m_input_done(false), m_input_done(false),
m_childpid(0), m_childpid(0),
m_input_queue(), m_input_queue(),
m_decompressor(osmium::io::CompressionFactory::instance().create_decompressor(file.compression(), open_input_file_or_url(m_file.filename(), &m_childpid))), m_decompressor(m_file.buffer() ?
osmium::io::CompressionFactory::instance().create_decompressor(file.compression(), m_file.buffer(), m_file.buffer_size()) :
osmium::io::CompressionFactory::instance().create_decompressor(file.compression(), open_input_file_or_url(m_file.filename(), &m_childpid))),
m_read_task(m_input_queue, m_decompressor.get(), m_input_done), m_read_task(m_input_queue, m_decompressor.get(), m_input_done),
m_input(osmium::io::detail::InputFormatFactory::instance().create_input(m_file, m_read_which_entities, m_input_queue)) { m_input(osmium::io::detail::InputFormatFactory::instance().create_input(m_file, m_read_which_entities, m_input_queue)) {
} }
@ -190,7 +193,11 @@ namespace osmium {
Reader& operator=(const Reader&) = delete; Reader& operator=(const Reader&) = delete;
~Reader() { ~Reader() {
close(); try {
close();
}
catch (...) {
}
} }
/** /**
@ -233,7 +240,10 @@ namespace osmium {
/** /**
* Reads the next buffer from the input. An invalid buffer signals * Reads the next buffer from the input. An invalid buffer signals
* end-of-file. Do not call read() after the end-of-file. * end-of-file. After end-of-file all read() calls will return an
* invalid buffer. An invalid buffer is also always returned if
* osmium::osm_entity_bits::nothing was set when the Reader was
* constructed.
* *
* @returns Buffer. * @returns Buffer.
* @throws Some form of std::runtime_error if there is an error. * @throws Some form of std::runtime_error if there is an error.
@ -243,12 +253,25 @@ namespace osmium {
// it in this (the main) thread. // it in this (the main) thread.
m_read_task.check_for_exception(); m_read_task.check_for_exception();
if (m_read_which_entities == osmium::osm_entity_bits::nothing) { if (m_read_which_entities == osmium::osm_entity_bits::nothing || m_input_done) {
// If the caller didn't want anything but the header, it will // If the caller didn't want anything but the header, it will
// always get an empty buffer here. // always get an empty buffer here.
return osmium::memory::Buffer(); return osmium::memory::Buffer();
} }
return m_input->read();
osmium::memory::Buffer buffer = m_input->read();
if (!buffer) {
m_input_done = true;
}
return buffer;
}
/**
* Has the end of file been reached? This is set after the last
* data has been read. It is also set by calling close().
*/
bool eof() {
return m_input_done;
} }
}; // class Reader }; // class Reader

View File

@ -90,6 +90,7 @@ namespace osmium {
m_output(osmium::io::detail::OutputFormatFactory::instance().create_output(m_file, m_output_queue)), m_output(osmium::io::detail::OutputFormatFactory::instance().create_output(m_file, m_output_queue)),
m_compressor(osmium::io::CompressionFactory::instance().create_compressor(file.compression(), osmium::io::detail::open_for_writing(m_file.filename(), allow_overwrite))), m_compressor(osmium::io::CompressionFactory::instance().create_compressor(file.compression(), osmium::io::detail::open_for_writing(m_file.filename(), allow_overwrite))),
m_write_task(m_output_queue, m_compressor.get()) { m_write_task(m_output_queue, m_compressor.get()) {
assert(!m_file.buffer());
m_output->write_header(header); m_output->write_header(header);
} }
@ -121,7 +122,7 @@ namespace osmium {
} }
/** /**
* Flush writes to output file and close it. If you do not * Flush writes to output file and closes it. If you do not
* call this, the destructor of Writer will also do the same * call this, the destructor of Writer will also do the same
* thing. But because this call might thrown an exception, * thing. But because this call might thrown an exception,
* it is better to call close() explicitly. * it is better to call close() explicitly.

View File

@ -49,17 +49,24 @@ DEALINGS IN THE SOFTWARE.
namespace osmium { namespace osmium {
/**
* Exception thrown by the osmium::memory::Buffer class when somebody tries
* to write data into a buffer and it doesn't fit. Buffers with internal
* memory management will not throw this exception, but increase their size.
*/
struct buffer_is_full : public std::runtime_error {
buffer_is_full() :
std::runtime_error("Osmium buffer is full") {
}
}; // struct buffer_is_full
/** /**
* @brief Memory management of items in buffers and iterators over this data. * @brief Memory management of items in buffers and iterators over this data.
*/ */
namespace memory { namespace memory {
/**
* Exception thrown by the Buffer class when somebody tries to write data
* into the buffer and it doesn't fit.
*/
class BufferIsFull : public std::exception {};
/** /**
* A memory area for storing OSM objects and other items. Each item stored * A memory area for storing OSM objects and other items. Each item stored
* has a type and a length. See the Item class for details. * has a type and a length. See the Item class for details.
@ -80,7 +87,7 @@ namespace osmium {
* create a Buffer object and have it manage the memory internally. It will * create a Buffer object and have it manage the memory internally. It will
* dynamically allocate memory and free it again after use. * dynamically allocate memory and free it again after use.
* *
* By default, if a buffer gets full it will throw a BufferIsFull exception. * By default, if a buffer gets full it will throw a buffer_is_full exception.
* You can use the set_full_callback() method to set a callback functor * You can use the set_full_callback() method to set a callback functor
* which will be called instead of throwing an exception. * which will be called instead of throwing an exception.
*/ */
@ -91,7 +98,7 @@ namespace osmium {
enum class auto_grow : bool { enum class auto_grow : bool {
yes = true, yes = true,
no = false no = false
}; }; // enum class auto_grow
private: private:
@ -112,7 +119,7 @@ namespace osmium {
* buffer, ie an empty hull of a buffer that has no actual memory * buffer, ie an empty hull of a buffer that has no actual memory
* associated with it. It can be used to signify end-of-input. * associated with it. It can be used to signify end-of-input.
*/ */
Buffer() : Buffer() noexcept :
m_memory(), m_memory(),
m_data(nullptr), m_data(nullptr),
m_capacity(0), m_capacity(0),
@ -126,7 +133,7 @@ namespace osmium {
* *
* @param data A pointer to some already initialized data. * @param data A pointer to some already initialized data.
* @param size The size of the initialized data. * @param size The size of the initialized data.
* @exception std::invalid_argument When the size isn't a multiple of the alignment. * @throws std::invalid_argument When the size isn't a multiple of the alignment.
*/ */
explicit Buffer(unsigned char* data, size_t size) : explicit Buffer(unsigned char* data, size_t size) :
m_memory(), m_memory(),
@ -146,7 +153,7 @@ namespace osmium {
* @param data A pointer to some (possibly initialized) data. * @param data A pointer to some (possibly initialized) data.
* @param capacity The size of the memory for this buffer. * @param capacity The size of the memory for this buffer.
* @param committed The size of the initialized data. If this is 0, the buffer startes out empty. * @param committed The size of the initialized data. If this is 0, the buffer startes out empty.
* @exception std::invalid_argument When the capacity or committed isn't a multiple of the alignment. * @throws std::invalid_argument When the capacity or committed isn't a multiple of the alignment.
*/ */
explicit Buffer(unsigned char* data, size_t capacity, size_t committed) : explicit Buffer(unsigned char* data, size_t capacity, size_t committed) :
m_memory(), m_memory(),
@ -193,21 +200,21 @@ namespace osmium {
/** /**
* Return a pointer to data inside the buffer. * Return a pointer to data inside the buffer.
*/ */
unsigned char* data() const { unsigned char* data() const noexcept {
return m_data; return m_data;
} }
/** /**
* Returns the capacity of the buffer, ie how many bytes it can contain. * Returns the capacity of the buffer, ie how many bytes it can contain.
*/ */
size_t capacity() const { size_t capacity() const noexcept {
return m_capacity; return m_capacity;
} }
/** /**
* Returns the number of bytes already filled in this buffer. * Returns the number of bytes already filled in this buffer.
*/ */
size_t committed() const { size_t committed() const noexcept {
return m_committed; return m_committed;
} }
@ -215,7 +222,7 @@ namespace osmium {
* Returns the number of bytes currently filled in this buffer that * Returns the number of bytes currently filled in this buffer that
* are not yet committed. * are not yet committed.
*/ */
size_t written() const { size_t written() const noexcept {
return m_written; return m_written;
} }
@ -223,13 +230,13 @@ namespace osmium {
* This tests if the current state of the buffer is aligned * This tests if the current state of the buffer is aligned
* properly. Can be used for asserts. * properly. Can be used for asserts.
*/ */
bool is_aligned() const { bool is_aligned() const noexcept {
return (m_written % align_bytes == 0) && (m_committed % align_bytes == 0); return (m_written % align_bytes == 0) && (m_committed % align_bytes == 0);
} }
/** /**
* Set functor to be called whenever the buffer is full * Set functor to be called whenever the buffer is full
* instead of throwing BufferIsFull. * instead of throwing buffer_is_full.
*/ */
void set_full_callback(std::function<void(Buffer&)> full) { void set_full_callback(std::function<void(Buffer&)> full) {
m_full = full; m_full = full;
@ -260,7 +267,7 @@ namespace osmium {
/** /**
* Mark currently written bytes in the buffer as committed. * Mark currently written bytes in the buffer as committed.
* *
* @return Last number of committed bytes before this commit. * @returns Last number of committed bytes before this commit.
*/ */
size_t commit() { size_t commit() {
assert(is_aligned()); assert(is_aligned());
@ -280,7 +287,7 @@ namespace osmium {
/** /**
* Clear the buffer. * Clear the buffer.
* *
* @return Number of bytes in the buffer before it was cleared. * @returns Number of bytes in the buffer before it was cleared.
*/ */
size_t clear() { size_t clear() {
const size_t committed = m_committed; const size_t committed = m_committed;
@ -293,7 +300,7 @@ namespace osmium {
* Get the data in the buffer at the given offset. * Get the data in the buffer at the given offset.
* *
* @tparam T Type we want to the data to be interpreted as. * @tparam T Type we want to the data to be interpreted as.
* @return Reference of given type pointing to the data in the buffer. * @returns Reference of given type pointing to the data in the buffer.
*/ */
template <class T> template <class T>
T& get(const size_t offset) const { T& get(const size_t offset) const {
@ -317,13 +324,13 @@ namespace osmium {
* * If no callback is defined and this buffer uses internal * * If no callback is defined and this buffer uses internal
* memory management, the buffers capacity is grown, so that * memory management, the buffers capacity is grown, so that
* the new data will fit. * the new data will fit.
* * Else the BufferIsFull exception is thrown. * * Else the buffer_is_full exception is thrown.
* *
* @param size Number of bytes to reserve. * @param size Number of bytes to reserve.
* @return Pointer to reserved space. Note that this pointer is * @returns Pointer to reserved space. Note that this pointer is
* only guaranteed to be valid until the next call to * only guaranteed to be valid until the next call to
* reserve_space(). * reserve_space().
* @throw BufferIsFull Might be thrown if the buffer is full. * @throws osmium::buffer_is_full Might be thrown if the buffer is full.
*/ */
unsigned char* reserve_space(const size_t size) { unsigned char* reserve_space(const size_t size) {
if (m_written + size > m_capacity) { if (m_written + size > m_capacity) {
@ -337,7 +344,7 @@ namespace osmium {
} }
grow(new_capacity); grow(new_capacity);
} else { } else {
throw BufferIsFull(); throw osmium::buffer_is_full();
} }
} }
unsigned char* data = &m_data[m_written]; unsigned char* data = &m_data[m_written];
@ -354,7 +361,7 @@ namespace osmium {
* *
* @tparam T Class of the item to be copied. * @tparam T Class of the item to be copied.
* @param item Reference to the item to be copied. * @param item Reference to the item to be copied.
* @return Reference to newly copied data in the buffer. * @returns Reference to newly copied data in the buffer.
*/ */
template <class T> template <class T>
T& add_item(const T& item) { T& add_item(const T& item) {
@ -483,6 +490,10 @@ namespace osmium {
*/ */
template <class TCallbackClass> template <class TCallbackClass>
void purge_removed(TCallbackClass* callback) { void purge_removed(TCallbackClass* callback) {
if (begin() == end()) {
return;
}
iterator it_write = begin(); iterator it_write = begin();
iterator next; iterator next;
@ -490,29 +501,29 @@ namespace osmium {
next = std::next(it_read); next = std::next(it_read);
if (!it_read->removed()) { if (!it_read->removed()) {
if (it_read != it_write) { if (it_read != it_write) {
assert(it_read->data() >= data()); assert(it_read.data() >= data());
assert(it_write->data() >= data()); assert(it_write.data() >= data());
size_t old_offset = static_cast<size_t>(it_read->data() - data()); size_t old_offset = static_cast<size_t>(it_read.data() - data());
size_t new_offset = static_cast<size_t>(it_write->data() - data()); size_t new_offset = static_cast<size_t>(it_write.data() - data());
callback->moving_in_buffer(old_offset, new_offset); callback->moving_in_buffer(old_offset, new_offset);
std::memmove(it_write->data(), it_read->data(), it_read->padded_size()); std::memmove(it_write.data(), it_read.data(), it_read->padded_size());
} }
++it_write; it_write.advance_once();
} }
} }
assert(it_write->data() >= data()); assert(it_write.data() >= data());
m_written = static_cast<size_t>(it_write->data() - data()); m_written = static_cast<size_t>(it_write.data() - data());
m_committed = m_written; m_committed = m_written;
} }
}; // class Buffer }; // class Buffer
inline bool operator==(const Buffer& lhs, const Buffer& rhs) { inline bool operator==(const Buffer& lhs, const Buffer& rhs) noexcept {
return lhs.data() == rhs.data() && lhs.capacity() == rhs.capacity() && lhs.committed() == rhs.committed(); return lhs.data() == rhs.data() && lhs.capacity() == rhs.capacity() && lhs.committed() == rhs.committed();
} }
inline bool operator!=(const Buffer& lhs, const Buffer& rhs) { inline bool operator!=(const Buffer& lhs, const Buffer& rhs) noexcept {
return ! (lhs == rhs); return ! (lhs == rhs);
} }

View File

@ -1,153 +1,153 @@
#ifndef OSMIUM_MEMORY_COLLECTION_HPP #ifndef OSMIUM_MEMORY_COLLECTION_HPP
#define OSMIUM_MEMORY_COLLECTION_HPP #define OSMIUM_MEMORY_COLLECTION_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <iterator> #include <iterator>
#include <iosfwd> #include <iosfwd>
#include <type_traits> #include <type_traits>
#include <osmium/memory/item.hpp> #include <osmium/memory/item.hpp>
namespace osmium { namespace osmium {
namespace memory { namespace memory {
template <class TMember> template <class TMember>
class CollectionIterator : public std::iterator<std::forward_iterator_tag, TMember> { class CollectionIterator : public std::iterator<std::forward_iterator_tag, TMember> {
// This data_type is either 'unsigned char*' or 'const unsigned char*' depending // This data_type is either 'unsigned char*' or 'const unsigned char*' depending
// on whether TMember is const. This allows this class to be used as an iterator and // on whether TMember is const. This allows this class to be used as an iterator and
// as a const_iterator. // as a const_iterator.
typedef typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type data_type; typedef typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type data_type;
data_type m_data; data_type m_data;
public: public:
CollectionIterator() : CollectionIterator() noexcept :
m_data(nullptr) { m_data(nullptr) {
} }
CollectionIterator(data_type data) : CollectionIterator(data_type data) noexcept :
m_data(data) { m_data(data) {
} }
CollectionIterator<TMember>& operator++() { CollectionIterator<TMember>& operator++() {
m_data = reinterpret_cast<TMember*>(m_data)->next(); m_data = reinterpret_cast<TMember*>(m_data)->next();
return *static_cast<CollectionIterator<TMember>*>(this); return *static_cast<CollectionIterator<TMember>*>(this);
} }
CollectionIterator<TMember> operator++(int) { CollectionIterator<TMember> operator++(int) {
CollectionIterator<TMember> tmp(*this); CollectionIterator<TMember> tmp(*this);
operator++(); operator++();
return tmp; return tmp;
} }
bool operator==(const CollectionIterator<TMember>& rhs) const { bool operator==(const CollectionIterator<TMember>& rhs) const noexcept {
return m_data == rhs.m_data; return m_data == rhs.m_data;
} }
bool operator!=(const CollectionIterator<TMember>& rhs) const { bool operator!=(const CollectionIterator<TMember>& rhs) const noexcept {
return m_data != rhs.m_data; return m_data != rhs.m_data;
} }
unsigned char* data() const { unsigned char* data() const noexcept {
return m_data; return m_data;
} }
TMember& operator*() const { TMember& operator*() const {
return *reinterpret_cast<TMember*>(m_data); return *reinterpret_cast<TMember*>(m_data);
} }
TMember* operator->() const { TMember* operator->() const {
return reinterpret_cast<TMember*>(m_data); return reinterpret_cast<TMember*>(m_data);
} }
template <typename TChar, typename TTraits> template <typename TChar, typename TTraits>
friend std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const CollectionIterator<TMember>& iter) { friend std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const CollectionIterator<TMember>& iter) {
return out << static_cast<void*>(iter.m_data); return out << static_cast<const void*>(iter.m_data);
} }
}; // class CollectionIterator }; // class CollectionIterator
template <class TMember, osmium::item_type TCollectionItemType> template <class TMember, osmium::item_type TCollectionItemType>
class Collection : public Item { class Collection : public Item {
public: public:
typedef CollectionIterator<TMember> iterator; typedef CollectionIterator<TMember> iterator;
typedef CollectionIterator<const TMember> const_iterator; typedef CollectionIterator<const TMember> const_iterator;
typedef TMember value_type; typedef TMember value_type;
static constexpr osmium::item_type itemtype = TCollectionItemType; static constexpr osmium::item_type itemtype = TCollectionItemType;
Collection() : Collection() :
Item(sizeof(Collection<TMember, TCollectionItemType>), TCollectionItemType) { Item(sizeof(Collection<TMember, TCollectionItemType>), TCollectionItemType) {
} }
bool empty() const { bool empty() const {
return sizeof(Collection<TMember, TCollectionItemType>) == byte_size(); return sizeof(Collection<TMember, TCollectionItemType>) == byte_size();
} }
iterator begin() { iterator begin() {
return iterator(data() + sizeof(Collection<TMember, TCollectionItemType>)); return iterator(data() + sizeof(Collection<TMember, TCollectionItemType>));
} }
iterator end() { iterator end() {
return iterator(data() + byte_size()); return iterator(data() + byte_size());
} }
const_iterator cbegin() const { const_iterator cbegin() const {
return const_iterator(data() + sizeof(Collection<TMember, TCollectionItemType>)); return const_iterator(data() + sizeof(Collection<TMember, TCollectionItemType>));
} }
const_iterator cend() const { const_iterator cend() const {
return const_iterator(data() + byte_size()); return const_iterator(data() + byte_size());
} }
const_iterator begin() const { const_iterator begin() const {
return cbegin(); return cbegin();
} }
const_iterator end() const { const_iterator end() const {
return cend(); return cend();
} }
}; // class Collection }; // class Collection
} // namespace memory } // namespace memory
} // namespace osmium } // namespace osmium
#endif // OSMIUM_MEMORY_COLLECTION_HPP #endif // OSMIUM_MEMORY_COLLECTION_HPP

View File

@ -52,11 +52,11 @@ namespace osmium {
// align datastructures to this many bytes // align datastructures to this many bytes
constexpr item_size_type align_bytes = 8; constexpr item_size_type align_bytes = 8;
inline size_t padded_length(size_t length) { inline size_t padded_length(size_t length) noexcept {
return (length + align_bytes - 1) & ~(align_bytes - 1); return (length + align_bytes - 1) & ~(align_bytes - 1);
} }
inline item_size_type padded_length(item_size_type length) { inline item_size_type padded_length(item_size_type length) noexcept {
return (length + align_bytes - 1) & ~(align_bytes - 1); return (length + align_bytes - 1) & ~(align_bytes - 1);
} }
@ -85,15 +85,15 @@ namespace osmium {
public: public:
unsigned char* data() { unsigned char* data() noexcept {
return reinterpret_cast<unsigned char*>(this); return reinterpret_cast<unsigned char*>(this);
} }
const unsigned char* data() const { const unsigned char* data() const noexcept {
return reinterpret_cast<const unsigned char*>(this); return reinterpret_cast<const unsigned char*>(this);
} }
}; }; // class ItemHelper
} // namespace detail } // namespace detail
@ -112,22 +112,14 @@ namespace osmium {
friend class osmium::builder::Builder; friend class osmium::builder::Builder;
unsigned char* next() { Item& add_size(const item_size_type size) noexcept {
return data() + padded_size();
}
const unsigned char* next() const {
return data() + padded_size();
}
Item& add_size(const item_size_type size) {
m_size += size; m_size += size;
return *this; return *this;
} }
protected: protected:
explicit Item(item_size_type size=0, item_type type=item_type()) : explicit Item(item_size_type size=0, item_type type=item_type()) noexcept :
m_size(size), m_size(size),
m_type(type), m_type(type),
m_removed(false) { m_removed(false) {
@ -139,14 +131,22 @@ namespace osmium {
Item& operator=(const Item&) = delete; Item& operator=(const Item&) = delete;
Item& operator=(Item&&) = delete; Item& operator=(Item&&) = delete;
Item& type(const item_type item_type) { Item& set_type(const item_type item_type) noexcept {
m_type = item_type; m_type = item_type;
return *this; return *this;
} }
public: public:
item_size_type byte_size() const { unsigned char* next() noexcept {
return data() + padded_size();
}
const unsigned char* next() const noexcept {
return data() + padded_size();
}
item_size_type byte_size() const noexcept {
return m_size; return m_size;
} }
@ -154,15 +154,15 @@ namespace osmium {
return padded_length(m_size); return padded_length(m_size);
} }
item_type type() const { item_type type() const noexcept {
return m_type; return m_type;
} }
bool removed() const { bool removed() const noexcept {
return m_removed; return m_removed;
} }
void removed(bool removed) { void set_removed(bool removed) noexcept {
m_removed = removed; m_removed = removed;
} }

View File

@ -1,181 +1,234 @@
#ifndef OSMIUM_ITEM_ITERATOR_HPP #ifndef OSMIUM_ITEM_ITERATOR_HPP
#define OSMIUM_ITEM_ITERATOR_HPP #define OSMIUM_ITEM_ITERATOR_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <cassert> #include <cassert>
#include <iterator> #include <iterator>
#include <iosfwd> #include <iosfwd>
#include <type_traits> #include <type_traits>
#include <osmium/memory/item.hpp> #include <osmium/memory/item.hpp>
#include <osmium/osm.hpp> #include <osmium/osm/item_type.hpp>
#include <osmium/osm/item_type.hpp>
namespace osmium {
namespace osmium {
class Node;
namespace memory { class Way;
class Relation;
namespace detail { class Area;
class Changeset;
template <class T> class OSMObject;
inline bool type_is_compatible(osmium::item_type) { class OSMEntity;
return true; class TagList;
} class WayNodeList;
class RelationMemberList;
template <> class InnerRing;
inline bool type_is_compatible<osmium::Node>(osmium::item_type t) { class OuterRing;
return t == osmium::item_type::node;
} namespace memory {
template <> namespace detail {
inline bool type_is_compatible<osmium::Way>(osmium::item_type t) {
return t == osmium::item_type::way; template <class T>
} inline bool type_is_compatible(osmium::item_type) noexcept {
return true;
template <> }
inline bool type_is_compatible<osmium::Relation>(osmium::item_type t) {
return t == osmium::item_type::relation; template <>
} inline bool type_is_compatible<osmium::Node>(osmium::item_type t) noexcept {
return t == osmium::item_type::node;
template <> }
inline bool type_is_compatible<osmium::Area>(osmium::item_type t) {
return t == osmium::item_type::area; template <>
} inline bool type_is_compatible<osmium::Way>(osmium::item_type t) noexcept {
return t == osmium::item_type::way;
template <> }
inline bool type_is_compatible<osmium::Changeset>(osmium::item_type t) {
return t == osmium::item_type::changeset; template <>
} inline bool type_is_compatible<osmium::Relation>(osmium::item_type t) noexcept {
return t == osmium::item_type::relation;
template <> }
inline bool type_is_compatible<osmium::OSMObject>(osmium::item_type t) {
return t == osmium::item_type::node || t == osmium::item_type::way || t == osmium::item_type::relation || t == osmium::item_type::area; template <>
} inline bool type_is_compatible<osmium::Area>(osmium::item_type t) noexcept {
return t == osmium::item_type::area;
template <> }
inline bool type_is_compatible<osmium::OSMEntity>(osmium::item_type t) {
return t == osmium::item_type::node || t == osmium::item_type::way || t == osmium::item_type::relation || t == osmium::item_type::area || t == osmium::item_type::changeset; template <>
} inline bool type_is_compatible<osmium::Changeset>(osmium::item_type t) noexcept {
return t == osmium::item_type::changeset;
} // namespace detail }
template <class TMember> template <>
class ItemIterator : public std::iterator<std::forward_iterator_tag, TMember> { inline bool type_is_compatible<osmium::OSMObject>(osmium::item_type t) noexcept {
return t == osmium::item_type::node || t == osmium::item_type::way || t == osmium::item_type::relation || t == osmium::item_type::area;
static_assert(std::is_base_of<osmium::memory::Item, TMember>::value, "TMember must derive from osmium::memory::Item"); }
// This data_type is either 'unsigned char*' or 'const unsigned char*' depending template <>
// on whether TMember is const. This allows this class to be used as an iterator and inline bool type_is_compatible<osmium::OSMEntity>(osmium::item_type t) noexcept {
// as a const_iterator. return t == osmium::item_type::node || t == osmium::item_type::way || t == osmium::item_type::relation || t == osmium::item_type::area || t == osmium::item_type::changeset;
typedef typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type data_type; }
data_type m_data; template <>
data_type m_end; inline bool type_is_compatible<osmium::TagList>(osmium::item_type t) noexcept {
return t == osmium::item_type::tag_list;
void advance_to_next_item_of_right_type() { }
while (m_data != m_end &&
!detail::type_is_compatible<typename std::remove_const<TMember>::type>(reinterpret_cast<const osmium::memory::Item*>(m_data)->type())) { template <>
m_data = reinterpret_cast<TMember*>(m_data)->next(); inline bool type_is_compatible<osmium::WayNodeList>(osmium::item_type t) noexcept {
} return t == osmium::item_type::way_node_list;
} }
public: template <>
inline bool type_is_compatible<osmium::RelationMemberList>(osmium::item_type t) noexcept {
ItemIterator() : return t == osmium::item_type::relation_member_list || t == osmium::item_type::relation_member_list_with_full_members;
m_data(nullptr), }
m_end(nullptr) {
} template <>
inline bool type_is_compatible<osmium::OuterRing>(osmium::item_type t) noexcept {
ItemIterator(data_type data, data_type end) : return t == osmium::item_type::outer_ring;
m_data(data), }
m_end(end) {
advance_to_next_item_of_right_type(); template <>
} inline bool type_is_compatible<osmium::InnerRing>(osmium::item_type t) noexcept {
return t == osmium::item_type::inner_ring;
ItemIterator<TMember>& operator++() { }
assert(m_data);
assert(m_data != m_end); } // namespace detail
m_data = reinterpret_cast<TMember*>(m_data)->next();
advance_to_next_item_of_right_type(); template <class TMember>
return *static_cast<ItemIterator<TMember>*>(this); class ItemIterator : public std::iterator<std::forward_iterator_tag, TMember> {
}
static_assert(std::is_base_of<osmium::memory::Item, TMember>::value, "TMember must derive from osmium::memory::Item");
ItemIterator<TMember> operator++(int) {
ItemIterator<TMember> tmp(*this); // This data_type is either 'unsigned char*' or 'const unsigned char*' depending
operator++(); // on whether TMember is const. This allows this class to be used as an iterator and
return tmp; // as a const_iterator.
} typedef typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type data_type;
bool operator==(const ItemIterator<TMember>& rhs) const { data_type m_data;
return m_data == rhs.m_data && m_end == rhs.m_end; data_type m_end;
}
void advance_to_next_item_of_right_type() {
bool operator!=(const ItemIterator<TMember>& rhs) const { while (m_data != m_end &&
return !(*this == rhs); !detail::type_is_compatible<typename std::remove_const<TMember>::type>(reinterpret_cast<const osmium::memory::Item*>(m_data)->type())) {
} m_data = reinterpret_cast<TMember*>(m_data)->next();
}
unsigned char* data() const { }
assert(m_data);
assert(m_data != m_end); public:
return m_data;
} ItemIterator() noexcept :
m_data(nullptr),
TMember& operator*() const { m_end(nullptr) {
assert(m_data); }
assert(m_data != m_end);
return *reinterpret_cast<TMember*>(m_data); ItemIterator(data_type data, data_type end) :
} m_data(data),
m_end(end) {
TMember* operator->() const { advance_to_next_item_of_right_type();
assert(m_data); }
assert(m_data != m_end);
return reinterpret_cast<TMember*>(m_data); template <class T>
} ItemIterator<T> cast() const {
return ItemIterator<T>(m_data, m_end);
explicit operator bool() const { }
return m_data != nullptr;
} ItemIterator<TMember>& operator++() {
assert(m_data);
template <typename TChar, typename TTraits> assert(m_data != m_end);
friend std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const ItemIterator<TMember>& iter) { m_data = reinterpret_cast<TMember*>(m_data)->next();
return out << static_cast<void*>(iter.m_data); advance_to_next_item_of_right_type();
} return *static_cast<ItemIterator<TMember>*>(this);
}
}; // class ItemIterator
/**
} // namespace memory * Like operator++() but will NOT skip items of unwanted
* types. Do not use this unless you know what you are
} // namespace osmium * doing.
*/
#endif // OSMIUM_ITEM_ITERATOR_HPP ItemIterator<TMember>& advance_once() {
assert(m_data);
assert(m_data != m_end);
m_data = reinterpret_cast<TMember*>(m_data)->next();
return *static_cast<ItemIterator<TMember>*>(this);
}
ItemIterator<TMember> operator++(int) {
ItemIterator<TMember> tmp(*this);
operator++();
return tmp;
}
bool operator==(const ItemIterator<TMember>& rhs) const {
return m_data == rhs.m_data && m_end == rhs.m_end;
}
bool operator!=(const ItemIterator<TMember>& rhs) const {
return !(*this == rhs);
}
unsigned char* data() const {
assert(m_data);
return m_data;
}
TMember& operator*() const {
assert(m_data);
assert(m_data != m_end);
return *reinterpret_cast<TMember*>(m_data);
}
TMember* operator->() const {
assert(m_data);
assert(m_data != m_end);
return reinterpret_cast<TMember*>(m_data);
}
explicit operator bool() const {
return m_data != nullptr;
}
template <typename TChar, typename TTraits>
friend std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const ItemIterator<TMember>& iter) {
return out << static_cast<void*>(iter.m_data);
}
}; // class ItemIterator
} // namespace memory
} // namespace osmium
#endif // OSMIUM_ITEM_ITERATOR_HPP

View File

@ -1,112 +1,112 @@
#ifndef OSMIUM_OBJECT_POINTER_COLLECTION_HPP #ifndef OSMIUM_OBJECT_POINTER_COLLECTION_HPP
#define OSMIUM_OBJECT_POINTER_COLLECTION_HPP #define OSMIUM_OBJECT_POINTER_COLLECTION_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm> #include <algorithm>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <boost/iterator/indirect_iterator.hpp> #include <boost/iterator/indirect_iterator.hpp>
#include <osmium/handler.hpp> #include <osmium/handler.hpp>
#include <osmium/memory/item.hpp> #include <osmium/memory/item.hpp>
#include <osmium/osm/object.hpp> #include <osmium/osm/object.hpp>
// IWYU pragma: no_forward_declare osmium::OSMObject // IWYU pragma: no_forward_declare osmium::OSMObject
// IWYU pragma: no_forward_declare osmium::memory::Item // IWYU pragma: no_forward_declare osmium::memory::Item
namespace osmium { namespace osmium {
/** /**
* A collection of pointers to OSM objects. The pointers can be easily * A collection of pointers to OSM objects. The pointers can be easily
* and quickly sorted or otherwise manipulated, while the objects * and quickly sorted or otherwise manipulated, while the objects
* themselves or the buffers they are in, do not have to be changed. * themselves or the buffers they are in, do not have to be changed.
* *
* An iterator is provided that can iterate over the pointers but looks * An iterator is provided that can iterate over the pointers but looks
* like it is iterating over the underlying OSM objects. * like it is iterating over the underlying OSM objects.
* *
* This class implements the visitor pattern which makes it easy to * This class implements the visitor pattern which makes it easy to
* populate the collection from a buffer of OSM objects: * populate the collection from a buffer of OSM objects:
* *
* osmium::ObjectPointerCollection objects; * osmium::ObjectPointerCollection objects;
* osmium::memory::Buffer buffer = reader.read(); * osmium::memory::Buffer buffer = reader.read();
* osmium::apply(buffer, objects); * osmium::apply(buffer, objects);
* *
*/ */
class ObjectPointerCollection : public osmium::handler::Handler { class ObjectPointerCollection : public osmium::handler::Handler {
std::vector<osmium::OSMObject*> m_objects; std::vector<osmium::OSMObject*> m_objects;
public: public:
typedef boost::indirect_iterator<std::vector<osmium::OSMObject*>::iterator, osmium::OSMObject> iterator; typedef boost::indirect_iterator<std::vector<osmium::OSMObject*>::iterator, osmium::OSMObject> iterator;
typedef boost::indirect_iterator<std::vector<osmium::OSMObject*>::const_iterator, const osmium::OSMObject> const_iterator; typedef boost::indirect_iterator<std::vector<osmium::OSMObject*>::const_iterator, const osmium::OSMObject> const_iterator;
ObjectPointerCollection() : ObjectPointerCollection() noexcept :
m_objects() { m_objects() {
} }
void osm_object(osmium::OSMObject& object) { void osm_object(osmium::OSMObject& object) {
m_objects.push_back(&object); m_objects.push_back(&object);
} }
/** /**
* Sort objects according to the given order functor. * Sort objects according to the given order functor.
*/ */
template <class TCompare> template <class TCompare>
void sort(TCompare&& compare) { void sort(TCompare&& compare) {
std::sort(m_objects.begin(), m_objects.end(), std::forward<TCompare>(compare)); std::sort(m_objects.begin(), m_objects.end(), std::forward<TCompare>(compare));
} }
iterator begin() { iterator begin() {
return iterator { m_objects.begin() }; return iterator { m_objects.begin() };
} }
iterator end() { iterator end() {
return iterator { m_objects.end() }; return iterator { m_objects.end() };
} }
const_iterator cbegin() const { const_iterator cbegin() const {
return const_iterator { m_objects.cbegin() }; return const_iterator { m_objects.cbegin() };
} }
const_iterator cend() const { const_iterator cend() const {
return const_iterator { m_objects.cend() }; return const_iterator { m_objects.cend() };
} }
}; // class ObjectPointerCollection }; // class ObjectPointerCollection
} // namespace osmium } // namespace osmium
#endif // OSMIUM_OBJECT_POINTER_COLLECTION_HPP #endif // OSMIUM_OBJECT_POINTER_COLLECTION_HPP

View File

@ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <cassert>
#include <cstdlib> #include <cstdlib>
#include <utility> #include <utility>
@ -123,7 +124,7 @@ namespace osmium {
* Was this area created from a way? (In contrast to areas * Was this area created from a way? (In contrast to areas
* created from a relation and their members.) * created from a relation and their members.)
*/ */
bool from_way() const { bool from_way() const noexcept {
return (positive_id() & 0x1) == 0; return (positive_id() & 0x1) == 0;
} }
@ -148,7 +149,19 @@ namespace osmium {
case osmium::item_type::inner_ring: case osmium::item_type::inner_ring:
++counter.second; ++counter.second;
break; break;
default: case osmium::item_type::tag_list:
// ignore tags
break;
case osmium::item_type::undefined:
case osmium::item_type::node:
case osmium::item_type::way:
case osmium::item_type::relation:
case osmium::item_type::area:
case osmium::item_type::changeset:
case osmium::item_type::way_node_list:
case osmium::item_type::relation_member_list:
case osmium::item_type::relation_member_list_with_full_members:
assert(false && "Children of Area can only be outer/inner_ring and tag_list.");
break; break;
} }
} }
@ -163,6 +176,14 @@ namespace osmium {
return num_rings().first > 1; return num_rings().first > 1;
} }
osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cbegin(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
return it.cast<const osmium::InnerRing>();
}
osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cend(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
return std::next(it).cast<const osmium::InnerRing>();
}
}; // class Area }; // class Area
static_assert(sizeof(Area) % osmium::memory::align_bytes == 0, "Class osmium::Area has wrong size to be aligned properly!"); static_assert(sizeof(Area) % osmium::memory::align_bytes == 0, "Class osmium::Area has wrong size to be aligned properly!");

View File

@ -54,7 +54,7 @@ namespace osmium {
* Create undefined Box. Use the extend() function * Create undefined Box. Use the extend() function
* to add actual bounds. * to add actual bounds.
*/ */
constexpr Box() : constexpr Box() noexcept :
m_bottom_left(), m_bottom_left(),
m_top_right() { m_top_right() {
} }
@ -83,16 +83,16 @@ namespace osmium {
if (location) { if (location) {
if (m_bottom_left) { if (m_bottom_left) {
if (location.x() < m_bottom_left.x()) { if (location.x() < m_bottom_left.x()) {
m_bottom_left.x(location.x()); m_bottom_left.set_x(location.x());
} }
if (location.x() > m_top_right.x()) { if (location.x() > m_top_right.x()) {
m_top_right.x(location.x()); m_top_right.set_x(location.x());
} }
if (location.y() < m_bottom_left.y()) { if (location.y() < m_bottom_left.y()) {
m_bottom_left.y(location.y()); m_bottom_left.set_y(location.y());
} }
if (location.y() > m_top_right.y()) { if (location.y() > m_top_right.y()) {
m_top_right.y(location.y()); m_top_right.set_y(location.y());
} }
} else { } else {
m_bottom_left = location; m_bottom_left = location;

View File

@ -52,8 +52,11 @@ namespace osmium {
} }
/** /**
* An OSM Changeset is of a group of changes made by a single user over a * \brief An OSM Changeset, a group of changes made by a single user over
* short period of time. * a short period of time.
*
* You can not create Changeset objects directly. Use the ChangesetBuilder
* class to create Changesets in a Buffer.
*/ */
class Changeset : public osmium::OSMEntity { class Changeset : public osmium::OSMEntity {
@ -71,7 +74,7 @@ namespace osmium {
OSMEntity(sizeof(Changeset), osmium::item_type::changeset) { OSMEntity(sizeof(Changeset), osmium::item_type::changeset) {
} }
void user_size(string_size_type size) { void set_user_size(string_size_type size) {
m_user_size = size; m_user_size = size;
} }
@ -83,30 +86,6 @@ namespace osmium {
return data() + osmium::memory::padded_length(sizeof(Changeset) + m_user_size); return data() + osmium::memory::padded_length(sizeof(Changeset) + m_user_size);
} }
template <class T>
T& subitem_of_type() {
for (iterator it = begin(); it != end(); ++it) {
if (it->type() == T::itemtype) {
return reinterpret_cast<T&>(*it);
}
}
static T subitem;
return subitem;
}
template <class T>
const T& subitem_of_type() const {
for (const_iterator it = cbegin(); it != cend(); ++it) {
if (it->type() == T::itemtype) {
return reinterpret_cast<const T&>(*it);
}
}
static const T subitem;
return subitem;
}
public: public:
/// Get ID of this changeset /// Get ID of this changeset
@ -117,9 +96,10 @@ namespace osmium {
/** /**
* Set ID of this changeset * Set ID of this changeset
* *
* @return Reference to changeset to make calls chainable. * @param id The id.
* @returns Reference to changeset to make calls chainable.
*/ */
Changeset& id(changeset_id_type id) noexcept { Changeset& set_id(changeset_id_type id) noexcept {
m_id = id; m_id = id;
return *this; return *this;
} }
@ -127,10 +107,11 @@ namespace osmium {
/** /**
* Set ID of this changeset. * Set ID of this changeset.
* *
* @return Reference to object to make calls chainable. * @param id The id.
* @returns Reference to object to make calls chainable.
*/ */
Changeset& id(const char* id) { Changeset& set_id(const char* id) {
return this->id(osmium::string_to_changeset_id(id)); return set_id(osmium::string_to_changeset_id(id));
} }
/// Get user id. /// Get user id.
@ -141,31 +122,34 @@ namespace osmium {
/** /**
* Set user id. * Set user id.
* *
* @return Reference to changeset to make calls chainable. * @param uid The user id.
* @returns Reference to changeset to make calls chainable.
*/ */
Changeset& uid(user_id_type uid) noexcept { Changeset& set_uid(user_id_type uid) noexcept {
m_uid = uid; m_uid = uid;
return *this; return *this;
} }
/** /**
* Set user id. * Set user id to given uid or to 0 (anonymous user) if the given
* Sets uid to 0 (anonymous) if the given uid is smaller than 0. * uid is smaller than 0.
* *
* @return Reference to changeset to make calls chainable. * @param uid The user id.
* @returns Reference to changeset to make calls chainable.
*/ */
Changeset& uid_from_signed(signed_user_id_type uid) noexcept { Changeset& set_uid_from_signed(signed_user_id_type uid) noexcept {
m_uid = uid < 0 ? 0 : static_cast<user_id_type>(uid); m_uid = uid < 0 ? 0 : static_cast<user_id_type>(uid);
return *this; return *this;
} }
/** /**
* Set user id. * Set user id to given uid or to 0 (anonymous user) if the given
* uid is smaller than 0.
* *
* @return Reference to changeset to make calls chainable. * @returns Reference to changeset to make calls chainable.
*/ */
Changeset& uid(const char* uid) { Changeset& set_uid(const char* uid) {
return this->uid_from_signed(string_to_user_id(uid)); return set_uid_from_signed(string_to_user_id(uid));
} }
/// Is this user anonymous? /// Is this user anonymous?
@ -181,17 +165,19 @@ namespace osmium {
/** /**
* Get timestamp when this changeset was closed. * Get timestamp when this changeset was closed.
* *
* This will return the empty Timestamp when the * @returns Timestamp. Will return the empty Timestamp when the
* changeset is not yet closed. * changeset is not yet closed.
*/ */
osmium::Timestamp closed_at() const noexcept { osmium::Timestamp closed_at() const noexcept {
return m_closed_at; return m_closed_at;
} }
/// Is this changeset open?
bool open() const noexcept { bool open() const noexcept {
return m_closed_at == osmium::Timestamp(); return m_closed_at == osmium::Timestamp();
} }
/// Is this changeset closed?
bool closed() const noexcept { bool closed() const noexcept {
return !open(); return !open();
} }
@ -200,9 +186,9 @@ namespace osmium {
* Set the timestamp when this changeset was created. * Set the timestamp when this changeset was created.
* *
* @param timestamp Timestamp * @param timestamp Timestamp
* @return Reference to changeset to make calls chainable. * @returns Reference to changeset to make calls chainable.
*/ */
Changeset& created_at(const osmium::Timestamp timestamp) { Changeset& set_created_at(const osmium::Timestamp timestamp) {
m_created_at = timestamp; m_created_at = timestamp;
return *this; return *this;
} }
@ -211,30 +197,43 @@ namespace osmium {
* Set the timestamp when this changeset was closed. * Set the timestamp when this changeset was closed.
* *
* @param timestamp Timestamp * @param timestamp Timestamp
* @return Reference to changeset to make calls chainable. * @returns Reference to changeset to make calls chainable.
*/ */
Changeset& closed_at(const osmium::Timestamp timestamp) { Changeset& set_closed_at(const osmium::Timestamp timestamp) {
m_closed_at = timestamp; m_closed_at = timestamp;
return *this; return *this;
} }
/// Get the number of changes in this changeset
num_changes_type num_changes() const noexcept { num_changes_type num_changes() const noexcept {
return m_num_changes; return m_num_changes;
} }
Changeset& num_changes(num_changes_type num_changes) noexcept { /// Set the number of changes in this changeset
Changeset& set_num_changes(num_changes_type num_changes) noexcept {
m_num_changes = num_changes; m_num_changes = num_changes;
return *this; return *this;
} }
Changeset& num_changes(const char* num_changes) noexcept { /// Set the number of changes in this changeset
return this->num_changes(osmium::string_to_num_changes(num_changes)); Changeset& set_num_changes(const char* num_changes) noexcept {
return set_num_changes(osmium::string_to_num_changes(num_changes));
} }
/**
* Get the bounding box of this changeset.
*
* @returns Bounding box. Can be empty.
*/
osmium::Box& bounds() noexcept { osmium::Box& bounds() noexcept {
return m_bounds; return m_bounds;
} }
/**
* Get the bounding box of this changeset.
*
* @returns Bounding box. Can be empty.
*/
const osmium::Box& bounds() const noexcept { const osmium::Box& bounds() const noexcept {
return m_bounds; return m_bounds;
} }
@ -244,33 +243,29 @@ namespace osmium {
return reinterpret_cast<const char*>(data() + sizeof(Changeset)); return reinterpret_cast<const char*>(data() + sizeof(Changeset));
} }
/// Get the list of tags.
TagList& tags() {
return subitem_of_type<TagList>();
}
/// Get the list of tags. /// Get the list of tags.
const TagList& tags() const { const TagList& tags() const {
return subitem_of_type<const TagList>(); return osmium::detail::subitem_of_type<const TagList>(cbegin(), cend());
} }
/** /**
* Set named attribute. * Set named attribute.
* *
* @param attr Name of the attribute (must be one of "id", "version", "changeset", "timestamp", "uid", "visible") * @param attr Name of the attribute (must be one of "id", "version",
* "changeset", "timestamp", "uid", "visible")
* @param value Value of the attribute * @param value Value of the attribute
*/ */
void set_attribute(const char* attr, const char* value) { void set_attribute(const char* attr, const char* value) {
if (!strcmp(attr, "id")) { if (!strcmp(attr, "id")) {
id(value); set_id(value);
} else if (!strcmp(attr, "num_changes")) { } else if (!strcmp(attr, "num_changes")) {
num_changes(value); set_num_changes(value);
} else if (!strcmp(attr, "created_at")) { } else if (!strcmp(attr, "created_at")) {
created_at(osmium::Timestamp(value)); set_created_at(osmium::Timestamp(value));
} else if (!strcmp(attr, "closed_at")) { } else if (!strcmp(attr, "closed_at")) {
closed_at(osmium::Timestamp(value)); set_closed_at(osmium::Timestamp(value));
} else if (!strcmp(attr, "uid")) { } else if (!strcmp(attr, "uid")) {
uid(value); set_uid(value);
} }
} }
@ -303,7 +298,8 @@ namespace osmium {
}; // class Changeset }; // class Changeset
static_assert(sizeof(Changeset) % osmium::memory::align_bytes == 0, "Class osmium::Changeset has wrong size to be aligned properly!"); static_assert(sizeof(Changeset) % osmium::memory::align_bytes == 0,
"Class osmium::Changeset has wrong size to be aligned properly!");
/** /**
* Changesets are equal if their IDs are equal. * Changesets are equal if their IDs are equal.

View File

@ -1,156 +1,156 @@
#ifndef OSMIUM_OSM_DIFF_OBJECT_HPP #ifndef OSMIUM_OSM_DIFF_OBJECT_HPP
#define OSMIUM_OSM_DIFF_OBJECT_HPP #define OSMIUM_OSM_DIFF_OBJECT_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <osmium/osm/item_type.hpp> #include <osmium/osm/item_type.hpp>
#include <osmium/osm/object.hpp> #include <osmium/osm/object.hpp>
#include <osmium/osm/timestamp.hpp> #include <osmium/osm/timestamp.hpp>
#include <osmium/osm/types.hpp> #include <osmium/osm/types.hpp>
namespace osmium { namespace osmium {
class Node; class Node;
class Way; class Way;
class Relation; class Relation;
class DiffObject { class DiffObject {
protected: protected:
osmium::OSMObject* m_prev; osmium::OSMObject* m_prev;
osmium::OSMObject* m_curr; osmium::OSMObject* m_curr;
osmium::OSMObject* m_next; osmium::OSMObject* m_next;
public: public:
DiffObject() : DiffObject() noexcept :
m_prev(nullptr), m_prev(nullptr),
m_curr(nullptr), m_curr(nullptr),
m_next(nullptr) { m_next(nullptr) {
} }
explicit DiffObject(osmium::OSMObject& prev, osmium::OSMObject& curr, osmium::OSMObject& next) : explicit DiffObject(osmium::OSMObject& prev, osmium::OSMObject& curr, osmium::OSMObject& next) noexcept :
m_prev(&prev), m_prev(&prev),
m_curr(&curr), m_curr(&curr),
m_next(&next) { m_next(&next) {
} }
DiffObject(const DiffObject& other) = default; DiffObject(const DiffObject& other) = default;
DiffObject& operator=(const DiffObject& other) = default; DiffObject& operator=(const DiffObject& other) = default;
DiffObject(DiffObject&& other) = default; DiffObject(DiffObject&& other) = default;
DiffObject& operator=(DiffObject&& other) = default; DiffObject& operator=(DiffObject&& other) = default;
const osmium::OSMObject& prev() const { const osmium::OSMObject& prev() const noexcept {
return *m_prev; return *m_prev;
} }
const osmium::OSMObject& curr() const { const osmium::OSMObject& curr() const noexcept {
return *m_curr; return *m_curr;
} }
const osmium::OSMObject& next() const { const osmium::OSMObject& next() const noexcept {
return *m_next; return *m_next;
} }
bool first() const { bool first() const noexcept {
return m_prev == m_curr; return m_prev == m_curr;
} }
bool last() const { bool last() const noexcept {
return m_curr == m_next; return m_curr == m_next;
} }
osmium::item_type type() const { osmium::item_type type() const noexcept {
return m_curr->type(); return m_curr->type();
} }
osmium::object_id_type id() const { osmium::object_id_type id() const noexcept {
return m_curr->id(); return m_curr->id();
} }
osmium::object_version_type version() const { osmium::object_version_type version() const noexcept {
return m_curr->version(); return m_curr->version();
} }
osmium::changeset_id_type changeset() const { osmium::changeset_id_type changeset() const noexcept {
return m_curr->changeset(); return m_curr->changeset();
} }
const osmium::Timestamp start_time() const { const osmium::Timestamp start_time() const noexcept {
return m_curr->timestamp(); return m_curr->timestamp();
} }
const osmium::Timestamp end_time() const { const osmium::Timestamp end_time() const noexcept {
return last() ? osmium::Timestamp() : m_next->timestamp(); return last() ? osmium::Timestamp() : m_next->timestamp();
} }
}; // class DiffObject }; // class DiffObject
template <class T> template <class T>
class DiffObjectDerived : public DiffObject { class DiffObjectDerived : public DiffObject {
public: public:
DiffObjectDerived(T& prev, T& curr, T& next) : DiffObjectDerived(T& prev, T& curr, T& next) noexcept :
DiffObject(prev, curr, next) { DiffObject(prev, curr, next) {
} }
DiffObjectDerived(const DiffObjectDerived& other) = default; DiffObjectDerived(const DiffObjectDerived& other) = default;
DiffObjectDerived& operator=(const DiffObjectDerived& other) = default; DiffObjectDerived& operator=(const DiffObjectDerived& other) = default;
DiffObjectDerived(DiffObjectDerived&& other) = default; DiffObjectDerived(DiffObjectDerived&& other) = default;
DiffObjectDerived& operator=(DiffObjectDerived&& other) = default; DiffObjectDerived& operator=(DiffObjectDerived&& other) = default;
const T& prev() const { const T& prev() const noexcept {
return *static_cast<const T*>(m_prev); return *static_cast<const T*>(m_prev);
} }
const T& curr() const { const T& curr() const noexcept {
return *static_cast<const T*>(m_curr); return *static_cast<const T*>(m_curr);
} }
const T& next() const { const T& next() const noexcept {
return *static_cast<const T*>(m_next); return *static_cast<const T*>(m_next);
} }
}; // class DiffObjectDerived }; // class DiffObjectDerived
typedef DiffObjectDerived<osmium::Node> DiffNode; typedef DiffObjectDerived<osmium::Node> DiffNode;
typedef DiffObjectDerived<osmium::Way> DiffWay; typedef DiffObjectDerived<osmium::Way> DiffWay;
typedef DiffObjectDerived<osmium::Relation> DiffRelation; typedef DiffObjectDerived<osmium::Relation> DiffRelation;
} // namespace osmium } // namespace osmium
#endif // OSMIUM_OSM_DIFF_OBJECT_HPP #endif // OSMIUM_OSM_DIFF_OBJECT_HPP

View File

@ -1,55 +1,74 @@
#ifndef OSMIUM_OSM_ENTITY_HPP #ifndef OSMIUM_OSM_ENTITY_HPP
#define OSMIUM_OSM_ENTITY_HPP #define OSMIUM_OSM_ENTITY_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <osmium/memory/item.hpp> #include <osmium/memory/item.hpp>
namespace osmium { namespace osmium {
/** namespace detail {
* OSMEntity is the parent class for the OSMObject class and the Changeset class.
*/ template <class TSubitem, class TIter>
class OSMEntity : public osmium::memory::Item { inline TSubitem& subitem_of_type(TIter it, TIter end) {
for (; it != end; ++it) {
public: if (it->type() == TSubitem::itemtype) {
return reinterpret_cast<TSubitem&>(*it);
explicit OSMEntity(osmium::memory::item_size_type size, osmium::item_type type) : }
Item(size, type) { }
}
// If no subitem of the TSubitem type was found,
}; // class OSMEntity // return a default constructed one.
static TSubitem subitem;
} // namespace osmium return subitem;
}
#endif // OSMIUM_OSM_ENTITY_HPP
} // namespace detail
/**
* \brief OSMEntity is the abstract base class for the OSMObject and
* Changeset classes.
*/
class OSMEntity : public osmium::memory::Item {
public:
explicit OSMEntity(osmium::memory::item_size_type size, osmium::item_type type) :
Item(size, type) {
}
}; // class OSMEntity
} // namespace osmium
#endif // OSMIUM_OSM_ENTITY_HPP

View File

@ -68,20 +68,20 @@ namespace osmium {
}; // enum type }; // enum type
inline type operator|(const type lhs, const type rhs) { inline type operator|(const type lhs, const type rhs) noexcept {
return static_cast<type>(static_cast<int>(lhs) | static_cast<int> (rhs)); return static_cast<type>(static_cast<int>(lhs) | static_cast<int> (rhs));
} }
inline type& operator|=(type& lhs, const type rhs) { inline type& operator|=(type& lhs, const type rhs) noexcept {
lhs = lhs | rhs; lhs = lhs | rhs;
return lhs; return lhs;
} }
inline type operator&(const type lhs, const type rhs) { inline type operator&(const type lhs, const type rhs) noexcept {
return static_cast<type>(static_cast<int>(lhs) & static_cast<int> (rhs)); return static_cast<type>(static_cast<int>(lhs) & static_cast<int> (rhs));
} }
inline type operator&=(type& lhs, const type rhs) { inline type operator&=(type& lhs, const type rhs) noexcept {
lhs = lhs & rhs; lhs = lhs & rhs;
return lhs; return lhs;
} }

View File

@ -56,7 +56,7 @@ namespace osmium {
}; // enum class item_type }; // enum class item_type
inline item_type char_to_item_type(const char c) { inline item_type char_to_item_type(const char c) noexcept {
switch (c) { switch (c) {
case 'X': case 'X':
return item_type::undefined; return item_type::undefined;
@ -87,7 +87,10 @@ namespace osmium {
} }
} }
inline char item_type_to_char(const item_type type) { // avoid g++ false positive
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wreturn-type"
inline char item_type_to_char(const item_type type) noexcept {
switch (type) { switch (type) {
case item_type::undefined: case item_type::undefined:
return 'X'; return 'X';
@ -116,7 +119,7 @@ namespace osmium {
} }
} }
inline const char* item_type_to_name(const item_type type) { inline const char* item_type_to_name(const item_type type) noexcept {
switch (type) { switch (type) {
case item_type::undefined: case item_type::undefined:
return "undefined"; return "undefined";
@ -144,12 +147,19 @@ namespace osmium {
return "inner_ring"; return "inner_ring";
} }
} }
#pragma GCC diagnostic pop
template <typename TChar, typename TTraits> template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const item_type item_type) { inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const item_type item_type) {
return out << item_type_to_char(item_type); return out << item_type_to_char(item_type);
} }
/**
* This exception is thrown when a visitor encounters an unknown item type.
* Under usual circumstance this should not happen. If it does happen, it
* probably means the buffer contains different kinds of objects than were
* expected or that there is some kind of data corruption.
*/
struct unknown_type : public std::runtime_error { struct unknown_type : public std::runtime_error {
unknown_type() : unknown_type() :

View File

@ -33,19 +33,16 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm>
#include <cassert>
#include <cmath> #include <cmath>
#include <cstdint> #include <cstdint>
#include <cstdio>
#include <iosfwd> #include <iosfwd>
#include <limits>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <osmium/util/compatibility.hpp> #include <osmium/util/compatibility.hpp>
#include <osmium/util/double.hpp>
namespace osmium { namespace osmium {
@ -86,7 +83,7 @@ namespace osmium {
public: public:
/// this value is used for a coordinate to mark it as undefined // this value is used for a coordinate to mark it as undefined
// MSVC doesn't declare std::numeric_limits<int32_t>::max() as // MSVC doesn't declare std::numeric_limits<int32_t>::max() as
// constexpr, so we hard code this for the time being. // constexpr, so we hard code this for the time being.
// static constexpr int32_t undefined_coordinate = std::numeric_limits<int32_t>::max(); // static constexpr int32_t undefined_coordinate = std::numeric_limits<int32_t>::max();
@ -105,7 +102,7 @@ namespace osmium {
/** /**
* Create undefined Location. * Create undefined Location.
*/ */
explicit constexpr Location() : explicit constexpr Location() noexcept :
m_x(undefined_coordinate), m_x(undefined_coordinate),
m_y(undefined_coordinate) { m_y(undefined_coordinate) {
} }
@ -115,7 +112,7 @@ namespace osmium {
* Note that these coordinates are coordinate_precision * Note that these coordinates are coordinate_precision
* times larger than the real coordinates. * times larger than the real coordinates.
*/ */
constexpr Location(const int32_t x, const int32_t y) : constexpr Location(const int32_t x, const int32_t y) noexcept :
m_x(x), m_x(x),
m_y(y) { m_y(y) {
} }
@ -125,7 +122,7 @@ namespace osmium {
* Note that these coordinates are coordinate_precision * Note that these coordinates are coordinate_precision
* times larger than the real coordinates. * times larger than the real coordinates.
*/ */
constexpr Location(const int64_t x, const int64_t y) : constexpr Location(const int64_t x, const int64_t y) noexcept :
m_x(static_cast<int32_t>(x)), m_x(static_cast<int32_t>(x)),
m_y(static_cast<int32_t>(y)) { m_y(static_cast<int32_t>(y)) {
} }
@ -171,12 +168,12 @@ namespace osmium {
return m_y; return m_y;
} }
Location& x(const int32_t x) noexcept { Location& set_x(const int32_t x) noexcept {
m_x = x; m_x = x;
return *this; return *this;
} }
Location& y(const int32_t y) noexcept { Location& set_y(const int32_t y) noexcept {
m_y = y; m_y = y;
return *this; return *this;
} }
@ -219,44 +216,21 @@ namespace osmium {
return fix_to_double(m_y); return fix_to_double(m_y);
} }
Location& lon(double lon) noexcept { Location& set_lon(double lon) noexcept {
m_x = double_to_fix(lon); m_x = double_to_fix(lon);
return *this; return *this;
} }
Location& lat(double lat) noexcept { Location& set_lat(double lat) noexcept {
m_y = double_to_fix(lat); m_y = double_to_fix(lat);
return *this; return *this;
} }
static constexpr int coordinate_length =
1 + /* sign */
3 + /* before . */
1 + /* . */
7 + /* after . */
1; /* null byte */
template <typename T>
static T coordinate2string(T iterator, double value) {
char buffer[coordinate_length];
#ifndef _MSC_VER
int len = snprintf(buffer, coordinate_length, "%.7f", value);
#else
int len = _snprintf(buffer, coordinate_length, "%.7f", value);
#endif
assert(len > 0 && len < coordinate_length);
while (buffer[len-1] == '0') --len;
if (buffer[len-1] == '.') --len;
return std::copy_n(buffer, len, iterator);
}
template <typename T> template <typename T>
T as_string(T iterator, const char separator) const { T as_string(T iterator, const char separator) const {
iterator = coordinate2string(iterator, lon()); iterator = osmium::util::double2string(iterator, lon(), 7);
*iterator++ = separator; *iterator++ = separator;
return coordinate2string(iterator, lat()); return osmium::util::double2string(iterator, lat(), 7);
} }
}; // class Location }; // class Location
@ -268,7 +242,7 @@ namespace osmium {
return lhs.x() == rhs.x() && lhs.y() == rhs.y(); return lhs.x() == rhs.x() && lhs.y() == rhs.y();
} }
inline OSMIUM_CONSTEXPR bool operator!=(const Location& lhs, const Location& rhs) { inline OSMIUM_CONSTEXPR bool operator!=(const Location& lhs, const Location& rhs) noexcept {
return ! (lhs == rhs); return ! (lhs == rhs);
} }
@ -281,15 +255,15 @@ namespace osmium {
return (lhs.x() == rhs.x() && lhs.y() < rhs.y()) || lhs.x() < rhs.x(); return (lhs.x() == rhs.x() && lhs.y() < rhs.y()) || lhs.x() < rhs.x();
} }
inline OSMIUM_CONSTEXPR bool operator>(const Location& lhs, const Location& rhs) { inline OSMIUM_CONSTEXPR bool operator>(const Location& lhs, const Location& rhs) noexcept {
return rhs < lhs; return rhs < lhs;
} }
inline OSMIUM_CONSTEXPR bool operator<=(const Location& lhs, const Location& rhs) { inline OSMIUM_CONSTEXPR bool operator<=(const Location& lhs, const Location& rhs) noexcept {
return ! (rhs < lhs); return ! (rhs < lhs);
} }
inline OSMIUM_CONSTEXPR bool operator>=(const Location& lhs, const Location& rhs) { inline OSMIUM_CONSTEXPR bool operator>=(const Location& lhs, const Location& rhs) noexcept {
return ! (lhs < rhs); return ! (lhs < rhs);
} }

View File

@ -58,15 +58,11 @@ namespace osmium {
static constexpr osmium::item_type itemtype = osmium::item_type::node; static constexpr osmium::item_type itemtype = osmium::item_type::node;
const osmium::Location location() const { osmium::Location location() const noexcept {
return m_location; return m_location;
} }
osmium::Location& location() { Node& set_location(const osmium::Location& location) {
return m_location;
}
Node& location(const osmium::Location& location) {
m_location = location; m_location = location;
return *this; return *this;
} }

View File

@ -54,20 +54,27 @@ namespace osmium {
public: public:
NodeRef(const osmium::object_id_type ref=0, const osmium::Location& location=Location()) : NodeRef(const osmium::object_id_type ref=0, const osmium::Location& location=Location()) noexcept :
m_ref(ref), m_ref(ref),
m_location(location) { m_location(location) {
} }
osmium::object_id_type ref() const { osmium::object_id_type ref() const noexcept {
return m_ref; return m_ref;
} }
osmium::unsigned_object_id_type positive_ref() const { osmium::unsigned_object_id_type positive_ref() const noexcept {
return static_cast<osmium::unsigned_object_id_type>(std::abs(m_ref)); return static_cast<osmium::unsigned_object_id_type>(std::abs(m_ref));
} }
osmium::Location location() const { /**
* Get reference to location in this NodeRef. Can be used to update it.
*/
osmium::Location& location() noexcept {
return m_location;
}
osmium::Location location() const noexcept {
return m_location; return m_location;
} }
@ -79,33 +86,47 @@ namespace osmium {
return m_location.lat(); return m_location.lat();
} }
void location(const osmium::Location& location) { int32_t x() const noexcept {
return m_location.x();
}
int32_t y() const noexcept {
return m_location.y();
}
NodeRef& set_ref(const osmium::object_id_type ref) noexcept {
m_ref = ref;
return *this;
}
NodeRef& set_location(const osmium::Location& location) noexcept {
m_location = location; m_location = location;
return *this;
} }
}; // class NodeRef }; // class NodeRef
inline bool operator==(const NodeRef& lhs, const NodeRef& rhs) { inline bool operator==(const NodeRef& lhs, const NodeRef& rhs) noexcept {
return lhs.ref() == rhs.ref(); return lhs.ref() == rhs.ref();
} }
inline bool operator!=(const NodeRef& lhs, const NodeRef& rhs) { inline bool operator!=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
return ! (lhs == rhs); return ! (lhs == rhs);
} }
inline bool operator<(const NodeRef& lhs, const NodeRef& rhs) { inline bool operator<(const NodeRef& lhs, const NodeRef& rhs) noexcept {
return lhs.ref() < rhs.ref(); return lhs.ref() < rhs.ref();
} }
inline bool operator>(const NodeRef& lhs, const NodeRef& rhs) { inline bool operator>(const NodeRef& lhs, const NodeRef& rhs) noexcept {
return rhs < lhs; return rhs < lhs;
} }
inline bool operator<=(const NodeRef& lhs, const NodeRef& rhs) { inline bool operator<=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
return ! (rhs < lhs); return ! (rhs < lhs);
} }
inline bool operator>=(const NodeRef& lhs, const NodeRef& rhs) { inline bool operator>=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
return ! (lhs < rhs); return ! (lhs < rhs);
} }
@ -122,7 +143,7 @@ namespace osmium {
*/ */
struct location_equal { struct location_equal {
bool operator()(const NodeRef& lhs, const NodeRef& rhs) const { bool operator()(const NodeRef& lhs, const NodeRef& rhs) const noexcept {
return lhs.location() == rhs.location(); return lhs.location() == rhs.location();
} }
@ -137,7 +158,7 @@ namespace osmium {
*/ */
struct location_less { struct location_less {
bool operator()(const NodeRef& lhs, const NodeRef& rhs) const { bool operator()(const NodeRef& lhs, const NodeRef& rhs) const noexcept {
return lhs.location() < rhs.location(); return lhs.location() < rhs.location();
} }

View File

@ -1,135 +1,135 @@
#ifndef OSMIUM_OSM_NODE_REF_LIST_HPP #ifndef OSMIUM_OSM_NODE_REF_LIST_HPP
#define OSMIUM_OSM_NODE_REF_LIST_HPP #define OSMIUM_OSM_NODE_REF_LIST_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <iterator> #include <iterator>
#include <osmium/memory/item.hpp> #include <osmium/memory/item.hpp>
#include <osmium/osm/item_type.hpp> #include <osmium/osm/item_type.hpp>
#include <osmium/osm/node_ref.hpp> #include <osmium/osm/node_ref.hpp>
namespace osmium { namespace osmium {
/** /**
* A vector of NodeRef objects. Usually this is not instatiated directly, * A vector of NodeRef objects. Usually this is not instatiated directly,
* but one of its subclasses are used. * but one of its subclasses are used.
*/ */
template <osmium::item_type TItemType> template <osmium::item_type TItemType>
class NodeRefList : public osmium::memory::Item { class NodeRefList : public osmium::memory::Item {
public: public:
static constexpr osmium::item_type itemtype = TItemType; static constexpr osmium::item_type itemtype = TItemType;
NodeRefList(): NodeRefList() noexcept :
osmium::memory::Item(sizeof(NodeRefList), TItemType) { osmium::memory::Item(sizeof(NodeRefList), TItemType) {
} }
bool empty() const { bool empty() const noexcept {
return sizeof(NodeRefList) == byte_size(); return sizeof(NodeRefList) == byte_size();
} }
size_t size() const noexcept { size_t size() const noexcept {
assert((osmium::memory::Item::byte_size() - sizeof(NodeRefList)) % sizeof(NodeRef) == 0); assert((osmium::memory::Item::byte_size() - sizeof(NodeRefList)) % sizeof(NodeRef) == 0);
return (osmium::memory::Item::byte_size() - sizeof(NodeRefList)) / sizeof(NodeRef); return (osmium::memory::Item::byte_size() - sizeof(NodeRefList)) / sizeof(NodeRef);
} }
const NodeRef& operator[](size_t n) const { const NodeRef& operator[](size_t n) const {
const NodeRef* node_ref = &*(this->cbegin()); const NodeRef* node_ref = &*(cbegin());
return node_ref[n]; return node_ref[n];
} }
const NodeRef& front() const { const NodeRef& front() const {
return operator[](0); return operator[](0);
} }
const NodeRef& back() const { const NodeRef& back() const {
return operator[](size()-1); return operator[](size()-1);
} }
bool is_closed() const { bool is_closed() const {
return front().ref() == back().ref(); return front().ref() == back().ref();
} }
bool ends_have_same_id() const { bool ends_have_same_id() const {
return front().ref() == back().ref(); return front().ref() == back().ref();
} }
bool ends_have_same_location() const { bool ends_have_same_location() const {
return front().location() == back().location(); return front().location() == back().location();
} }
typedef NodeRef* iterator; typedef NodeRef* iterator;
typedef const NodeRef* const_iterator; typedef const NodeRef* const_iterator;
typedef std::reverse_iterator<const NodeRef*> const_reverse_iterator; typedef std::reverse_iterator<const NodeRef*> const_reverse_iterator;
iterator begin() { iterator begin() {
return iterator(data() + sizeof(NodeRefList)); return iterator(data() + sizeof(NodeRefList));
} }
iterator end() { iterator end() {
return iterator(data() + byte_size()); return iterator(data() + byte_size());
} }
const_iterator cbegin() const { const_iterator cbegin() const {
return const_iterator(data() + sizeof(NodeRefList)); return const_iterator(data() + sizeof(NodeRefList));
} }
const_iterator cend() const { const_iterator cend() const {
return const_iterator(data() + byte_size()); return const_iterator(data() + byte_size());
} }
const_iterator begin() const { const_iterator begin() const {
return cbegin(); return cbegin();
} }
const_iterator end() const { const_iterator end() const {
return cend(); return cend();
} }
const_reverse_iterator crbegin() const { const_reverse_iterator crbegin() const {
return const_reverse_iterator(this->cend()); return const_reverse_iterator(cend());
} }
const_reverse_iterator crend() const { const_reverse_iterator crend() const {
return const_reverse_iterator(this->cbegin()); return const_reverse_iterator(cbegin());
} }
}; // class NodeRefList }; // class NodeRefList
} // namespace osmium } // namespace osmium
#endif // OSMIUM_OSM_NODE_REF_LIST_HPP #endif // OSMIUM_OSM_NODE_REF_LIST_HPP

View File

@ -41,6 +41,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/memory/collection.hpp> #include <osmium/memory/collection.hpp>
#include <osmium/memory/item.hpp> #include <osmium/memory/item.hpp>
#include <osmium/memory/item_iterator.hpp>
#include <osmium/osm/entity.hpp> #include <osmium/osm/entity.hpp>
#include <osmium/osm/item_type.hpp> #include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp> #include <osmium/osm/location.hpp>
@ -62,19 +63,19 @@ namespace osmium {
user_id_type m_uid; user_id_type m_uid;
changeset_id_type m_changeset; changeset_id_type m_changeset;
size_t sizeof_object() const { size_t sizeof_object() const noexcept {
return sizeof(OSMObject) + (type() == item_type::node ? sizeof(osmium::Location) : 0) + sizeof(string_size_type); return sizeof(OSMObject) + (type() == item_type::node ? sizeof(osmium::Location) : 0) + sizeof(string_size_type);
} }
unsigned char* user_position() { unsigned char* user_position() noexcept {
return data() + sizeof_object() - sizeof(string_size_type); return data() + sizeof_object() - sizeof(string_size_type);
} }
const unsigned char* user_position() const { const unsigned char* user_position() const noexcept {
return data() + sizeof_object() - sizeof(string_size_type); return data() + sizeof_object() - sizeof(string_size_type);
} }
string_size_type user_size() const { string_size_type user_size() const noexcept {
return *reinterpret_cast<const string_size_type*>(user_position()); return *reinterpret_cast<const string_size_type*>(user_position());
} }
@ -98,52 +99,28 @@ namespace osmium {
m_changeset(0) { m_changeset(0) {
} }
void user_size(string_size_type size) { void set_user_size(string_size_type size) {
*reinterpret_cast<string_size_type*>(user_position()) = size; *reinterpret_cast<string_size_type*>(user_position()) = size;
} }
template <class T>
T& subitem_of_type() {
for (iterator it = begin(); it != end(); ++it) {
if (it->type() == T::itemtype) {
return reinterpret_cast<T&>(*it);
}
}
static T subitem;
return subitem;
}
template <class T>
const T& subitem_of_type() const {
for (const_iterator it = cbegin(); it != cend(); ++it) {
if (it->type() == T::itemtype) {
return reinterpret_cast<const T&>(*it);
}
}
static const T subitem;
return subitem;
}
public: public:
/// Get ID of this object. /// Get ID of this object.
object_id_type id() const { object_id_type id() const noexcept {
return m_id; return m_id;
} }
/// Get absolute value of the ID of this object. /// Get absolute value of the ID of this object.
unsigned_object_id_type positive_id() const { unsigned_object_id_type positive_id() const noexcept {
return static_cast<unsigned_object_id_type>(std::abs(m_id)); return static_cast<unsigned_object_id_type>(std::abs(m_id));
} }
/** /**
* Set ID of this object. * Set ID of this object.
* *
* @return Reference to object to make calls chainable. * @returns Reference to object to make calls chainable.
*/ */
OSMObject& id(object_id_type id) { OSMObject& set_id(object_id_type id) noexcept {
m_id = id; m_id = id;
return *this; return *this;
} }
@ -151,28 +128,28 @@ namespace osmium {
/** /**
* Set ID of this object. * Set ID of this object.
* *
* @return Reference to object to make calls chainable. * @returns Reference to object to make calls chainable.
*/ */
OSMObject& id(const char* id) { OSMObject& set_id(const char* id) {
return this->id(osmium::string_to_object_id(id)); return set_id(osmium::string_to_object_id(id));
} }
/// Is this object marked as deleted? /// Is this object marked as deleted?
bool deleted() const { bool deleted() const noexcept {
return m_deleted; return m_deleted;
} }
/// Is this object marked visible (ie not deleted)? /// Is this object marked visible (ie not deleted)?
bool visible() const { bool visible() const noexcept {
return !deleted(); return !deleted();
} }
/** /**
* Mark this object as deleted (or not). * Mark this object as deleted (or not).
* *
* @return Reference to object to make calls chainable. * @returns Reference to object to make calls chainable.
*/ */
OSMObject& deleted(bool deleted) { OSMObject& set_deleted(bool deleted) noexcept {
m_deleted = deleted; m_deleted = deleted;
return *this; return *this;
} }
@ -180,9 +157,9 @@ namespace osmium {
/** /**
* Mark this object as visible (ie not deleted) (or not). * Mark this object as visible (ie not deleted) (or not).
* *
* @return Reference to object to make calls chainable. * @returns Reference to object to make calls chainable.
*/ */
OSMObject& visible(bool visible) { OSMObject& set_visible(bool visible) noexcept {
m_deleted = !visible; m_deleted = !visible;
return *this; return *this;
} }
@ -191,13 +168,13 @@ namespace osmium {
* Mark this object as visible (ie not deleted) or deleted. * Mark this object as visible (ie not deleted) or deleted.
* *
* @param visible Either "true" or "false" * @param visible Either "true" or "false"
* @return Reference to object to make calls chainable. * @returns Reference to object to make calls chainable.
*/ */
OSMObject& visible(const char* visible) { OSMObject& set_visible(const char* visible) {
if (!strcmp("true", visible)) { if (!strcmp("true", visible)) {
this->visible(true); set_visible(true);
} else if (!strcmp("false", visible)) { } else if (!strcmp("false", visible)) {
this->visible(false); set_visible(false);
} else { } else {
throw std::invalid_argument("Unknown value for visible attribute (allowed is 'true' or 'false')"); throw std::invalid_argument("Unknown value for visible attribute (allowed is 'true' or 'false')");
} }
@ -205,16 +182,16 @@ namespace osmium {
} }
/// Get version of this object. /// Get version of this object.
object_version_type version() const { object_version_type version() const noexcept {
return m_version; return m_version;
} }
/** /**
* Set object version. * Set object version.
* *
* @return Reference to object to make calls chainable. * @returns Reference to object to make calls chainable.
*/ */
OSMObject& version(object_version_type version) { OSMObject& set_version(object_version_type version) noexcept {
m_version = version; m_version = version;
return *this; return *this;
} }
@ -222,23 +199,23 @@ namespace osmium {
/** /**
* Set object version. * Set object version.
* *
* @return Reference to object to make calls chainable. * @returns Reference to object to make calls chainable.
*/ */
OSMObject& version(const char* version) { OSMObject& set_version(const char* version) {
return this->version(string_to_object_version(version)); return set_version(string_to_object_version(version));
} }
/// Get changeset id of this object. /// Get changeset id of this object.
changeset_id_type changeset() const { changeset_id_type changeset() const noexcept {
return m_changeset; return m_changeset;
} }
/** /**
* Set changeset id of this object. * Set changeset id of this object.
* *
* @return Reference to object to make calls chainable. * @returns Reference to object to make calls chainable.
*/ */
OSMObject& changeset(changeset_id_type changeset) { OSMObject& set_changeset(changeset_id_type changeset) noexcept {
m_changeset = changeset; m_changeset = changeset;
return *this; return *this;
} }
@ -246,23 +223,23 @@ namespace osmium {
/** /**
* Set changeset id of this object. * Set changeset id of this object.
* *
* @return Reference to object to make calls chainable. * @returns Reference to object to make calls chainable.
*/ */
OSMObject& changeset(const char* changeset) { OSMObject& set_changeset(const char* changeset) {
return this->changeset(string_to_changeset_id(changeset)); return set_changeset(string_to_changeset_id(changeset));
} }
/// Get user id of this object. /// Get user id of this object.
user_id_type uid() const { user_id_type uid() const noexcept {
return m_uid; return m_uid;
} }
/** /**
* Set user id of this object. * Set user id of this object.
* *
* @return Reference to object to make calls chainable. * @returns Reference to object to make calls chainable.
*/ */
OSMObject& uid(user_id_type uid) { OSMObject& set_uid(user_id_type uid) noexcept {
m_uid = uid; m_uid = uid;
return *this; return *this;
} }
@ -271,9 +248,9 @@ namespace osmium {
* Set user id of this object. * Set user id of this object.
* Sets uid to 0 (anonymous) if the given uid is smaller than 0. * Sets uid to 0 (anonymous) if the given uid is smaller than 0.
* *
* @return Reference to object to make calls chainable. * @returns Reference to object to make calls chainable.
*/ */
OSMObject& uid_from_signed(signed_user_id_type uid) { OSMObject& set_uid_from_signed(signed_user_id_type uid) noexcept {
m_uid = uid < 0 ? 0 : static_cast<user_id_type>(uid); m_uid = uid < 0 ? 0 : static_cast<user_id_type>(uid);
return *this; return *this;
} }
@ -281,19 +258,19 @@ namespace osmium {
/** /**
* Set user id of this object. * Set user id of this object.
* *
* @return Reference to object to make calls chainable. * @returns Reference to object to make calls chainable.
*/ */
OSMObject& uid(const char* uid) { OSMObject& set_uid(const char* uid) {
return this->uid_from_signed(string_to_user_id(uid)); return set_uid_from_signed(string_to_user_id(uid));
} }
/// Is this user anonymous? /// Is this user anonymous?
bool user_is_anonymous() const { bool user_is_anonymous() const noexcept {
return m_uid == 0; return m_uid == 0;
} }
/// Get timestamp when this object last changed. /// Get timestamp when this object last changed.
osmium::Timestamp timestamp() const { osmium::Timestamp timestamp() const noexcept {
return m_timestamp; return m_timestamp;
} }
@ -301,26 +278,21 @@ namespace osmium {
* Set the timestamp when this object last changed. * Set the timestamp when this object last changed.
* *
* @param timestamp Timestamp * @param timestamp Timestamp
* @return Reference to object to make calls chainable. * @returns Reference to object to make calls chainable.
*/ */
OSMObject& timestamp(const osmium::Timestamp timestamp) { OSMObject& set_timestamp(const osmium::Timestamp timestamp) noexcept {
m_timestamp = timestamp; m_timestamp = timestamp;
return *this; return *this;
} }
/// Get user name for this object. /// Get user name for this object.
const char* user() const { const char* user() const noexcept {
return reinterpret_cast<const char*>(data() + sizeof_object()); return reinterpret_cast<const char*>(data() + sizeof_object());
} }
/// Get the list of tags for this object.
TagList& tags() {
return subitem_of_type<TagList>();
}
/// Get the list of tags for this object. /// Get the list of tags for this object.
const TagList& tags() const { const TagList& tags() const {
return subitem_of_type<const TagList>(); return osmium::detail::subitem_of_type<const TagList>(cbegin(), cend());
} }
/** /**
@ -341,17 +313,17 @@ namespace osmium {
*/ */
void set_attribute(const char* attr, const char* value) { void set_attribute(const char* attr, const char* value) {
if (!strcmp(attr, "id")) { if (!strcmp(attr, "id")) {
id(value); set_id(value);
} else if (!strcmp(attr, "version")) { } else if (!strcmp(attr, "version")) {
version(value); set_version(value);
} else if (!strcmp(attr, "changeset")) { } else if (!strcmp(attr, "changeset")) {
changeset(value); set_changeset(value);
} else if (!strcmp(attr, "timestamp")) { } else if (!strcmp(attr, "timestamp")) {
timestamp(osmium::Timestamp(value)); set_timestamp(osmium::Timestamp(value));
} else if (!strcmp(attr, "uid")) { } else if (!strcmp(attr, "uid")) {
uid(value); set_uid(value);
} else if (!strcmp(attr, "visible")) { } else if (!strcmp(attr, "visible")) {
visible(value); set_visible(value);
} }
} }
@ -363,7 +335,7 @@ namespace osmium {
} }
iterator end() { iterator end() {
return iterator(data() + padded_size()); return iterator(next());
} }
const_iterator cbegin() const { const_iterator cbegin() const {
@ -371,7 +343,7 @@ namespace osmium {
} }
const_iterator cend() const { const_iterator cend() const {
return const_iterator(data() + padded_size()); return const_iterator(next());
} }
const_iterator begin() const { const_iterator begin() const {
@ -382,6 +354,42 @@ namespace osmium {
return cend(); return cend();
} }
template <class T>
using t_iterator = osmium::memory::ItemIterator<T>;
template <class T>
using t_const_iterator = osmium::memory::ItemIterator<const T>;
template <class T>
t_iterator<T> begin() {
return t_iterator<T>(subitems_position(), next());
}
template <class T>
t_iterator<T> end() {
return t_iterator<T>(next(), next());
}
template <class T>
t_const_iterator<T> cbegin() const {
return t_const_iterator<T>(subitems_position(), next());
}
template <class T>
t_const_iterator<T> cend() const {
return t_const_iterator<T>(next(), next());
}
template <class T>
t_const_iterator<T> begin() const {
return cbegin<T>();
}
template <class T>
t_const_iterator<T> end() const {
return cend<T>();
}
}; // class OSMObject }; // class OSMObject
static_assert(sizeof(OSMObject) % osmium::memory::align_bytes == 0, "Class osmium::OSMObject has wrong size to be aligned properly!"); static_assert(sizeof(OSMObject) % osmium::memory::align_bytes == 0, "Class osmium::OSMObject has wrong size to be aligned properly!");
@ -389,13 +397,13 @@ namespace osmium {
/** /**
* OSMObjects are equal if their type, id, and version are equal. * OSMObjects are equal if their type, id, and version are equal.
*/ */
inline bool operator==(const OSMObject& lhs, const OSMObject& rhs) { inline bool operator==(const OSMObject& lhs, const OSMObject& rhs) noexcept {
return lhs.type() == rhs.type() && return lhs.type() == rhs.type() &&
lhs.id() == rhs.id() && lhs.id() == rhs.id() &&
lhs.version() == rhs.version(); lhs.version() == rhs.version();
} }
inline bool operator!=(const OSMObject& lhs, const OSMObject& rhs) { inline bool operator!=(const OSMObject& lhs, const OSMObject& rhs) noexcept {
return ! (lhs == rhs); return ! (lhs == rhs);
} }
@ -404,7 +412,7 @@ namespace osmium {
* Note that we use the absolute value of the id for a * Note that we use the absolute value of the id for a
* better ordering of objects with negative id. * better ordering of objects with negative id.
*/ */
inline bool operator<(const OSMObject& lhs, const OSMObject& rhs) { inline bool operator<(const OSMObject& lhs, const OSMObject& rhs) noexcept {
if (lhs.type() != rhs.type()) { if (lhs.type() != rhs.type()) {
return lhs.type() < rhs.type(); return lhs.type() < rhs.type();
} }
@ -412,15 +420,15 @@ namespace osmium {
lhs.positive_id() < rhs.positive_id(); lhs.positive_id() < rhs.positive_id();
} }
inline bool operator>(const OSMObject& lhs, const OSMObject& rhs) { inline bool operator>(const OSMObject& lhs, const OSMObject& rhs) noexcept {
return rhs < lhs; return rhs < lhs;
} }
inline bool operator<=(const OSMObject& lhs, const OSMObject& rhs) { inline bool operator<=(const OSMObject& lhs, const OSMObject& rhs) noexcept {
return ! (rhs < lhs); return ! (rhs < lhs);
} }
inline bool operator>=(const OSMObject& lhs, const OSMObject& rhs) { inline bool operator>=(const OSMObject& lhs, const OSMObject& rhs) noexcept {
return ! (lhs < rhs); return ! (lhs < rhs);
} }

View File

@ -1,110 +1,110 @@
#ifndef OSMIUM_OSM_OBJECT_COMPARISONS_HPP #ifndef OSMIUM_OSM_OBJECT_COMPARISONS_HPP
#define OSMIUM_OSM_OBJECT_COMPARISONS_HPP #define OSMIUM_OSM_OBJECT_COMPARISONS_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <osmium/osm/object.hpp> #include <osmium/osm/object.hpp>
namespace osmium { namespace osmium {
/** /**
* Function object class for comparing OSM objects for equality by type, id, and version. * Function object class for comparing OSM objects for equality by type, id, and version.
*/ */
struct object_equal_type_id_version { struct object_equal_type_id_version {
bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const { bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
return lhs == rhs; return lhs == rhs;
} }
bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const { bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
return *lhs == *rhs; return *lhs == *rhs;
} }
}; // struct object_equal_type_id_version }; // struct object_equal_type_id_version
/** /**
* Function object class for comparing OSM objects for equality by type and id, * Function object class for comparing OSM objects for equality by type and id,
* ignoring the version. * ignoring the version.
*/ */
struct object_equal_type_id { struct object_equal_type_id {
bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const { bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
return lhs.type() == rhs.type() && return lhs.type() == rhs.type() &&
lhs.id() == rhs.id(); lhs.id() == rhs.id();
} }
bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const { bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
return operator()(*lhs, *rhs); return operator()(*lhs, *rhs);
} }
}; // struct object_equal_type_id }; // struct object_equal_type_id
/** /**
* Function object class for ordering OSM objects by type, id, and version. * Function object class for ordering OSM objects by type, id, and version.
*/ */
struct object_order_type_id_version { struct object_order_type_id_version {
bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const { bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
return lhs < rhs; return lhs < rhs;
} }
bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const { bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
return *lhs < *rhs; return *lhs < *rhs;
} }
}; // struct object_order_type_id_version }; // struct object_order_type_id_version
/** /**
* Function object class for ordering OSM objects by type, id, and reverse version, * Function object class for ordering OSM objects by type, id, and reverse version,
* ie objects are ordered by type and id, but later versions of an object are * ie objects are ordered by type and id, but later versions of an object are
* ordered before earlier versions of the same object. * ordered before earlier versions of the same object.
*/ */
struct object_order_type_id_reverse_version { struct object_order_type_id_reverse_version {
bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const { bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
if (lhs.type() != rhs.type()) { if (lhs.type() != rhs.type()) {
return lhs.type() < rhs.type(); return lhs.type() < rhs.type();
} }
return (lhs.id() == rhs.id() && lhs.version() > rhs.version()) || return (lhs.id() == rhs.id() && lhs.version() > rhs.version()) ||
lhs.positive_id() < rhs.positive_id(); lhs.positive_id() < rhs.positive_id();
} }
bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const { bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
return operator()(*lhs, *rhs); return operator()(*lhs, *rhs);
} }
}; // struct object_order_type_id_reverse_version }; // struct object_order_type_id_reverse_version
} // namespace osmium } // namespace osmium
#endif // OSMIUM_OSM_OBJECT_COMPARISONS_HPP #endif // OSMIUM_OSM_OBJECT_COMPARISONS_HPP

View File

@ -93,7 +93,7 @@ namespace osmium {
} }
} }
void set_role_size(string_size_type size) { void set_role_size(string_size_type size) noexcept {
m_role_size = size; m_role_size = size;
} }
@ -101,34 +101,34 @@ namespace osmium {
static constexpr item_type collection_type = item_type::relation_member_list; static constexpr item_type collection_type = item_type::relation_member_list;
RelationMember(const object_id_type ref=0, const item_type type=item_type(), const bool full=false) : RelationMember(const object_id_type ref=0, const item_type type=item_type(), const bool full=false) noexcept :
m_ref(ref), m_ref(ref),
m_type(type), m_type(type),
m_flags(full ? 1 : 0) { m_flags(full ? 1 : 0) {
} }
object_id_type ref() const { object_id_type ref() const noexcept {
return m_ref; return m_ref;
} }
RelationMember& ref(object_id_type ref) { RelationMember& ref(object_id_type ref) noexcept {
m_ref = ref; m_ref = ref;
return *this; return *this;
} }
unsigned_object_id_type positive_ref() const { unsigned_object_id_type positive_ref() const noexcept {
return static_cast<unsigned_object_id_type>(std::abs(m_ref)); return static_cast<unsigned_object_id_type>(std::abs(m_ref));
} }
item_type type() const { item_type type() const noexcept {
return m_type; return m_type;
} }
bool full_member() const { bool full_member() const noexcept {
return m_flags == 1; return m_flags == 1;
} }
const char* role() const { const char* role() const noexcept {
return reinterpret_cast<const char*>(data() + sizeof(RelationMember)); return reinterpret_cast<const char*>(data() + sizeof(RelationMember));
} }
@ -164,7 +164,7 @@ namespace osmium {
friend class osmium::builder::ObjectBuilder<osmium::Relation>; friend class osmium::builder::ObjectBuilder<osmium::Relation>;
Relation() : Relation() noexcept :
OSMObject(sizeof(Relation), osmium::item_type::relation) { OSMObject(sizeof(Relation), osmium::item_type::relation) {
} }
@ -173,11 +173,11 @@ namespace osmium {
static constexpr osmium::item_type itemtype = osmium::item_type::relation; static constexpr osmium::item_type itemtype = osmium::item_type::relation;
RelationMemberList& members() { RelationMemberList& members() {
return subitem_of_type<RelationMemberList>(); return osmium::detail::subitem_of_type<RelationMemberList>(begin(), end());
} }
const RelationMemberList& members() const { const RelationMemberList& members() const {
return subitem_of_type<const RelationMemberList>(); return osmium::detail::subitem_of_type<const RelationMemberList>(cbegin(), cend());
} }
}; // class Relation }; // class Relation

View File

@ -51,7 +51,7 @@ namespace osmium {
public: public:
explicit constexpr Segment(const osmium::Location& location1, const osmium::Location& location2) : explicit constexpr Segment(const osmium::Location& location1, const osmium::Location& location2) noexcept :
m_first(location1), m_first(location1),
m_second(location2) { m_second(location2) {
} }
@ -65,12 +65,12 @@ namespace osmium {
~Segment() = default; ~Segment() = default;
/// Return first Location of Segment. /// Return first Location of Segment.
OSMIUM_CONSTEXPR osmium::Location first() const { OSMIUM_CONSTEXPR osmium::Location first() const noexcept {
return m_first; return m_first;
} }
/// Return second Location of Segment. /// Return second Location of Segment.
OSMIUM_CONSTEXPR osmium::Location second() const { OSMIUM_CONSTEXPR osmium::Location second() const noexcept {
return m_second; return m_second;
} }
@ -84,11 +84,11 @@ namespace osmium {
}; // class Segment }; // class Segment
/// Segments are equal if both their locations are equal /// Segments are equal if both their locations are equal
inline OSMIUM_CONSTEXPR bool operator==(const Segment& lhs, const Segment& rhs) { inline OSMIUM_CONSTEXPR bool operator==(const Segment& lhs, const Segment& rhs) noexcept {
return lhs.first() == rhs.first() && lhs.second() == rhs.second(); return lhs.first() == rhs.first() && lhs.second() == rhs.second();
} }
inline OSMIUM_CONSTEXPR bool operator!=(const Segment& lhs, const Segment& rhs) { inline OSMIUM_CONSTEXPR bool operator!=(const Segment& lhs, const Segment& rhs) noexcept {
return ! (lhs == rhs); return ! (lhs == rhs);
} }

View File

@ -76,7 +76,7 @@ namespace osmium {
static constexpr item_type collection_type = item_type::tag_list; static constexpr item_type collection_type = item_type::tag_list;
const char* key() const { const char* key() const noexcept {
return reinterpret_cast<const char*>(data()); return reinterpret_cast<const char*>(data());
} }

View File

@ -67,13 +67,13 @@ namespace osmium {
public: public:
constexpr Timestamp() : constexpr Timestamp() noexcept :
m_timestamp(0) { m_timestamp(0) {
} }
// Not "explicit" so that conversions from time_t work // Not "explicit" so that conversions from time_t work
// like in node.timestamp(123); // like in node.timestamp(123);
constexpr Timestamp(time_t timestamp) : constexpr Timestamp(time_t timestamp) noexcept :
m_timestamp(static_cast<uint32_t>(timestamp)) { m_timestamp(static_cast<uint32_t>(timestamp)) {
} }
@ -82,7 +82,7 @@ namespace osmium {
* Throws std::invalid_argument, if the timestamp can not be parsed. * Throws std::invalid_argument, if the timestamp can not be parsed.
*/ */
explicit Timestamp(const char* timestamp) { explicit Timestamp(const char* timestamp) {
#ifndef WIN32 #ifndef _WIN32
struct tm tm { struct tm tm {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}; };
@ -105,14 +105,24 @@ namespace osmium {
#endif #endif
} }
constexpr time_t seconds_since_epoch() const { constexpr time_t seconds_since_epoch() const noexcept {
return static_cast<time_t>(m_timestamp); return static_cast<time_t>(m_timestamp);
} }
constexpr operator time_t() const { constexpr operator time_t() const noexcept {
return static_cast<time_t>(m_timestamp); return static_cast<time_t>(m_timestamp);
} }
template <typename T>
void operator+=(T time_difference) noexcept {
m_timestamp += time_difference;
}
template <typename T>
void operator-=(T time_difference) noexcept {
m_timestamp -= time_difference;
}
/** /**
* Return UTC Unix time as string in ISO date/time format. * Return UTC Unix time as string in ISO date/time format.
*/ */
@ -140,11 +150,11 @@ namespace osmium {
}; // class Timestamp }; // class Timestamp
inline OSMIUM_CONSTEXPR Timestamp start_of_time() { inline OSMIUM_CONSTEXPR Timestamp start_of_time() noexcept {
return Timestamp(1); return Timestamp(1);
} }
inline OSMIUM_CONSTEXPR Timestamp end_of_time() { inline OSMIUM_CONSTEXPR Timestamp end_of_time() noexcept {
return Timestamp(std::numeric_limits<time_t>::max()); return Timestamp(std::numeric_limits<time_t>::max());
} }

View File

@ -71,19 +71,19 @@ namespace osmium {
* segment. The first() location is checked first() and only if they have the * segment. The first() location is checked first() and only if they have the
* same first() location the second() location is taken into account. * same first() location the second() location is taken into account.
*/ */
inline bool operator<(const UndirectedSegment& lhs, const UndirectedSegment& rhs) { inline bool operator<(const UndirectedSegment& lhs, const UndirectedSegment& rhs) noexcept {
return (lhs.first() == rhs.first() && lhs.second() < rhs.second()) || lhs.first() < rhs.first(); return (lhs.first() == rhs.first() && lhs.second() < rhs.second()) || lhs.first() < rhs.first();
} }
inline bool operator>(const UndirectedSegment& lhs, const UndirectedSegment& rhs) { inline bool operator>(const UndirectedSegment& lhs, const UndirectedSegment& rhs) noexcept {
return rhs < lhs; return rhs < lhs;
} }
inline bool operator<=(const UndirectedSegment& lhs, const UndirectedSegment& rhs) { inline bool operator<=(const UndirectedSegment& lhs, const UndirectedSegment& rhs) noexcept {
return ! (rhs < lhs); return ! (rhs < lhs);
} }
inline bool operator>=(const UndirectedSegment& lhs, const UndirectedSegment& rhs) { inline bool operator>=(const UndirectedSegment& lhs, const UndirectedSegment& rhs) noexcept {
return ! (lhs < rhs); return ! (lhs < rhs);
} }

View File

@ -1,115 +1,115 @@
#ifndef OSMIUM_OSM_WAY_HPP #ifndef OSMIUM_OSM_WAY_HPP
#define OSMIUM_OSM_WAY_HPP #define OSMIUM_OSM_WAY_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <osmium/memory/item.hpp> #include <osmium/memory/item.hpp>
#include <osmium/osm/item_type.hpp> #include <osmium/osm/item_type.hpp>
#include <osmium/osm/object.hpp> #include <osmium/osm/object.hpp>
#include <osmium/osm/types.hpp> #include <osmium/osm/types.hpp>
#include <osmium/osm/node_ref.hpp> #include <osmium/osm/node_ref.hpp>
#include <osmium/osm/node_ref_list.hpp> #include <osmium/osm/node_ref_list.hpp>
namespace osmium { namespace osmium {
namespace builder { namespace builder {
template <class T> class ObjectBuilder; template <class T> class ObjectBuilder;
} }
/** /**
* List of node references (id and location) in a way. * List of node references (id and location) in a way.
*/ */
class WayNodeList : public NodeRefList<osmium::item_type::way_node_list> { class WayNodeList : public NodeRefList<osmium::item_type::way_node_list> {
public: public:
WayNodeList(): WayNodeList():
NodeRefList<osmium::item_type::way_node_list>() { NodeRefList<osmium::item_type::way_node_list>() {
} }
}; // class WayNodeList }; // class WayNodeList
static_assert(sizeof(WayNodeList) % osmium::memory::align_bytes == 0, "Class osmium::WayNodeList has wrong size to be aligned properly!"); static_assert(sizeof(WayNodeList) % osmium::memory::align_bytes == 0, "Class osmium::WayNodeList has wrong size to be aligned properly!");
class Way : public OSMObject { class Way : public OSMObject {
friend class osmium::builder::ObjectBuilder<osmium::Way>; friend class osmium::builder::ObjectBuilder<osmium::Way>;
Way() : Way() noexcept :
OSMObject(sizeof(Way), osmium::item_type::way) { OSMObject(sizeof(Way), osmium::item_type::way) {
} }
public: public:
WayNodeList& nodes() { WayNodeList& nodes() {
return subitem_of_type<WayNodeList>(); return osmium::detail::subitem_of_type<WayNodeList>(begin(), end());
} }
const WayNodeList& nodes() const { const WayNodeList& nodes() const {
return subitem_of_type<const WayNodeList>(); return osmium::detail::subitem_of_type<const WayNodeList>(cbegin(), cend());
} }
/** /**
* Update all nodes in a way with the ID of the given NodeRef with the * Update all nodes in a way with the ID of the given NodeRef with the
* location of the given NodeRef. * location of the given NodeRef.
*/ */
void update_node_location(const NodeRef& new_node_ref) { void update_node_location(const NodeRef& new_node_ref) {
for (auto& node_ref : nodes()) { for (auto& node_ref : nodes()) {
if (node_ref.ref() == new_node_ref.ref()) { if (node_ref.ref() == new_node_ref.ref()) {
node_ref.location(new_node_ref.location()); node_ref.set_location(new_node_ref.location());
} }
} }
} }
/** /**
* Do the nodes in this way form a closed ring? * Do the nodes in this way form a closed ring?
*/ */
bool is_closed() const { bool is_closed() const {
return nodes().is_closed(); return nodes().is_closed();
} }
bool ends_have_same_id() const { bool ends_have_same_id() const {
return nodes().ends_have_same_id(); return nodes().ends_have_same_id();
} }
bool ends_have_same_location() const { bool ends_have_same_location() const {
return nodes().ends_have_same_location(); return nodes().ends_have_same_location();
} }
}; // class Way }; // class Way
static_assert(sizeof(Way) % osmium::memory::align_bytes == 0, "Class osmium::Way has wrong size to be aligned properly!"); static_assert(sizeof(Way) % osmium::memory::align_bytes == 0, "Class osmium::Way has wrong size to be aligned properly!");
} // namespace osmium } // namespace osmium
#endif // OSMIUM_OSM_WAY_HPP #endif // OSMIUM_OSM_WAY_HPP

File diff suppressed because it is too large Load Diff

View File

@ -1,131 +1,158 @@
#ifndef OSMIUM_RELATIONS_DETAIL_MEMBER_META_HPP #ifndef OSMIUM_RELATIONS_DETAIL_MEMBER_META_HPP
#define OSMIUM_RELATIONS_DETAIL_MEMBER_META_HPP #define OSMIUM_RELATIONS_DETAIL_MEMBER_META_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <cstddef> #include <algorithm>
#include <iosfwd> #include <cstddef>
#include <iosfwd>
#include <osmium/osm/types.hpp> #include <iterator>
namespace osmium { #include <osmium/osm/types.hpp>
namespace relations { namespace osmium {
/** namespace relations {
* Helper class for the Collector class.
* /**
* Stores an object ID and information where the object should be * Helper class for the Collector class.
* stored. *
*/ * Stores an object ID and information where the object should be
class MemberMeta { * stored.
*/
/** class MemberMeta {
* Object ID of this relation member. Can be a node, way, or relation ID.
* It depends on the vector in which this object is stored which kind of /**
* object is referenced here. * Object ID of this relation member. Can be a node, way, or relation ID.
*/ * It depends on the vector in which this object is stored which kind of
osmium::object_id_type m_member_id; * object is referenced here.
*/
/** osmium::object_id_type m_member_id;
* Position of the relation this member is a part of in the
* m_relations vector. /**
*/ * Position of the relation this member is a part of in the
size_t m_relation_pos; * m_relations vector.
*/
/** size_t m_relation_pos;
* Position of this member in the list of members of the
* relation this member is a part of. /**
*/ * Position of this member in the list of members of the
size_t m_member_pos; * relation this member is a part of.
*/
/** size_t m_member_pos;
* Offset in the buffer where the object is stored.
*/ /**
size_t m_buffer_offset { 0 }; * Offset in the buffer where the object is stored.
*/
public: size_t m_buffer_offset { 0 };
/** bool m_removed = false;
* Create new MemberMeta. The variant with zeros for relation_pos and
* member_pos is used to create dummy MemberMeta that can be compared public:
* to the MemberMeta in the vectors using the equal_range algorithm.
*/ /**
explicit MemberMeta(osmium::object_id_type member_id, size_t relation_pos=0, size_t member_pos=0) : * Create new MemberMeta. The variant with zeros for relation_pos and
m_member_id(member_id), * member_pos is used to create dummy MemberMeta that can be compared
m_relation_pos(relation_pos), * to the MemberMeta in the vectors using the equal_range algorithm.
m_member_pos(member_pos) { */
} explicit MemberMeta(osmium::object_id_type member_id, size_t relation_pos=0, size_t member_pos=0) noexcept :
m_member_id(member_id),
osmium::object_id_type member_id() const { m_relation_pos(relation_pos),
return m_member_id; m_member_pos(member_pos) {
} }
size_t relation_pos() const { osmium::object_id_type member_id() const noexcept {
return m_relation_pos; return m_member_id;
} }
size_t member_pos() const { size_t relation_pos() const noexcept {
return m_member_pos; return m_relation_pos;
} }
size_t buffer_offset() const { size_t member_pos() const noexcept {
return m_buffer_offset; return m_member_pos;
} }
void buffer_offset(size_t offset) { size_t buffer_offset() const noexcept {
m_buffer_offset = offset; return m_buffer_offset;
} }
}; // class MemberMeta void set_buffer_offset(size_t offset) noexcept {
m_buffer_offset = offset;
/** }
* Compares two MemberMeta objects by only looking at the member id.
* Used to sort a vector of MemberMeta objects and to later find bool removed() const noexcept {
* them using binary search. return m_removed;
*/ }
inline bool operator<(const MemberMeta& a, const MemberMeta& b) {
return a.member_id() < b.member_id(); void remove() noexcept {
} m_removed = true;
}
template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const MemberMeta& mm) { }; // class MemberMeta
out << "MemberMeta(member_id=" << mm.member_id() << " relation_pos=" << mm.relation_pos() << " member_pos=" << mm.member_pos() << " buffer_offset=" << mm.buffer_offset() << ")";
return out; /**
} * Compares two MemberMeta objects by only looking at the member id.
* Used to sort a vector of MemberMeta objects and to later find
} // namespace relations * them using binary search.
*/
} // namespace osmium inline bool operator<(const MemberMeta& a, const MemberMeta& b) noexcept {
return a.member_id() < b.member_id();
#endif // OSMIUM_RELATIONS_DETAIL_MEMBER_META_HPP }
template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const MemberMeta& mm) {
out << "MemberMeta(member_id=" << mm.member_id() << " relation_pos=" << mm.relation_pos() << " member_pos=" << mm.member_pos() << " buffer_offset=" << mm.buffer_offset() << ")";
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 <class 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
#endif // OSMIUM_RELATIONS_DETAIL_MEMBER_META_HPP

View File

@ -1,136 +1,136 @@
#ifndef OSMIUM_RELATIONS_DETAIL_RELATION_META_HPP #ifndef OSMIUM_RELATIONS_DETAIL_RELATION_META_HPP
#define OSMIUM_RELATIONS_DETAIL_RELATION_META_HPP #define OSMIUM_RELATIONS_DETAIL_RELATION_META_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <iosfwd> #include <iosfwd>
namespace osmium { namespace osmium {
namespace relations { namespace relations {
/** /**
* Helper class for the Collector class. * Helper class for the Collector class.
* *
* Stores information needed to collect all members of a relation. This * Stores information needed to collect all members of a relation. This
* includes the offset of the relation in a buffer plus the information * includes the offset of the relation in a buffer plus the information
* needed to add members to this relation. * needed to add members to this relation.
*/ */
class RelationMeta { class RelationMeta {
/// The relation we are assembling. /// The relation we are assembling.
size_t m_relation_offset; size_t m_relation_offset;
/** /**
* The number of members still needed before the relation is complete. * The number of members still needed before the relation is
* This will be set to the number of members we are interested in and * complete. This will be set to the number of members we are
* then count down for every member we find. When it is 0, the relation * interested in and then count down for every member we find.
* is complete. * When it is 0, the relation is complete.
*/ */
int m_need_members = 0; int m_need_members = 0;
public: public:
/** /**
* Initialize an empty RelationMeta. This is needed to zero out relations * Initialize an empty RelationMeta. This is needed to zero out
* that have been completed. * relations that have been completed.
*/ */
RelationMeta() : RelationMeta() noexcept :
m_relation_offset(0) { m_relation_offset(0) {
} }
explicit RelationMeta(size_t relation_offset) : explicit RelationMeta(size_t relation_offset) noexcept :
m_relation_offset(relation_offset) { m_relation_offset(relation_offset) {
} }
/** /**
* Get offset of relation in buffer. * Get offset of relation in buffer.
*/ */
size_t relation_offset() const { size_t relation_offset() const noexcept {
return m_relation_offset; return m_relation_offset;
} }
/** /**
* Increment the m_need_members counter. * Increment the m_need_members counter.
*/ */
void increment_need_members() { void increment_need_members() noexcept {
++m_need_members; ++m_need_members;
} }
/** /**
* This decrements the "members needed" counter. * This decrements the "members needed" counter.
*/ */
void got_one_member() { void got_one_member() {
assert(m_need_members > 0); assert(m_need_members > 0);
--m_need_members; --m_need_members;
} }
/** /**
* Returns true if all members for this relation are available. * Returns true if all members for this relation are available.
*/ */
bool has_all_members() const { bool has_all_members() const noexcept {
return m_need_members == 0; return m_need_members == 0;
} }
}; // class RelationMeta }; // class RelationMeta
template <typename TChar, typename TTraits> template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const RelationMeta& rm) { inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const RelationMeta& rm) {
out << "RelationMeta(relation_offset=" << rm.relation_offset() << " has_all_members=" << rm.has_all_members() << ")"; out << "RelationMeta(relation_offset=" << rm.relation_offset() << " has_all_members=" << rm.has_all_members() << ")";
return out; return out;
} }
/** /**
* Function object to check if a relation is complete. * Function object to check if a relation is complete.
*/ */
struct has_all_members { struct has_all_members {
typedef RelationMeta& argument_type; typedef RelationMeta& argument_type;
typedef bool result_type; typedef bool result_type;
/** /**
* @return true if this relation is complete, false otherwise. * @returns true if this relation is complete, false otherwise.
*/ */
bool operator()(RelationMeta& relation_info) const { bool operator()(RelationMeta& relation_info) const {
return relation_info.has_all_members(); return relation_info.has_all_members();
} }
}; // struct has_all_members }; // struct has_all_members
} // namespace relations } // namespace relations
} // namespace osmium } // namespace osmium
#endif // OSMIUM_RELATIONS_DETAIL_RELATION_META_HPP #endif // OSMIUM_RELATIONS_DETAIL_RELATION_META_HPP

View File

@ -51,27 +51,27 @@ namespace osmium {
bool operator()(const TKey& rule_key, const char* tag_key) { bool operator()(const TKey& rule_key, const char* tag_key) {
return rule_key == tag_key; return rule_key == tag_key;
} }
}; }; // struct match_key
struct match_key_prefix { struct match_key_prefix {
bool operator()(const std::string& rule_key, const char* tag_key) { bool operator()(const std::string& rule_key, const char* tag_key) {
return rule_key.compare(0, std::string::npos, tag_key, 0, rule_key.size()) == 0; return rule_key.compare(0, std::string::npos, tag_key, 0, rule_key.size()) == 0;
} }
}; }; // struct match_key_prefix
template <class TValue> template <class TValue>
struct match_value { struct match_value {
bool operator()(const TValue& rule_value, const char* tag_value) { bool operator()(const TValue& rule_value, const char* tag_value) {
return rule_value == tag_value; return rule_value == tag_value;
} }
}; }; // struct match_value
template <> template <>
struct match_value<void> { struct match_value<void> {
bool operator()(const bool, const char*) { bool operator()(const bool, const char*) {
return true; return true;
} }
}; }; // struct match_value<void>
template <class TKey, class TValue=void, class TKeyComp=match_key<TKey>, class TValueComp=match_value<TValue>> template <class TKey, class TValue=void, class TKeyComp=match_key<TKey>, class TValueComp=match_value<TValue>>
class Filter { class Filter {
@ -99,7 +99,7 @@ namespace osmium {
result(r) { result(r) {
} }
}; }; // struct Rule
std::vector<Rule> m_rules; std::vector<Rule> m_rules;
bool m_default_result; bool m_default_result;
@ -135,7 +135,7 @@ namespace osmium {
return m_default_result; return m_default_result;
} }
}; // Filter }; // class Filter
typedef Filter<std::string, std::string> KeyValueFilter; typedef Filter<std::string, std::string> KeyValueFilter;
typedef Filter<std::string> KeyFilter; typedef Filter<std::string> KeyFilter;

View File

@ -1,58 +1,58 @@
#ifndef OSMIUM_TAGS_REGEX_FILTER_HPP #ifndef OSMIUM_TAGS_REGEX_FILTER_HPP
#define OSMIUM_TAGS_REGEX_FILTER_HPP #define OSMIUM_TAGS_REGEX_FILTER_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <regex> #include <regex>
#include <string> #include <string>
#include <osmium/tags/filter.hpp> #include <osmium/tags/filter.hpp>
namespace osmium { namespace osmium {
namespace tags { namespace tags {
template <> template <>
struct match_value<std::regex> { struct match_value<std::regex> {
bool operator()(const std::regex& rule_value, const char* tag_value) { bool operator()(const std::regex& rule_value, const char* tag_value) {
return std::regex_match(tag_value, rule_value); return std::regex_match(tag_value, rule_value);
} }
}; }; // struct match_value<std::regex>
typedef Filter<std::string, std::regex> RegexFilter; typedef Filter<std::string, std::regex> RegexFilter;
} // namespace tags } // namespace tags
} // namespace osmium } // namespace osmium
#endif // OSMIUM_TAGS_REGEX_FILTER_HPP #endif // OSMIUM_TAGS_REGEX_FILTER_HPP

View File

@ -1,104 +1,104 @@
#ifndef OSMIUM_THREAD_FUNCTION_WRAPPER_HPP #ifndef OSMIUM_THREAD_FUNCTION_WRAPPER_HPP
#define OSMIUM_THREAD_FUNCTION_WRAPPER_HPP #define OSMIUM_THREAD_FUNCTION_WRAPPER_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm> #include <algorithm>
#include <memory> #include <memory>
namespace osmium { namespace osmium {
namespace thread { namespace thread {
class function_wrapper { class function_wrapper {
struct impl_base { struct impl_base {
virtual void call() = 0; virtual void call() = 0;
virtual ~impl_base() { virtual ~impl_base() {
} }
}; }; // struct impl_base
std::unique_ptr<impl_base> impl; std::unique_ptr<impl_base> impl;
template <typename F> template <typename F>
struct impl_type : impl_base { struct impl_type : impl_base {
F m_functor; F m_functor;
impl_type(F&& functor) : impl_type(F&& functor) :
m_functor(std::move(functor)) { m_functor(std::move(functor)) {
} }
void call() { void call() {
m_functor(); m_functor();
} }
}; }; // struct impl_type
public: public:
// Constructor must not be "explicit" for wrapper // Constructor must not be "explicit" for wrapper
// to work seemlessly. // to work seemlessly.
template <typename F> template <typename F>
function_wrapper(F&& f) : function_wrapper(F&& f) :
impl(new impl_type<F>(std::move(f))) { impl(new impl_type<F>(std::move(f))) {
} }
void operator()() { void operator()() {
impl->call(); impl->call();
} }
function_wrapper() = default; function_wrapper() = default;
function_wrapper(function_wrapper&& other) : function_wrapper(function_wrapper&& other) :
impl(std::move(other.impl)) { impl(std::move(other.impl)) {
} }
function_wrapper& operator=(function_wrapper&& other) { function_wrapper& operator=(function_wrapper&& other) {
impl = std::move(other.impl); impl = std::move(other.impl);
return *this; return *this;
} }
function_wrapper(const function_wrapper&) = delete; function_wrapper(const function_wrapper&) = delete;
function_wrapper(function_wrapper&) = delete; function_wrapper(function_wrapper&) = delete;
function_wrapper& operator=(const function_wrapper&) = delete; function_wrapper& operator=(const function_wrapper&) = delete;
explicit operator bool() const { explicit operator bool() const {
return static_cast<bool>(impl); return static_cast<bool>(impl);
} }
}; // class function_wrapper }; // class function_wrapper
} // namespace thread } // namespace thread
} // namespace osmium } // namespace osmium
#endif // OSMIUM_THREAD_FUNCTION_WRAPPER_HPP #endif // OSMIUM_THREAD_FUNCTION_WRAPPER_HPP

View File

@ -1,180 +1,204 @@
#ifndef OSMIUM_THREAD_POOL_HPP #ifndef OSMIUM_THREAD_POOL_HPP
#define OSMIUM_THREAD_POOL_HPP #define OSMIUM_THREAD_POOL_HPP
/* /*
This file is part of Osmium (http://osmcode.org/libosmium). This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README). Copyright 2013,2014 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003 Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute, this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the 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 Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following: do so, all subject to the following:
The copyright notices in the Software and this entire statement, including The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer, 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 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 all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by works are solely in the form of machine-executable object code generated by
a source language processor. a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 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 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm> #include <algorithm>
#include <atomic> #include <atomic>
#include <cstddef> #include <cstddef>
#include <cstdlib> #include <cstdlib>
#include <future> #include <future>
#include <thread> #include <thread>
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
#include <osmium/thread/queue.hpp> #include <osmium/thread/queue.hpp>
#include <osmium/thread/name.hpp> #include <osmium/thread/name.hpp>
#include <osmium/thread/function_wrapper.hpp> #include <osmium/thread/function_wrapper.hpp>
namespace osmium { namespace osmium {
/** /**
* @brief Threading-related low-level code * @brief Threading-related low-level code
*/ */
namespace thread { namespace thread {
/** /**
* Thread pool. * Thread pool.
*/ */
class Pool { class Pool {
// This class makes sure pool threads are joined when the pool is destructed // This class makes sure pool threads are joined when the pool is destructed
class thread_joiner { class thread_joiner {
std::vector<std::thread>& m_threads; std::vector<std::thread>& m_threads;
public: public:
explicit thread_joiner(std::vector<std::thread>& threads) : explicit thread_joiner(std::vector<std::thread>& threads) :
m_threads(threads) { m_threads(threads) {
} }
~thread_joiner() { ~thread_joiner() {
for (auto& thread : m_threads) { for (auto& thread : m_threads) {
if (thread.joinable()) { if (thread.joinable()) {
thread.join(); thread.join();
} }
} }
} }
}; // class thread_joiner }; // class thread_joiner
std::atomic<bool> m_done; std::atomic<bool> m_done;
osmium::thread::Queue<function_wrapper> m_work_queue; osmium::thread::Queue<function_wrapper> m_work_queue;
std::vector<std::thread> m_threads; std::vector<std::thread> m_threads;
thread_joiner m_joiner; thread_joiner m_joiner;
int m_num_threads; int m_num_threads;
void worker_thread() { void worker_thread() {
osmium::thread::set_thread_name("_osmium_worker"); osmium::thread::set_thread_name("_osmium_worker");
while (!m_done) { while (!m_done) {
function_wrapper task; function_wrapper task;
m_work_queue.wait_and_pop_with_timeout(task); m_work_queue.wait_and_pop_with_timeout(task);
if (task) { if (task) {
task(); task();
} }
} }
} }
/** /**
* Create thread pool with the given number of threads. If * Create thread pool with the given number of threads. If
* num_threads is 0, the number of threads is read from * num_threads is 0, the number of threads is read from
* the environment variable OSMIUM_POOL_THREADS. The default * the environment variable OSMIUM_POOL_THREADS. The default
* value in that case is -2. * value in that case is -2.
* *
* If the number of threads is a negative number, it will be * If the number of threads is a negative number, it will be
* set to the actual number of cores on the system plus the * set to the actual number of cores on the system plus the
* given number, ie it will leave a number of cores unused. * given number, ie it will leave a number of cores unused.
* *
* In all cases the minimum number of threads in the pool is 1. * In all cases the minimum number of threads in the pool is 1.
*/ */
explicit Pool(int num_threads) : explicit Pool(int num_threads) :
m_done(false), m_done(false),
m_work_queue(), m_work_queue(),
m_threads(), m_threads(),
m_joiner(m_threads), m_joiner(m_threads),
m_num_threads(num_threads) { m_num_threads(num_threads) {
if (m_num_threads == 0) { if (m_num_threads == 0) {
const char* env_threads = getenv("OSMIUM_POOL_THREADS"); const char* env_threads = getenv("OSMIUM_POOL_THREADS");
if (env_threads) { if (env_threads) {
m_num_threads = std::atoi(env_threads); m_num_threads = std::atoi(env_threads);
} else { } else {
m_num_threads = -2; m_num_threads = -2;
} }
} }
if (m_num_threads <= 0) { if (m_num_threads <= 0) {
m_num_threads = std::max(1, static_cast<int>(std::thread::hardware_concurrency()) + m_num_threads); m_num_threads = std::max(1, static_cast<int>(std::thread::hardware_concurrency()) + m_num_threads);
} }
try { try {
for (int i=0; i < m_num_threads; ++i) { for (int i=0; i < m_num_threads; ++i) {
m_threads.push_back(std::thread(&Pool::worker_thread, this)); m_threads.push_back(std::thread(&Pool::worker_thread, this));
} }
} catch (...) { } catch (...) {
m_done = true; m_done = true;
throw; throw;
} }
} }
public: public:
static constexpr int default_num_threads = 0; static constexpr int default_num_threads = 0;
static Pool& instance() { static Pool& instance() {
static Pool pool(default_num_threads); static Pool pool(default_num_threads);
return pool; return pool;
} }
~Pool() { ~Pool() {
m_done = true; m_done = true;
} }
size_t queue_size() const { size_t queue_size() const {
return m_work_queue.size(); return m_work_queue.size();
} }
bool queue_empty() const { bool queue_empty() const {
return m_work_queue.empty(); return m_work_queue.empty();
} }
template <typename TFunction> template <typename TFunction>
std::future<typename std::result_of<TFunction()>::type> submit(TFunction f) { std::future<typename std::result_of<TFunction()>::type> submit(TFunction f) {
typedef typename std::result_of<TFunction()>::type result_type; typedef typename std::result_of<TFunction()>::type result_type;
std::packaged_task<result_type()> task(std::move(f)); std::packaged_task<result_type()> task(std::move(f));
std::future<result_type> future_result(task.get_future()); std::future<result_type> future_result(task.get_future());
m_work_queue.push(std::move(task)); m_work_queue.push(std::move(task));
return future_result; return future_result;
} }
}; // class Pool }; // class Pool
} // namespace thread /**
* Wrapper for classes that can't be copied but need to be copyable for
} // namespace osmium * putting them in the pool.
*/
#endif // OSMIUM_THREAD_POOL_HPP template <class TWrapped>
class SharedPtrWrapper {
std::shared_ptr<TWrapped> m_task;
public:
typedef typename std::result_of<TWrapped()>::type result_type;
template <typename... TArgs>
SharedPtrWrapper(TArgs&&... args) :
m_task(std::make_shared<TWrapped>(std::forward<TArgs>(args)...)) {
}
result_type operator()() {
return m_task->operator()();
}
}; // class SharedPtrWrapper
} // namespace thread
} // namespace osmium
#endif // OSMIUM_THREAD_POOL_HPP

View File

@ -1,5 +1,5 @@
#ifndef OSMIUM_CONFIG_CONSTEXPR_HPP #ifndef OSMIUM_UTIL_COMPATIBILITY_HPP
#define OSMIUM_CONFIG_CONSTEXPR_HPP #define OSMIUM_UTIL_COMPATIBILITY_HPP
/* /*
@ -44,4 +44,4 @@ DEALINGS IN THE SOFTWARE.
# define OSMIUM_NORETURN [[noreturn]] # define OSMIUM_NORETURN [[noreturn]]
#endif #endif
#endif // OSMIUM_CONFIG_CONSTEXPR_HPP #endif // OSMIUM_UTIL_COMPATIBILITY_HPP

View File

@ -87,7 +87,7 @@ namespace osmium {
public: public:
explicit VerboseOutput(bool verbose=false) : explicit VerboseOutput(bool verbose=false) noexcept :
m_start(time(NULL)), m_start(time(NULL)),
m_verbose(verbose), m_verbose(verbose),
m_newline(true) { m_newline(true) {