Merge commit 'babbda98a6ea1d53a8bc5015ef5dfb313c47186a' into libosmium-2.10.0

This commit is contained in:
Daniel J. Hofmann
2016-11-11 15:50:02 +01:00
120 changed files with 4266 additions and 2031 deletions
+26 -26
View File
@@ -193,12 +193,12 @@ namespace osmium {
}; // struct location_to_ring_map
inline bool operator==(const location_to_ring_map& a, const location_to_ring_map& b) noexcept {
return a.location == b.location;
inline bool operator==(const location_to_ring_map& lhs, const location_to_ring_map& rhs) noexcept {
return lhs.location == rhs.location;
}
inline bool operator<(const location_to_ring_map& a, const location_to_ring_map& b) noexcept {
return a.location < b.location;
inline bool operator<(const location_to_ring_map& lhs, const location_to_ring_map& rhs) noexcept {
return lhs.location < rhs.location;
}
} // namespace detail
@@ -288,7 +288,7 @@ namespace osmium {
}
void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Way& way) const {
builder.add_item(&way.tags());
builder.add_item(way.tags());
}
void add_common_tags(osmium::builder::TagListBuilder& tl_builder, std::set<const osmium::Way*>& ways) const {
@@ -333,7 +333,7 @@ namespace osmium {
}
static void copy_tags_without_type(osmium::builder::AreaBuilder& builder, const osmium::TagList& tags) {
osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
osmium::builder::TagListBuilder tl_builder{builder};
for (const osmium::Tag& tag : tags) {
if (std::strcmp(tag.key(), "type")) {
tl_builder.add_tag(tag.key(), tag.value());
@@ -354,7 +354,7 @@ namespace osmium {
}
if (m_config.keep_type_tag) {
builder.add_item(&relation.tags());
builder.add_item(relation.tags());
} else {
copy_tags_without_type(builder, relation.tags());
}
@@ -373,12 +373,12 @@ namespace osmium {
if (debug()) {
std::cerr << " only one outer way\n";
}
builder.add_item(&(*ways.cbegin())->tags());
builder.add_item((*ways.cbegin())->tags());
} else {
if (debug()) {
std::cerr << " multiple outer ways, get common tags\n";
}
osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
osmium::builder::TagListBuilder tl_builder{builder};
add_common_tags(tl_builder, ways);
}
}
@@ -386,7 +386,7 @@ namespace osmium {
template <typename TBuilder>
static void build_ring_from_proto_ring(osmium::builder::AreaBuilder& builder, const detail::ProtoRing& ring) {
TBuilder ring_builder(builder.buffer(), &builder);
TBuilder ring_builder{builder};
ring_builder.add_node_ref(ring.get_node_ref_start());
for (const auto& segment : ring.segments()) {
ring_builder.add_node_ref(segment->stop());
@@ -458,8 +458,8 @@ namespace osmium {
}
detail::NodeRefSegment* get_next_segment(const osmium::Location& location) {
auto it = std::lower_bound(m_locations.begin(), m_locations.end(), slocation{}, [this, &location](const slocation& a, const slocation& b) {
return a.location(m_segment_list, location) < b.location(m_segment_list, location);
auto it = std::lower_bound(m_locations.begin(), m_locations.end(), slocation{}, [this, &location](const slocation& lhs, const slocation& rhs) {
return lhs.location(m_segment_list, location) < rhs.location(m_segment_list, location);
});
assert(it != m_locations.end());
@@ -744,8 +744,8 @@ namespace osmium {
m_locations.emplace_back(n, true);
}
std::stable_sort(m_locations.begin(), m_locations.end(), [this](const slocation& a, const slocation& b) {
return a.location(m_segment_list) < b.location(m_segment_list);
std::stable_sort(m_locations.begin(), m_locations.end(), [this](const slocation& lhs, const slocation& rhs) {
return lhs.location(m_segment_list) < rhs.location(m_segment_list);
});
}
@@ -1015,8 +1015,8 @@ namespace osmium {
std::vector<location_to_ring_map> xrings = create_location_to_ring_map(open_ring_its);
const auto ring_min = std::min_element(xrings.begin(), xrings.end(), [](const location_to_ring_map& a, const location_to_ring_map& b) {
return a.ring().min_segment() < b.ring().min_segment();
const auto ring_min = std::min_element(xrings.begin(), xrings.end(), [](const location_to_ring_map& lhs, const location_to_ring_map& rhs) {
return lhs.ring().min_segment() < rhs.ring().min_segment();
});
find_inner_outer_complex();
@@ -1068,11 +1068,11 @@ namespace osmium {
// Find the candidate with the smallest/largest area
const auto chosen_cand = ring_min_is_outer ?
std::min_element(candidates.cbegin(), candidates.cend(), [](const candidate& a, const candidate& b) {
return std::abs(a.sum) < std::abs(b.sum);
std::min_element(candidates.cbegin(), candidates.cend(), [](const candidate& lhs, const candidate& rhs) {
return std::abs(lhs.sum) < std::abs(rhs.sum);
}) :
std::max_element(candidates.cbegin(), candidates.cend(), [](const candidate& a, const candidate& b) {
return std::abs(a.sum) < std::abs(b.sum);
std::max_element(candidates.cbegin(), candidates.cend(), [](const candidate& lhs, const candidate& rhs) {
return std::abs(lhs.sum) < std::abs(rhs.sum);
});
if (debug()) {
@@ -1103,8 +1103,8 @@ namespace osmium {
const auto locs = make_range(std::equal_range(m_locations.begin(),
m_locations.end(),
slocation{},
[this, &location](const slocation& a, const slocation& b) {
return a.location(m_segment_list, location) < b.location(m_segment_list, location);
[this, &location](const slocation& lhs, const slocation& rhs) {
return lhs.location(m_segment_list, location) < rhs.location(m_segment_list, location);
}));
for (auto& loc : locs) {
if (!m_segment_list[loc.item].is_done()) {
@@ -1267,8 +1267,8 @@ namespace osmium {
}
for (const auto& location : m_split_locations) {
if (m_config.problem_reporter) {
auto it = std::lower_bound(m_locations.cbegin(), m_locations.cend(), slocation{}, [this, &location](const slocation& a, const slocation& b) {
return a.location(m_segment_list, location) < b.location(m_segment_list, location);
auto it = std::lower_bound(m_locations.cbegin(), m_locations.cend(), slocation{}, [this, &location](const slocation& lhs, const slocation& rhs) {
return lhs.location(m_segment_list, location) < rhs.location(m_segment_list, location);
});
assert(it != m_locations.cend());
const osmium::object_id_type id = it->node_ref(m_segment_list).ref();
@@ -1362,7 +1362,7 @@ namespace osmium {
#endif
bool create_area(osmium::memory::Buffer& out_buffer, const osmium::Way& way) {
osmium::builder::AreaBuilder builder(out_buffer);
osmium::builder::AreaBuilder builder{out_buffer};
builder.initialize_from_object(way);
const bool area_okay = create_rings();
@@ -1382,7 +1382,7 @@ namespace osmium {
bool create_area(osmium::memory::Buffer& out_buffer, const osmium::Relation& relation, const std::vector<const osmium::Way*>& members) {
m_num_members = members.size();
osmium::builder::AreaBuilder builder(out_buffer);
osmium::builder::AreaBuilder builder{out_buffer};
builder.initialize_from_object(relation);
const bool area_okay = create_rings();
@@ -379,8 +379,8 @@ namespace osmium {
sl[2] = {1, s2.first().location() };
sl[3] = {1, s2.second().location()};
std::sort(sl, sl+4, [](const seg_loc& a, const seg_loc& b) {
return a.location < b.location;
std::sort(sl, sl+4, [](const seg_loc& lhs, const seg_loc& rhs) {
return lhs.location < rhs.location;
});
if (sl[1].location == sl[2].location) {
@@ -101,7 +101,7 @@ namespace osmium {
* Calculate the number of segments in all the ways together.
*/
static size_t get_num_segments(const std::vector<const osmium::Way*>& members) noexcept {
return std::accumulate(members.cbegin(), members.cend(), 0, [](size_t sum, const osmium::Way* way) {
return std::accumulate(members.cbegin(), members.cend(), static_cast<size_t>(0), [](size_t sum, const osmium::Way* way) {
if (way->nodes().empty()) {
return sum;
} else {
+10 -10
View File
@@ -73,18 +73,18 @@ namespace osmium {
}; // struct vec
// addition
constexpr inline vec operator+(const vec& a, const vec& b) noexcept {
return vec{a.x + b.x, a.y + b.y};
constexpr inline vec operator+(const vec& lhs, const vec& rhs) noexcept {
return vec{lhs.x + rhs.x, lhs.y + rhs.y};
}
// subtraction
constexpr inline vec operator-(const vec& a, const vec& b) noexcept {
return vec{a.x - b.x, a.y - b.y};
constexpr inline vec operator-(const vec& lhs, const vec& rhs) noexcept {
return vec{lhs.x - rhs.x, lhs.y - rhs.y};
}
// cross product
constexpr inline int64_t operator*(const vec& a, const vec& b) noexcept {
return a.x * b.y - a.y * b.x;
constexpr inline int64_t operator*(const vec& lhs, const vec& rhs) noexcept {
return lhs.x * rhs.y - lhs.y * rhs.x;
}
// scale vector
@@ -98,13 +98,13 @@ namespace osmium {
}
// equality
constexpr inline bool operator==(const vec& a, const vec& b) noexcept {
return a.x == b.x && a.y == b.y;
constexpr inline bool operator==(const vec& lhs, const vec& rhs) noexcept {
return lhs.x == rhs.x && lhs.y == rhs.y;
}
// inequality
constexpr inline bool operator!=(const vec& a, const vec& b) noexcept {
return !(a == b);
constexpr inline bool operator!=(const vec& lhs, const vec& rhs) noexcept {
return !(lhs == rhs);
}
template <typename TChar, typename TTraits>
+37 -27
View File
@@ -617,7 +617,7 @@ namespace osmium {
template <typename TBuilder, typename... TArgs>
inline void add_user(TBuilder& builder, const TArgs&... args) {
builder.add_user(get_user(args...));
builder.set_user(get_user(args...));
}
// ==============================================================
@@ -761,11 +761,13 @@ namespace osmium {
static_assert(sizeof...(args) > 0, "add_node() must have buffer and at least one additional argument");
static_assert(detail::are_all_handled_by<detail::any_node_handlers, TArgs...>::value, "Attribute not allowed in add_node()");
NodeBuilder builder(buffer);
{
NodeBuilder builder(buffer);
detail::add_basic<detail::node_handler>(builder, args...);
detail::add_user(builder, args...);
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
detail::add_basic<detail::node_handler>(builder, args...);
detail::add_user(builder, args...);
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
}
return buffer.commit();
}
@@ -782,12 +784,14 @@ namespace osmium {
static_assert(sizeof...(args) > 0, "add_way() must have buffer and at least one additional argument");
static_assert(detail::are_all_handled_by<detail::any_way_handlers, TArgs...>::value, "Attribute not allowed in add_way()");
WayBuilder builder(buffer);
{
WayBuilder builder(buffer);
detail::add_basic<detail::object_handler>(builder, args...);
detail::add_user(builder, args...);
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
detail::add_list<WayNodeListBuilder, detail::nodes_handler>(builder, args...);
detail::add_basic<detail::object_handler>(builder, args...);
detail::add_user(builder, args...);
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
detail::add_list<WayNodeListBuilder, detail::nodes_handler>(builder, args...);
}
return buffer.commit();
}
@@ -804,12 +808,14 @@ namespace osmium {
static_assert(sizeof...(args) > 0, "add_relation() must have buffer and at least one additional argument");
static_assert(detail::are_all_handled_by<detail::any_relation_handlers, TArgs...>::value, "Attribute not allowed in add_relation()");
RelationBuilder builder(buffer);
{
RelationBuilder builder(buffer);
detail::add_basic<detail::object_handler>(builder, args...);
detail::add_user(builder, args...);
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
detail::add_list<RelationMemberListBuilder, detail::members_handler>(builder, args...);
detail::add_basic<detail::object_handler>(builder, args...);
detail::add_user(builder, args...);
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
detail::add_list<RelationMemberListBuilder, detail::members_handler>(builder, args...);
}
return buffer.commit();
}
@@ -826,12 +832,14 @@ namespace osmium {
static_assert(sizeof...(args) > 0, "add_changeset() must have buffer and at least one additional argument");
static_assert(detail::are_all_handled_by<detail::any_changeset_handlers, TArgs...>::value, "Attribute not allowed in add_changeset()");
ChangesetBuilder builder(buffer);
{
ChangesetBuilder builder(buffer);
detail::add_basic<detail::changeset_handler>(builder, args...);
detail::add_user(builder, args...);
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
detail::add_list<ChangesetDiscussionBuilder, detail::discussion_handler>(builder, args...);
detail::add_basic<detail::changeset_handler>(builder, args...);
detail::add_user(builder, args...);
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
detail::add_list<ChangesetDiscussionBuilder, detail::discussion_handler>(builder, args...);
}
return buffer.commit();
}
@@ -848,15 +856,17 @@ namespace osmium {
static_assert(sizeof...(args) > 0, "add_area() must have buffer and at least one additional argument");
static_assert(detail::are_all_handled_by<detail::any_area_handlers, TArgs...>::value, "Attribute not allowed in add_area()");
AreaBuilder builder(buffer);
{
AreaBuilder builder(buffer);
detail::add_basic<detail::object_handler>(builder, args...);
detail::add_user(builder, args...);
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
detail::add_basic<detail::object_handler>(builder, args...);
detail::add_user(builder, args...);
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
(void)std::initializer_list<int>{
(detail::ring_handler::set_value(builder, args), 0)...
};
(void)std::initializer_list<int>{
(detail::ring_handler::set_value(builder, args), 0)...
};
}
return buffer.commit();
}
+45 -60
View File
@@ -45,6 +45,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/memory/item.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/util/cast.hpp>
#include <osmium/util/compatibility.hpp>
namespace osmium {
@@ -53,6 +54,10 @@ namespace osmium {
*/
namespace builder {
/**
* Parent class for individual builder classes. Instantiate one of
* its derived classes.
*/
class Builder {
osmium::memory::Buffer& m_buffer;
@@ -71,20 +76,34 @@ namespace osmium {
m_buffer(buffer),
m_parent(parent),
m_item_offset(buffer.written()) {
m_buffer.reserve_space(size);
reserve_space(size);
assert(buffer.is_aligned());
if (m_parent) {
assert(m_buffer.builder_count() == 1 && "Only one sub-builder can be open at any time.");
m_parent->add_size(size);
} else {
assert(m_buffer.builder_count() == 0 && "Only one builder can be open at any time.");
}
#ifndef NDEBUG
m_buffer.increment_builder_count();
#endif
}
#ifdef NDEBUG
~Builder() = default;
#else
~Builder() noexcept {
m_buffer.decrement_builder_count();
}
#endif
osmium::memory::Item& item() const {
return *reinterpret_cast<osmium::memory::Item*>(m_buffer.data() + m_item_offset);
}
public:
unsigned char* reserve_space(size_t size) {
return m_buffer.reserve_space(size);
}
/**
* Add padding to buffer (if needed) to align data properly.
@@ -102,7 +121,7 @@ namespace osmium {
void add_padding(bool self = false) {
const auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
if (padding != osmium::memory::align_bytes) {
std::fill_n(m_buffer.reserve_space(padding), padding, 0);
std::fill_n(reserve_space(padding), padding, 0);
if (self) {
add_size(padding);
} else if (m_parent) {
@@ -123,12 +142,6 @@ namespace osmium {
return item().byte_size();
}
void add_item(const osmium::memory::Item* item) {
unsigned char* target = m_buffer.reserve_space(item->padded_size());
std::copy_n(reinterpret_cast<const unsigned char*>(item), item->padded_size(), target);
add_size(item->padded_size());
}
/**
* Reserve space for an object of class T in buffer and return
* pointer to it.
@@ -136,7 +149,7 @@ namespace osmium {
template <typename T>
T* reserve_space_for() {
assert(m_buffer.is_aligned());
return reinterpret_cast<T*>(m_buffer.reserve_space(sizeof(T)));
return reinterpret_cast<T*>(reserve_space(sizeof(T)));
}
/**
@@ -149,7 +162,7 @@ namespace osmium {
* @returns The number of bytes appended (length).
*/
osmium::memory::item_size_type append(const char* data, const osmium::memory::item_size_type length) {
unsigned char* target = m_buffer.reserve_space(length);
unsigned char* target = reserve_space(length);
std::copy_n(reinterpret_cast<const unsigned char*>(data), length, target);
return length;
}
@@ -170,65 +183,37 @@ namespace osmium {
* @returns The number of bytes appended (always 1).
*/
osmium::memory::item_size_type append_zero() {
*m_buffer.reserve_space(1) = '\0';
*reserve_space(1) = '\0';
return 1;
}
public:
/// Return the buffer this builder is using.
osmium::memory::Buffer& buffer() noexcept {
return m_buffer;
}
/**
* Add a subitem to the object being built. This can be something
* like a TagList or RelationMemberList.
*/
void add_item(const osmium::memory::Item& item) {
m_buffer.add_item(item);
add_size(item.padded_size());
}
/**
* @deprecated Use the version of add_item() taking a
* reference instead.
*/
OSMIUM_DEPRECATED void add_item(const osmium::memory::Item* item) {
assert(item);
add_item(*item);
}
}; // class Builder
template <typename TItem>
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:
explicit ObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
Builder(buffer, parent, sizeof(TItem)) {
new (&item()) TItem();
}
TItem& object() noexcept {
return static_cast<TItem&>(item());
}
/**
* Add user name to buffer.
*
* @param user Pointer to user name.
* @param length Length of user name (without \0 termination).
*/
void add_user(const char* user, const string_size_type length) {
object().set_user_size(length + 1);
add_size(append(user, length) + append_zero());
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)));
}
/**
* 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()));
}
}; // class ObjectBuilder
} // namespace builder
} // namespace osmium
@@ -45,6 +45,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/builder/builder.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/tag.hpp>
@@ -55,6 +56,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/relation.hpp>
#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/util/compatibility.hpp>
namespace osmium {
@@ -66,12 +68,18 @@ namespace osmium {
namespace builder {
class TagListBuilder : public ObjectBuilder<TagList> {
class TagListBuilder : public Builder {
public:
explicit TagListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
ObjectBuilder<TagList>(buffer, parent) {
Builder(buffer, parent, sizeof(TagList)) {
new (&item()) TagList();
}
explicit TagListBuilder(Builder& parent) :
Builder(parent.buffer(), &parent, sizeof(TagList)) {
new (&item()) TagList();
}
~TagListBuilder() {
@@ -169,21 +177,27 @@ namespace osmium {
}; // class TagListBuilder
template <typename T>
class NodeRefListBuilder : public ObjectBuilder<T> {
class NodeRefListBuilder : public Builder {
public:
explicit NodeRefListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
ObjectBuilder<T>(buffer, parent) {
Builder(buffer, parent, sizeof(T)) {
new (&item()) T();
}
explicit NodeRefListBuilder(Builder& parent) :
Builder(parent.buffer(), &parent, sizeof(T)) {
new (&item()) T();
}
~NodeRefListBuilder() {
static_cast<Builder*>(this)->add_padding();
add_padding();
}
void add_node_ref(const NodeRef& node_ref) {
new (static_cast<Builder*>(this)->reserve_space_for<osmium::NodeRef>()) osmium::NodeRef(node_ref);
static_cast<Builder*>(this)->add_size(sizeof(osmium::NodeRef));
new (reserve_space_for<osmium::NodeRef>()) osmium::NodeRef(node_ref);
add_size(sizeof(osmium::NodeRef));
}
void add_node_ref(const object_id_type ref, const osmium::Location& location = Location{}) {
@@ -196,7 +210,7 @@ namespace osmium {
using OuterRingBuilder = NodeRefListBuilder<OuterRing>;
using InnerRingBuilder = NodeRefListBuilder<InnerRing>;
class RelationMemberListBuilder : public ObjectBuilder<RelationMemberList> {
class RelationMemberListBuilder : public Builder {
/**
* Add role to buffer.
@@ -219,7 +233,13 @@ namespace osmium {
public:
explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
ObjectBuilder<RelationMemberList>(buffer, parent) {
Builder(buffer, parent, sizeof(RelationMemberList)) {
new (&item()) RelationMemberList();
}
explicit RelationMemberListBuilder(Builder& parent) :
Builder(parent.buffer(), &parent, sizeof(RelationMemberList)) {
new (&item()) RelationMemberList();
}
~RelationMemberListBuilder() {
@@ -245,7 +265,7 @@ namespace osmium {
add_size(sizeof(RelationMember));
add_role(*member, role, role_length);
if (full_member) {
add_item(full_member);
add_item(*full_member);
}
}
@@ -281,7 +301,7 @@ namespace osmium {
}; // class RelationMemberListBuilder
class ChangesetDiscussionBuilder : public ObjectBuilder<ChangesetDiscussion> {
class ChangesetDiscussionBuilder : public Builder {
osmium::ChangesetComment* m_comment = nullptr;
@@ -309,7 +329,13 @@ namespace osmium {
public:
explicit ChangesetDiscussionBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
ObjectBuilder<ChangesetDiscussion>(buffer, parent) {
Builder(buffer, parent, sizeof(ChangesetDiscussion)) {
new (&item()) ChangesetDiscussion();
}
explicit ChangesetDiscussionBuilder(Builder& parent) :
Builder(parent.buffer(), &parent, sizeof(ChangesetDiscussion)) {
new (&item()) ChangesetDiscussion();
}
~ChangesetDiscussionBuilder() {
@@ -339,19 +365,101 @@ namespace osmium {
}; // class ChangesetDiscussionBuilder
template <typename T>
class OSMObjectBuilder : public ObjectBuilder<T> {
#define OSMIUM_FORWARD(setter) \
template <typename... TArgs> \
type& setter(TArgs&&... args) { \
object().setter(std::forward<TArgs>(args)...); \
return static_cast<type&>(*this); \
}
template <typename TDerived, typename T>
class OSMObjectBuilder : public Builder {
using type = TDerived;
constexpr static const size_t min_size_for_user = osmium::memory::padded_length(sizeof(string_size_type) + 1);
public:
explicit OSMObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
ObjectBuilder<T>(buffer, parent) {
static_cast<Builder*>(this)->reserve_space_for<string_size_type>();
static_cast<Builder*>(this)->add_size(sizeof(string_size_type));
Builder(buffer, parent, sizeof(T) + min_size_for_user) {
new (&item()) T();
add_size(min_size_for_user);
std::fill_n(object().data() + sizeof(T), min_size_for_user, 0);
object().set_user_size(1);
}
/**
* Get a reference to the object buing built.
*
* Note that this reference will be invalidated by every action
* on the builder that might make the buffer grow. This includes
* calls to set_user() and any time a new sub-builder is created.
*/
T& object() noexcept {
return static_cast<T&>(item());
}
/**
* Set user name.
*
* @param user Pointer to user name.
* @param length Length of user name (without \0 termination).
*/
TDerived& set_user(const char* user, const string_size_type length) {
const auto size_of_object = sizeof(T) + sizeof(string_size_type);
assert(object().user_size() == 1 && (size() <= size_of_object + osmium::memory::padded_length(1))
&& "set_user() must be called at most once and before any sub-builders");
const auto available_space = min_size_for_user - sizeof(string_size_type) - 1;
if (length > available_space) {
const auto space_needed = osmium::memory::padded_length(length - available_space);
reserve_space(space_needed);
add_size(static_cast<uint32_t>(space_needed));
}
std::copy_n(user, length, object().data() + size_of_object);
std::fill_n(object().data() + size_of_object + length, osmium::memory::padded_length(length + 1) - length, 0);
object().set_user_size(length + 1);
return static_cast<TDerived&>(*this);
}
/**
* Set user name.
*
* @param user Pointer to \0-terminated user name.
*/
TDerived& set_user(const char* user) {
return set_user(user, static_cast_with_assert<string_size_type>(std::strlen(user)));
}
/**
* Set user name.
*
* @param user User name.
*/
TDerived& set_user(const std::string& user) {
return set_user(user.data(), static_cast_with_assert<string_size_type>(user.size()));
}
/// @deprecated Use set_user(...) instead.
template <typename... TArgs>
OSMIUM_DEPRECATED void add_user(TArgs&&... args) {
set_user(std::forward<TArgs>(args)...);
}
OSMIUM_FORWARD(set_id)
OSMIUM_FORWARD(set_visible)
OSMIUM_FORWARD(set_deleted)
OSMIUM_FORWARD(set_version)
OSMIUM_FORWARD(set_changeset)
OSMIUM_FORWARD(set_uid)
OSMIUM_FORWARD(set_uid_from_signed)
OSMIUM_FORWARD(set_timestamp)
OSMIUM_FORWARD(set_attribute)
OSMIUM_FORWARD(set_removed)
void add_tags(const std::initializer_list<std::pair<const char*, const char*>>& tags) {
osmium::builder::TagListBuilder tl_builder(static_cast<Builder*>(this)->buffer(), this);
osmium::builder::TagListBuilder tl_builder{buffer(), this};
for (const auto& p : tags) {
tl_builder.add_tag(p.first, p.second);
}
@@ -359,19 +467,40 @@ namespace osmium {
}; // class OSMObjectBuilder
using NodeBuilder = OSMObjectBuilder<osmium::Node>;
using RelationBuilder = OSMObjectBuilder<osmium::Relation>;
class NodeBuilder : public OSMObjectBuilder<NodeBuilder, Node> {
class WayBuilder : public OSMObjectBuilder<osmium::Way> {
using type = NodeBuilder;
public:
explicit NodeBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
OSMObjectBuilder<NodeBuilder, Node>(buffer, parent) {
}
explicit NodeBuilder(Builder& parent) :
OSMObjectBuilder<NodeBuilder, Node>(parent.buffer(), &parent) {
}
OSMIUM_FORWARD(set_location)
}; // class NodeBuilder
class WayBuilder : public OSMObjectBuilder<WayBuilder, Way> {
using type = WayBuilder;
public:
explicit WayBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
OSMObjectBuilder<osmium::Way>(buffer, parent) {
OSMObjectBuilder<WayBuilder, Way>(buffer, parent) {
}
explicit WayBuilder(Builder& parent) :
OSMObjectBuilder<WayBuilder, Way>(parent.buffer(), &parent) {
}
void add_node_refs(const std::initializer_list<osmium::NodeRef>& nodes) {
osmium::builder::WayNodeListBuilder builder(buffer(), this);
osmium::builder::WayNodeListBuilder builder{buffer(), this};
for (const auto& node_ref : nodes) {
builder.add_node_ref(node_ref);
}
@@ -379,32 +508,147 @@ namespace osmium {
}; // class WayBuilder
class AreaBuilder : public OSMObjectBuilder<osmium::Area> {
class RelationBuilder : public OSMObjectBuilder<RelationBuilder, Relation> {
using type = RelationBuilder;
public:
explicit RelationBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
OSMObjectBuilder<RelationBuilder, Relation>(buffer, parent) {
}
explicit RelationBuilder(Builder& parent) :
OSMObjectBuilder<RelationBuilder, Relation>(parent.buffer(), &parent) {
}
}; // class RelationBuilder
class AreaBuilder : public OSMObjectBuilder<AreaBuilder, Area> {
using type = AreaBuilder;
public:
explicit AreaBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
OSMObjectBuilder<osmium::Area>(buffer, parent) {
OSMObjectBuilder<AreaBuilder, Area>(buffer, parent) {
}
explicit AreaBuilder(Builder& parent) :
OSMObjectBuilder<AreaBuilder, Area>(parent.buffer(), &parent) {
}
/**
* Initialize area attributes from the attributes of the given object.
*/
void initialize_from_object(const osmium::OSMObject& source) {
osmium::Area& area = object();
area.set_id(osmium::object_id_to_area_id(source.id(), source.type()));
area.set_version(source.version());
area.set_changeset(source.changeset());
area.set_timestamp(source.timestamp());
area.set_visible(source.visible());
area.set_uid(source.uid());
add_user(source.user());
set_id(osmium::object_id_to_area_id(source.id(), source.type()));
set_version(source.version());
set_changeset(source.changeset());
set_timestamp(source.timestamp());
set_visible(source.visible());
set_uid(source.uid());
set_user(source.user());
}
}; // class AreaBuilder
using ChangesetBuilder = ObjectBuilder<osmium::Changeset>;
class ChangesetBuilder : public Builder {
using type = ChangesetBuilder;
constexpr static const size_t min_size_for_user = osmium::memory::padded_length(1);
public:
explicit ChangesetBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
Builder(buffer, parent, sizeof(Changeset) + min_size_for_user) {
new (&item()) Changeset();
add_size(min_size_for_user);
std::fill_n(object().data() + sizeof(Changeset), min_size_for_user, 0);
object().set_user_size(1);
}
/**
* Get a reference to the changeset buing built.
*
* Note that this reference will be invalidated by every action
* on the builder that might make the buffer grow. This includes
* calls to set_user() and any time a new sub-builder is created.
*/
Changeset& object() noexcept {
return static_cast<Changeset&>(item());
}
OSMIUM_FORWARD(set_id)
OSMIUM_FORWARD(set_uid)
OSMIUM_FORWARD(set_uid_from_signed)
OSMIUM_FORWARD(set_created_at)
OSMIUM_FORWARD(set_closed_at)
OSMIUM_FORWARD(set_num_changes)
OSMIUM_FORWARD(set_num_comments)
OSMIUM_FORWARD(set_attribute)
OSMIUM_FORWARD(set_removed)
// @deprecated Use set_bounds() instead.
OSMIUM_DEPRECATED osmium::Box& bounds() noexcept {
return object().bounds();
}
ChangesetBuilder& set_bounds(const osmium::Box& box) noexcept {
object().bounds() = box;
return *this;
}
/**
* Set user name.
*
* @param user Pointer to user name.
* @param length Length of user name (without \0 termination).
*/
ChangesetBuilder& set_user(const char* user, const string_size_type length) {
assert(object().user_size() == 1 && (size() <= sizeof(Changeset) + osmium::memory::padded_length(1))
&& "set_user() must be called at most once and before any sub-builders");
const auto available_space = min_size_for_user - 1;
if (length > available_space) {
const auto space_needed = osmium::memory::padded_length(length - available_space);
reserve_space(space_needed);
add_size(static_cast<uint32_t>(space_needed));
}
std::copy_n(user, length, object().data() + sizeof(Changeset));
std::fill_n(object().data() + sizeof(Changeset) + length, osmium::memory::padded_length(length + 1) - length, 0);
object().set_user_size(length + 1);
return *this;
}
/**
* Set user name.
*
* @param user Pointer to \0-terminated user name.
*/
ChangesetBuilder& set_user(const char* user) {
return set_user(user, static_cast_with_assert<string_size_type>(std::strlen(user)));
}
/**
* Set user name.
*
* @param user User name.
*/
ChangesetBuilder& set_user(const std::string& user) {
return set_user(user.data(), static_cast_with_assert<string_size_type>(user.size()));
}
/// @deprecated Use set_user(...) instead.
template <typename... TArgs>
OSMIUM_DEPRECATED void add_user(TArgs&&... args) {
set_user(std::forward<TArgs>(args)...);
}
}; // class ChangesetBuilder
#undef OSMIUM_FORWARD
} // namespace builder
+1 -1
View File
@@ -95,7 +95,7 @@ namespace osmium {
return m_message.c_str();
}
}; // struct geometry_error
}; // class geometry_error
/**
* @brief Everything related to geometry handling.
+15 -1
View File
@@ -33,12 +33,22 @@ DEALINGS IN THE SOFTWARE.
*/
#include <geos/version.h>
#if defined(GEOS_VERSION_MAJOR) && defined(GEOS_VERSION_MINOR) && (GEOS_VERSION_MAJOR < 3 || (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR <= 5))
#define OSMIUM_WITH_GEOS
/**
* @file
*
* This file contains code for conversion of OSM geometries into GDAL
* This file contains code for conversion of OSM geometries into GEOS
* geometries.
*
* Note that everything in this file is deprecated and only works up to
* GEOS 3.5. It uses the GEOS C++ API which the GEOS project does not consider
* to be a stable, external API. We probably should have used the GEOS C API
* instead.
*
* @attention If you include this file, you'll need to link with `libgeos`.
*/
@@ -88,6 +98,7 @@ namespace osmium {
namespace detail {
/// @deprecated
class GEOSFactoryImpl {
std::unique_ptr<const geos::geom::PrecisionModel> m_precision_model;
@@ -245,6 +256,7 @@ namespace osmium {
} // namespace detail
/// @deprecated
template <typename TProjection = IdentityProjection>
using GEOSFactory = GeometryFactory<osmium::geom::detail::GEOSFactoryImpl, TProjection>;
@@ -254,4 +266,6 @@ namespace osmium {
#undef THROW
#endif
#endif // OSMIUM_GEOM_GEOS_HPP
+5 -5
View File
@@ -43,11 +43,11 @@ namespace osmium {
/**
* Check whether one geometry contains another.
*/
inline bool contains(const osmium::Box& a, const osmium::Box& b) {
return ((a.bottom_left().x() >= b.bottom_left().x()) &&
(a.top_right().x() <= b.top_right().x()) &&
(a.bottom_left().y() >= b.bottom_left().y()) &&
(a.top_right().y() <= b.top_right().y()));
inline bool contains(const osmium::Box& lhs, const osmium::Box& rhs) {
return ((lhs.bottom_left().x() >= rhs.bottom_left().x()) &&
(lhs.top_right().x() <= rhs.top_right().x()) &&
(lhs.bottom_left().y() >= rhs.bottom_left().y()) &&
(lhs.top_right().y() <= rhs.top_right().y()));
}
} // namespace geom
+10 -10
View File
@@ -118,23 +118,23 @@ namespace osmium {
}; // struct Tile
/// Tiles are equal if all their attributes are equal.
inline bool operator==(const Tile& a, const Tile& b) {
return a.z == b.z && a.x == b.x && a.y == b.y;
inline bool operator==(const Tile& lhs, const Tile& rhs) {
return lhs.z == rhs.z && lhs.x == rhs.x && lhs.y == rhs.y;
}
inline bool operator!=(const Tile& a, const Tile& b) {
return ! (a == b);
inline bool operator!=(const Tile& lhs, const Tile& rhs) {
return ! (lhs == rhs);
}
/**
* This defines an arbitrary order on tiles for use in std::map etc.
*/
inline bool operator<(const Tile& a, const Tile& b) {
if (a.z < b.z) return true;
if (a.z > b.z) return false;
if (a.x < b.x) return true;
if (a.x > b.x) return false;
return a.y < b.y;
inline bool operator<(const Tile& lhs, const Tile& rhs) {
if (lhs.z < rhs.z) return true;
if (lhs.z > rhs.z) return false;
if (lhs.x < rhs.x) return true;
if (lhs.x > rhs.x) return false;
return lhs.y < rhs.y;
}
} // namespace geom
@@ -51,6 +51,9 @@ namespace osmium {
namespace handler {
/**
* Writes OSM data in the Osmium-internal serialized format to disk
* keeping track of object offsets in the indexes given to the
* constructor.
*
* Note: This handler will only work if either all object IDs are
* positive or all object IDs are negative.
@@ -95,10 +98,8 @@ namespace osmium {
m_offset += relation.byte_size();
}
// XXX
void operator()(const osmium::memory::Buffer& buffer) {
osmium::io::detail::reliable_write(m_data_fd, buffer.data(), buffer.committed());
osmium::apply(buffer.begin(), buffer.end(), *this);
}
@@ -165,7 +165,7 @@ namespace osmium {
}
}
if (error && !m_ignore_errors) {
throw osmium::not_found("location for one or more nodes not found in node location index");
throw osmium::not_found{"location for one or more nodes not found in node location index"};
}
}
@@ -46,6 +46,8 @@ namespace osmium {
namespace handler {
/**
* This handler updates the indexes given to the constructor with
* the relations between objects.
*
* Note: This handler will only work if either all object IDs are
* positive or all object IDs are negative.
+3 -38
View File
@@ -33,50 +33,15 @@ DEALINGS IN THE SOFTWARE.
*/
#include <type_traits>
#include <vector>
#include <osmium/index/id_set.hpp>
namespace osmium {
namespace index {
/**
* Index storing one bit for each Id. The index automatically scales
* with the Ids stored. Default value is 'false'. Storage uses
* std::vector<bool> and needs a minimum of memory if the Ids are
* dense.
*/
/// @deprecated Use osmium::index::IdSet instead.
template <typename T>
class BoolVector {
static_assert(std::is_unsigned<T>::value, "Needs unsigned type");
std::vector<bool> m_bits;
public:
BoolVector() = default;
BoolVector(const BoolVector&) = default;
BoolVector(BoolVector&&) = default;
BoolVector& operator=(const BoolVector&) = default;
BoolVector& operator=(BoolVector&&) = default;
~BoolVector() noexcept = default;
void set(T id, bool value = true) {
if (m_bits.size() <= id) {
m_bits.resize(id + 1024 * 1024);
}
m_bits[id] = value;
}
bool get(T id) const {
return id < m_bits.size() && m_bits[id];
}
}; // class BoolVector
using BoolVector = IdSet<T>;
} // namespace index
@@ -85,11 +85,11 @@ namespace osmium {
try {
const TValue& value = m_vector.at(id);
if (value == osmium::index::empty_value<TValue>()) {
not_found_error(id);
throw osmium::not_found{id};
}
return value;
} catch (const std::out_of_range&) {
not_found_error(id);
throw osmium::not_found{id};
}
}
@@ -180,7 +180,7 @@ namespace osmium {
return a.first < b.first;
});
if (result == m_vector.end() || result->first != id) {
not_found_error(id);
throw osmium::not_found{id};
} else {
return result->second;
}
+431
View File
@@ -0,0 +1,431 @@
#ifndef OSMIUM_INDEX_ID_SET_HPP
#define OSMIUM_INDEX_ID_SET_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013-2016 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
#include <cassert>
#include <cstring>
#include <memory>
#include <type_traits>
#include <unordered_set>
#include <vector>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/types.hpp>
namespace osmium {
namespace index {
/**
* Virtual parent class for IdSets. Use one of the implementations
* provided.
*/
template <typename T>
class IdSet {
public:
virtual ~IdSet() {
}
/**
* Add the given Id to the set.
*/
virtual void set(T id) = 0;
/**
* Is the Id in the set?
*/
virtual bool get(T id) const noexcept = 0;
/**
* Is the set empty?
*/
virtual bool empty() const = 0;
/**
* Clear the set.
*/
virtual void clear() = 0;
}; // class IdSet
template <typename T>
class IdSetDense;
/**
* Const_iterator for iterating over a IdSetDense.
*/
template <typename T>
class IdSetDenseIterator {
const IdSetDense<T>* m_set;
T m_value;
T m_last;
void next() noexcept {
while (m_value != m_last && !m_set->get(m_value)) {
const auto cid = IdSetDense<T>::chunk_id(m_value);
assert(cid < m_set->m_data.size());
if (!m_set->m_data[cid]) {
m_value = (cid + 1) << (IdSetDense<T>::chunk_bits + 3);
} else {
const auto slot = m_set->m_data[cid][IdSetDense<T>::offset(m_value)];
if (slot == 0) {
m_value += 8;
m_value &= ~0x7;
} else {
++m_value;
}
}
}
}
public:
using iterator_category = std::forward_iterator_tag;
using value_type = T;
using pointer = value_type*;
using reference = value_type&;
IdSetDenseIterator(const IdSetDense<T>* set, T value, T last) noexcept :
m_set(set),
m_value(value),
m_last(last) {
next();
}
IdSetDenseIterator<T>& operator++() noexcept {
if (m_value != m_last) {
++m_value;
next();
}
return *this;
}
IdSetDenseIterator<T> operator++(int) noexcept {
IdSetDenseIterator<T> tmp(*this);
operator++();
return tmp;
}
bool operator==(const IdSetDenseIterator<T>& rhs) const noexcept {
return m_set == rhs.m_set && m_value == rhs.m_value;
}
bool operator!=(const IdSetDenseIterator<T>& rhs) const noexcept {
return ! (*this == rhs);
}
T operator*() const noexcept {
assert(m_value < m_last);
return m_value;
}
}; // class IdSetDenseIterator
/**
* A set of Ids of the given type. Internal storage is in chunks of
* arrays used as bit fields. Internally those chunks will be allocated
* as needed, so it works relatively efficiently with both smaller
* and larger Id sets. If it is not used, no memory is allocated at
* all.
*/
template <typename T>
class IdSetDense : public IdSet<T> {
static_assert(std::is_unsigned<T>::value, "Needs unsigned type");
static_assert(sizeof(T) >= 4, "Needs at least 32bit type");
friend class IdSetDenseIterator<T>;
// This value is a compromise. For node Ids it could be bigger
// which would mean less (but larger) memory allocations. For
// relations Ids it could be smaller, because they would all fit
// into a smaller allocation.
constexpr static const size_t chunk_bits = 22;
constexpr static const size_t chunk_size = 1 << chunk_bits;
std::vector<std::unique_ptr<unsigned char[]>> m_data;
size_t m_size = 0;
static size_t chunk_id(T id) noexcept {
return id >> (chunk_bits + 3);
}
static size_t offset(T id) noexcept {
return (id >> 3) & ((1 << chunk_bits) - 1);
}
static unsigned char bitmask(T id) noexcept {
return 1 << (id & 0x7);
}
T last() const noexcept {
return m_data.size() * chunk_size * 8;
}
unsigned char& get_element(T id) {
const auto cid = chunk_id(id);
if (cid >= m_data.size()) {
m_data.resize(cid + 1);
}
auto& chunk = m_data[cid];
if (!chunk) {
chunk.reset(new unsigned char[chunk_size]);
::memset(chunk.get(), 0, chunk_size);
}
return chunk[offset(id)];
}
public:
using const_iterator = IdSetDenseIterator<T>;
IdSetDense() = default;
/**
* Add the Id to the set if it is not already in there.
*
* @param id The Id to set.
* @returns true if the Id was added, false if it was already set.
*/
bool check_and_set(T id) {
auto& element = get_element(id);
if ((element & bitmask(id)) == 0) {
element |= bitmask(id);
++m_size;
return true;
}
return false;
}
/**
* Add the given Id to the set.
*
* @param id The Id to set.
*/
void set(T id) override final {
(void)check_and_set(id);
}
/**
* Remove the given Id from the set.
*
* @param id The Id to set.
*/
void unset(T id) {
auto& element = get_element(id);
if ((element & bitmask(id)) != 0) {
element &= ~bitmask(id);
--m_size;
}
}
/**
* Is the Id in the set?
*
* @param id The Id to check.
*/
bool get(T id) const noexcept override final {
if (chunk_id(id) >= m_data.size()) {
return false;
}
auto* r = m_data[chunk_id(id)].get();
if (!r) {
return false;
}
return (r[offset(id)] & bitmask(id)) != 0;
}
/**
* Is the set empty?
*/
bool empty() const noexcept override final {
return m_size == 0;
}
/**
* The number of Ids stored in the set.
*/
size_t size() const noexcept {
return m_size;
}
/**
* Clear the set.
*/
void clear() override final {
m_data.clear();
m_size = 0;
}
IdSetDenseIterator<T> begin() const {
return IdSetDenseIterator<T>{this, 0, last()};
}
IdSetDenseIterator<T> end() const {
return IdSetDenseIterator<T>{this, last(), last()};
}
}; // class IdSetDense
/**
* IdSet implementation for small Id sets. It writes the Ids
* into a vector and uses linear search.
*/
template <typename T>
class IdSetSmall : public IdSet<T> {
std::vector<T> m_data;
public:
/**
* Add the given Id to the set.
*/
void set(T id) override final {
m_data.push_back(id);
}
/**
* Is the Id in the set? Uses linear search.
*
* @param id The Id to check.
*/
bool get(T id) const noexcept override final {
const auto it = std::find(m_data.cbegin(), m_data.cend(), id);
return it != m_data.cend();
}
/**
* Is the Id in the set? Uses a binary search. For larger sets
* this might be more efficient than calling get(), the set
* must be sorted.
*
* @param id The Id to check.
* @pre You must have called sort_unique() before calling this
* or be sure there are no duplicates and the Ids have been
* set in order.
*/
bool get_binary_search(T id) const noexcept {
return std::binary_search(m_data.cbegin(), m_data.cend(), id);
}
/**
* Is the set empty?
*/
bool empty() const noexcept override final {
return m_data.empty();
}
/**
* Clear the set.
*/
void clear() override final {
m_data.clear();
}
/**
* Sort the internal vector and remove any duplicates. Call this
* before using size(), get_binary_search() or using an iterator.
*/
void sort_unique() {
std::sort(m_data.begin(), m_data.end());
const auto last = std::unique(m_data.begin(), m_data.end());
m_data.erase(last, m_data.end());
}
/**
* The number of Ids stored in the set.
*
* @pre You must have called sort_unique() before calling this
* or be sure there are no duplicates.
*/
size_t size() const noexcept {
return m_data.size();
}
/// Iterator type. There is no non-const iterator.
using const_iterator = typename std::vector<T>::const_iterator;
const_iterator begin() const noexcept {
return m_data.cbegin();
}
const_iterator end() const noexcept {
return m_data.cend();
}
const_iterator cbegin() const noexcept {
return m_data.cbegin();
}
const_iterator cend() const noexcept {
return m_data.cend();
}
}; // class IdSetSmall
template <template<typename> class IdSetType>
class NWRIdSet {
using id_set_type = IdSetType<osmium::unsigned_object_id_type>;
id_set_type m_sets[3];
public:
id_set_type& operator()(osmium::item_type type) noexcept {
return m_sets[osmium::item_type_to_nwr_index(type)];
}
const id_set_type& operator()(osmium::item_type type) const noexcept {
return m_sets[osmium::item_type_to_nwr_index(type)];
}
}; // class NWRIdSet
} // namespace index
} // namespace osmium
#endif // OSMIUM_INDEX_ID_SET_HPP
+4 -8
View File
@@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <string>
@@ -57,6 +56,10 @@ namespace osmium {
std::runtime_error(what) {
}
explicit not_found(uint64_t id) :
std::runtime_error(std::string{"id "} + std::to_string(id) + " not found") {
}
}; // struct not_found
/**
@@ -64,13 +67,6 @@ namespace osmium {
*/
namespace index {
template <typename TKey>
OSMIUM_NORETURN void not_found_error(TKey key) {
std::stringstream s;
s << "id " << key << " not found";
throw not_found(s.str());
}
/**
* Some of the index classes need an "empty" value that can
* never appear in real data. This function must return this
+16 -11
View File
@@ -48,6 +48,18 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
struct map_factory_error : public std::runtime_error {
explicit map_factory_error(const char* message) :
std::runtime_error(message) {
}
explicit map_factory_error(const std::string& message) :
std::runtime_error(message) {
}
}; // struct map_factory_error
namespace index {
/**
@@ -148,14 +160,14 @@ namespace osmium {
// default implementation is empty
}
// This function could usually be const in derived classes,
// This function can usually be const in derived classes,
// but not always. It could, for instance, sort internal data.
// This is why it is not declared const here.
virtual void dump_as_list(const int /*fd*/) {
throw std::runtime_error("can't dump as list");
}
// This function could usually be const in derived classes,
// This function can usually be const in derived classes,
// but not always. It could, for instance, sort internal data.
// This is why it is not declared const here.
virtual void dump_as_array(const int /*fd*/) {
@@ -188,13 +200,6 @@ namespace osmium {
MapFactory(MapFactory&&) = delete;
MapFactory& operator=(MapFactory&&) = delete;
OSMIUM_NORETURN static void error(const std::string& map_type_name) {
std::string error_message {"Support for map type '"};
error_message += map_type_name;
error_message += "' not compiled into this binary.";
throw std::runtime_error(error_message);
}
public:
static MapFactory<id_type, value_type>& instance() {
@@ -226,7 +231,7 @@ namespace osmium {
std::vector<std::string> config = osmium::split_string(config_string, ',');
if (config.empty()) {
throw std::runtime_error("Need non-empty map type name.");
throw map_factory_error{"Need non-empty map type name"};
}
auto it = m_callbacks.find(config[0]);
@@ -234,7 +239,7 @@ namespace osmium {
return std::unique_ptr<map_type>((it->second)(config));
}
error(config[0]);
throw map_factory_error{std::string{"Support for map type '"} + config[0] + "' not compiled into this binary"};
}
}; // class MapFactory
+1 -1
View File
@@ -63,7 +63,7 @@ namespace osmium {
}
const TValue get(const TId id) const final {
not_found_error(id);
throw osmium::not_found{id};
}
size_t size() const final {
@@ -79,7 +79,7 @@ namespace osmium {
const TValue get(const TId id) const final {
auto it = m_elements.find(id);
if (it == m_elements.end()) {
not_found_error(id);
throw osmium::not_found{id};
}
return it->second;
}
@@ -99,10 +99,10 @@ namespace osmium {
const TValue get(const TId id) const final {
if (id >= m_elements.size()) {
not_found_error(id);
throw osmium::not_found{id};
}
if (m_elements[id] == osmium::index::empty_value<TValue>()) {
not_found_error(id);
throw osmium::not_found{id};
}
return m_elements[id];
}
+26 -34
View File
@@ -145,10 +145,11 @@ namespace osmium {
private:
using compression_map_type = std::map<const osmium::io::file_compression,
std::tuple<create_compressor_type,
create_decompressor_type_fd,
create_decompressor_type_buffer>>;
using callbacks_type = std::tuple<create_compressor_type,
create_decompressor_type_fd,
create_decompressor_type_buffer>;
using compression_map_type = std::map<const osmium::io::file_compression, callbacks_type>;
compression_map_type m_callbacks;
@@ -160,11 +161,17 @@ namespace osmium {
CompressionFactory(CompressionFactory&&) = delete;
CompressionFactory& operator=(CompressionFactory&&) = delete;
OSMIUM_NORETURN void error(osmium::io::file_compression compression) {
std::string error_message {"Support for compression '"};
const callbacks_type& find_callbacks(osmium::io::file_compression compression) const {
const auto it = m_callbacks.find(compression);
if (it != m_callbacks.end()) {
return it->second;
}
std::string error_message{"Support for compression '"};
error_message += as_string(compression);
error_message += "' not compiled into this binary.";
throw unsupported_file_format_error(error_message);
error_message += "' not compiled into this binary";
throw unsupported_file_format_error{error_message};
}
public:
@@ -189,36 +196,21 @@ namespace osmium {
}
template <typename... TArgs>
std::unique_ptr<osmium::io::Compressor> create_compressor(osmium::io::file_compression compression, TArgs&&... args) {
auto it = m_callbacks.find(compression);
if (it != m_callbacks.end()) {
return std::unique_ptr<osmium::io::Compressor>(std::get<0>(it->second)(std::forward<TArgs>(args)...));
}
error(compression);
std::unique_ptr<osmium::io::Compressor> create_compressor(osmium::io::file_compression compression, TArgs&&... args) const {
const auto callbacks = find_callbacks(compression);
return std::unique_ptr<osmium::io::Compressor>(std::get<0>(callbacks)(std::forward<TArgs>(args)...));
}
std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, int fd) {
auto it = m_callbacks.find(compression);
if (it != m_callbacks.end()) {
auto p = std::unique_ptr<osmium::io::Decompressor>(std::get<1>(it->second)(fd));
p->set_file_size(osmium::util::file_size(fd));
return p;
}
error(compression);
std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, int fd) const {
const auto callbacks = find_callbacks(compression);
auto p = std::unique_ptr<osmium::io::Decompressor>(std::get<1>(callbacks)(fd));
p->set_file_size(osmium::util::file_size(fd));
return p;
}
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);
std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, const char* buffer, size_t size) const {
const auto callbacks = find_callbacks(compression);
return std::unique_ptr<osmium::io::Decompressor>(std::get<2>(callbacks)(buffer, size));
}
}; // class CompressionFactory
@@ -55,12 +55,17 @@ namespace osmium {
namespace detail {
struct reader_options {
osmium::osm_entity_bits::type read_which_entities = osm_entity_bits::all;
osmium::io::read_meta read_metadata = read_meta::yes;
};
class Parser {
future_buffer_queue_type& m_output_queue;
std::promise<osmium::io::Header>& m_header_promise;
queue_wrapper<std::string> m_input_queue;
osmium::osm_entity_bits::type m_read_types;
reader_options m_options;
bool m_header_is_done;
protected:
@@ -73,11 +78,15 @@ namespace osmium {
return m_input_queue.has_reached_end_of_data();
}
osmium::osm_entity_bits::type read_types() const {
return m_read_types;
osmium::osm_entity_bits::type read_types() const noexcept {
return m_options.read_which_entities;
}
bool header_is_done() const {
osmium::io::read_meta read_metadata() const noexcept {
return m_options.read_metadata;
}
bool header_is_done() const noexcept {
return m_header_is_done;
}
@@ -111,11 +120,11 @@ namespace osmium {
Parser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_types) :
osmium::io::detail::reader_options options) :
m_output_queue(output_queue),
m_header_promise(header_promise),
m_input_queue(input_queue),
m_read_types(read_types),
m_options(options),
m_header_is_done(false) {
}
@@ -157,7 +166,7 @@ namespace osmium {
using create_parser_type = std::function<std::unique_ptr<Parser>(future_string_queue_type&,
future_buffer_queue_type&,
std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_which_entities)>;
osmium::io::detail::reader_options options)>;
private:
@@ -80,7 +80,7 @@ namespace osmium {
struct o5m_error : public io_error {
explicit o5m_error(const char* what) :
io_error(std::string("o5m format error: ") + what) {
io_error(std::string{"o5m format error: "} + what) {
}
}; // struct o5m_error
@@ -135,7 +135,7 @@ namespace osmium {
const char* get(uint64_t index) const {
if (m_table.empty() || index == 0 || index > number_of_entries) {
throw o5m_error("reference to non-existing string in table");
throw o5m_error{"reference to non-existing string in table"};
}
auto entry = (current_entry + number_of_entries - index) % number_of_entries;
return &m_table[entry * entry_size];
@@ -191,7 +191,7 @@ namespace osmium {
static const unsigned char header_magic[] = { 0xff, 0xe0, 0x04, 'o', '5' };
if (std::strncmp(reinterpret_cast<const char*>(header_magic), m_data, sizeof(header_magic))) {
throw o5m_error("wrong header magic");
throw o5m_error{"wrong header magic"};
}
m_data += sizeof(header_magic);
@@ -203,7 +203,7 @@ namespace osmium {
} else if (*m_data == 'c') { // o5c change file
m_header.set_has_multiple_object_versions(true);
} else {
throw o5m_error("wrong header magic");
throw o5m_error{"wrong header magic"};
}
m_data++;
@@ -211,7 +211,7 @@ namespace osmium {
void check_file_format_version() {
if (*m_data != '2') {
throw o5m_error("wrong header magic");
throw o5m_error{"wrong header magic"};
}
m_data++;
@@ -219,7 +219,7 @@ namespace osmium {
void decode_header() {
if (! ensure_bytes_available(7)) { // overall length of header
throw o5m_error("file too short (incomplete header info)");
throw o5m_error{"file too short (incomplete header info)"};
}
check_header_magic();
@@ -260,7 +260,7 @@ namespace osmium {
if (**dataptr == 0x00) { // get inline string
(*dataptr)++;
if (*dataptr == end) {
throw o5m_error("string format error");
throw o5m_error{"string format error"};
}
return *dataptr;
} else { // get from reference table
@@ -277,7 +277,7 @@ namespace osmium {
auto uid = protozero::decode_varint(&data, end);
if (data == end) {
throw o5m_error("missing user name");
throw o5m_error{"missing user name"};
}
const char* user = ++data;
@@ -290,7 +290,7 @@ namespace osmium {
while (*data++) {
if (data == end) {
throw o5m_error("no null byte in user name");
throw o5m_error{"no null byte in user name"};
}
}
@@ -302,24 +302,24 @@ namespace osmium {
return std::make_pair(static_cast_with_assert<osmium::user_id_type>(uid), user);
}
void decode_tags(osmium::builder::Builder* builder, const char** dataptr, const char* const end) {
osmium::builder::TagListBuilder tl_builder(m_buffer, builder);
void decode_tags(osmium::builder::Builder& parent, const char** dataptr, const char* const end) {
osmium::builder::TagListBuilder builder{parent};
while(*dataptr != end) {
while (*dataptr != end) {
bool update_pointer = (**dataptr == 0x00);
const char* data = decode_string(dataptr, end);
const char* start = data;
while (*data++) {
if (data == end) {
throw o5m_error("no null byte in tag key");
throw o5m_error{"no null byte in tag key"};
}
}
const char* value = data;
while (*data++) {
if (data == end) {
throw o5m_error("no null byte in tag value");
throw o5m_error{"no null byte in tag value"};
}
}
@@ -328,7 +328,7 @@ namespace osmium {
*dataptr = data;
}
tl_builder.add_tag(start, value);
builder.add_tag(start, value);
}
}
@@ -357,50 +357,46 @@ namespace osmium {
}
void decode_node(const char* data, const char* const end) {
osmium::builder::NodeBuilder builder(m_buffer);
osmium::Node& node = builder.object();
osmium::builder::NodeBuilder builder{m_buffer};
node.set_id(m_delta_id.update(zvarint(&data, end)));
builder.set_id(m_delta_id.update(zvarint(&data, end)));
builder.add_user(decode_info(node, &data, end));
builder.set_user(decode_info(builder.object(), &data, end));
if (data == end) {
// no location, object is deleted
builder.object().set_visible(false);
builder.object().set_location(osmium::Location{});
builder.set_visible(false);
builder.set_location(osmium::Location{});
} else {
auto lon = m_delta_lon.update(zvarint(&data, end));
auto lat = m_delta_lat.update(zvarint(&data, end));
builder.object().set_location(osmium::Location{lon, lat});
builder.set_location(osmium::Location{lon, lat});
if (data != end) {
decode_tags(&builder, &data, end);
decode_tags(builder, &data, end);
}
}
m_buffer.commit();
}
void decode_way(const char* data, const char* const end) {
osmium::builder::WayBuilder builder(m_buffer);
osmium::Way& way = builder.object();
osmium::builder::WayBuilder builder{m_buffer};
way.set_id(m_delta_id.update(zvarint(&data, end)));
builder.set_id(m_delta_id.update(zvarint(&data, end)));
builder.add_user(decode_info(way, &data, end));
builder.set_user(decode_info(builder.object(), &data, end));
if (data == end) {
// no reference section, object is deleted
builder.object().set_visible(false);
builder.set_visible(false);
} else {
auto reference_section_length = protozero::decode_varint(&data, end);
if (reference_section_length > 0) {
const char* const end_refs = data + reference_section_length;
if (end_refs > end) {
throw o5m_error("way nodes ref section too long");
throw o5m_error{"way nodes ref section too long"};
}
osmium::builder::WayNodeListBuilder wn_builder(m_buffer, &builder);
osmium::builder::WayNodeListBuilder wn_builder{builder};
while (data < end_refs) {
wn_builder.add_node_ref(m_delta_way_node_id.update(zvarint(&data, end)));
@@ -408,16 +404,14 @@ namespace osmium {
}
if (data != end) {
decode_tags(&builder, &data, end);
decode_tags(builder, &data, end);
}
}
m_buffer.commit();
}
osmium::item_type decode_member_type(char c) {
if (c < '0' || c > '2') {
throw o5m_error("unknown member type");
throw o5m_error{"unknown member type"};
}
return osmium::nwr_index_to_item_type(c - '0');
}
@@ -429,13 +423,13 @@ namespace osmium {
auto member_type = decode_member_type(*data++);
if (data == end) {
throw o5m_error("missing role");
throw o5m_error{"missing role"};
}
const char* role = data;
while (*data++) {
if (data == end) {
throw o5m_error("no null byte in role");
throw o5m_error{"no null byte in role"};
}
}
@@ -448,30 +442,29 @@ namespace osmium {
}
void decode_relation(const char* data, const char* const end) {
osmium::builder::RelationBuilder builder(m_buffer);
osmium::Relation& relation = builder.object();
osmium::builder::RelationBuilder builder{m_buffer};
relation.set_id(m_delta_id.update(zvarint(&data, end)));
builder.set_id(m_delta_id.update(zvarint(&data, end)));
builder.add_user(decode_info(relation, &data, end));
builder.set_user(decode_info(builder.object(), &data, end));
if (data == end) {
// no reference section, object is deleted
builder.object().set_visible(false);
builder.set_visible(false);
} else {
auto reference_section_length = protozero::decode_varint(&data, end);
if (reference_section_length > 0) {
const char* const end_refs = data + reference_section_length;
if (end_refs > end) {
throw o5m_error("relation format error");
throw o5m_error{"relation format error"};
}
osmium::builder::RelationMemberListBuilder rml_builder(m_buffer, &builder);
osmium::builder::RelationMemberListBuilder rml_builder{builder};
while (data < end_refs) {
auto delta_id = zvarint(&data, end);
if (data == end) {
throw o5m_error("relation member format error");
throw o5m_error{"relation member format error"};
}
auto type_role = decode_role(&data, end);
auto i = osmium::item_type_to_nwr_index(type_role.first);
@@ -481,11 +474,9 @@ namespace osmium {
}
if (data != end) {
decode_tags(&builder, &data, end);
decode_tags(builder, &data, end);
}
}
m_buffer.commit();
}
void decode_bbox(const char* data, const char* const end) {
@@ -537,11 +528,11 @@ namespace osmium {
try {
length = protozero::decode_varint(&m_data, m_end);
} catch (const protozero::end_of_buffer_exception&) {
throw o5m_error("premature end of file");
throw o5m_error{"premature end of file"};
}
if (! ensure_bytes_available(length)) {
throw o5m_error("premature end of file");
throw o5m_error{"premature end of file"};
}
switch (ds_type) {
@@ -549,18 +540,21 @@ namespace osmium {
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::node) {
decode_node(m_data, m_data + length);
m_buffer.commit();
}
break;
case dataset_type::way:
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::way) {
decode_way(m_data, m_data + length);
m_buffer.commit();
}
break;
case dataset_type::relation:
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::relation) {
decode_relation(m_data, m_data + length);
m_buffer.commit();
}
break;
case dataset_type::bounding_box:
@@ -598,8 +592,8 @@ namespace osmium {
O5mParser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_types) :
Parser(input_queue, output_queue, header_promise, read_types),
osmium::io::detail::reader_options options) :
Parser(input_queue, output_queue, header_promise, options),
m_header(),
m_buffer(buffer_size),
m_input(),
@@ -625,8 +619,8 @@ namespace osmium {
[](future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_which_entities) {
return std::unique_ptr<Parser>(new O5mParser(input_queue, output_queue, header_promise, read_which_entities));
osmium::io::detail::reader_options options) {
return std::unique_ptr<Parser>(new O5mParser(input_queue, output_queue, header_promise, options));
});
// dummy function to silence the unused variable warning from above
@@ -82,8 +82,8 @@ namespace osmium {
OPLParser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_types) :
Parser(input_queue, output_queue, header_promise, read_types) {
osmium::io::detail::reader_options options) :
Parser(input_queue, output_queue, header_promise, options) {
set_header_value(osmium::io::Header{});
}
@@ -137,8 +137,8 @@ namespace osmium {
[](future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_which_entities) {
return std::unique_ptr<Parser>(new OPLParser(input_queue, output_queue, header_promise, read_which_entities));
osmium::io::detail::reader_options options) {
return std::unique_ptr<Parser>(new OPLParser(input_queue, output_queue, header_promise, options));
});
// dummy function to silence the unused variable warning from above
@@ -365,9 +365,8 @@ namespace osmium {
inline void opl_parse_node(const char** data, osmium::memory::Buffer& buffer) {
osmium::builder::NodeBuilder builder{buffer};
osmium::Node& node = builder.object();
node.set_id(opl_parse_id(data));
builder.set_id(opl_parse_id(data));
const char* tags_begin = nullptr;
@@ -382,19 +381,19 @@ namespace osmium {
++(*data);
switch (c) {
case 'v':
node.set_version(opl_parse_version(data));
builder.set_version(opl_parse_version(data));
break;
case 'd':
node.set_visible(opl_parse_visible(data));
builder.set_visible(opl_parse_visible(data));
break;
case 'c':
node.set_changeset(opl_parse_changeset_id(data));
builder.set_changeset(opl_parse_changeset_id(data));
break;
case 't':
node.set_timestamp(opl_parse_timestamp(data));
builder.set_timestamp(opl_parse_timestamp(data));
break;
case 'i':
node.set_uid(opl_parse_uid(data));
builder.set_uid(opl_parse_uid(data));
break;
case 'u':
opl_parse_string(data, user);
@@ -422,23 +421,20 @@ namespace osmium {
}
if (location.valid()) {
node.set_location(location);
builder.set_location(location);
}
builder.add_user(user);
builder.set_user(user);
if (tags_begin) {
opl_parse_tags(tags_begin, buffer, &builder);
}
buffer.commit();
}
inline void opl_parse_way(const char** data, osmium::memory::Buffer& buffer) {
osmium::builder::WayBuilder builder{buffer};
osmium::Way& way = builder.object();
way.set_id(opl_parse_id(data));
builder.set_id(opl_parse_id(data));
const char* tags_begin = nullptr;
@@ -455,19 +451,19 @@ namespace osmium {
++(*data);
switch (c) {
case 'v':
way.set_version(opl_parse_version(data));
builder.set_version(opl_parse_version(data));
break;
case 'd':
way.set_visible(opl_parse_visible(data));
builder.set_visible(opl_parse_visible(data));
break;
case 'c':
way.set_changeset(opl_parse_changeset_id(data));
builder.set_changeset(opl_parse_changeset_id(data));
break;
case 't':
way.set_timestamp(opl_parse_timestamp(data));
builder.set_timestamp(opl_parse_timestamp(data));
break;
case 'i':
way.set_uid(opl_parse_uid(data));
builder.set_uid(opl_parse_uid(data));
break;
case 'u':
opl_parse_string(data, user);
@@ -488,15 +484,13 @@ namespace osmium {
}
}
builder.add_user(user);
builder.set_user(user);
if (tags_begin) {
opl_parse_tags(tags_begin, buffer, &builder);
}
opl_parse_way_nodes(nodes_begin, nodes_end, buffer, &builder);
buffer.commit();
}
inline void opl_parse_relation_members(const char* s, const char* e, osmium::memory::Buffer& buffer, osmium::builder::RelationBuilder* parent_builder = nullptr) {
@@ -536,9 +530,8 @@ namespace osmium {
inline void opl_parse_relation(const char** data, osmium::memory::Buffer& buffer) {
osmium::builder::RelationBuilder builder{buffer};
osmium::Relation& relation = builder.object();
relation.set_id(opl_parse_id(data));
builder.set_id(opl_parse_id(data));
const char* tags_begin = nullptr;
@@ -555,19 +548,19 @@ namespace osmium {
++(*data);
switch (c) {
case 'v':
relation.set_version(opl_parse_version(data));
builder.set_version(opl_parse_version(data));
break;
case 'd':
relation.set_visible(opl_parse_visible(data));
builder.set_visible(opl_parse_visible(data));
break;
case 'c':
relation.set_changeset(opl_parse_changeset_id(data));
builder.set_changeset(opl_parse_changeset_id(data));
break;
case 't':
relation.set_timestamp(opl_parse_timestamp(data));
builder.set_timestamp(opl_parse_timestamp(data));
break;
case 'i':
relation.set_uid(opl_parse_uid(data));
builder.set_uid(opl_parse_uid(data));
break;
case 'u':
opl_parse_string(data, user);
@@ -588,7 +581,7 @@ namespace osmium {
}
}
builder.add_user(user);
builder.set_user(user);
if (tags_begin) {
opl_parse_tags(tags_begin, buffer, &builder);
@@ -597,15 +590,12 @@ namespace osmium {
if (members_begin != members_end) {
opl_parse_relation_members(members_begin, members_end, buffer, &builder);
}
buffer.commit();
}
inline void opl_parse_changeset(const char** data, osmium::memory::Buffer& buffer) {
osmium::builder::ChangesetBuilder builder{buffer};
osmium::Changeset& changeset = builder.object();
changeset.set_id(opl_parse_changeset_id(data));
builder.set_id(opl_parse_changeset_id(data));
const char* tags_begin = nullptr;
@@ -621,19 +611,19 @@ namespace osmium {
++(*data);
switch (c) {
case 'k':
changeset.set_num_changes(opl_parse_int<osmium::num_changes_type>(data));
builder.set_num_changes(opl_parse_int<osmium::num_changes_type>(data));
break;
case 's':
changeset.set_created_at(opl_parse_timestamp(data));
builder.set_created_at(opl_parse_timestamp(data));
break;
case 'e':
changeset.set_closed_at(opl_parse_timestamp(data));
builder.set_closed_at(opl_parse_timestamp(data));
break;
case 'd':
changeset.set_num_comments(opl_parse_int<osmium::num_comments_type>(data));
builder.set_num_comments(opl_parse_int<osmium::num_comments_type>(data));
break;
case 'i':
changeset.set_uid(opl_parse_uid(data));
builder.set_uid(opl_parse_uid(data));
break;
case 'u':
opl_parse_string(data, user);
@@ -672,17 +662,17 @@ namespace osmium {
}
if (location1.valid() && location2.valid()) {
changeset.bounds().extend(location1);
changeset.bounds().extend(location2);
osmium::Box box;
box.extend(location1);
box.extend(location2);
builder.set_bounds(box);
}
builder.add_user(user);
builder.set_user(user);
if (tags_begin) {
opl_parse_tags(tags_begin, buffer, &builder);
}
buffer.commit();
}
inline bool opl_parse_line(uint64_t line_count,
@@ -702,6 +692,7 @@ namespace osmium {
if (read_types & osmium::osm_entity_bits::node) {
++data;
opl_parse_node(&data, buffer);
buffer.commit();
return true;
}
break;
@@ -709,6 +700,7 @@ namespace osmium {
if (read_types & osmium::osm_entity_bits::way) {
++data;
opl_parse_way(&data, buffer);
buffer.commit();
return true;
}
break;
@@ -716,6 +708,7 @@ namespace osmium {
if (read_types & osmium::osm_entity_bits::relation) {
++data;
opl_parse_relation(&data, buffer);
buffer.commit();
return true;
}
break;
@@ -723,6 +716,7 @@ namespace osmium {
if (read_types & osmium::osm_entity_bits::changeset) {
++data;
opl_parse_changeset(&data, buffer);
buffer.commit();
return true;
}
break;
+126 -44
View File
@@ -50,6 +50,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
#include <osmium/io/detail/protobuf_tags.hpp>
#include <osmium/io/detail/zlib.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/box.hpp>
@@ -94,6 +95,8 @@ namespace osmium {
osmium::memory::Buffer m_buffer { initial_buffer_size };
osmium::io::read_meta m_read_metadata;
void decode_stringtable(const data_view& data) {
if (!m_stringtable.empty()) {
throw osmium::pbf_error("more than one stringtable in pbf file");
@@ -143,13 +146,19 @@ namespace osmium {
case OSMFormat::PrimitiveGroup::repeated_Node_nodes:
if (m_read_types & osmium::osm_entity_bits::node) {
decode_node(pbf_primitive_group.get_view());
m_buffer.commit();
} else {
pbf_primitive_group.skip();
}
break;
case OSMFormat::PrimitiveGroup::optional_DenseNodes_dense:
if (m_read_types & osmium::osm_entity_bits::node) {
decode_dense_nodes(pbf_primitive_group.get_view());
if (m_read_metadata == osmium::io::read_meta::yes) {
decode_dense_nodes(pbf_primitive_group.get_view());
} else {
decode_dense_nodes_without_metadata(pbf_primitive_group.get_view());
}
m_buffer.commit();
} else {
pbf_primitive_group.skip();
}
@@ -157,6 +166,7 @@ namespace osmium {
case OSMFormat::PrimitiveGroup::repeated_Way_ways:
if (m_read_types & osmium::osm_entity_bits::way) {
decode_way(pbf_primitive_group.get_view());
m_buffer.commit();
} else {
pbf_primitive_group.skip();
}
@@ -164,6 +174,7 @@ namespace osmium {
case OSMFormat::PrimitiveGroup::repeated_Relation_relations:
if (m_read_types & osmium::osm_entity_bits::relation) {
decode_relation(pbf_primitive_group.get_view());
m_buffer.commit();
} else {
pbf_primitive_group.skip();
}
@@ -221,9 +232,9 @@ namespace osmium {
using kv_type = protozero::iterator_range<protozero::pbf_reader::const_uint32_iterator>;
void build_tag_list(osmium::builder::Builder& builder, const kv_type& keys, const kv_type& vals) {
void build_tag_list(osmium::builder::Builder& parent, const kv_type& keys, const kv_type& vals) {
if (!keys.empty()) {
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
osmium::builder::TagListBuilder builder{parent};
auto kit = keys.begin();
auto vit = vals.begin();
while (kit != keys.end()) {
@@ -233,7 +244,7 @@ namespace osmium {
}
const auto& k = m_stringtable.at(*kit++);
const auto& v = m_stringtable.at(*vit++);
tl_builder.add_tag(k.first, k.second, v.first, v.second);
builder.add_tag(k.first, k.second, v.first, v.second);
}
}
}
@@ -243,7 +254,7 @@ namespace osmium {
}
void decode_node(const data_view& data) {
osmium::builder::NodeBuilder builder(m_buffer);
osmium::builder::NodeBuilder builder{m_buffer};
osmium::Node& node = builder.object();
kv_type keys;
@@ -266,7 +277,11 @@ namespace osmium {
vals = pbf_node.get_packed_uint32();
break;
case OSMFormat::Node::optional_Info_info:
user = decode_info(pbf_node.get_view(), builder.object());
if (m_read_metadata == osmium::io::read_meta::yes) {
user = decode_info(pbf_node.get_view(), builder.object());
} else {
pbf_node.skip();
}
break;
case OSMFormat::Node::required_sint64_lat:
lat = pbf_node.get_sint64();
@@ -290,15 +305,13 @@ namespace osmium {
));
}
builder.add_user(user.first, user.second);
builder.set_user(user.first, user.second);
build_tag_list(builder, keys, vals);
m_buffer.commit();
}
void decode_way(const data_view& data) {
osmium::builder::WayBuilder builder(m_buffer);
osmium::builder::WayBuilder builder{m_buffer};
kv_type keys;
kv_type vals;
@@ -321,7 +334,11 @@ namespace osmium {
vals = pbf_way.get_packed_uint32();
break;
case OSMFormat::Way::optional_Info_info:
user = decode_info(pbf_way.get_view(), builder.object());
if (m_read_metadata == osmium::io::read_meta::yes) {
user = decode_info(pbf_way.get_view(), builder.object());
} else {
pbf_way.skip();
}
break;
case OSMFormat::Way::packed_sint64_refs:
refs = pbf_way.get_packed_sint64();
@@ -337,10 +354,10 @@ namespace osmium {
}
}
builder.add_user(user.first, user.second);
builder.set_user(user.first, user.second);
if (!refs.empty()) {
osmium::builder::WayNodeListBuilder wnl_builder(m_buffer, &builder);
osmium::builder::WayNodeListBuilder wnl_builder{builder};
osmium::util::DeltaDecode<int64_t> ref;
if (lats.empty()) {
for (const auto& ref_value : refs) {
@@ -363,12 +380,10 @@ namespace osmium {
}
build_tag_list(builder, keys, vals);
m_buffer.commit();
}
void decode_relation(const data_view& data) {
osmium::builder::RelationBuilder builder(m_buffer);
osmium::builder::RelationBuilder builder{m_buffer};
kv_type keys;
kv_type vals;
@@ -391,7 +406,11 @@ namespace osmium {
vals = pbf_relation.get_packed_uint32();
break;
case OSMFormat::Relation::optional_Info_info:
user = decode_info(pbf_relation.get_view(), builder.object());
if (m_read_metadata == osmium::io::read_meta::yes) {
user = decode_info(pbf_relation.get_view(), builder.object());
} else {
pbf_relation.skip();
}
break;
case OSMFormat::Relation::packed_int32_roles_sid:
roles = pbf_relation.get_packed_int32();
@@ -407,10 +426,10 @@ namespace osmium {
}
}
builder.add_user(user.first, user.second);
builder.set_user(user.first, user.second);
if (!refs.empty()) {
osmium::builder::RelationMemberListBuilder rml_builder(m_buffer, &builder);
osmium::builder::RelationMemberListBuilder rml_builder{builder};
osmium::util::DeltaDecode<int64_t> ref;
while (!roles.empty() && !refs.empty() && !types.empty()) {
const auto& r = m_stringtable.at(roles.front());
@@ -431,8 +450,84 @@ namespace osmium {
}
build_tag_list(builder, keys, vals);
}
void build_tag_list_from_dense_nodes(osmium::builder::NodeBuilder& builder, protozero::pbf_reader::const_int32_iterator& it, protozero::pbf_reader::const_int32_iterator last) {
osmium::builder::TagListBuilder tl_builder{builder};
while (it != last && *it != 0) {
const auto& k = m_stringtable.at(*it++);
if (it == last) {
throw osmium::pbf_error("PBF format error"); // this is against the spec, keys/vals must come in pairs
}
const auto& v = m_stringtable.at(*it++);
tl_builder.add_tag(k.first, k.second, v.first, v.second);
}
if (it != last) {
++it;
}
}
void decode_dense_nodes_without_metadata(const data_view& data) {
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> ids;
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lats;
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lons;
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> tags;
protozero::pbf_message<OSMFormat::DenseNodes> pbf_dense_nodes(data);
while (pbf_dense_nodes.next()) {
switch (pbf_dense_nodes.tag()) {
case OSMFormat::DenseNodes::packed_sint64_id:
ids = pbf_dense_nodes.get_packed_sint64();
break;
case OSMFormat::DenseNodes::packed_sint64_lat:
lats = pbf_dense_nodes.get_packed_sint64();
break;
case OSMFormat::DenseNodes::packed_sint64_lon:
lons = pbf_dense_nodes.get_packed_sint64();
break;
case OSMFormat::DenseNodes::packed_int32_keys_vals:
tags = pbf_dense_nodes.get_packed_int32();
break;
default:
pbf_dense_nodes.skip();
}
}
osmium::util::DeltaDecode<int64_t> dense_id;
osmium::util::DeltaDecode<int64_t> dense_latitude;
osmium::util::DeltaDecode<int64_t> dense_longitude;
auto tag_it = tags.begin();
while (!ids.empty()) {
if (lons.empty() ||
lats.empty()) {
// this is against the spec, must have same number of elements
throw osmium::pbf_error("PBF format error");
}
osmium::builder::NodeBuilder builder{m_buffer};
osmium::Node& node = builder.object();
node.set_id(dense_id.update(ids.front()));
ids.drop_front();
const auto lon = dense_longitude.update(lons.front());
lons.drop_front();
const auto lat = dense_latitude.update(lats.front());
lats.drop_front();
builder.object().set_location(osmium::Location(
convert_pbf_coordinate(lon),
convert_pbf_coordinate(lat)
));
if (tag_it != tags.end()) {
build_tag_list_from_dense_nodes(builder, tag_it, tags.end());
}
}
m_buffer.commit();
}
void decode_dense_nodes(const data_view& data) {
@@ -522,7 +617,7 @@ namespace osmium {
bool visible = true;
osmium::builder::NodeBuilder builder(m_buffer);
osmium::builder::NodeBuilder builder{m_buffer};
osmium::Node& node = builder.object();
node.set_id(dense_id.update(ids.front()));
@@ -569,9 +664,7 @@ namespace osmium {
const auto& u = m_stringtable.at(dense_user_sid.update(user_sids.front()));
user_sids.drop_front();
builder.add_user(u.first, u.second);
} else {
builder.add_user("");
builder.set_user(u.first, u.second);
}
// even if the node isn't visible, there's still a record
@@ -588,31 +681,18 @@ namespace osmium {
}
if (tag_it != tags.end()) {
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
while (tag_it != tags.end() && *tag_it != 0) {
const auto& k = m_stringtable.at(*tag_it++);
if (tag_it == tags.end()) {
throw osmium::pbf_error("PBF format error"); // this is against the spec, keys/vals must come in pairs
}
const auto& v = m_stringtable.at(*tag_it++);
tl_builder.add_tag(k.first, k.second, v.first, v.second);
}
if (tag_it != tags.end()) {
++tag_it;
}
build_tag_list_from_dense_nodes(builder, tag_it, tags.end());
}
m_buffer.commit();
}
}
public:
PBFPrimitiveBlockDecoder(const data_view& data, osmium::osm_entity_bits::type read_types) :
PBFPrimitiveBlockDecoder(const data_view& data, osmium::osm_entity_bits::type read_types, osmium::io::read_meta read_metadata) :
m_data(data),
m_read_types(read_types) {
m_read_types(read_types),
m_read_metadata(read_metadata) {
}
PBFPrimitiveBlockDecoder(const PBFPrimitiveBlockDecoder&) = delete;
@@ -789,12 +869,14 @@ namespace osmium {
std::shared_ptr<std::string> m_input_buffer;
osmium::osm_entity_bits::type m_read_types;
osmium::io::read_meta m_read_metadata;
public:
PBFDataBlobDecoder(std::string&& input_buffer, osmium::osm_entity_bits::type read_types) :
PBFDataBlobDecoder(std::string&& input_buffer, osmium::osm_entity_bits::type read_types, osmium::io::read_meta read_metadata) :
m_input_buffer(std::make_shared<std::string>(std::move(input_buffer))),
m_read_types(read_types) {
m_read_types(read_types),
m_read_metadata(read_metadata) {
}
PBFDataBlobDecoder(const PBFDataBlobDecoder&) = default;
@@ -807,7 +889,7 @@ namespace osmium {
osmium::memory::Buffer operator()() {
std::string output;
PBFPrimitiveBlockDecoder decoder(decode_blob(*m_input_buffer, output), m_read_types);
PBFPrimitiveBlockDecoder decoder(decode_blob(*m_input_buffer, output), m_read_types, m_read_metadata);
return decoder();
}
@@ -180,7 +180,7 @@ namespace osmium {
while (const auto size = check_type_and_get_blob_size("OSMData")) {
std::string input_buffer = read_from_input_queue_with_check(size);
PBFDataBlobDecoder data_blob_parser{ std::move(input_buffer), read_types() };
PBFDataBlobDecoder data_blob_parser{std::move(input_buffer), read_types(), read_metadata()};
if (osmium::config::use_pool_threads_for_pbf_parsing()) {
send_to_output_queue(osmium::thread::Pool::instance().submit(std::move(data_blob_parser)));
@@ -195,8 +195,8 @@ namespace osmium {
PBFParser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_types) :
Parser(input_queue, output_queue, header_promise, read_types),
osmium::io::detail::reader_options options) :
Parser(input_queue, output_queue, header_promise, options),
m_input_buffer() {
}
@@ -221,8 +221,8 @@ namespace osmium {
[](future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_which_entities) {
return std::unique_ptr<Parser>(new PBFParser(input_queue, output_queue, header_promise, read_which_entities));
osmium::io::detail::reader_options options) {
return std::unique_ptr<Parser>(new PBFParser(input_queue, output_queue, header_promise, options));
});
// dummy function to silence the unused variable warning from above
@@ -33,10 +33,10 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
#include <exception>
#include <future>
#include <string>
#include <utility>
#include <osmium/memory/buffer.hpp>
#include <osmium/thread/queue.hpp>
@@ -59,13 +59,6 @@ namespace osmium {
*/
using future_buffer_queue_type = future_queue_type<osmium::memory::Buffer>;
/**
* This type of queue contains OSM file data in the form it is
* stored on disk, ie encoded as XML, PBF, etc.
* The "end of file" is marked by an empty string.
*/
using string_queue_type = osmium::thread::Queue<std::string>;
/**
* This type of queue contains OSM file data in the form it is
* stored on disk, ie encoded as XML, PBF, etc.
@@ -95,11 +88,11 @@ namespace osmium {
add_to_queue<T>(queue, T{});
}
inline bool at_end_of_data(const std::string& data) {
inline bool at_end_of_data(const std::string& data) noexcept {
return data.empty();
}
inline bool at_end_of_data(osmium::memory::Buffer& buffer) {
inline bool at_end_of_data(osmium::memory::Buffer& buffer) noexcept {
return !buffer;
}
@@ -80,8 +80,8 @@ namespace osmium {
XML_Error error_code;
std::string error_string;
explicit xml_error(XML_Parser parser) :
io_error(std::string("XML parsing error at line ")
explicit xml_error(const XML_Parser& parser) :
io_error(std::string{"XML parsing error at line "}
+ std::to_string(XML_GetCurrentLineNumber(parser))
+ ", column "
+ std::to_string(XML_GetCurrentColumnNumber(parser))
@@ -117,7 +117,7 @@ namespace osmium {
}
explicit format_version_error(const char* v) :
io_error(std::string("Can not read file with version ") + v),
io_error(std::string{"Can not read file with version "} + v),
version(v) {
}
@@ -201,7 +201,7 @@ namespace osmium {
static void entity_declaration_handler(void*,
const XML_Char*, int, const XML_Char*, int, const XML_Char*,
const XML_Char*, const XML_Char*, const XML_Char*) {
throw osmium::xml_error("XML entities are not supported");
throw osmium::xml_error{"XML entities are not supported"};
}
public:
@@ -209,7 +209,7 @@ namespace osmium {
explicit ExpatXMLParser(T* callback_object) :
m_parser(XML_ParserCreate(nullptr)) {
if (!m_parser) {
throw osmium::io_error("Internal error: Can not create 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);
@@ -229,7 +229,7 @@ namespace osmium {
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);
throw osmium::xml_error{m_parser};
}
}
@@ -271,37 +271,32 @@ namespace osmium {
return user;
}
void init_changeset(osmium::builder::ChangesetBuilder* builder, const XML_Char** attrs) {
const char* user = "";
osmium::Changeset& new_changeset = builder->object();
void init_changeset(osmium::builder::ChangesetBuilder& builder, const XML_Char** attrs) {
osmium::Box box;
osmium::Location min;
osmium::Location max;
check_attributes(attrs, [&min, &max, &user, &new_changeset](const XML_Char* name, const XML_Char* value) {
check_attributes(attrs, [&builder, &box](const XML_Char* name, const XML_Char* value) {
if (!std::strcmp(name, "min_lon")) {
min.set_lon(value);
box.bottom_left().set_lon(value);
} else if (!std::strcmp(name, "min_lat")) {
min.set_lat(value);
box.bottom_left().set_lat(value);
} else if (!std::strcmp(name, "max_lon")) {
max.set_lon(value);
box.top_right().set_lon(value);
} else if (!std::strcmp(name, "max_lat")) {
max.set_lat(value);
box.top_right().set_lat(value);
} else if (!std::strcmp(name, "user")) {
user = value;
builder.set_user(value);
} else {
new_changeset.set_attribute(name, value);
builder.set_attribute(name, value);
}
});
new_changeset.bounds().extend(min);
new_changeset.bounds().extend(max);
builder->add_user(user);
builder.set_bounds(box);
}
void get_tag(osmium::builder::Builder* builder, const XML_Char** attrs) {
void get_tag(osmium::builder::Builder& builder, const XML_Char** attrs) {
const char* k = "";
const char* v = "";
check_attributes(attrs, [&k, &v](const XML_Char* name, const XML_Char* value) {
if (name[0] == 'k' && name[1] == 0) {
k = value;
@@ -309,8 +304,9 @@ namespace osmium {
v = value;
}
});
if (!m_tl_builder) {
m_tl_builder = std::unique_ptr<osmium::builder::TagListBuilder>(new osmium::builder::TagListBuilder(m_buffer, builder));
m_tl_builder.reset(new osmium::builder::TagListBuilder{builder});
}
m_tl_builder->add_tag(k, v);
}
@@ -330,17 +326,17 @@ namespace osmium {
if (!std::strcmp(name, "version")) {
m_header.set("version", value);
if (std::strcmp(value, "0.6")) {
throw osmium::format_version_error(value);
throw osmium::format_version_error{value};
}
} else if (!std::strcmp(name, "generator")) {
m_header.set("generator", value);
}
});
if (m_header.get("version") == "") {
throw osmium::format_version_error();
throw osmium::format_version_error{};
}
} else {
throw osmium::xml_error(std::string("Unknown top-level element: ") + element);
throw osmium::xml_error{std::string{"Unknown top-level element: "} + element};
}
m_context = context::top;
break;
@@ -349,8 +345,8 @@ namespace osmium {
if (!std::strcmp(element, "node")) {
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::node) {
m_node_builder = std::unique_ptr<osmium::builder::NodeBuilder>(new osmium::builder::NodeBuilder(m_buffer));
m_node_builder->add_user(init_object(m_node_builder->object(), attrs));
m_node_builder.reset(new osmium::builder::NodeBuilder{m_buffer});
m_node_builder->set_user(init_object(m_node_builder->object(), attrs));
m_context = context::node;
} else {
m_context = context::ignored_node;
@@ -358,8 +354,8 @@ namespace osmium {
} else if (!std::strcmp(element, "way")) {
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::way) {
m_way_builder = std::unique_ptr<osmium::builder::WayBuilder>(new osmium::builder::WayBuilder(m_buffer));
m_way_builder->add_user(init_object(m_way_builder->object(), attrs));
m_way_builder.reset(new osmium::builder::WayBuilder{m_buffer});
m_way_builder->set_user(init_object(m_way_builder->object(), attrs));
m_context = context::way;
} else {
m_context = context::ignored_way;
@@ -367,8 +363,8 @@ namespace osmium {
} else if (!std::strcmp(element, "relation")) {
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::relation) {
m_relation_builder = std::unique_ptr<osmium::builder::RelationBuilder>(new osmium::builder::RelationBuilder(m_buffer));
m_relation_builder->add_user(init_object(m_relation_builder->object(), attrs));
m_relation_builder.reset(new osmium::builder::RelationBuilder{m_buffer});
m_relation_builder->set_user(init_object(m_relation_builder->object(), attrs));
m_context = context::relation;
} else {
m_context = context::ignored_relation;
@@ -376,8 +372,8 @@ namespace osmium {
} else if (!std::strcmp(element, "changeset")) {
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::changeset) {
m_changeset_builder = std::unique_ptr<osmium::builder::ChangesetBuilder>(new osmium::builder::ChangesetBuilder(m_buffer));
init_changeset(m_changeset_builder.get(), attrs);
m_changeset_builder.reset(new osmium::builder::ChangesetBuilder{m_buffer});
init_changeset(*m_changeset_builder, attrs);
m_context = context::changeset;
} else {
m_context = context::ignored_changeset;
@@ -407,7 +403,7 @@ namespace osmium {
m_last_context = context::node;
m_context = context::in_object;
if (!std::strcmp(element, "tag")) {
get_tag(m_node_builder.get(), attrs);
get_tag(*m_node_builder, attrs);
}
break;
case context::way:
@@ -417,7 +413,7 @@ namespace osmium {
m_tl_builder.reset();
if (!m_wnl_builder) {
m_wnl_builder = std::unique_ptr<osmium::builder::WayNodeListBuilder>(new osmium::builder::WayNodeListBuilder(m_buffer, m_way_builder.get()));
m_wnl_builder.reset(new osmium::builder::WayNodeListBuilder{*m_way_builder});
}
NodeRef nr;
@@ -433,7 +429,7 @@ namespace osmium {
m_wnl_builder->add_node_ref(nr);
} else if (!std::strcmp(element, "tag")) {
m_wnl_builder.reset();
get_tag(m_way_builder.get(), attrs);
get_tag(*m_way_builder, attrs);
}
break;
case context::relation:
@@ -443,7 +439,7 @@ namespace osmium {
m_tl_builder.reset();
if (!m_rml_builder) {
m_rml_builder = std::unique_ptr<osmium::builder::RelationMemberListBuilder>(new osmium::builder::RelationMemberListBuilder(m_buffer, m_relation_builder.get()));
m_rml_builder.reset(new osmium::builder::RelationMemberListBuilder{*m_relation_builder});
}
item_type type = item_type::undefined;
@@ -459,15 +455,15 @@ namespace osmium {
}
});
if (type != item_type::node && type != item_type::way && type != item_type::relation) {
throw osmium::xml_error("Unknown type on relation member");
throw osmium::xml_error{"Unknown type on relation member"};
}
if (ref == 0) {
throw osmium::xml_error("Missing ref on relation member");
throw osmium::xml_error{"Missing ref on relation member"};
}
m_rml_builder->add_member(type, ref, role);
} else if (!std::strcmp(element, "tag")) {
m_rml_builder.reset();
get_tag(m_relation_builder.get(), attrs);
get_tag(*m_relation_builder, attrs);
}
break;
case context::changeset:
@@ -476,12 +472,12 @@ namespace osmium {
m_context = context::discussion;
m_tl_builder.reset();
if (!m_changeset_discussion_builder) {
m_changeset_discussion_builder = std::unique_ptr<osmium::builder::ChangesetDiscussionBuilder>(new osmium::builder::ChangesetDiscussionBuilder(m_buffer, m_changeset_builder.get()));
m_changeset_discussion_builder.reset(new osmium::builder::ChangesetDiscussionBuilder{*m_changeset_builder});
}
} else if (!std::strcmp(element, "tag")) {
m_context = context::in_object;
m_changeset_discussion_builder.reset();
get_tag(m_changeset_builder.get(), attrs);
get_tag(*m_changeset_builder, attrs);
}
break;
case context::discussion:
@@ -632,8 +628,8 @@ namespace osmium {
XMLParser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_types) :
Parser(input_queue, output_queue, header_promise, read_types),
osmium::io::detail::reader_options options) :
Parser(input_queue, output_queue, header_promise, options),
m_context(context::root),
m_last_context(context::root),
m_in_delete_section(false),
@@ -657,7 +653,7 @@ namespace osmium {
ExpatXMLParser<XMLParser> parser(this);
while (!input_done()) {
std::string data = get_input();
const std::string data{get_input()};
parser(data, input_done());
if (read_types() == osmium::osm_entity_bits::nothing && header_is_done()) {
break;
@@ -680,8 +676,8 @@ namespace osmium {
[](future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_which_entities) {
return std::unique_ptr<Parser>(new XMLParser(input_queue, output_queue, header_promise, read_which_entities));
osmium::io::detail::reader_options options) {
return std::unique_ptr<Parser>(new XMLParser{input_queue, output_queue, header_promise, options});
});
// dummy function to silence the unused variable warning from above
@@ -49,6 +49,11 @@ namespace osmium {
debug = 6
};
enum class read_meta {
no = 0,
yes = 1
};
// avoid g++ false positive
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wreturn-type"
+63 -16
View File
@@ -44,17 +44,37 @@ namespace osmium {
namespace io {
/**
* Meta information from the header of an OSM file.
*/
* Meta information from the header of an OSM file.
*
* The header can contain any number of bounding boxes, although
* usually there is only a single one (or none). PBF files only
* allow a single bounding box, but XML files can have multiple ones,
* although it is unusual and the semantics are unclear, so it is
* discouraged to create files with multiple bounding boxes.
*
* The header contains a flag telling you whether this file can
* contain multiple versions of the same object. This is true for
* history files and for change files, but not for normal OSM data
* files. Not all OSM file formats can distinguish between those
* cases, so the flag might be wrong.
*
* In addition the header can contain any number of key-value pairs
* with additional information. Most often this is used to set the
* "generator", the program that generated the file. Depending on
* the file format some of these key-value pairs are handled
* specially. The the Options parent class for details on how to
* set and get those key-value pairs.
*/
class Header : public osmium::util::Options {
/// Bounding boxes
std::vector<osmium::Box> m_boxes;
/**
* Are there possibly multiple versions of the same object in this stream of objects?
* This is true for history files and for change files, but not for normal OSM files.
*/
* Are there possibly multiple versions of the same object in
* this stream of objects? This should be true for history files
* and for change files, but not for normal OSM data files.
*/
bool m_has_multiple_object_versions = false;
public:
@@ -65,49 +85,76 @@ namespace osmium {
Options(values) {
}
Header(const Header&) = default;
Header& operator=(const Header&) = default;
Header(Header&&) = default;
Header& operator=(Header&&) = default;
~Header() = default;
/**
* Get the bounding boxes defined in the header.
*/
std::vector<osmium::Box>& boxes() noexcept {
return m_boxes;
}
/**
* Get the bounding boxes defined in the header.
*/
const std::vector<osmium::Box>& boxes() const noexcept {
return m_boxes;
}
/**
* Set all the bounding boxes in the header.
*/
Header& boxes(const std::vector<osmium::Box>& boxes) noexcept {
m_boxes = boxes;
return *this;
}
/**
* Get the first (or only if there is only one) bounding box.
*
* Returns an empty, invalid box if there is none.
*/
osmium::Box box() const {
return m_boxes.empty() ? osmium::Box() : m_boxes.front();
return m_boxes.empty() ? osmium::Box{} : m_boxes.front();
}
/**
* Join up all the bounding boxes in the header into one and return
* it. This method is what you probably want to use unless you want
* to handle the possibly multiple bounding boxes yourself.
*
* Returns an empty, invalid box if there is none.
*/
osmium::Box joined_boxes() const {
osmium::Box box;
for (const auto& b : m_boxes) {
box.extend(b.bottom_left());
box.extend(b.top_right());
box.extend(b);
}
return box;
}
/**
* Add the given bounding box to the list of bounding boxes in the
* header.
*
* @returns The header itself to allow chaining.
*/
Header& add_box(const osmium::Box& box) {
m_boxes.push_back(box);
return *this;
}
/**
* Can this file contain multiple versions of the same object?
*/
bool has_multiple_object_versions() const noexcept {
return m_has_multiple_object_versions;
}
/**
* Set the flag that tells us whether this file can contain
* multiple versions of the same object?
*
* @returns The header itself to allow chaining.
*/
Header& set_has_multiple_object_versions(bool value) noexcept {
m_has_multiple_object_versions = value;
return *this;
+46 -17
View File
@@ -91,7 +91,6 @@ namespace osmium {
class Reader {
osmium::io::File m_file;
osmium::osm_entity_bits::type m_read_which_entities;
enum class status {
okay = 0, // normal reading
@@ -118,15 +117,25 @@ namespace osmium {
size_t m_file_size;
osmium::io::detail::reader_options m_options;
void set_option(osmium::osm_entity_bits::type value) noexcept {
m_options.read_which_entities = value;
}
void set_option(osmium::io::read_meta value) noexcept {
m_options.read_metadata = value;
}
// This function will run in a separate thread.
static void parser_thread(const osmium::io::File& file,
detail::future_string_queue_type& input_queue,
detail::future_buffer_queue_type& osmdata_queue,
std::promise<osmium::io::Header>&& header_promise,
osmium::osm_entity_bits::type read_which_entities) {
osmium::io::detail::reader_options options) {
std::promise<osmium::io::Header> promise = std::move(header_promise);
const auto creator = detail::ParserFactory::instance().get_creator_function(file);
const auto parser = creator(input_queue, osmdata_queue, promise, read_which_entities);
const auto parser = creator(input_queue, osmdata_queue, promise, options);
parser->parse();
}
@@ -205,15 +214,28 @@ namespace osmium {
/**
* Create new Reader object.
*
* @param file The file we want to open.
* @param read_which_entities Which OSM entities (nodes, ways, relations, and/or changesets)
* should be read from the input file. It can speed the read up
* significantly if objects that are not needed anyway are not
* parsed.
* @param file The file (contains name and format info) to open.
* @param args All further arguments are optional and can appear
* in any order:
*
* * osmium::osm_entities::bits: Which OSM entities (nodes, ways,
* relations, and/or changesets) should be read from the
* input file. It can speed the read up significantly if
* objects that are not needed anyway are not parsed.
*
* * osmium::io::read_meta: Read meta data or not. The default is
* osmium::io::read_meta::yes which means that meta data
* is read normally. If you set this to
* osmium::io::read_meta::no, meta data (like version, uid,
* etc.) is not read possibly speeding up the read. Not all
* file formats use this setting.
*
* @throws osmium::io_error If there was an error.
* @throws std::system_error If the file could not be opened.
*/
explicit Reader(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities = osmium::osm_entity_bits::all) :
template <typename... TArgs>
explicit Reader(const osmium::io::File& file, TArgs&&... args) :
m_file(file.check()),
m_read_which_entities(read_which_entities),
m_status(status::okay),
m_childpid(0),
m_input_queue(detail::get_input_queue_size(), "raw_input"),
@@ -227,17 +249,24 @@ namespace osmium {
m_header(),
m_thread(),
m_file_size(m_decompressor->file_size()) {
(void)std::initializer_list<int>{
(set_option(args), 0)...
};
std::promise<osmium::io::Header> header_promise;
m_header_future = header_promise.get_future();
m_thread = osmium::thread::thread_handler{parser_thread, std::ref(m_file), std::ref(m_input_queue), std::ref(m_osmdata_queue), std::move(header_promise), read_which_entities};
m_thread = osmium::thread::thread_handler{parser_thread, std::ref(m_file), std::ref(m_input_queue), std::ref(m_osmdata_queue), std::move(header_promise), m_options};
}
explicit Reader(const std::string& filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) :
Reader(osmium::io::File(filename), read_types) {
template <typename... TArgs>
explicit Reader(const std::string& filename, TArgs&&... args) :
Reader(osmium::io::File(filename), std::forward<TArgs>(args)...) {
}
explicit Reader(const char* filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) :
Reader(osmium::io::File(filename), read_types) {
template <typename... TArgs>
explicit Reader(const char* filename, TArgs&&... args) :
Reader(osmium::io::File(filename), std::forward<TArgs>(args)...) {
}
Reader(const Reader&) = delete;
@@ -304,7 +333,7 @@ namespace osmium {
try {
if (m_header_future.valid()) {
m_header = m_header_future.get();
if (m_read_which_entities == osmium::osm_entity_bits::nothing) {
if (m_options.read_which_entities == osmium::osm_entity_bits::nothing) {
m_status = status::eof;
}
}
@@ -330,7 +359,7 @@ namespace osmium {
osmium::memory::Buffer buffer;
if (m_status != status::okay ||
m_read_which_entities == osmium::osm_entity_bits::nothing) {
m_options.read_which_entities == osmium::osm_entity_bits::nothing) {
throw io_error("Can not read from reader when in status 'closed', 'eof', or 'error'");
}
+56 -26
View File
@@ -113,6 +113,9 @@ namespace osmium {
size_t m_capacity;
size_t m_written;
size_t m_committed;
#ifndef NDEBUG
uint8_t m_builder_count{0};
#endif
auto_grow m_auto_grow {auto_grow::no};
std::function<void(Buffer&)> m_full;
@@ -216,13 +219,28 @@ namespace osmium {
~Buffer() = default;
#ifndef NDEBUG
void increment_builder_count() noexcept {
++m_builder_count;
}
void decrement_builder_count() noexcept {
assert(m_builder_count > 0);
--m_builder_count;
}
uint8_t builder_count() const noexcept {
return m_builder_count;
}
#endif
/**
* Return a pointer to data inside the buffer.
*
* @pre The buffer must be valid.
*/
unsigned char* data() const noexcept {
assert(m_data);
assert(m_data && "This must be a valid buffer");
return m_data;
}
@@ -258,7 +276,7 @@ namespace osmium {
* @pre The buffer must be valid.
*/
bool is_aligned() const noexcept {
assert(m_data);
assert(m_data && "This must be a valid buffer");
return (m_written % align_bytes == 0) && (m_committed % align_bytes == 0);
}
@@ -283,7 +301,7 @@ namespace osmium {
* than the difference between committed() and capacity().
*/
OSMIUM_DEPRECATED void set_full_callback(std::function<void(Buffer&)> full) {
assert(m_data);
assert(m_data && "This must be a valid buffer");
m_full = full;
}
@@ -292,7 +310,6 @@ namespace osmium {
* This works only with internally memory-managed buffers.
* If the given size is not larger than the current capacity,
* nothing is done.
* Already written but not committed data is discarded.
*
* @pre The buffer must be valid.
*
@@ -305,7 +322,7 @@ namespace osmium {
* @throws std::bad_alloc if there isn't enough memory available.
*/
void grow(size_t size) {
assert(m_data);
assert(m_data && "This must be a valid buffer");
if (!m_memory) {
throw std::logic_error("Can't grow Buffer if it doesn't use internal memory management.");
}
@@ -325,15 +342,18 @@ namespace osmium {
/**
* Mark currently written bytes in the buffer as committed.
*
* @pre The buffer must be valid and aligned properly (as indicated
* @pre The buffer must be valid.
* @pre The buffer must be aligned properly (as indicated
* by is_aligned().
* @pre No builder can be open on this buffer.
*
* @returns Number of committed bytes before this commit. Can be
* used as an offset into the buffer to get to the
* object being committed by this call.
*/
size_t commit() {
assert(m_data);
assert(m_data && "This must be a valid buffer");
assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
assert(is_aligned());
const size_t offset = m_committed;
@@ -345,9 +365,11 @@ namespace osmium {
* Roll back changes in buffer to last committed state.
*
* @pre The buffer must be valid.
* @pre No builder can be open on this buffer.
*/
void rollback() {
assert(m_data);
assert(m_data && "This must be a valid buffer");
assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
m_written = m_committed;
}
@@ -356,9 +378,12 @@ namespace osmium {
*
* No-op on an invalid buffer.
*
* @pre No builder can be open on this buffer.
*
* @returns Number of bytes in the buffer before it was cleared.
*/
size_t clear() {
assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
const size_t committed = m_committed;
m_written = 0;
m_committed = 0;
@@ -377,7 +402,7 @@ namespace osmium {
*/
template <typename T>
T& get(const size_t offset) const {
assert(m_data);
assert(m_data && "This must be a valid buffer");
return *reinterpret_cast<T*>(&m_data[offset]);
}
@@ -415,7 +440,7 @@ namespace osmium {
* no callback defined and the buffer isn't auto-growing.
*/
unsigned char* reserve_space(const size_t size) {
assert(m_data);
assert(m_data && "This must be a valid buffer");
// try to flush the buffer empty first.
if (m_written + size > m_capacity && m_full) {
m_full(*this);
@@ -455,7 +480,7 @@ namespace osmium {
*/
template <typename T>
T& add_item(const T& item) {
assert(m_data);
assert(m_data && "This must be a valid buffer");
unsigned char* target = reserve_space(item.padded_size());
std::copy_n(reinterpret_cast<const unsigned char*>(&item), item.padded_size(), target);
return *reinterpret_cast<T*>(target);
@@ -465,6 +490,7 @@ namespace osmium {
* Add committed contents of the given buffer to this buffer.
*
* @pre The buffer must be valid.
* @pre No builder can be open on this buffer.
*
* Note that you have to eventually call commit() to actually
* commit this data.
@@ -472,7 +498,9 @@ namespace osmium {
* @param buffer The source of the copy. Must be valid.
*/
void add_buffer(const Buffer& buffer) {
assert(m_data && buffer);
assert(m_data && "This must be a valid buffer");
assert(buffer && "Buffer parameter must be a valid buffer");
assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
unsigned char* target = reserve_space(buffer.committed());
std::copy_n(buffer.data(), buffer.committed(), target);
}
@@ -482,11 +510,13 @@ namespace osmium {
* you can use std::back_inserter.
*
* @pre The buffer must be valid.
* @pre No builder can be open on this buffer.
*
* @param item The item to be added.
*/
void push_back(const osmium::memory::Item& item) {
assert(m_data);
assert(m_data && "This must be a valid buffer");
assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
add_item(item);
commit();
}
@@ -537,7 +567,7 @@ namespace osmium {
*/
template <typename T>
t_iterator<T> begin() {
assert(m_data);
assert(m_data && "This must be a valid buffer");
return t_iterator<T>(m_data, m_data + m_committed);
}
@@ -550,7 +580,7 @@ namespace osmium {
* @returns Iterator to first OSMEntity in the buffer.
*/
iterator begin() {
assert(m_data);
assert(m_data && "This must be a valid buffer");
return iterator(m_data, m_data + m_committed);
}
@@ -565,7 +595,7 @@ namespace osmium {
*/
template <typename T>
t_iterator<T> get_iterator(size_t offset) {
assert(m_data);
assert(m_data && "This must be a valid buffer");
return t_iterator<T>(m_data + offset, m_data + m_committed);
}
@@ -579,7 +609,7 @@ namespace osmium {
* buffer.
*/
iterator get_iterator(size_t offset) {
assert(m_data);
assert(m_data && "This must be a valid buffer");
return iterator(m_data + offset, m_data + m_committed);
}
@@ -593,7 +623,7 @@ namespace osmium {
*/
template <typename T>
t_iterator<T> end() {
assert(m_data);
assert(m_data && "This must be a valid buffer");
return t_iterator<T>(m_data + m_committed, m_data + m_committed);
}
@@ -606,40 +636,40 @@ namespace osmium {
* @returns End iterator.
*/
iterator end() {
assert(m_data);
assert(m_data && "This must be a valid buffer");
return iterator(m_data + m_committed, m_data + m_committed);
}
template <typename T>
t_const_iterator<T> cbegin() const {
assert(m_data);
assert(m_data && "This must be a valid buffer");
return t_const_iterator<T>(m_data, m_data + m_committed);
}
const_iterator cbegin() const {
assert(m_data);
assert(m_data && "This must be a valid buffer");
return const_iterator(m_data, m_data + m_committed);
}
template <typename T>
t_const_iterator<T> get_iterator(size_t offset) const {
assert(m_data);
assert(m_data && "This must be a valid buffer");
return t_const_iterator<T>(m_data + offset, m_data + m_committed);
}
const_iterator get_iterator(size_t offset) const {
assert(m_data);
assert(m_data && "This must be a valid buffer");
return const_iterator(m_data + offset, m_data + m_committed);
}
template <typename T>
t_const_iterator<T> cend() const {
assert(m_data);
assert(m_data && "This must be a valid buffer");
return t_const_iterator<T>(m_data + m_committed, m_data + m_committed);
}
const_iterator cend() const {
assert(m_data);
assert(m_data && "This must be a valid buffer");
return const_iterator(m_data + m_committed, m_data + m_committed);
}
@@ -698,7 +728,7 @@ namespace osmium {
*/
template <typename TCallbackClass>
void purge_removed(TCallbackClass* callback) {
assert(m_data);
assert(m_data && "This must be a valid buffer");
if (begin() == end()) {
return;
}
+32 -15
View File
@@ -46,9 +46,9 @@ namespace osmium {
template <typename TMember>
class CollectionIterator {
// This data_type is either 'unsigned char*' or 'const unsigned char*' depending
// on whether TMember is const. This allows this class to be used as an iterator and
// as a const_iterator.
// This data_type is either 'unsigned char*' or 'const unsigned
// char*' depending on whether TMember is const. This allows this
// class to be used as an iterator and as a const_iterator.
using data_type = typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type;
data_type m_data;
@@ -92,11 +92,11 @@ namespace osmium {
return m_data;
}
TMember& operator*() const {
TMember& operator*() const noexcept {
return *reinterpret_cast<TMember*>(m_data);
}
TMember* operator->() const {
TMember* operator->() const noexcept {
return reinterpret_cast<TMember*>(m_data);
}
@@ -118,9 +118,12 @@ namespace osmium {
public:
using iterator = CollectionIterator<TMember>;
using const_iterator = CollectionIterator<const TMember>;
using value_type = TMember;
using value_type = TMember;
using reference = TMember&;
using const_reference = const TMember&;
using iterator = CollectionIterator<TMember>;
using const_iterator = CollectionIterator<const TMember>;
using size_type = size_t;
static constexpr osmium::item_type itemtype = TCollectionItemType;
@@ -128,31 +131,45 @@ namespace osmium {
Item(sizeof(Collection<TMember, TCollectionItemType>), TCollectionItemType) {
}
bool empty() const {
/**
* Does this collection contain any items?
*
* Complexity: Constant.
*/
bool empty() const noexcept {
return sizeof(Collection<TMember, TCollectionItemType>) == byte_size();
}
iterator begin() {
/**
* Returns the number of items in this collection.
*
* Complexity: Linear in the number of items.
*/
size_type size() const noexcept {
return static_cast<size_type>(std::distance(begin(), end()));
}
iterator begin() noexcept {
return iterator(data() + sizeof(Collection<TMember, TCollectionItemType>));
}
iterator end() {
iterator end() noexcept {
return iterator(data() + byte_size());
}
const_iterator cbegin() const {
const_iterator cbegin() const noexcept {
return const_iterator(data() + sizeof(Collection<TMember, TCollectionItemType>));
}
const_iterator cend() const {
const_iterator cend() const noexcept {
return const_iterator(data() + byte_size());
}
const_iterator begin() const {
const_iterator begin() const noexcept {
return cbegin();
}
const_iterator end() const {
const_iterator end() const noexcept {
return cend();
}
+2 -2
View File
@@ -59,9 +59,9 @@ namespace osmium {
using item_size_type = uint32_t;
// align datastructures to this many bytes
constexpr item_size_type align_bytes = 8;
constexpr const item_size_type align_bytes = 8;
inline std::size_t padded_length(std::size_t length) noexcept {
inline constexpr std::size_t padded_length(std::size_t length) noexcept {
return (length + align_bytes - 1) & ~(align_bytes - 1);
}
+10 -2
View File
@@ -50,7 +50,8 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
namespace builder {
template <class T> class ObjectBuilder;
template <typename TDerived, typename T>
class OSMObjectBuilder;
} // namespace builder
/**
@@ -117,7 +118,8 @@ namespace osmium {
*/
class Area : public OSMObject {
friend class osmium::builder::ObjectBuilder<osmium::Area>;
template <typename TDerived, typename T>
friend class osmium::builder::OSMObjectBuilder;
Area() :
OSMObject(sizeof(Area), osmium::item_type::area) {
@@ -130,6 +132,8 @@ namespace osmium {
/**
* Was this area created from a way? (In contrast to areas
* created from a relation and their members.)
*
* Complexity: Constant.
*/
bool from_way() const noexcept {
return (positive_id() & 0x1) == 0;
@@ -137,6 +141,8 @@ namespace osmium {
/**
* Return the Id of the way or relation this area was created from.
*
* Complexity: Constant.
*/
osmium::object_id_type orig_id() const noexcept {
return osmium::area_id_to_object_id(id());
@@ -145,6 +151,8 @@ namespace osmium {
/**
* Count the number of outer and inner rings of this area.
*
* Complexity: Linear in the number of rings.
*
* @returns Pair (number outer rings, number inner rings)
*/
std::pair<size_t, size_t> num_rings() const {
+7 -11
View File
@@ -51,7 +51,7 @@ namespace osmium {
namespace builder {
class ChangesetDiscussionBuilder;
template <typename T> class ObjectBuilder;
class ChangesetBuilder;
} // namespace builder
class Changeset;
@@ -129,20 +129,12 @@ namespace osmium {
class ChangesetDiscussion : public osmium::memory::Collection<ChangesetComment, osmium::item_type::changeset_discussion> {
friend class osmium::builder::ObjectBuilder<osmium::Changeset>;
public:
using size_type = size_t;
ChangesetDiscussion() :
osmium::memory::Collection<ChangesetComment, osmium::item_type::changeset_discussion>() {
}
size_type size() const noexcept {
return static_cast<size_type>(std::distance(begin(), end()));
}
}; // class ChangesetDiscussion
static_assert(sizeof(ChangesetDiscussion) % osmium::memory::align_bytes == 0, "Class osmium::ChangesetDiscussion has wrong size to be aligned properly!");
@@ -156,7 +148,7 @@ namespace osmium {
*/
class Changeset : public osmium::OSMEntity {
friend class osmium::builder::ObjectBuilder<osmium::Changeset>;
friend class osmium::builder::ChangesetBuilder;
osmium::Box m_bounds;
osmium::Timestamp m_created_at;
@@ -173,10 +165,14 @@ namespace osmium {
OSMEntity(sizeof(Changeset), osmium::item_type::changeset) {
}
void set_user_size(string_size_type size) {
void set_user_size(string_size_type size) noexcept {
m_user_size = size;
}
string_size_type user_size() const noexcept {
return m_user_size;
}
unsigned char* subitems_position() {
return data() + osmium::memory::padded_length(sizeof(Changeset) + m_user_size);
}
+21 -21
View File
@@ -100,15 +100,15 @@ namespace osmium {
return m_crc;
}
void update_bool(const bool value) {
void update_bool(const bool value) noexcept {
m_crc.process_byte(value);
}
void update_int8(const uint8_t value) {
void update_int8(const uint8_t value) noexcept {
m_crc.process_byte(value);
}
void update_int16(const uint16_t value) {
void update_int16(const uint16_t value) noexcept {
#if __BYTE_ORDER == __LITTLE_ENDIAN
m_crc.process_bytes(&value, sizeof(uint16_t));
#else
@@ -117,7 +117,7 @@ namespace osmium {
#endif
}
void update_int32(const uint32_t value) {
void update_int32(const uint32_t value) noexcept {
#if __BYTE_ORDER == __LITTLE_ENDIAN
m_crc.process_bytes(&value, sizeof(uint32_t));
#else
@@ -126,7 +126,7 @@ namespace osmium {
#endif
}
void update_int64(const uint64_t value) {
void update_int64(const uint64_t value) noexcept {
#if __BYTE_ORDER == __LITTLE_ENDIAN
m_crc.process_bytes(&value, sizeof(uint64_t));
#else
@@ -135,57 +135,57 @@ namespace osmium {
#endif
}
void update_string(const char* str) {
void update_string(const char* str) noexcept {
while (*str) {
m_crc.process_byte(*str++);
}
}
void update(const Timestamp& timestamp) {
void update(const Timestamp& timestamp) noexcept {
update_int32(uint32_t(timestamp));
}
void update(const osmium::Location& location) {
void update(const osmium::Location& location) noexcept {
update_int32(location.x());
update_int32(location.y());
}
void update(const osmium::Box& box) {
void update(const osmium::Box& box) noexcept {
update(box.bottom_left());
update(box.top_right());
}
void update(const NodeRef& node_ref) {
void update(const NodeRef& node_ref) noexcept {
update_int64(node_ref.ref());
update(node_ref.location());
}
void update(const NodeRefList& node_refs) {
void update(const NodeRefList& node_refs) noexcept {
for (const NodeRef& node_ref : node_refs) {
update(node_ref);
}
}
void update(const TagList& tags) {
void update(const TagList& tags) noexcept {
for (const Tag& tag : tags) {
update_string(tag.key());
update_string(tag.value());
}
}
void update(const osmium::RelationMember& member) {
void update(const osmium::RelationMember& member) noexcept {
update_int64(member.ref());
update_int16(uint16_t(member.type()));
update_string(member.role());
}
void update(const osmium::RelationMemberList& members) {
void update(const osmium::RelationMemberList& members) noexcept {
for (const RelationMember& member : members) {
update(member);
}
}
void update(const osmium::OSMObject& object) {
void update(const osmium::OSMObject& object) noexcept {
update_int64(object.id());
update_bool(object.visible());
update_int32(object.version());
@@ -195,22 +195,22 @@ namespace osmium {
update(object.tags());
}
void update(const osmium::Node& node) {
void update(const osmium::Node& node) noexcept {
update(static_cast<const osmium::OSMObject&>(node));
update(node.location());
}
void update(const osmium::Way& way) {
void update(const osmium::Way& way) noexcept {
update(static_cast<const osmium::OSMObject&>(way));
update(way.nodes());
}
void update(const osmium::Relation& relation) {
void update(const osmium::Relation& relation) noexcept {
update(static_cast<const osmium::OSMObject&>(relation));
update(relation.members());
}
void update(const osmium::Area& area) {
void update(const osmium::Area& area) noexcept {
update(static_cast<const osmium::OSMObject&>(area));
for (const auto& subitem : area) {
if (subitem.type() == osmium::item_type::outer_ring ||
@@ -220,7 +220,7 @@ namespace osmium {
}
}
void update(const osmium::ChangesetDiscussion& discussion) {
void update(const osmium::ChangesetDiscussion& discussion) noexcept {
for (const auto& comment : discussion) {
update(comment.date());
update_int32(comment.uid());
@@ -229,7 +229,7 @@ namespace osmium {
}
}
void update(const osmium::Changeset& changeset) {
void update(const osmium::Changeset& changeset) noexcept {
update_int64(changeset.id());
update(changeset.created_at());
update(changeset.closed_at());
+14 -12
View File
@@ -60,7 +60,9 @@ namespace osmium {
* assert(! (entities & osmium::osm_entity_bits::changeset));
* @endcode
*/
enum type : unsigned char {
enum type : unsigned char { // this should have been an enum class
// but now we can't change it any more
// without breaking lots of code
nothing = 0x00,
node = 0x01,
@@ -75,8 +77,16 @@ namespace osmium {
}; // enum type
inline type operator|(const type lhs, const type rhs) noexcept {
return static_cast<type>(static_cast<int>(lhs) | static_cast<int> (rhs));
inline constexpr type operator|(const type lhs, const type rhs) noexcept {
return static_cast<type>(static_cast<int>(lhs) | static_cast<int>(rhs));
}
inline constexpr type operator&(const type lhs, const type rhs) noexcept {
return static_cast<type>(static_cast<int>(lhs) & static_cast<int>(rhs));
}
inline constexpr type operator~(const type value) noexcept {
return all & static_cast<type>(~static_cast<int>(value));
}
inline type& operator|=(type& lhs, const type rhs) noexcept {
@@ -84,14 +94,6 @@ namespace osmium {
return lhs;
}
inline type operator&(const type lhs, const type rhs) noexcept {
return static_cast<type>(static_cast<int>(lhs) & static_cast<int> (rhs));
}
inline type operator~(const type value) noexcept {
return static_cast<type>(~static_cast<int>(value));
}
inline type operator&=(type& lhs, const type rhs) noexcept {
lhs = lhs & rhs;
return lhs;
@@ -104,7 +106,7 @@ namespace osmium {
* changeset.
*/
inline type from_item_type(osmium::item_type item_type) noexcept {
auto ut = static_cast<std::underlying_type<osmium::item_type>::type>(item_type);
const auto ut = static_cast<std::underlying_type<osmium::item_type>::type>(item_type);
assert(ut <= 0x05);
if (ut == 0) {
return nothing;
+32 -22
View File
@@ -86,23 +86,31 @@ namespace osmium {
++str;
}
// there has to be at least one digit
if (*str >= '0' && *str <= '9') {
result = *str - '0';
++str;
if (*str != '.') {
// there has to be at least one digit
if (*str >= '0' && *str <= '9') {
result = *str - '0';
++str;
} else {
goto error;
}
// optional additional digits before decimal point
while (*str >= '0' && *str <= '9' && max_digits > 0) {
result = result * 10 + (*str - '0');
++str;
--max_digits;
}
if (max_digits == 0) {
goto error;
}
} else {
goto error;
}
// optional additional digits before decimal point
while (*str >= '0' && *str <= '9' && max_digits > 0) {
result = result * 10 + (*str - '0');
++str;
--max_digits;
}
if (max_digits == 0) {
goto error;
// need at least one digit after decimal dot if there was no
// digit before decimal dot
if (*(str + 1) < '0' || *(str + 1) > '9') {
goto error;
}
}
// optional decimal point
@@ -163,18 +171,20 @@ namespace osmium {
}
if (scale < 0) {
result = 0;
for (; scale < 0 && result > 0; ++scale) {
result /= 10;
}
} else {
for (; scale > 0; --scale) {
result *= 10;
}
}
result = (result + 5) / 10 * sign;
result = (result + 5) / 10 * sign;
if (result > std::numeric_limits<int32_t>::max() ||
result < std::numeric_limits<int32_t>::min()) {
goto error;
}
if (result > std::numeric_limits<int32_t>::max() ||
result < std::numeric_limits<int32_t>::min()) {
goto error;
}
*data = str;
+5 -3
View File
@@ -41,12 +41,14 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
namespace builder {
template <typename T> class ObjectBuilder;
template <typename TDerived, typename T>
class OSMObjectBuilder;
} // namespace builder
class Node : public OSMObject {
friend class osmium::builder::ObjectBuilder<osmium::Node>;
template <typename TDerived, typename T>
friend class osmium::builder::OSMObjectBuilder;
osmium::Location m_location;
@@ -62,7 +64,7 @@ namespace osmium {
return m_location;
}
Node& set_location(const osmium::Location& location) {
Node& set_location(const osmium::Location& location) noexcept {
m_location = location;
return *this;
}
+27 -6
View File
@@ -52,12 +52,23 @@ namespace osmium {
public:
using value_type = NodeRef;
using reference = NodeRef&;
using const_reference = const NodeRef&;
using iterator = NodeRef*;
using const_iterator = const NodeRef*;
using const_reverse_iterator = std::reverse_iterator<const NodeRef*>;
using difference_type = std::ptrdiff_t;
using size_type = std::size_t;
explicit NodeRefList(osmium::item_type itemtype) noexcept :
osmium::memory::Item(sizeof(NodeRefList), itemtype) {
}
/**
* Checks whether the collection is empty.
*
* Complexity: Constant.
*/
bool empty() const noexcept {
return sizeof(NodeRefList) == byte_size();
@@ -65,8 +76,10 @@ namespace osmium {
/**
* Returns the number of NodeRefs in the collection.
*
* Complexity: Constant.
*/
size_t size() const noexcept {
size_type size() const noexcept {
const auto size_node_refs = byte_size() - sizeof(NodeRefList);
assert(size_node_refs % sizeof(NodeRef) == 0);
return size_node_refs / sizeof(NodeRef);
@@ -75,11 +88,13 @@ namespace osmium {
/**
* Access specified element.
*
* Complexity: Constant.
*
* @pre @code n < size() @endcode
*
* @param n Get the n-th element of the collection.
*/
const NodeRef& operator[](size_t n) const noexcept {
const NodeRef& operator[](size_type n) const noexcept {
assert(n < size());
const NodeRef* node_ref = &*(cbegin());
return node_ref[n];
@@ -88,6 +103,8 @@ namespace osmium {
/**
* Access the first element.
*
* Complexity: Constant.
*
* @pre @code !empty() @endcode
*/
const NodeRef& front() const noexcept {
@@ -98,6 +115,8 @@ namespace osmium {
/**
* Access the last element.
*
* Complexity: Constant.
*
* @pre @code !empty() @endcode
*/
const NodeRef& back() const noexcept {
@@ -109,6 +128,8 @@ namespace osmium {
* Checks whether the first and last node in the collection have the
* same ID. The locations are not checked.
*
* Complexity: Constant.
*
* @pre @code !empty() @endcode
*/
bool is_closed() const noexcept {
@@ -119,6 +140,8 @@ namespace osmium {
* Checks whether the first and last node in the collection have the
* same ID. The locations are not checked.
*
* Complexity: Constant.
*
* @pre @code !empty() @endcode
*/
bool ends_have_same_id() const noexcept {
@@ -129,6 +152,8 @@ namespace osmium {
* Checks whether the first and last node in the collection have the
* same location. The IDs are not checked.
*
* Complexity: Constant.
*
* @pre @code !empty() @endcode
* @pre @code front().location() && back().location() @endcode
*/
@@ -137,10 +162,6 @@ namespace osmium {
return front().location() == back().location();
}
using iterator = NodeRef*;
using const_iterator = const NodeRef*;
using const_reverse_iterator = std::reverse_iterator<const NodeRef*>;
/// Returns an iterator to the beginning.
iterator begin() noexcept {
return iterator(data() + sizeof(NodeRefList));
+8
View File
@@ -52,11 +52,19 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
namespace builder {
template <typename TDerived, typename T>
class OSMObjectBuilder;
} // namespace builder
/**
* OSMObject (Node, Way, Relation, or Area).
*/
class OSMObject : public osmium::OSMEntity {
template <typename TDerived, typename T>
friend class osmium::builder::OSMObjectBuilder;
object_id_type m_id;
bool m_deleted : 1;
object_version_type m_version : 31;
+8 -9
View File
@@ -43,11 +43,14 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/util/compatibility.hpp>
namespace osmium {
namespace builder {
template <typename> class ObjectBuilder;
template <typename TDerived, typename T>
class OSMObjectBuilder;
class RelationMemberListBuilder;
} // namespace builder
@@ -109,7 +112,8 @@ namespace osmium {
return m_ref;
}
RelationMember& ref(object_id_type ref) noexcept {
/// @deprecated Use set_ref() instead.
OSMIUM_DEPRECATED RelationMember& ref(object_id_type ref) noexcept {
m_ref = ref;
return *this;
}
@@ -149,23 +153,18 @@ namespace osmium {
public:
using size_type = size_t;
RelationMemberList() :
osmium::memory::Collection<RelationMember, osmium::item_type::relation_member_list>() {
}
size_type size() const noexcept {
return static_cast<size_type>(std::distance(begin(), end()));
}
}; // class RelationMemberList
static_assert(sizeof(RelationMemberList) % osmium::memory::align_bytes == 0, "Class osmium::RelationMemberList has wrong size to be aligned properly!");
class Relation : public OSMObject {
friend class osmium::builder::ObjectBuilder<osmium::Relation>;
template <typename TDerived, typename T>
friend class osmium::builder::OSMObjectBuilder;
Relation() noexcept :
OSMObject(sizeof(Relation), osmium::item_type::relation) {
+6 -13
View File
@@ -86,12 +86,14 @@ namespace osmium {
}; // class Tag
inline bool operator==(const Tag& a, const Tag& b) {
return !std::strcmp(a.key(), b.key()) && !std::strcmp(a.value(), b.value());
inline bool operator==(const Tag& lhs, const Tag& rhs) {
return !std::strcmp(lhs.key(), rhs.key()) &&
!std::strcmp(lhs.value(), rhs.value());
}
inline bool operator<(const Tag& a, const Tag& b) {
return (!std::strcmp(a.key(), b.key()) && (std::strcmp(a.value(), b.value()) < 0)) || (std::strcmp(a.key(), b.key()) < 0);
inline bool operator<(const Tag& lhs, const Tag& rhs) {
const auto c = std::strcmp(lhs.key(), rhs.key());
return (c == 0 ? std::strcmp(lhs.value(), rhs.value()) : c) < 0;
}
/**
@@ -112,19 +114,10 @@ namespace osmium {
public:
using size_type = size_t;
TagList() :
osmium::memory::Collection<Tag, osmium::item_type::tag_list>() {
}
/**
* Returns the number of tags in this tag list.
*/
size_type size() const noexcept {
return static_cast<size_type>(std::distance(begin(), end()));
}
/**
* Get tag value for the given tag key. If the key is not set, returns
* the default_value.
+4 -2
View File
@@ -44,7 +44,8 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
namespace builder {
template <typename T> class ObjectBuilder;
template <typename TDerived, typename T>
class OSMObjectBuilder;
} // namespace builder
/**
@@ -66,7 +67,8 @@ namespace osmium {
class Way : public OSMObject {
friend class osmium::builder::ObjectBuilder<osmium::Way>;
template <typename TDerived, typename T>
friend class osmium::builder::OSMObjectBuilder;
Way() noexcept :
OSMObject(sizeof(Way), osmium::item_type::way) {
@@ -40,6 +40,7 @@ DEALINGS IN THE SOFTWARE.
#include <functional>
#include <iomanip>
#include <iostream>
#include <utility>
#include <vector>
#include <osmium/osm/item_type.hpp>
@@ -353,7 +354,7 @@ namespace osmium {
member_meta(member.type()).emplace_back(member.ref(), m_relations.size(), n);
relation_meta.increment_need_members();
} else {
member.ref(0); // set member id to zero to indicate we are not interested
member.set_ref(0); // set member id to zero to indicate we are not interested
}
++n;
}
@@ -494,12 +495,65 @@ namespace osmium {
return m_members_buffer;
}
/**
* Is the given member available in the members buffer?
*
* If you also need the offset of the object, use
* get_availability_and_offset() instead, it is more efficient
* that way.
*
* @param type Item type
* @param id Object Id
* @returns True if the object is available, false otherwise.
*/
bool is_available(osmium::item_type type, osmium::object_id_type id) {
const auto range = find_member_meta(type, id);
assert(!range.empty());
return range.begin()->is_available();
}
/**
* Get offset of a member in the members buffer.
*
* @pre The member must be available. If you are not sure, call
* get_availability_and_offset() instead.
* @param type Item type
* @param id Object Id
* @returns The offset of the object in the members buffer.
*/
size_t get_offset(osmium::item_type type, osmium::object_id_type id) {
const auto range = find_member_meta(type, id);
assert(!range.empty());
assert(range.begin()->is_available());
return range.begin()->buffer_offset();
}
/**
* Checks whether a member is available in the members buffer
* and returns its offset.
*
* If the member is not available, the boolean returned as the
* first element in the pair is false. In that case the offset
* in the second element is undefined.
*
* If the member is available, the boolean returned as the first
* element in the pair is true and the second element of the
* pair contains the offset into the members buffer.
*
* @param type Item type
* @param id Object Id
* @returns Pair of bool (showing availability) and the offset.
*/
std::pair<bool, size_t> get_availability_and_offset(osmium::item_type type, osmium::object_id_type id) {
const auto range = find_member_meta(type, id);
assert(!range.empty());
if (range.begin()->is_available()) {
return std::make_pair(true, range.begin()->buffer_offset());
} else {
return std::make_pair(false, 0);
}
}
template <typename TIter>
void read_relations(TIter begin, TIter end) {
HandlerPass1 handler(*static_cast<TCollector*>(this));
@@ -525,7 +579,7 @@ namespace osmium {
/**
* Decide whether to purge removed members and then do it.
*
* Currently the purging is done every thousand calls.
* Currently the purging is done every 10000 calls.
* This could probably be improved upon.
*/
void possibly_purge_removed_members() {
@@ -35,6 +35,7 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef>
#include <iosfwd>
#include <limits>
#include <osmium/osm/types.hpp>
@@ -71,24 +72,44 @@ namespace osmium {
/**
* Offset in the buffer where the object is stored.
*
* The default value is one that will never be valid, so it is
* easier to catch problems.
*/
size_t m_buffer_offset { 0 };
size_t m_buffer_offset = std::numeric_limits<size_t>::max();
/**
* Has this member been found in the input data.
*/
bool m_available = false;
/**
* Marks this member as removed. It can not be used any more.
*/
bool m_removed = false;
public:
/**
* Create new MemberMeta. The variant with zeros for relation_pos and
* member_pos is used to create dummy MemberMeta that can be compared
* to the MemberMeta in the vectors using the equal_range algorithm.
* Create new MemberMeta.
*/
explicit MemberMeta(osmium::object_id_type member_id, size_t relation_pos=0, size_t member_pos=0) noexcept :
explicit MemberMeta(osmium::object_id_type member_id, size_t relation_pos, size_t member_pos) noexcept :
m_member_id(member_id),
m_relation_pos(relation_pos),
m_member_pos(member_pos) {
}
/**
* Create new MemberMeta. This constructor is used to create
* dummy MemberMeta objects that can be compared to the
* MemberMetas in a vector using the equal_range algorithm.
*/
explicit MemberMeta(osmium::object_id_type member_id) noexcept :
m_member_id(member_id),
m_relation_pos(0),
m_member_pos(0) {
}
osmium::object_id_type member_id() const noexcept {
return m_member_id;
}
@@ -107,6 +128,11 @@ namespace osmium {
void set_buffer_offset(size_t offset) noexcept {
m_buffer_offset = offset;
m_available = true;
}
bool is_available() const noexcept {
return m_available;
}
bool removed() const noexcept {
@@ -124,8 +150,8 @@ namespace osmium {
* Used to sort a vector of MemberMeta objects and to later find
* them using binary search.
*/
inline bool operator<(const MemberMeta& a, const MemberMeta& b) noexcept {
return a.member_id() < b.member_id();
inline bool operator<(const MemberMeta& lhs, const MemberMeta& rhs) noexcept {
return lhs.member_id() < rhs.member_id();
}
template <typename TChar, typename TTraits>
+40 -17
View File
@@ -51,7 +51,7 @@ namespace osmium {
namespace thread {
static const std::chrono::milliseconds full_queue_sleep_duration { 10 }; // XXX
static const std::chrono::milliseconds max_wait{10};
/**
* A thread-safe queue.
@@ -70,9 +70,12 @@ namespace osmium {
std::queue<T> m_queue;
/// Used to signal readers when data is available in the queue.
/// Used to signal consumers when data is available in the queue.
std::condition_variable m_data_available;
/// Used to signal producers when queue is not full.
std::condition_variable m_space_available;
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
/// The largest size the queue has been so far.
size_t m_largest_size;
@@ -109,7 +112,8 @@ namespace osmium {
m_name(name),
m_mutex(),
m_queue(),
m_data_available()
m_data_available(),
m_space_available()
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
,
m_largest_size(0),
@@ -123,13 +127,20 @@ namespace osmium {
~Queue() {
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
std::cerr << "queue '" << m_name << "' with max_size=" << m_max_size << " had largest size " << m_largest_size << " and was full " << m_full_counter << " times in " << m_push_counter << " push() calls and was empty " << m_empty_counter << " times in " << m_pop_counter << " pop() calls\n";
std::cerr << "queue '" << m_name
<< "' with max_size=" << m_max_size
<< " had largest size " << m_largest_size
<< " and was full " << m_full_counter
<< " times in " << m_push_counter
<< " push() calls and was empty " << m_empty_counter
<< " times in " << m_pop_counter
<< " pop() calls\n";
#endif
}
/**
* Push an element onto the queue. If the queue has a max size, this
* call will block if the queue is full.
* Push an element onto the queue. If the queue has a max size,
* this call will block if the queue is full.
*/
void push(T value) {
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
@@ -137,13 +148,16 @@ namespace osmium {
#endif
if (m_max_size) {
while (size() >= m_max_size) {
std::this_thread::sleep_for(full_queue_sleep_duration);
std::unique_lock<std::mutex> lock{m_mutex};
m_space_available.wait_for(lock, max_wait, [this] {
return m_queue.size() < m_max_size;
});
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
++m_full_counter;
#endif
}
}
std::lock_guard<std::mutex> lock(m_mutex);
std::lock_guard<std::mutex> lock{m_mutex};
m_queue.push(std::move(value));
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
if (m_largest_size < m_queue.size()) {
@@ -157,7 +171,7 @@ namespace osmium {
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
++m_pop_counter;
#endif
std::unique_lock<std::mutex> lock(m_mutex);
std::unique_lock<std::mutex> lock{m_mutex};
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
if (m_queue.empty()) {
++m_empty_counter;
@@ -169,6 +183,10 @@ namespace osmium {
if (!m_queue.empty()) {
value = std::move(m_queue.front());
m_queue.pop();
lock.unlock();
if (m_max_size) {
m_space_available.notify_one();
}
}
}
@@ -176,25 +194,30 @@ namespace osmium {
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
++m_pop_counter;
#endif
std::lock_guard<std::mutex> lock(m_mutex);
if (m_queue.empty()) {
{
std::lock_guard<std::mutex> lock{m_mutex};
if (m_queue.empty()) {
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
++m_empty_counter;
++m_empty_counter;
#endif
return false;
return false;
}
value = std::move(m_queue.front());
m_queue.pop();
}
if (m_max_size) {
m_space_available.notify_one();
}
value = std::move(m_queue.front());
m_queue.pop();
return true;
}
bool empty() const {
std::lock_guard<std::mutex> lock(m_mutex);
std::lock_guard<std::mutex> lock{m_mutex};
return m_queue.empty();
}
size_t size() const {
std::lock_guard<std::mutex> lock(m_mutex);
std::lock_guard<std::mutex> lock{m_mutex};
return m_queue.size();
}
@@ -172,6 +172,18 @@ namespace osmium {
}
}
/**
* Removes the progress bar. Call this before doing any other output.
* The next time update() is called, the progress bar will be visible
* again.
*/
void remove() {
if (m_enable) {
std::cerr << spc() << " \r";
m_prev_percent = 100 + 1;
}
}
}; // class ProgressBar
} // namespace osmium
+2 -2
View File
@@ -34,9 +34,9 @@ DEALINGS IN THE SOFTWARE.
*/
#define LIBOSMIUM_VERSION_MAJOR 2
#define LIBOSMIUM_VERSION_MINOR 9
#define LIBOSMIUM_VERSION_MINOR 10
#define LIBOSMIUM_VERSION_PATCH 0
#define LIBOSMIUM_VERSION_STRING "2.9.0"
#define LIBOSMIUM_VERSION_STRING "2.10.0"
#endif // OSMIUM_VERSION_HPP