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;
} }
@ -226,10 +226,15 @@ namespace osmium {
return osmium::Location(); return osmium::Location();
} }
auto d = (static_cast<int64_t>(s2.second().y()) - static_cast<int64_t>(s2.first().y())) *
(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())) - 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())); ((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

@ -178,13 +178,13 @@ namespace osmium {
// 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;
} }
} }

View File

@ -74,7 +74,7 @@ namespace osmium {
* @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;
} }

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

@ -46,45 +46,45 @@ namespace osmium {
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

View File

@ -38,9 +38,12 @@ DEALINGS IN THE SOFTWARE.
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <new> #include <new>
#include <type_traits>
#include <osmium/memory/buffer.hpp> #include <osmium/memory/buffer.hpp>
#include <osmium/memory/item.hpp> #include <osmium/memory/item.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/util/cast.hpp>
namespace osmium { namespace osmium {
@ -63,7 +66,7 @@ namespace osmium {
protected: protected:
explicit Builder(osmium::memory::Buffer& buffer, Builder* parent, size_t size) : explicit Builder(osmium::memory::Buffer& buffer, Builder* parent, osmium::memory::item_size_type size) :
m_buffer(buffer), m_buffer(buffer),
m_parent(parent), m_parent(parent),
m_item_offset(buffer.written()) { m_item_offset(buffer.written()) {
@ -96,7 +99,7 @@ namespace osmium {
* *
*/ */
void add_padding(bool self=false) { void add_padding(bool self=false) {
size_t padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes); auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
if (padding != osmium::memory::align_bytes) { if (padding != osmium::memory::align_bytes) {
std::memset(m_buffer.reserve_space(padding), 0, padding); std::memset(m_buffer.reserve_space(padding), 0, padding);
if (self) { if (self) {
@ -115,7 +118,7 @@ namespace osmium {
} }
} }
uint32_t size() const { uint32_t size() const noexcept {
return item().byte_size(); return item().byte_size();
} }
@ -135,41 +138,79 @@ namespace osmium {
} }
/** /**
* Append \0-terminated string to buffer. * Append data to buffer.
*
* @param data Pointer to data.
* @param length Length of data in bytes. If data is a
* \0-terminated string, length must contain the
* \0 byte.
*/ */
size_t append(const char* str) { osmium::memory::item_size_type append(const char* data, const osmium::memory::item_size_type length) {
size_t length = std::strlen(str) + 1; std::memcpy(m_buffer.reserve_space(length), data, length);
std::memcpy(m_buffer.reserve_space(length), str, length);
return length; return length;
} }
/**
* Append \0-terminated string to buffer.
*/
osmium::memory::item_size_type append(const char* str) {
return append(str, static_cast<osmium::memory::item_size_type>(std::strlen(str) + 1));
}
/// Return the buffer this builder is using. /// Return the buffer this builder is using.
osmium::memory::Buffer& buffer() { osmium::memory::Buffer& buffer() noexcept {
return m_buffer; return m_buffer;
} }
}; // class Builder }; // class Builder
template <class T> template <class TItem>
class ObjectBuilder : public Builder { class ObjectBuilder : public Builder {
static_assert(std::is_base_of<osmium::memory::Item, TItem>::value,
"ObjectBuilder can only build objects derived from osmium::memory::Item");
public: public:
explicit ObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) : explicit ObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
Builder(buffer, parent, sizeof(T)) { Builder(buffer, parent, sizeof(TItem)) {
new (&item()) T(); new (&item()) TItem();
} }
T& object() { TItem& object() noexcept {
return static_cast<T&>(item()); return static_cast<TItem&>(item());
} }
void add_user(const char* user) { /**
object().user_size(std::strlen(user) + 1); * Add user name to buffer.
add_size(append(user)); *
* @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_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 }; // class ObjectBuilder
} // namespace builder } // namespace builder

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

@ -142,7 +142,7 @@ auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) ->
flush_dispatch(m_handler, 0); flush_dispatch(m_handler, 0);
} }
}; // HandlerWrapper }; // class HandlerWrapper
} // namespace detail } // namespace detail
@ -186,7 +186,7 @@ auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) ->
m_impl->flush(); m_impl->flush();
} }
}; // DynamicHandler }; // class DynamicHandler
} // namspace handler } // namspace handler

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

@ -38,8 +38,6 @@ DEALINGS IN THE SOFTWARE.
#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/location.hpp>
#include <osmium/osm/node_ref.hpp> #include <osmium/osm/node_ref.hpp>
#include <osmium/osm/way.hpp> #include <osmium/osm/way.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

@ -38,6 +38,10 @@ DEALINGS IN THE SOFTWARE.
namespace osmium { namespace osmium {
/**
* Exception thrown when a projection object can not be initialized or the
* projection of some coordinates can not be calculated.
*/
struct projection_error : public std::runtime_error { struct projection_error : public std::runtime_error {
projection_error(const std::string& what) : projection_error(const std::string& what) :
@ -55,12 +59,12 @@ namespace osmium {
constexpr double PI = 3.14159265358979323846; constexpr double PI = 3.14159265358979323846;
/// Convert angle from degrees to radians. /// Convert angle from degrees to radians.
inline constexpr double deg_to_rad(double degree) { inline constexpr double deg_to_rad(double degree) noexcept {
return degree * (PI / 180.0); return degree * (PI / 180.0);
} }
/// Convert angle from radians to degrees. /// Convert angle from radians to degrees.
inline constexpr double rad_to_deg(double radians) { inline constexpr double rad_to_deg(double radians) noexcept {
return radians * (180.0 / PI); return radians * (180.0 / PI);
} }

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

@ -76,12 +76,12 @@ namespace osmium {
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)

View File

@ -60,55 +60,55 @@ namespace osmium {
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);
} }
@ -116,18 +116,18 @@ namespace osmium {
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";
@ -137,7 +137,7 @@ namespace osmium {
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) {
} }
@ -145,7 +145,7 @@ namespace osmium {
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=|"
@ -158,21 +158,21 @@ namespace osmium {
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="
@ -181,7 +181,7 @@ namespace osmium {
<< 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);
} }
} }
@ -190,28 +190,28 @@ namespace osmium {
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";
} }
} }
@ -238,35 +238,35 @@ namespace osmium {
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()
@ -276,12 +276,12 @@ namespace osmium {
<< 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);
} }

View File

@ -33,6 +33,8 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <type_traits>
#include <osmium/handler.hpp> #include <osmium/handler.hpp>
#include <osmium/index/index.hpp> #include <osmium/index/index.hpp>
#include <osmium/index/map/dummy.hpp> #include <osmium/index/map/dummy.hpp>
@ -59,6 +61,12 @@ namespace osmium {
template <class TStoragePosIDs, class TStorageNegIDs = dummy_type> template <class TStoragePosIDs, class TStorageNegIDs = dummy_type>
class NodeLocationsForWays : public osmium::handler::Handler { class NodeLocationsForWays : public osmium::handler::Handler {
static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStoragePosIDs>::value,
"Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStorageNegIDs>::value,
"Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
/// Object that handles the actual storage of the node locations (with positive IDs). /// Object that handles the actual storage of the node locations (with positive IDs).
TStoragePosIDs& m_storage_pos; TStoragePosIDs& m_storage_pos;
@ -100,9 +108,9 @@ namespace osmium {
m_must_sort = true; m_must_sort = true;
const osmium::object_id_type id = node.id(); const osmium::object_id_type id = node.id();
if (id >= 0) { if (id >= 0) {
m_storage_pos.set(id, node.location()); m_storage_pos.set(static_cast<osmium::unsigned_object_id_type>( id), node.location());
} else { } else {
m_storage_neg.set(-id, node.location()); m_storage_neg.set(static_cast<osmium::unsigned_object_id_type>(-id), node.location());
} }
} }
@ -110,7 +118,11 @@ namespace osmium {
* Get location of node with given id. * Get location of node with given id.
*/ */
osmium::Location get_node_location(const osmium::object_id_type id) const { osmium::Location get_node_location(const osmium::object_id_type id) const {
return id >= 0 ? m_storage_pos.get(id) : m_storage_neg.get(-id); if (id >= 0) {
return m_storage_pos.get(static_cast<osmium::unsigned_object_id_type>( id));
} else {
return m_storage_neg.get(static_cast<osmium::unsigned_object_id_type>(-id));
}
} }
/** /**
@ -126,7 +138,7 @@ namespace osmium {
bool error = false; bool error = false;
for (auto& node_ref : way.nodes()) { for (auto& node_ref : way.nodes()) {
try { try {
node_ref.location(get_node_location(node_ref.ref())); node_ref.set_location(get_node_location(node_ref.ref()));
if (!node_ref.location()) { if (!node_ref.location()) {
error = true; error = true;
} }
@ -135,10 +147,20 @@ namespace osmium {
} }
} }
if (error && !m_ignore_errors) { if (error && !m_ignore_errors) {
throw osmium::not_found("not found"); 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 }; // class NodeLocationsForWays
} // namespace handler } // namespace handler

View File

@ -61,7 +61,7 @@ namespace osmium {
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),
@ -93,23 +93,23 @@ namespace osmium {
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;
} }
@ -124,7 +124,7 @@ namespace osmium {
return m_data[n]; return m_data[n];
} }
void clear() { void clear() noexcept {
m_size = 0; m_size = 0;
} }
@ -141,36 +141,36 @@ namespace osmium {
} }
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;
} }

View File

@ -68,8 +68,7 @@ namespace osmium {
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;
} }
} }

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

@ -97,12 +97,7 @@ namespace osmium {
Map() = default; Map() = default;
// workaround for a bug in GCC 4.7
#if __GNUC__ == 4 && __GNUC_MINOR__ < 8
virtual ~Map() {}
#else
virtual ~Map() = default; virtual ~Map() = default;
#endif
virtual void reserve(const size_t) { virtual void reserve(const size_t) {
// default implementation is empty // default implementation is empty
@ -145,6 +140,10 @@ namespace osmium {
// default implementation is empty // default implementation is empty
} }
virtual void dump_as_list(int /*fd*/) const {
std::runtime_error("can't dump as list");
}
}; // class Map }; // class Map
} // namespace map } // namespace map

View File

@ -117,7 +117,7 @@ namespace osmium {
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) {

View File

@ -94,7 +94,7 @@ namespace osmium {
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));

View File

@ -169,7 +169,7 @@ namespace osmium {
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());
} }

View File

@ -114,6 +114,10 @@ namespace osmium {
// default implementation is empty // default implementation is empty
} }
virtual void dump_as_list(int /*fd*/) const {
std::runtime_error("can't dump as list");
}
}; // class Multimap }; // class Multimap
} // namespace map } // namespace map

