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
+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