View File

@ -112,7 +112,7 @@ namespace osmium {
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> {
@ -174,7 +174,7 @@ namespace osmium {
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);
} }
@ -188,7 +188,7 @@ namespace osmium {
m_main.sort(); m_main.sort();
} }
}; // Hybrid }; // class Hybrid
} // namespace multimap } // namespace multimap

View File

@ -130,7 +130,7 @@ namespace osmium {
// 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);

View File

@ -84,6 +84,16 @@ namespace osmium {
}); });
} }
std::pair<const_iterator, const_iterator> get_all(const TId id) const {
const element_type element {
id,
osmium::index::empty_value<TValue>()
};
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 size() const override final { size_t size() const override final {
return m_vector.size(); return m_vector.size();
} }
@ -126,7 +136,7 @@ namespace osmium {
); );
} }
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());
} }

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,19 +211,38 @@ 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 {
if (m_buffer) {
if (m_buffer_size == 0) {
return std::string();
}
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'); std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0');
ssize_t nread = ::read(m_fd, const_cast<char*>(buffer.data()), buffer.size()); ssize_t nread = ::read(m_fd, const_cast<char*>(buffer.data()), buffer.size());
if (nread < 0) { if (nread < 0) {
@ -214,6 +251,7 @@ namespace osmium {
buffer.resize(static_cast<size_t>(nread)); buffer.resize(static_cast<size_t>(nread));
return buffer; return buffer;
} }
}
void close() override final { void close() override final {
if (m_fd >= 0) { if (m_fd >= 0) {
@ -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;
}
XML_SetUserData(parser, this);
XML_SetElementHandler(parser, start_element_wrapper, end_element_wrapper);
try {
int done;
do { do {
std::string data; std::string data;
m_input_queue.wait_and_pop(data); m_input_queue.wait_and_pop(data);
done = data.empty(); last = data.empty();
try { try {
if (XML_Parse(parser, data.data(), data.size(), done) == XML_STATUS_ERROR) { parser(data, last);
throw osmium::xml_error(parser);
}
} catch (ParserIsDone&) { } catch (ParserIsDone&) {
throw; return true;
} catch (...) { } catch (...) {
m_queue.push(osmium::memory::Buffer()); // empty buffer to signify eof 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; throw;
} }
} while (!done && !m_done); } while (!last && !m_done);
header_is_done(); // make sure we'll always fulfill the promise
if (m_buffer.committed() > 0) { if (m_buffer.committed() > 0) {
m_queue.push(std::move(m_buffer)); m_queue.push(std::move(m_buffer));
} }
m_queue.push(osmium::memory::Buffer()); // empty buffer to signify eof m_queue.push(osmium::memory::Buffer()); // empty buffer to signify eof
} catch (ParserIsDone&) {
// intentionally left blank
}
XML_ParserFree(parser);
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,21 +414,17 @@ namespace osmium {
} }
void header_is_done() { void header_is_done() {
if (!m_promise_fulfilled) {
m_header_promise.set_value(m_header);
m_promise_fulfilled = true;
if (m_read_types == osmium::osm_entity_bits::nothing) { if (m_read_types == osmium::osm_entity_bits::nothing) {
throw ParserIsDone(); throw ParserIsDone();
} }
} }
}
void start_element(const XML_Char* element, const XML_Char** attrs) { void start_element(const XML_Char* element, const XML_Char** attrs) {
switch (m_context) { switch (m_context) {
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

@ -45,6 +45,9 @@ DEALINGS IN THE SOFTWARE.
namespace osmium { namespace osmium {
/**
* Exception thrown when some kind of input/output operation failed.
*/
struct io_error : public std::runtime_error { struct io_error : public std::runtime_error {
io_error(const std::string& what) : io_error(const std::string& what) :
@ -87,6 +90,9 @@ namespace osmium {
std::string m_filename; std::string m_filename;
const char* m_buffer;
size_t m_buffer_size;
std::string m_format_string; std::string m_format_string;
file_format m_file_format {file_format::unknown}; file_format m_file_format {file_format::unknown};
@ -110,6 +116,8 @@ namespace osmium {
explicit File(const std::string& filename = "", const std::string& format = "") : explicit File(const std::string& filename = "", const std::string& format = "") :
Options(), Options(),
m_filename(filename), m_filename(filename),
m_buffer(nullptr),
m_buffer_size(0),
m_format_string(format) { m_format_string(format) {
// stdin/stdout // stdin/stdout
@ -131,6 +139,29 @@ namespace osmium {
} }
} }
/**
* Create File using buffer pointer and size and type and encoding
* from given format specification.
*
* @param buffer Pointer to buffer with data.
* @param size Size of buffer.
* @param format File format as string. See the description of the
* parse_format() function for details.
*/
explicit File(const char* buffer, size_t size, const std::string& format = "") :
Options(),
m_filename(),
m_buffer(buffer),
m_buffer_size(size),
m_format_string(format) {
default_settings_for_stdinout();
if (format != "") {
parse_format(format);
}
}
File(const File& other) = default; File(const File& other) = default;
File& operator=(const File& other) = default; File& operator=(const File& other) = default;
@ -139,6 +170,14 @@ namespace osmium {
~File() = default; ~File() = default;
const char* buffer() const noexcept {
return m_buffer;
}
size_t buffer_size() const noexcept {
return m_buffer_size;
}
void parse_format(const std::string& format) { void parse_format(const std::string& format) {
std::vector<std::string> options = detail::split(format, ','); std::vector<std::string> options = detail::split(format, ',');
@ -270,29 +309,29 @@ namespace osmium {
m_file_compression = file_compression::none; m_file_compression = file_compression::none;
} }
file_format format() const { file_format format() const noexcept {
return m_file_format; return m_file_format;
} }
File& format(file_format format) { File& set_format(file_format format) noexcept {
m_file_format = format; m_file_format = format;
return *this; return *this;
} }
file_compression compression() const { file_compression compression() const noexcept {
return m_file_compression; return m_file_compression;
} }
File& compression(file_compression compression) { File& set_compression(file_compression compression) noexcept {
m_file_compression = compression; m_file_compression = compression;
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;
} }
File& has_multiple_object_versions(bool value) { File& set_has_multiple_object_versions(bool value) noexcept {
m_has_multiple_object_versions = value; m_has_multiple_object_versions = value;
return *this; return *this;
} }
@ -306,7 +345,7 @@ namespace osmium {
return *this; return *this;
} }
const std::string& filename() const { const std::string& filename() const noexcept {
return m_filename; return m_filename;
} }

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

@ -53,36 +53,38 @@ namespace osmium {
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_wrapper(size_t buffer_size) :
buffer(buffer_size, osmium::memory::Buffer::auto_grow::no) { buffer(buffer_size, osmium::memory::Buffer::auto_grow::no) {
} }
};
}; // struct buffer_wrapper
static constexpr size_t default_buffer_size = 10 * 1024 * 1024; static constexpr size_t default_buffer_size = 10 * 1024 * 1024;
TDest& m_destination; TDest* m_destination;
std::shared_ptr<buffer_wrapper> m_buffer_wrapper; std::shared_ptr<buffer_wrapper> m_buffer_wrapper;
public: public:
explicit OutputIterator(TDest& destination, const size_t buffer_size = default_buffer_size) : explicit OutputIterator(TDest& destination, const size_t buffer_size = default_buffer_size) :
m_destination(destination), m_destination(&destination),
m_buffer_wrapper(std::make_shared<buffer_wrapper>(buffer_size)) { m_buffer_wrapper(std::make_shared<buffer_wrapper>(buffer_size)) {
} }
void flush() { void flush() {
osmium::memory::Buffer buffer(m_buffer_wrapper->buffer.capacity(), osmium::memory::Buffer::auto_grow::no); osmium::memory::Buffer buffer(m_buffer_wrapper->buffer.capacity(), osmium::memory::Buffer::auto_grow::no);
std::swap(m_buffer_wrapper->buffer, buffer); std::swap(m_buffer_wrapper->buffer, buffer);
m_destination(std::move(buffer)); (*m_destination)(std::move(buffer));
} }
OutputIterator& operator=(const osmium::memory::Item& item) { OutputIterator& operator=(const osmium::memory::Item& item) {
try { try {
m_buffer_wrapper->buffer.push_back(item); m_buffer_wrapper->buffer.push_back(item);
} catch (osmium::memory::BufferIsFull&) { } catch (osmium::buffer_is_full&) {
flush(); flush();
m_buffer_wrapper->buffer.push_back(item); m_buffer_wrapper->buffer.push_back(item);
} }

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,8 +193,12 @@ namespace osmium {
Reader& operator=(const Reader&) = delete; Reader& operator=(const Reader&) = delete;
~Reader() { ~Reader() {
try {
close(); close();
} }
catch (...) {
}
}
/** /**
* Close down the Reader. A call to this is optional, because the * Close down the Reader. A call to this is optional, because the
@ -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

@ -55,11 +55,11 @@ namespace osmium {
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) {
} }
@ -74,15 +74,15 @@ namespace osmium {
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;
} }
@ -96,7 +96,7 @@ namespace osmium {
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

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

@ -39,55 +39,92 @@ DEALINGS IN THE SOFTWARE.
#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;
class Way;
class Relation;
class Area;
class Changeset;
class OSMObject;
class OSMEntity;
class TagList;
class WayNodeList;
class RelationMemberList;
class InnerRing;
class OuterRing;
namespace memory { namespace memory {
namespace detail { namespace detail {
template <class T> template <class T>
inline bool type_is_compatible(osmium::item_type) { inline bool type_is_compatible(osmium::item_type) noexcept {
return true; return true;
} }
template <> template <>
inline bool type_is_compatible<osmium::Node>(osmium::item_type t) { inline bool type_is_compatible<osmium::Node>(osmium::item_type t) noexcept {
return t == osmium::item_type::node; return t == osmium::item_type::node;
} }
template <> template <>
inline bool type_is_compatible<osmium::Way>(osmium::item_type t) { inline bool type_is_compatible<osmium::Way>(osmium::item_type t) noexcept {
return t == osmium::item_type::way; return t == osmium::item_type::way;
} }
template <> template <>
inline bool type_is_compatible<osmium::Relation>(osmium::item_type t) { inline bool type_is_compatible<osmium::Relation>(osmium::item_type t) noexcept {
return t == osmium::item_type::relation; return t == osmium::item_type::relation;
} }
template <> template <>
inline bool type_is_compatible<osmium::Area>(osmium::item_type t) { inline bool type_is_compatible<osmium::Area>(osmium::item_type t) noexcept {
return t == osmium::item_type::area; return t == osmium::item_type::area;
} }
template <> template <>
inline bool type_is_compatible<osmium::Changeset>(osmium::item_type t) { inline bool type_is_compatible<osmium::Changeset>(osmium::item_type t) noexcept {
return t == osmium::item_type::changeset; return t == osmium::item_type::changeset;
} }
template <> template <>
inline bool type_is_compatible<osmium::OSMObject>(osmium::item_type t) { 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; return t == osmium::item_type::node || t == osmium::item_type::way || t == osmium::item_type::relation || t == osmium::item_type::area;
} }
template <> template <>
inline bool type_is_compatible<osmium::OSMEntity>(osmium::item_type t) { inline bool type_is_compatible<osmium::OSMEntity>(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 || t == osmium::item_type::changeset; 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::TagList>(osmium::item_type t) noexcept {
return t == osmium::item_type::tag_list;
}
template <>
inline bool type_is_compatible<osmium::WayNodeList>(osmium::item_type t) noexcept {
return t == osmium::item_type::way_node_list;
}
template <>
inline bool type_is_compatible<osmium::RelationMemberList>(osmium::item_type t) noexcept {
return t == osmium::item_type::relation_member_list || t == osmium::item_type::relation_member_list_with_full_members;
}
template <>
inline bool type_is_compatible<osmium::OuterRing>(osmium::item_type t) noexcept {
return t == osmium::item_type::outer_ring;
}
template <>
inline bool type_is_compatible<osmium::InnerRing>(osmium::item_type t) noexcept {
return t == osmium::item_type::inner_ring;
}
} // namespace detail } // namespace detail
template <class TMember> template <class TMember>
@ -112,7 +149,7 @@ namespace osmium {
public: public:
ItemIterator() : ItemIterator() noexcept :
m_data(nullptr), m_data(nullptr),
m_end(nullptr) { m_end(nullptr) {
} }
@ -123,6 +160,11 @@ namespace osmium {
advance_to_next_item_of_right_type(); advance_to_next_item_of_right_type();
} }
template <class T>
ItemIterator<T> cast() const {
return ItemIterator<T>(m_data, m_end);
}
ItemIterator<TMember>& operator++() { ItemIterator<TMember>& operator++() {
assert(m_data); assert(m_data);
assert(m_data != m_end); assert(m_data != m_end);
@ -131,6 +173,18 @@ namespace osmium {
return *static_cast<ItemIterator<TMember>*>(this); return *static_cast<ItemIterator<TMember>*>(this);
} }
/**
* Like operator++() but will NOT skip items of unwanted
* types. Do not use this unless you know what you are
* doing.
*/
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> operator++(int) {
ItemIterator<TMember> tmp(*this); ItemIterator<TMember> tmp(*this);
operator++(); operator++();
@ -147,7 +201,6 @@ namespace osmium {
unsigned char* data() const { unsigned char* data() const {
assert(m_data); assert(m_data);
assert(m_data != m_end);
return m_data; return m_data;
} }

View File

@ -73,7 +73,7 @@ namespace osmium {
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() {
} }

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

@ -54,13 +54,13 @@ namespace osmium {
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) {
@ -72,47 +72,47 @@ namespace osmium {
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();
} }
@ -123,7 +123,7 @@ namespace osmium {
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) {
} }
@ -133,15 +133,15 @@ namespace osmium {
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);
} }

View File

@ -37,8 +37,27 @@ DEALINGS IN THE SOFTWARE.
namespace osmium { namespace osmium {
namespace detail {
template <class TSubitem, class TIter>
inline TSubitem& subitem_of_type(TIter it, TIter end) {
for (; it != end; ++it) {
if (it->type() == TSubitem::itemtype) {
return reinterpret_cast<TSubitem&>(*it);
}
}
// If no subitem of the TSubitem type was found,
// return a default constructed one.
static TSubitem subitem;
return subitem;
}
} // namespace detail
/** /**
* OSMEntity is the parent class for the OSMObject class and the Changeset class. * \brief OSMEntity is the abstract base class for the OSMObject and
* Changeset classes.
*/ */
class OSMEntity : public osmium::memory::Item { class OSMEntity : public osmium::memory::Item {

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

@ -54,11 +54,11 @@ namespace osmium {
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();
} }
@ -68,7 +68,7 @@ namespace osmium {
} }
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];
} }
@ -121,11 +121,11 @@ namespace osmium {
} }
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

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

@ -42,11 +42,11 @@ namespace osmium {
*/ */
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;
} }
@ -58,12 +58,12 @@ namespace osmium {
*/ */
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);
} }
@ -74,11 +74,11 @@ namespace osmium {
*/ */
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;
} }
@ -91,7 +91,7 @@ namespace osmium {
*/ */
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();
} }
@ -99,7 +99,7 @@ namespace osmium {
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);
} }

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

@ -65,18 +65,18 @@ namespace osmium {
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());
} }
/** /**
@ -86,7 +86,7 @@ namespace osmium {
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());
} }
} }
} }

View File

@ -103,7 +103,7 @@ namespace osmium {
public: public:
HandlerPass1(TCollector& collector) : HandlerPass1(TCollector& collector) noexcept :
m_collector(collector) { m_collector(collector) {
} }
@ -146,23 +146,25 @@ namespace osmium {
auto& mmv = m_collector.member_meta(object.type()); auto& mmv = m_collector.member_meta(object.type());
auto range = std::equal_range(mmv.begin(), mmv.end(), MemberMeta(object.id())); auto range = std::equal_range(mmv.begin(), mmv.end(), MemberMeta(object.id()));
if (range.first == range.second) { if (osmium::relations::count_not_removed(range.first, range.second) == 0) {
// nothing found // nothing found
return false; return false;
} }
{ {
const size_t member_offset = m_collector.members_buffer().committed();
m_collector.members_buffer().add_item(object); m_collector.members_buffer().add_item(object);
m_collector.members_buffer().commit(); const size_t member_offset = m_collector.members_buffer().commit();
for (auto it = range.first; it != range.second; ++it) { for (auto it = range.first; it != range.second; ++it) {
it->buffer_offset(member_offset); it->set_buffer_offset(member_offset);
} }
} }
for (auto it = range.first; it != range.second; ++it) { for (auto it = range.first; it != range.second; ++it) {
MemberMeta& member_meta = *it; MemberMeta& member_meta = *it;
if (member_meta.removed()) {
break;
}
assert(member_meta.member_id() == object.id()); assert(member_meta.member_id() == object.id());
assert(member_meta.relation_pos() < m_collector.m_relations.size()); assert(member_meta.relation_pos() < m_collector.m_relations.size());
RelationMeta& relation_meta = m_collector.m_relations[member_meta.relation_pos()]; RelationMeta& relation_meta = m_collector.m_relations[member_meta.relation_pos()];
@ -178,12 +180,17 @@ namespace osmium {
} }
} }
// Remove MemberMetas that were marked as removed.
mmv.erase(std::remove_if(mmv.begin(), mmv.end(), [](MemberMeta& mm) {
return mm.removed();
}), mmv.end());
return true; return true;
} }
public: public:
HandlerPass2(TCollector& collector) : HandlerPass2(TCollector& collector) noexcept :
m_collector(collector), m_collector(collector),
m_want_types((TNodes?1:0) + (TWays?1:0) + (TRelations?1:0)) { m_want_types((TNodes?1:0) + (TWays?1:0) + (TRelations?1:0)) {
} }
@ -484,7 +491,7 @@ namespace osmium {
auto range = std::equal_range(mmv.begin(), mmv.end(), osmium::relations::MemberMeta(object.id())); auto range = std::equal_range(mmv.begin(), mmv.end(), osmium::relations::MemberMeta(object.id()));
for (auto it = range.first; it != range.second; ++it) { for (auto it = range.first; it != range.second; ++it) {
assert(it->buffer_offset() == old_offset); assert(it->buffer_offset() == old_offset);
it->buffer_offset(new_offset); it->set_buffer_offset(new_offset);
} }
} }

View File

@ -33,8 +33,10 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm>
#include <cstddef> #include <cstddef>
#include <iosfwd> #include <iosfwd>
#include <iterator>
#include <osmium/osm/types.hpp> #include <osmium/osm/types.hpp>
@ -74,6 +76,8 @@ namespace osmium {
*/ */
size_t m_buffer_offset { 0 }; size_t m_buffer_offset { 0 };
bool m_removed = false;
public: public:
/** /**
@ -81,32 +85,40 @@ namespace osmium {
* member_pos is used to create dummy MemberMeta that can be compared * member_pos is used to create dummy MemberMeta that can be compared
* to the MemberMeta in the vectors using the equal_range algorithm. * 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) : explicit MemberMeta(osmium::object_id_type member_id, size_t relation_pos=0, size_t member_pos=0) noexcept :
m_member_id(member_id), m_member_id(member_id),
m_relation_pos(relation_pos), m_relation_pos(relation_pos),
m_member_pos(member_pos) { m_member_pos(member_pos) {
} }
osmium::object_id_type member_id() const { osmium::object_id_type member_id() const noexcept {
return m_member_id; return m_member_id;
} }
size_t relation_pos() const { size_t relation_pos() const noexcept {
return m_relation_pos; return m_relation_pos;
} }
size_t member_pos() const { size_t member_pos() const noexcept {
return m_member_pos; return m_member_pos;
} }
size_t buffer_offset() const { size_t buffer_offset() const noexcept {
return m_buffer_offset; return m_buffer_offset;
} }
void buffer_offset(size_t offset) { void set_buffer_offset(size_t offset) noexcept {
m_buffer_offset = offset; m_buffer_offset = offset;
} }
bool removed() const noexcept {
return m_removed;
}
void remove() noexcept {
m_removed = true;
}
}; // class MemberMeta }; // class MemberMeta
/** /**
@ -114,7 +126,7 @@ namespace osmium {
* Used to sort a vector of MemberMeta objects and to later find * Used to sort a vector of MemberMeta objects and to later find
* them using binary search. * them using binary search.
*/ */
inline bool operator<(const MemberMeta& a, const MemberMeta& b) { inline bool operator<(const MemberMeta& a, const MemberMeta& b) noexcept {
return a.member_id() < b.member_id(); return a.member_id() < b.member_id();
} }
@ -124,6 +136,21 @@ namespace osmium {
return out; 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 relations
} // namespace osmium } // namespace osmium

View File

@ -54,38 +54,38 @@ namespace osmium {
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;
} }
@ -100,7 +100,7 @@ namespace osmium {
/** /**
* 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;
} }
@ -121,7 +121,7 @@ namespace osmium {
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();

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

@ -47,7 +47,7 @@ namespace osmium {
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;

View File

@ -46,7 +46,7 @@ namespace osmium {
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;
@ -61,7 +61,7 @@ namespace osmium {
void call() { void call() {
m_functor(); m_functor();
} }
}; }; // struct impl_type
public: public:

View File

@ -173,6 +173,30 @@ namespace osmium {
}; // class Pool }; // class Pool
/**
* Wrapper for classes that can't be copied but need to be copyable for
* putting them in the pool.
*/
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 thread
} // namespace osmium } // namespace osmium

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) {