Merge commit '6eb4f090f98f6b17a23c57768c16b7716b6c9cbd' as 'third_party/libosmium'
This commit is contained in:
@@ -0,0 +1,922 @@
|
||||
#ifndef OSMIUM_BUILDER_ATTR_HPP
|
||||
#define OSMIUM_BUILDER_ATTR_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <cstddef>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/builder/builder.hpp>
|
||||
#include <osmium/builder/osm_object_builder.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/changeset.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/relation.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace builder {
|
||||
|
||||
namespace detail {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// workaround for bug in MSVC
|
||||
|
||||
template <typename THandler, typename... TTypes>
|
||||
struct is_handled_by;
|
||||
|
||||
template <typename THandler>
|
||||
struct is_handled_by<THandler> {
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <typename THandler, typename T, typename... TRest>
|
||||
struct is_handled_by<THandler, T, TRest...> {
|
||||
static constexpr bool value = std::is_base_of<typename T::handler, THandler>::value ||
|
||||
is_handled_by<THandler, TRest...>::value;
|
||||
};
|
||||
|
||||
template <typename THandler, typename... TTypes>
|
||||
struct are_all_handled_by;
|
||||
|
||||
template <typename THandler, typename T>
|
||||
struct are_all_handled_by<THandler, T> {
|
||||
static constexpr bool value = std::is_base_of<typename T::handler, THandler>::value;
|
||||
};
|
||||
|
||||
template <typename THandler, typename T, typename... TRest>
|
||||
struct are_all_handled_by<THandler, T, TRest...> {
|
||||
static constexpr bool value = std::is_base_of<typename T::handler, THandler>::value &&
|
||||
are_all_handled_by<THandler, TRest...>::value;
|
||||
};
|
||||
#else
|
||||
// True if Predicate matches for none of the types Ts
|
||||
template <template<typename> class Predicate, typename... Ts>
|
||||
struct static_none_of : std::is_same<std::tuple<std::false_type, typename Predicate<Ts>::type...>,
|
||||
std::tuple<typename Predicate<Ts>::type..., std::false_type>>
|
||||
{};
|
||||
|
||||
// True if Predicate matches for all of the types Ts
|
||||
template <template<typename> class Predicate, typename... Ts>
|
||||
struct static_all_of : std::is_same<std::tuple<std::true_type, typename Predicate<Ts>::type...>,
|
||||
std::tuple<typename Predicate<Ts>::type..., std::true_type>>
|
||||
{};
|
||||
|
||||
// True if THandler is derived from the handler for at least one of the types in TTypes
|
||||
template <typename THandler, typename... TTypes>
|
||||
struct is_handled_by {
|
||||
template <typename T>
|
||||
using HasHandler = std::is_base_of<typename T::handler, THandler>;
|
||||
|
||||
static constexpr bool value = !static_none_of<HasHandler, TTypes...>::value;
|
||||
};
|
||||
|
||||
// True if THandler is derived from the handlers of all the types in TTypes
|
||||
template <typename THandler, typename... TTypes>
|
||||
struct are_all_handled_by {
|
||||
template <typename T>
|
||||
using HasHandler = std::is_base_of<typename T::handler, THandler>;
|
||||
|
||||
static constexpr bool value = static_all_of<HasHandler, TTypes...>::value;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
// Wraps any type, so that we can derive from it
|
||||
template <typename TType>
|
||||
struct type_wrapper {
|
||||
|
||||
using type = TType;
|
||||
|
||||
TType value;
|
||||
|
||||
constexpr explicit type_wrapper(const TType& v) :
|
||||
value(v) {
|
||||
}
|
||||
|
||||
}; // struct type_wrapper
|
||||
|
||||
// Small wrapper for begin/end iterator
|
||||
template <typename TType>
|
||||
struct iterator_wrapper {
|
||||
|
||||
using type = TType;
|
||||
|
||||
TType first;
|
||||
TType last;
|
||||
|
||||
constexpr iterator_wrapper(TType begin, TType end) :
|
||||
first(begin),
|
||||
last(end) {}
|
||||
|
||||
constexpr TType begin() const {
|
||||
return first;
|
||||
}
|
||||
|
||||
constexpr TType end() const {
|
||||
return last;
|
||||
}
|
||||
|
||||
}; // struct iterator_wrapper
|
||||
|
||||
|
||||
struct entity_handler {};
|
||||
struct object_handler;
|
||||
struct node_handler;
|
||||
struct tags_handler;
|
||||
struct nodes_handler;
|
||||
struct members_handler;
|
||||
struct changeset_handler;
|
||||
struct discussion_handler;
|
||||
struct ring_handler;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#define OSMIUM_ATTRIBUTE(_handler, _name, _type) \
|
||||
struct _name : public osmium::builder::detail::type_wrapper<_type> { \
|
||||
using handler = osmium::builder::detail::_handler;
|
||||
|
||||
#define OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(_handler, _name, _type) \
|
||||
OSMIUM_ATTRIBUTE(_handler, _name, _type) \
|
||||
constexpr explicit _name(std::add_const<_type>::type& value) : \
|
||||
type_wrapper(value) {} \
|
||||
}
|
||||
|
||||
#define OSMIUM_ATTRIBUTE_ITER(_handler, _name) \
|
||||
template <typename TIterator> \
|
||||
struct _name : public osmium::builder::detail::iterator_wrapper<TIterator> { \
|
||||
using handler = osmium::builder::detail::_handler; \
|
||||
constexpr _name(TIterator first, TIterator last) : \
|
||||
osmium::builder::detail::iterator_wrapper<TIterator>(first, last) {} \
|
||||
}
|
||||
|
||||
namespace attr {
|
||||
|
||||
OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(object_handler, _id, osmium::object_id_type);
|
||||
OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(object_handler, _version, osmium::object_version_type);
|
||||
OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(entity_handler, _uid, osmium::user_id_type);
|
||||
OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(entity_handler, _cid, osmium::changeset_id_type);
|
||||
|
||||
OSMIUM_ATTRIBUTE(object_handler, _deleted, bool)
|
||||
constexpr explicit _deleted(bool value = true) noexcept :
|
||||
type_wrapper(value) {}
|
||||
};
|
||||
|
||||
OSMIUM_ATTRIBUTE(object_handler, _visible, bool)
|
||||
constexpr explicit _visible(bool value = true) noexcept :
|
||||
type_wrapper(value) {}
|
||||
};
|
||||
|
||||
OSMIUM_ATTRIBUTE(object_handler, _timestamp, osmium::Timestamp)
|
||||
constexpr explicit _timestamp(const osmium::Timestamp& value) noexcept :
|
||||
type_wrapper(value) {}
|
||||
constexpr explicit _timestamp(time_t value) noexcept :
|
||||
type_wrapper(osmium::Timestamp{value}) {}
|
||||
constexpr explicit _timestamp(uint32_t value) noexcept :
|
||||
type_wrapper(osmium::Timestamp{value}) {}
|
||||
explicit _timestamp(const char* value) :
|
||||
type_wrapper(osmium::Timestamp{value}) {}
|
||||
explicit _timestamp(const std::string& value) :
|
||||
type_wrapper(osmium::Timestamp{value}) {}
|
||||
};
|
||||
|
||||
OSMIUM_ATTRIBUTE(node_handler, _location, osmium::Location)
|
||||
constexpr explicit _location(const osmium::Location& value) noexcept :
|
||||
type_wrapper(value) {}
|
||||
explicit _location(double lat, double lon) :
|
||||
type_wrapper(osmium::Location{lat, lon}) {}
|
||||
};
|
||||
|
||||
OSMIUM_ATTRIBUTE(entity_handler, _user, const char*)
|
||||
constexpr explicit _user(const char* val) noexcept :
|
||||
type_wrapper(val) {}
|
||||
explicit _user(const std::string& val) noexcept :
|
||||
type_wrapper(val.c_str()) {}
|
||||
};
|
||||
|
||||
using pair_of_cstrings = std::pair<const char* const, const char* const>;
|
||||
using pair_of_strings = std::pair<const std::string&, const std::string&>;
|
||||
|
||||
class member_type {
|
||||
|
||||
osmium::item_type m_type;
|
||||
osmium::object_id_type m_ref;
|
||||
const char* m_role;
|
||||
|
||||
public:
|
||||
|
||||
constexpr member_type(osmium::item_type type, osmium::object_id_type ref, const char* role = "") noexcept :
|
||||
m_type(type),
|
||||
m_ref(ref),
|
||||
m_role(role) {
|
||||
}
|
||||
|
||||
constexpr osmium::item_type type() const noexcept {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
constexpr osmium::object_id_type ref() const noexcept {
|
||||
return m_ref;
|
||||
}
|
||||
|
||||
constexpr const char* role() const noexcept {
|
||||
return m_role;
|
||||
}
|
||||
|
||||
}; // class member_type
|
||||
|
||||
class member_type_string {
|
||||
|
||||
osmium::item_type m_type;
|
||||
osmium::object_id_type m_ref;
|
||||
std::string m_role;
|
||||
|
||||
public:
|
||||
|
||||
member_type_string(osmium::item_type type, osmium::object_id_type ref, std::string&& role) :
|
||||
m_type(type),
|
||||
m_ref(ref),
|
||||
m_role(std::move(role)) {
|
||||
}
|
||||
|
||||
osmium::item_type type() const noexcept {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
osmium::object_id_type ref() const noexcept {
|
||||
return m_ref;
|
||||
}
|
||||
|
||||
const char* role() const noexcept {
|
||||
return m_role.c_str();
|
||||
}
|
||||
|
||||
}; // class member_type_string
|
||||
|
||||
class comment_type {
|
||||
|
||||
osmium::Timestamp m_date;
|
||||
osmium::user_id_type m_uid;
|
||||
const char* m_user;
|
||||
const char* m_text;
|
||||
|
||||
public:
|
||||
|
||||
constexpr comment_type(osmium::Timestamp date, osmium::user_id_type uid, const char* user, const char* text) noexcept :
|
||||
m_date(date),
|
||||
m_uid(uid),
|
||||
m_user(user),
|
||||
m_text(text) {
|
||||
}
|
||||
|
||||
constexpr osmium::Timestamp date() const noexcept {
|
||||
return m_date;
|
||||
}
|
||||
|
||||
constexpr osmium::user_id_type uid() const noexcept {
|
||||
return m_uid;
|
||||
}
|
||||
|
||||
constexpr const char* user() const noexcept {
|
||||
return m_user;
|
||||
}
|
||||
|
||||
constexpr const char* text() const noexcept {
|
||||
return m_text;
|
||||
}
|
||||
|
||||
}; // class comment_type
|
||||
|
||||
namespace detail {
|
||||
|
||||
OSMIUM_ATTRIBUTE_ITER(tags_handler, tags_from_iterator_pair);
|
||||
|
||||
OSMIUM_ATTRIBUTE_ITER(nodes_handler, nodes_from_iterator_pair);
|
||||
|
||||
OSMIUM_ATTRIBUTE_ITER(members_handler, members_from_iterator_pair);
|
||||
|
||||
OSMIUM_ATTRIBUTE_ITER(discussion_handler, comments_from_iterator_pair);
|
||||
|
||||
OSMIUM_ATTRIBUTE_ITER(ring_handler, outer_ring_from_iterator_pair);
|
||||
OSMIUM_ATTRIBUTE_ITER(ring_handler, inner_ring_from_iterator_pair);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
OSMIUM_ATTRIBUTE(tags_handler, _tag, pair_of_cstrings)
|
||||
explicit _tag(const pair_of_cstrings& value) noexcept :
|
||||
type_wrapper(value) {}
|
||||
explicit _tag(const std::pair<const char* const, const char*>& value) :
|
||||
type_wrapper(pair_of_cstrings{value.first, value.second}) {}
|
||||
explicit _tag(const std::pair<const char*, const char* const>& value) :
|
||||
type_wrapper(pair_of_cstrings{value.first, value.second}) {}
|
||||
explicit _tag(const std::pair<const char*, const char*>& value) :
|
||||
type_wrapper(pair_of_cstrings{value.first, value.second}) {}
|
||||
explicit _tag(const pair_of_strings& value) :
|
||||
type_wrapper(std::make_pair(value.first.c_str(), value.second.c_str())) {}
|
||||
explicit _tag(const char* key, const char* val) :
|
||||
type_wrapper(std::make_pair(key, val)) {}
|
||||
explicit _tag(const std::string& key, const std::string& val) :
|
||||
type_wrapper(std::make_pair(key.c_str(), val.c_str())) {}
|
||||
};
|
||||
|
||||
template <typename TTagIterator>
|
||||
inline constexpr detail::tags_from_iterator_pair<TTagIterator> _tags(TTagIterator first, TTagIterator last) {
|
||||
return detail::tags_from_iterator_pair<TTagIterator>(first, last);
|
||||
}
|
||||
|
||||
template <typename TContainer>
|
||||
inline detail::tags_from_iterator_pair<typename TContainer::const_iterator> _tags(const TContainer& container) {
|
||||
return detail::tags_from_iterator_pair<typename TContainer::const_iterator>(std::begin(container), std::end(container));
|
||||
}
|
||||
|
||||
using tag_ilist = std::initializer_list<std::pair<const char*, const char*>>;
|
||||
inline detail::tags_from_iterator_pair<tag_ilist::const_iterator> _tags(const tag_ilist& container) {
|
||||
return detail::tags_from_iterator_pair<tag_ilist::const_iterator>(std::begin(container), std::end(container));
|
||||
}
|
||||
|
||||
|
||||
|
||||
OSMIUM_ATTRIBUTE(nodes_handler, _node, osmium::NodeRef)
|
||||
constexpr explicit _node(osmium::object_id_type value) noexcept :
|
||||
type_wrapper(NodeRef{value}) {}
|
||||
constexpr explicit _node(const NodeRef& value) noexcept :
|
||||
type_wrapper(value) {}
|
||||
};
|
||||
|
||||
template <typename TIdIterator>
|
||||
inline constexpr detail::nodes_from_iterator_pair<TIdIterator> _nodes(TIdIterator first, TIdIterator last) {
|
||||
return detail::nodes_from_iterator_pair<TIdIterator>(first, last);
|
||||
}
|
||||
|
||||
template <typename TContainer>
|
||||
inline detail::nodes_from_iterator_pair<typename TContainer::const_iterator> _nodes(const TContainer& container) {
|
||||
return detail::nodes_from_iterator_pair<typename TContainer::const_iterator>(std::begin(container), std::end(container));
|
||||
}
|
||||
|
||||
using object_id_ilist = std::initializer_list<osmium::object_id_type>;
|
||||
inline detail::nodes_from_iterator_pair<object_id_ilist::const_iterator> _nodes(const object_id_ilist& container) {
|
||||
return detail::nodes_from_iterator_pair<object_id_ilist::const_iterator>(std::begin(container), std::end(container));
|
||||
}
|
||||
|
||||
using node_ref_ilist = std::initializer_list<osmium::NodeRef>;
|
||||
inline detail::nodes_from_iterator_pair<node_ref_ilist::const_iterator> _nodes(const node_ref_ilist& container) {
|
||||
return detail::nodes_from_iterator_pair<node_ref_ilist::const_iterator>(std::begin(container), std::end(container));
|
||||
}
|
||||
|
||||
|
||||
OSMIUM_ATTRIBUTE(members_handler, _member, member_type)
|
||||
constexpr explicit _member(const member_type& value) noexcept :
|
||||
type_wrapper(value) {}
|
||||
constexpr explicit _member(osmium::item_type type, osmium::object_id_type id) noexcept :
|
||||
type_wrapper({type, id}) {}
|
||||
constexpr explicit _member(osmium::item_type type, osmium::object_id_type id, const char* role) noexcept :
|
||||
type_wrapper({type, id, role}) {}
|
||||
explicit _member(osmium::item_type type, osmium::object_id_type id, const std::string& role) noexcept :
|
||||
type_wrapper({type, id, role.c_str()}) {}
|
||||
explicit _member(const osmium::RelationMember& member) noexcept :
|
||||
type_wrapper({member.type(), member.ref(), member.role()}) {}
|
||||
};
|
||||
|
||||
template <typename TMemberIterator>
|
||||
inline constexpr detail::members_from_iterator_pair<TMemberIterator> _members(TMemberIterator first, TMemberIterator last) {
|
||||
return detail::members_from_iterator_pair<TMemberIterator>(first, last);
|
||||
}
|
||||
|
||||
template <typename TContainer>
|
||||
inline detail::members_from_iterator_pair<typename TContainer::const_iterator> _members(const TContainer& container) {
|
||||
return detail::members_from_iterator_pair<typename TContainer::const_iterator>(std::begin(container), std::end(container));
|
||||
}
|
||||
|
||||
using member_ilist = std::initializer_list<member_type>;
|
||||
inline detail::members_from_iterator_pair<member_ilist::const_iterator> _members(const member_ilist& container) {
|
||||
return detail::members_from_iterator_pair<member_ilist::const_iterator>(std::begin(container), std::end(container));
|
||||
}
|
||||
|
||||
|
||||
OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(changeset_handler, _num_changes, osmium::num_changes_type);
|
||||
OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(changeset_handler, _num_comments, osmium::num_comments_type);
|
||||
OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(changeset_handler, _created_at, osmium::Timestamp);
|
||||
OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(changeset_handler, _closed_at, osmium::Timestamp);
|
||||
|
||||
OSMIUM_ATTRIBUTE(discussion_handler, _comment, comment_type)
|
||||
constexpr explicit _comment(const comment_type& value) noexcept :
|
||||
type_wrapper(value) {}
|
||||
explicit _comment(const osmium::ChangesetComment& comment) noexcept :
|
||||
type_wrapper({comment.date(), comment.uid(), comment.user(), comment.text()}) {}
|
||||
};
|
||||
|
||||
template <typename TCommentIterator>
|
||||
inline constexpr detail::comments_from_iterator_pair<TCommentIterator> _comments(TCommentIterator first, TCommentIterator last) {
|
||||
return detail::comments_from_iterator_pair<TCommentIterator>(first, last);
|
||||
}
|
||||
|
||||
template <typename TContainer>
|
||||
inline detail::comments_from_iterator_pair<typename TContainer::const_iterator> _comments(const TContainer& container) {
|
||||
return detail::comments_from_iterator_pair<typename TContainer::const_iterator>(std::begin(container), std::end(container));
|
||||
}
|
||||
|
||||
using comment_ilist = std::initializer_list<comment_type>;
|
||||
inline detail::comments_from_iterator_pair<comment_ilist::const_iterator> _comments(const comment_ilist& container) {
|
||||
return detail::comments_from_iterator_pair<comment_ilist::const_iterator>(std::begin(container), std::end(container));
|
||||
}
|
||||
|
||||
|
||||
template <typename TIdIterator>
|
||||
inline constexpr detail::outer_ring_from_iterator_pair<TIdIterator> _outer_ring(TIdIterator first, TIdIterator last) {
|
||||
return detail::outer_ring_from_iterator_pair<TIdIterator>(first, last);
|
||||
}
|
||||
|
||||
template <typename TContainer>
|
||||
inline detail::outer_ring_from_iterator_pair<typename TContainer::const_iterator> _outer_ring(const TContainer& container) {
|
||||
return detail::outer_ring_from_iterator_pair<typename TContainer::const_iterator>(std::begin(container), std::end(container));
|
||||
}
|
||||
|
||||
using object_id_ilist = std::initializer_list<osmium::object_id_type>;
|
||||
inline detail::outer_ring_from_iterator_pair<object_id_ilist::const_iterator> _outer_ring(const object_id_ilist& container) {
|
||||
return detail::outer_ring_from_iterator_pair<object_id_ilist::const_iterator>(std::begin(container), std::end(container));
|
||||
}
|
||||
|
||||
using node_ref_ilist = std::initializer_list<osmium::NodeRef>;
|
||||
inline detail::outer_ring_from_iterator_pair<node_ref_ilist::const_iterator> _outer_ring(const node_ref_ilist& container) {
|
||||
return detail::outer_ring_from_iterator_pair<node_ref_ilist::const_iterator>(std::begin(container), std::end(container));
|
||||
}
|
||||
|
||||
template <typename TIdIterator>
|
||||
inline constexpr detail::inner_ring_from_iterator_pair<TIdIterator> _inner_ring(TIdIterator first, TIdIterator last) {
|
||||
return detail::inner_ring_from_iterator_pair<TIdIterator>(first, last);
|
||||
}
|
||||
|
||||
template <typename TContainer>
|
||||
inline detail::inner_ring_from_iterator_pair<typename TContainer::const_iterator> _inner_ring(const TContainer& container) {
|
||||
return detail::inner_ring_from_iterator_pair<typename TContainer::const_iterator>(std::begin(container), std::end(container));
|
||||
}
|
||||
|
||||
using object_id_ilist = std::initializer_list<osmium::object_id_type>;
|
||||
inline detail::inner_ring_from_iterator_pair<object_id_ilist::const_iterator> _inner_ring(const object_id_ilist& container) {
|
||||
return detail::inner_ring_from_iterator_pair<object_id_ilist::const_iterator>(std::begin(container), std::end(container));
|
||||
}
|
||||
|
||||
using node_ref_ilist = std::initializer_list<osmium::NodeRef>;
|
||||
inline detail::inner_ring_from_iterator_pair<node_ref_ilist::const_iterator> _inner_ring(const node_ref_ilist& container) {
|
||||
return detail::inner_ring_from_iterator_pair<node_ref_ilist::const_iterator>(std::begin(container), std::end(container));
|
||||
}
|
||||
|
||||
|
||||
} // namespace attr
|
||||
|
||||
#undef OSMIUM_ATTRIBUTE_ITER
|
||||
#undef OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR
|
||||
#undef OSMIUM_ATTRIBUTE
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct changeset_handler : public entity_handler {
|
||||
|
||||
template <typename TDummy>
|
||||
static void set_value(osmium::Changeset&, const TDummy&) noexcept {
|
||||
}
|
||||
|
||||
static void set_value(osmium::Changeset& changeset, attr::_cid id) noexcept {
|
||||
changeset.set_id(id.value);
|
||||
}
|
||||
|
||||
static void set_value(osmium::Changeset& changeset, attr::_num_changes num_changes) noexcept {
|
||||
changeset.set_num_changes(num_changes.value);
|
||||
}
|
||||
|
||||
static void set_value(osmium::Changeset& changeset, attr::_num_comments num_comments) noexcept {
|
||||
changeset.set_num_comments(num_comments.value);
|
||||
}
|
||||
|
||||
static void set_value(osmium::Changeset& changeset, attr::_created_at created_at) noexcept {
|
||||
changeset.set_created_at(created_at.value);
|
||||
}
|
||||
|
||||
static void set_value(osmium::Changeset& changeset, attr::_closed_at closed_at) noexcept {
|
||||
changeset.set_closed_at(closed_at.value);
|
||||
}
|
||||
|
||||
static void set_value(osmium::Changeset& changeset, attr::_uid uid) noexcept {
|
||||
changeset.set_uid(uid.value);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct object_handler : public entity_handler {
|
||||
|
||||
template <typename TDummy>
|
||||
static void set_value(osmium::OSMObject&, const TDummy&) noexcept {
|
||||
}
|
||||
|
||||
static void set_value(osmium::OSMObject& object, attr::_id id) noexcept {
|
||||
object.set_id(id.value);
|
||||
}
|
||||
|
||||
static void set_value(osmium::OSMObject& object, attr::_version version) noexcept {
|
||||
object.set_version(version.value);
|
||||
}
|
||||
|
||||
static void set_value(osmium::OSMObject& object, attr::_visible visible) noexcept {
|
||||
object.set_visible(visible.value);
|
||||
}
|
||||
|
||||
static void set_value(osmium::OSMObject& object, attr::_deleted deleted) noexcept {
|
||||
object.set_deleted(deleted.value);
|
||||
}
|
||||
|
||||
static void set_value(osmium::OSMObject& object, attr::_timestamp timestamp) noexcept {
|
||||
object.set_timestamp(timestamp.value);
|
||||
}
|
||||
|
||||
static void set_value(osmium::OSMObject& object, attr::_cid changeset) noexcept {
|
||||
object.set_changeset(changeset.value);
|
||||
}
|
||||
|
||||
static void set_value(osmium::OSMObject& object, attr::_uid uid) noexcept {
|
||||
object.set_uid(uid.value);
|
||||
}
|
||||
|
||||
}; // object_handler
|
||||
|
||||
struct node_handler : public object_handler {
|
||||
|
||||
using object_handler::set_value;
|
||||
|
||||
static void set_value(osmium::Node& node, attr::_location location) noexcept {
|
||||
node.set_location(location.value);
|
||||
}
|
||||
|
||||
}; // node_handler
|
||||
|
||||
template <typename THandler, typename TBuilder, typename... TArgs>
|
||||
inline void add_basic(TBuilder& builder, const TArgs&... args) noexcept {
|
||||
(void)std::initializer_list<int>{
|
||||
(THandler::set_value(builder.object(), args), 0)...
|
||||
};
|
||||
}
|
||||
|
||||
// ==============================================================
|
||||
|
||||
template <typename... TArgs>
|
||||
inline constexpr const char* get_user(const attr::_user& user, const TArgs&...) noexcept {
|
||||
return user.value;
|
||||
}
|
||||
|
||||
inline constexpr const char* get_user() noexcept {
|
||||
return "";
|
||||
}
|
||||
|
||||
template <typename TFirst, typename... TRest>
|
||||
inline constexpr typename std::enable_if<!std::is_same<attr::_user, TFirst>::value, const char*>::type
|
||||
get_user(const TFirst&, const TRest&... args) noexcept {
|
||||
return get_user(args...);
|
||||
}
|
||||
|
||||
template <typename TBuilder, typename... TArgs>
|
||||
inline void add_user(TBuilder& builder, const TArgs&... args) {
|
||||
builder.set_user(get_user(args...));
|
||||
}
|
||||
|
||||
// ==============================================================
|
||||
|
||||
struct tags_handler {
|
||||
|
||||
template <typename TDummy>
|
||||
static void set_value(TagListBuilder&, const TDummy&) noexcept {
|
||||
}
|
||||
|
||||
static void set_value(TagListBuilder& builder, const attr::_tag& tag) {
|
||||
builder.add_tag(tag.value);
|
||||
}
|
||||
|
||||
template <typename TIterator>
|
||||
static void set_value(TagListBuilder& builder, const attr::detail::tags_from_iterator_pair<TIterator>& tags) {
|
||||
for (const auto& tag : tags) {
|
||||
builder.add_tag(tag);
|
||||
}
|
||||
}
|
||||
|
||||
}; // struct tags_handler
|
||||
|
||||
struct nodes_handler {
|
||||
|
||||
template <typename TDummy>
|
||||
static void set_value(WayNodeListBuilder&, const TDummy&) noexcept {
|
||||
}
|
||||
|
||||
static void set_value(WayNodeListBuilder& builder, const attr::_node& node_ref) {
|
||||
builder.add_node_ref(node_ref.value);
|
||||
}
|
||||
|
||||
template <typename TIterator>
|
||||
static void set_value(WayNodeListBuilder& builder, const attr::detail::nodes_from_iterator_pair<TIterator>& nodes) {
|
||||
for (const auto& ref : nodes) {
|
||||
builder.add_node_ref(ref);
|
||||
}
|
||||
}
|
||||
|
||||
}; // struct nodes_handler
|
||||
|
||||
struct members_handler {
|
||||
|
||||
template <typename TDummy>
|
||||
static void set_value(RelationMemberListBuilder&, const TDummy&) noexcept {
|
||||
}
|
||||
|
||||
static void set_value(RelationMemberListBuilder& builder, const attr::_member& member) {
|
||||
builder.add_member(member.value.type(), member.value.ref(), member.value.role());
|
||||
}
|
||||
|
||||
template <typename TIterator>
|
||||
static void set_value(RelationMemberListBuilder& builder, const attr::detail::members_from_iterator_pair<TIterator>& members) {
|
||||
for (const auto& member : members) {
|
||||
builder.add_member(member.type(), member.ref(), member.role());
|
||||
}
|
||||
}
|
||||
|
||||
}; // struct members_handler
|
||||
|
||||
struct discussion_handler {
|
||||
|
||||
template <typename TDummy>
|
||||
static void set_value(ChangesetDiscussionBuilder&, const TDummy&) noexcept {
|
||||
}
|
||||
|
||||
static void set_value(ChangesetDiscussionBuilder& builder, const attr::_comment& comment) {
|
||||
builder.add_comment(comment.value.date(), comment.value.uid(), comment.value.user());
|
||||
builder.add_comment_text(comment.value.text());
|
||||
}
|
||||
|
||||
template <typename TIterator>
|
||||
static void set_value(ChangesetDiscussionBuilder& builder, const attr::detail::comments_from_iterator_pair<TIterator>& comments) {
|
||||
for (const auto& comment : comments) {
|
||||
builder.add_comment(comment.date(), comment.uid(), comment.user());
|
||||
builder.add_comment_text(comment.text());
|
||||
}
|
||||
}
|
||||
|
||||
}; // struct discussion_handler
|
||||
|
||||
struct ring_handler {
|
||||
|
||||
template <typename TDummy>
|
||||
static void set_value(AreaBuilder&, const TDummy&) noexcept {
|
||||
}
|
||||
|
||||
template <typename TIterator>
|
||||
static void set_value(AreaBuilder& parent, const attr::detail::outer_ring_from_iterator_pair<TIterator>& nodes) {
|
||||
OuterRingBuilder builder(parent.buffer(), &parent);
|
||||
for (const auto& ref : nodes) {
|
||||
builder.add_node_ref(ref);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TIterator>
|
||||
static void set_value(AreaBuilder& parent, const attr::detail::inner_ring_from_iterator_pair<TIterator>& nodes) {
|
||||
InnerRingBuilder builder(parent.buffer(), &parent);
|
||||
for (const auto& ref : nodes) {
|
||||
builder.add_node_ref(ref);
|
||||
}
|
||||
}
|
||||
|
||||
}; // struct ring_handler
|
||||
|
||||
// ==============================================================
|
||||
|
||||
template <typename TBuilder, typename THandler, typename... TArgs>
|
||||
inline typename std::enable_if<!is_handled_by<THandler, TArgs...>::value>::type
|
||||
add_list(osmium::builder::Builder&, const TArgs&...) noexcept {
|
||||
}
|
||||
|
||||
template <typename TBuilder, typename THandler, typename... TArgs>
|
||||
inline typename std::enable_if<is_handled_by<THandler, TArgs...>::value>::type
|
||||
add_list(osmium::builder::Builder& parent, const TArgs&... args) {
|
||||
TBuilder builder(parent.buffer(), &parent);
|
||||
(void)std::initializer_list<int>{
|
||||
(THandler::set_value(builder, args), 0)...
|
||||
};
|
||||
}
|
||||
|
||||
struct any_node_handlers : public node_handler, public tags_handler {};
|
||||
struct any_way_handlers : public object_handler, public tags_handler, public nodes_handler {};
|
||||
struct any_relation_handlers : public object_handler, public tags_handler, public members_handler {};
|
||||
struct any_area_handlers : public object_handler, public tags_handler, public ring_handler {};
|
||||
struct any_changeset_handlers : public changeset_handler, public tags_handler, public discussion_handler {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
/**
|
||||
* Create a node using the given arguments and add it to the given buffer.
|
||||
*
|
||||
* @param buffer The buffer to which the node will be added.
|
||||
* @param args The attributes of the node.
|
||||
* @returns The position in the buffer where this node was added.
|
||||
*/
|
||||
template <typename... TArgs>
|
||||
inline size_t add_node(osmium::memory::Buffer& buffer, const TArgs&... args) {
|
||||
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);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a way using the given arguments and add it to the given buffer.
|
||||
*
|
||||
* @param buffer The buffer to which the way will be added.
|
||||
* @param args The attributes of the way.
|
||||
* @returns The position in the buffer where this way was added.
|
||||
*/
|
||||
template <typename... TArgs>
|
||||
inline size_t add_way(osmium::memory::Buffer& buffer, const TArgs&... args) {
|
||||
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);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a relation using the given arguments and add it to the given buffer.
|
||||
*
|
||||
* @param buffer The buffer to which the relation will be added.
|
||||
* @param args The attributes of the relation.
|
||||
* @returns The position in the buffer where this relation was added.
|
||||
*/
|
||||
template <typename... TArgs>
|
||||
inline size_t add_relation(osmium::memory::Buffer& buffer, const TArgs&... args) {
|
||||
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);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a changeset using the given arguments and add it to the given buffer.
|
||||
*
|
||||
* @param buffer The buffer to which the changeset will be added.
|
||||
* @param args The attributes of the changeset.
|
||||
* @returns The position in the buffer where this changeset was added.
|
||||
*/
|
||||
template <typename... TArgs>
|
||||
inline size_t add_changeset(osmium::memory::Buffer& buffer, const TArgs&... args) {
|
||||
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);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a area using the given arguments and add it to the given buffer.
|
||||
*
|
||||
* @param buffer The buffer to which the area will be added.
|
||||
* @param args The attributes of the area.
|
||||
* @returns The position in the buffer where this area was added.
|
||||
*/
|
||||
template <typename... TArgs>
|
||||
inline size_t add_area(osmium::memory::Buffer& buffer, const TArgs&... args) {
|
||||
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);
|
||||
|
||||
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)...
|
||||
};
|
||||
}
|
||||
|
||||
return buffer.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WayNodeList using the given arguments and add it to the given buffer.
|
||||
*
|
||||
* @param buffer The buffer to which the list will be added.
|
||||
* @param args The contents of the list.
|
||||
* @returns The position in the buffer where this list was added.
|
||||
*/
|
||||
template <typename... TArgs>
|
||||
inline size_t add_way_node_list(osmium::memory::Buffer& buffer, const TArgs&... args) {
|
||||
static_assert(sizeof...(args) > 0, "add_way_node_list() must have buffer and at least one additional argument");
|
||||
static_assert(detail::are_all_handled_by<detail::nodes_handler, TArgs...>::value, "Attribute not allowed in add_way_node_list()");
|
||||
|
||||
{
|
||||
WayNodeListBuilder builder(buffer);
|
||||
(void)std::initializer_list<int>{
|
||||
(detail::nodes_handler::set_value(builder, args), 0)...
|
||||
};
|
||||
}
|
||||
|
||||
return buffer.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a TagList using the given arguments and add it to the given buffer.
|
||||
*
|
||||
* @param buffer The buffer to which the list will be added.
|
||||
* @param args The contents of the list.
|
||||
* @returns The position in the buffer where this list was added.
|
||||
*/
|
||||
template <typename... TArgs>
|
||||
inline size_t add_tag_list(osmium::memory::Buffer& buffer, const TArgs&... args) {
|
||||
static_assert(sizeof...(args) > 0, "add_tag_list() must have buffer and at least one additional argument");
|
||||
static_assert(detail::are_all_handled_by<detail::tags_handler, TArgs...>::value, "Attribute not allowed in add_tag_list()");
|
||||
|
||||
{
|
||||
TagListBuilder builder(buffer);
|
||||
(void)std::initializer_list<int>{
|
||||
(detail::tags_handler::set_value(builder, args), 0)...
|
||||
};
|
||||
}
|
||||
|
||||
return buffer.commit();
|
||||
}
|
||||
|
||||
} // namespace builder
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_BUILDER_ATTR_HPP
|
||||
@@ -0,0 +1,235 @@
|
||||
#ifndef OSMIUM_BUILDER_BUILDER_HPP
|
||||
#define OSMIUM_BUILDER_BUILDER_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/memory/item.hpp>
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
/**
|
||||
* @brief Classes for building OSM objects and other items in buffers
|
||||
*/
|
||||
namespace builder {
|
||||
|
||||
/**
|
||||
* Parent class for individual builder classes. Instantiate one of
|
||||
* its derived classes.
|
||||
*/
|
||||
class Builder {
|
||||
|
||||
osmium::memory::Buffer& m_buffer;
|
||||
Builder* m_parent;
|
||||
std::size_t m_item_offset;
|
||||
|
||||
Builder(const Builder&) = delete;
|
||||
Builder(Builder&&) = delete;
|
||||
|
||||
Builder& operator=(const Builder&) = delete;
|
||||
Builder& operator=(Builder&&) = delete;
|
||||
|
||||
protected:
|
||||
|
||||
explicit Builder(osmium::memory::Buffer& buffer, Builder* parent, osmium::memory::item_size_type size) :
|
||||
m_buffer(buffer),
|
||||
m_parent(parent),
|
||||
m_item_offset(buffer.written()) {
|
||||
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);
|
||||
}
|
||||
|
||||
unsigned char* reserve_space(std::size_t size) {
|
||||
return m_buffer.reserve_space(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add padding to buffer (if needed) to align data properly.
|
||||
*
|
||||
* This calculates how many padding bytes are needed and adds
|
||||
* as many zero bytes to the buffer. It also adds this number
|
||||
* to the size of the current item (if the "self" param is
|
||||
* true) and recursively to all the parent items.
|
||||
*
|
||||
* @param self If true add number of padding bytes to size
|
||||
* of current item. Size is always added to
|
||||
* parent item (if any).
|
||||
*
|
||||
*/
|
||||
void add_padding(bool self = false) {
|
||||
// We know the padding is only a very small number, so it will
|
||||
// always fit.
|
||||
const auto padding = static_cast<osmium::memory::item_size_type>(osmium::memory::align_bytes - (size() % osmium::memory::align_bytes));
|
||||
if (padding != osmium::memory::align_bytes) {
|
||||
std::fill_n(reserve_space(padding), padding, 0);
|
||||
if (self) {
|
||||
add_size(padding);
|
||||
} else if (m_parent) {
|
||||
m_parent->add_size(padding);
|
||||
assert(m_parent->size() % osmium::memory::align_bytes == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_size(osmium::memory::item_size_type size) {
|
||||
item().add_size(size);
|
||||
if (m_parent) {
|
||||
m_parent->add_size(size);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t size() const noexcept {
|
||||
return item().byte_size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve space for an object of class T in buffer and return
|
||||
* pointer to it.
|
||||
*/
|
||||
template <typename T>
|
||||
T* reserve_space_for() {
|
||||
assert(m_buffer.is_aligned());
|
||||
return reinterpret_cast<T*>(reserve_space(sizeof(T)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Append data to buffer.
|
||||
*
|
||||
* @param data Pointer to data.
|
||||
* @param length Length of data in bytes. If data is a
|
||||
* \0-terminated string, length must contain the
|
||||
* \0 byte.
|
||||
* @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 = reserve_space(length);
|
||||
std::copy_n(reinterpret_cast<const unsigned char*>(data), length, target);
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append data to buffer and append an additional \0.
|
||||
*
|
||||
* @param data Pointer to data.
|
||||
* @param length Length of data in bytes.
|
||||
* @returns The number of bytes appended (length + 1).
|
||||
*/
|
||||
osmium::memory::item_size_type append_with_zero(const char* data, const osmium::memory::item_size_type length) {
|
||||
unsigned char* target = reserve_space(length + 1);
|
||||
std::copy_n(reinterpret_cast<const unsigned char*>(data), length, target);
|
||||
target[length] = '\0';
|
||||
return length + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append \0-terminated string to buffer.
|
||||
*
|
||||
* @param str \0-terminated string.
|
||||
* @returns The number of bytes appended (strlen(str) + 1).
|
||||
*/
|
||||
osmium::memory::item_size_type append(const char* str) {
|
||||
return append(str, static_cast<osmium::memory::item_size_type>(std::strlen(str) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Append '\0' to the buffer.
|
||||
*
|
||||
* @deprecated Use append_with_zero() instead.
|
||||
*
|
||||
* @returns The number of bytes appended (always 1).
|
||||
*/
|
||||
OSMIUM_DEPRECATED osmium::memory::item_size_type append_zero() {
|
||||
*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
|
||||
|
||||
} // namespace builder
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_BUILDER_BUILDER_HPP
|
||||
@@ -0,0 +1,120 @@
|
||||
#ifndef OSMIUM_BUILDER_BUILDER_HELPER_HPP
|
||||
#define OSMIUM_BUILDER_BUILDER_HELPER_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <cstddef>
|
||||
#include <initializer_list>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/builder/osm_object_builder.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class NodeRef;
|
||||
class TagList;
|
||||
class WayNodeList;
|
||||
|
||||
namespace builder {
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Use osmium::builder::add_way_node_list() instead.
|
||||
*/
|
||||
OSMIUM_DEPRECATED inline const osmium::WayNodeList& build_way_node_list(osmium::memory::Buffer& buffer, const std::initializer_list<osmium::NodeRef>& nodes) {
|
||||
const size_t pos = buffer.committed();
|
||||
{
|
||||
osmium::builder::WayNodeListBuilder wnl_builder(buffer);
|
||||
for (const auto& node_ref : nodes) {
|
||||
wnl_builder.add_node_ref(node_ref);
|
||||
}
|
||||
}
|
||||
buffer.commit();
|
||||
return buffer.get<const osmium::WayNodeList>(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Use osmium::builder::add_tag_list() instead.
|
||||
*/
|
||||
OSMIUM_DEPRECATED inline const osmium::TagList& build_tag_list(osmium::memory::Buffer& buffer, const std::initializer_list<std::pair<const char*, const char*>>& tags) {
|
||||
const size_t pos = buffer.committed();
|
||||
{
|
||||
osmium::builder::TagListBuilder tl_builder(buffer);
|
||||
for (const auto& p : tags) {
|
||||
tl_builder.add_tag(p.first, p.second);
|
||||
}
|
||||
}
|
||||
buffer.commit();
|
||||
return buffer.get<const osmium::TagList>(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Use osmium::builder::add_tag_list() instead.
|
||||
*/
|
||||
OSMIUM_DEPRECATED inline const osmium::TagList& build_tag_list_from_map(osmium::memory::Buffer& buffer, const std::map<const char*, const char*>& tags) {
|
||||
const size_t pos = buffer.committed();
|
||||
{
|
||||
osmium::builder::TagListBuilder tl_builder(buffer);
|
||||
for (const auto& p : tags) {
|
||||
tl_builder.add_tag(p.first, p.second);
|
||||
}
|
||||
}
|
||||
buffer.commit();
|
||||
return buffer.get<const osmium::TagList>(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Use osmium::builder::add_tag_list() instead.
|
||||
*/
|
||||
OSMIUM_DEPRECATED inline const osmium::TagList& build_tag_list_from_func(osmium::memory::Buffer& buffer, std::function<void(osmium::builder::TagListBuilder&)> func) {
|
||||
const size_t pos = buffer.committed();
|
||||
{
|
||||
osmium::builder::TagListBuilder tl_builder(buffer);
|
||||
func(tl_builder);
|
||||
}
|
||||
buffer.commit();
|
||||
return buffer.get<const osmium::TagList>(pos);
|
||||
}
|
||||
|
||||
} // namespace builder
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_BUILDER_BUILDER_HELPER_HPP
|
||||
@@ -0,0 +1,680 @@
|
||||
#ifndef OSMIUM_BUILDER_OSM_OBJECT_BUILDER_HPP
|
||||
#define OSMIUM_BUILDER_OSM_OBJECT_BUILDER_HPP
|
||||
|
||||
/*
|
||||
|
||||
This file is part of Osmium (http://osmcode.org/libosmium).
|
||||
|
||||
Copyright 2013-2017 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 <cstdint>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <new>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/builder/builder.hpp>
|
||||
#include <osmium/memory/item.hpp>
|
||||
#include <osmium/osm/area.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/changeset.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/relation.hpp>
|
||||
#include <osmium/osm/tag.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
#include <osmium/util/cast.hpp>
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace memory {
|
||||
class Buffer;
|
||||
} // namespace memory
|
||||
|
||||
namespace builder {
|
||||
|
||||
class TagListBuilder : public Builder {
|
||||
|
||||
public:
|
||||
|
||||
explicit TagListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
|
||||
Builder(buffer, parent, sizeof(TagList)) {
|
||||
new (&item()) TagList{};
|
||||
}
|
||||
|
||||
explicit TagListBuilder(Builder& parent) :
|
||||
Builder(parent.buffer(), &parent, sizeof(TagList)) {
|
||||
new (&item()) TagList{};
|
||||
}
|
||||
|
||||
~TagListBuilder() {
|
||||
add_padding();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add tag to buffer.
|
||||
*
|
||||
* @param key Tag key (0-terminated string).
|
||||
* @param value Tag value (0-terminated string).
|
||||
*/
|
||||
void add_tag(const char* key, const char* value) {
|
||||
if (std::strlen(key) > osmium::max_osm_string_length) {
|
||||
throw std::length_error{"OSM tag key is too long"};
|
||||
}
|
||||
if (std::strlen(value) > osmium::max_osm_string_length) {
|
||||
throw std::length_error{"OSM tag value is too long"};
|
||||
}
|
||||
add_size(append(key));
|
||||
add_size(append(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add tag to buffer.
|
||||
*
|
||||
* @param key Pointer to tag key.
|
||||
* @param key_length Length of key (not including the \0 byte).
|
||||
* @param value Pointer to tag value.
|
||||
* @param value_length Length of value (not including the \0 byte).
|
||||
*/
|
||||
void add_tag(const char* key, const std::size_t key_length, const char* value, const std::size_t value_length) {
|
||||
if (key_length > osmium::max_osm_string_length) {
|
||||
throw std::length_error{"OSM tag key is too long"};
|
||||
}
|
||||
if (value_length > osmium::max_osm_string_length) {
|
||||
throw std::length_error{"OSM tag value is too long"};
|
||||
}
|
||||
add_size(append_with_zero(key, osmium::memory::item_size_type(key_length)));
|
||||
add_size(append_with_zero(value, osmium::memory::item_size_type(value_length)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add tag to buffer.
|
||||
*
|
||||
* @param key Tag key.
|
||||
* @param value Tag value.
|
||||
*/
|
||||
void add_tag(const std::string& key, const std::string& value) {
|
||||
if (key.size() > osmium::max_osm_string_length) {
|
||||
throw std::length_error{"OSM tag key is too long"};
|
||||
}
|
||||
if (value.size() > osmium::max_osm_string_length) {
|
||||
throw std::length_error{"OSM tag value is too long"};
|
||||
}
|
||||
add_size(append(key.data(), osmium::memory::item_size_type(key.size()) + 1));
|
||||
add_size(append(value.data(), osmium::memory::item_size_type(value.size()) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add tag to buffer.
|
||||
*
|
||||
* @param tag Tag.
|
||||
*/
|
||||
void add_tag(const osmium::Tag& tag) {
|
||||
add_size(append(tag.key()));
|
||||
add_size(append(tag.value()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add tag to buffer.
|
||||
*
|
||||
* @param tag Pair of key/value 0-terminated strings.
|
||||
*/
|
||||
void add_tag(const std::pair<const char* const, const char* const>& tag) {
|
||||
add_tag(tag.first, tag.second);
|
||||
}
|
||||
void add_tag(const std::pair<const char* const, const char*>& tag) {
|
||||
add_tag(tag.first, tag.second);
|
||||
}
|
||||
void add_tag(const std::pair<const char*, const char* const>& tag) {
|
||||
add_tag(tag.first, tag.second);
|
||||
}
|
||||
void add_tag(const std::pair<const char*, const char*>& tag) {
|
||||
add_tag(tag.first, tag.second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add tag to buffer.
|
||||
*
|
||||
* @param tag Pair of std::string references.
|
||||
*/
|
||||
void add_tag(const std::pair<const std::string&, const std::string&>& tag) {
|
||||
add_tag(tag.first, tag.second);
|
||||
}
|
||||
|
||||
}; // class TagListBuilder
|
||||
|
||||
template <typename T>
|
||||
class NodeRefListBuilder : public Builder {
|
||||
|
||||
public:
|
||||
|
||||
explicit NodeRefListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
|
||||
Builder(buffer, parent, sizeof(T)) {
|
||||
new (&item()) T{};
|
||||
}
|
||||
|
||||
explicit NodeRefListBuilder(Builder& parent) :
|
||||
Builder(parent.buffer(), &parent, sizeof(T)) {
|
||||
new (&item()) T{};
|
||||
}
|
||||
|
||||
~NodeRefListBuilder() {
|
||||
add_padding();
|
||||
}
|
||||
|
||||
void add_node_ref(const NodeRef& node_ref) {
|
||||
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{}) {
|
||||
add_node_ref(NodeRef{ref, location});
|
||||
}
|
||||
|
||||
}; // class NodeRefListBuilder
|
||||
|
||||
using WayNodeListBuilder = NodeRefListBuilder<WayNodeList>;
|
||||
using OuterRingBuilder = NodeRefListBuilder<OuterRing>;
|
||||
using InnerRingBuilder = NodeRefListBuilder<InnerRing>;
|
||||
|
||||
class RelationMemberListBuilder : public Builder {
|
||||
|
||||
/**
|
||||
* Add role to buffer.
|
||||
*
|
||||
* @param member Relation member object where the length of the role
|
||||
* will be set.
|
||||
* @param role The role.
|
||||
* @param length Length of role (without \0 termination).
|
||||
* @throws std:length_error If role is longer than osmium::max_osm_string_length
|
||||
*/
|
||||
void add_role(osmium::RelationMember& member, const char* role, const std::size_t length) {
|
||||
if (length > osmium::max_osm_string_length) {
|
||||
throw std::length_error{"OSM relation member role is too long"};
|
||||
}
|
||||
member.set_role_size(osmium::string_size_type(length) + 1);
|
||||
add_size(append_with_zero(role, osmium::memory::item_size_type(length)));
|
||||
add_padding(true);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
|
||||
Builder(buffer, parent, sizeof(RelationMemberList)) {
|
||||
new (&item()) RelationMemberList{};
|
||||
}
|
||||
|
||||
explicit RelationMemberListBuilder(Builder& parent) :
|
||||
Builder(parent.buffer(), &parent, sizeof(RelationMemberList)) {
|
||||
new (&item()) RelationMemberList{};
|
||||
}
|
||||
|
||||
~RelationMemberListBuilder() {
|
||||
add_padding();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a member to the relation.
|
||||
*
|
||||
* @param type The type (node, way, or relation).
|
||||
* @param ref The ID of the member.
|
||||
* @param role The role of the member.
|
||||
* @param role_length Length of the role (without \0 termination).
|
||||
* @param full_member Optional pointer to the member object. If it
|
||||
* is available a copy will be added to the
|
||||
* relation.
|
||||
* @throws std:length_error If role_length is greater than
|
||||
* osmium::max_osm_string_length
|
||||
*/
|
||||
void add_member(osmium::item_type type, object_id_type ref, const char* role, const std::size_t role_length, const osmium::OSMObject* full_member = nullptr) {
|
||||
osmium::RelationMember* member = reserve_space_for<osmium::RelationMember>();
|
||||
new (member) osmium::RelationMember{ref, type, full_member != nullptr};
|
||||
add_size(sizeof(RelationMember));
|
||||
add_role(*member, role, role_length);
|
||||
if (full_member) {
|
||||
add_item(*full_member);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a member to the relation.
|
||||
*
|
||||
* @param type The type (node, way, or relation).
|
||||
* @param ref The ID of the member.
|
||||
* @param role The role of the member (\0 terminated string).
|
||||
* @param full_member Optional pointer to the member object. If it
|
||||
* is available a copy will be added to the
|
||||
* relation.
|
||||
* @throws std:length_error If role is longer than osmium::max_osm_string_length
|
||||
*/
|
||||
void add_member(osmium::item_type type, object_id_type ref, const char* role, const osmium::OSMObject* full_member = nullptr) {
|
||||
add_member(type, ref, role, std::strlen(role), full_member);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a member to the relation.
|
||||
*
|
||||
* @param type The type (node, way, or relation).
|
||||
* @param ref The ID of the member.
|
||||
* @param role The role of the member.
|
||||
* @param full_member Optional pointer to the member object. If it
|
||||
* is available a copy will be added to the
|
||||
* relation.
|
||||
* @throws std:length_error If role is longer than osmium::max_osm_string_length
|
||||
*/
|
||||
void add_member(osmium::item_type type, object_id_type ref, const std::string& role, const osmium::OSMObject* full_member = nullptr) {
|
||||
add_member(type, ref, role.data(), role.size(), full_member);
|
||||
}
|
||||
|
||||
}; // class RelationMemberListBuilder
|
||||
|
||||
class ChangesetDiscussionBuilder : public Builder {
|
||||
|
||||
osmium::ChangesetComment* m_comment = nullptr;
|
||||
|
||||
void add_user(osmium::ChangesetComment& comment, const char* user, const std::size_t length) {
|
||||
if (length > osmium::max_osm_string_length) {
|
||||
throw std::length_error{"OSM user name is too long"};
|
||||
}
|
||||
comment.set_user_size(osmium::string_size_type(length) + 1);
|
||||
add_size(append_with_zero(user, osmium::memory::item_size_type(length)));
|
||||
}
|
||||
|
||||
void add_text(osmium::ChangesetComment& comment, const char* text, const std::size_t length) {
|
||||
if (length > std::numeric_limits<osmium::changeset_comment_size_type>::max() - 1) {
|
||||
throw std::length_error{"OSM changeset comment is too long"};
|
||||
}
|
||||
comment.set_text_size(osmium::changeset_comment_size_type(length) + 1);
|
||||
add_size(append_with_zero(text, osmium::memory::item_size_type(length)));
|
||||
add_padding(true);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
explicit ChangesetDiscussionBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
|
||||
Builder(buffer, parent, sizeof(ChangesetDiscussion)) {
|
||||
new (&item()) ChangesetDiscussion{};
|
||||
}
|
||||
|
||||
explicit ChangesetDiscussionBuilder(Builder& parent) :
|
||||
Builder(parent.buffer(), &parent, sizeof(ChangesetDiscussion)) {
|
||||
new (&item()) ChangesetDiscussion{};
|
||||
}
|
||||
|
||||
~ChangesetDiscussionBuilder() {
|
||||
assert(!m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!");
|
||||
add_padding();
|
||||
}
|
||||
|
||||
void add_comment(osmium::Timestamp date, osmium::user_id_type uid, const char* user) {
|
||||
assert(!m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!");
|
||||
m_comment = reserve_space_for<osmium::ChangesetComment>();
|
||||
new (m_comment) osmium::ChangesetComment{date, uid};
|
||||
add_size(sizeof(ChangesetComment));
|
||||
add_user(*m_comment, user, std::strlen(user));
|
||||
}
|
||||
|
||||
void add_comment_text(const char* text) {
|
||||
assert(m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!");
|
||||
osmium::ChangesetComment& comment = *m_comment;
|
||||
m_comment = nullptr;
|
||||
add_text(comment, text, std::strlen(text));
|
||||
}
|
||||
|
||||
void add_comment_text(const std::string& text) {
|
||||
assert(m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!");
|
||||
osmium::ChangesetComment& comment = *m_comment;
|
||||
m_comment = nullptr;
|
||||
add_text(comment, text.c_str(), text.size());
|
||||
}
|
||||
|
||||
}; // class ChangesetDiscussionBuilder
|
||||
|
||||
#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 std::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) :
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a const 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.
|
||||
*/
|
||||
const T& cobject() const noexcept {
|
||||
return static_cast<const 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(cobject().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);
|
||||
std::fill_n(reserve_space(space_needed), space_needed, 0);
|
||||
add_size(static_cast<uint32_t>(space_needed));
|
||||
}
|
||||
std::copy_n(user, length, object().data() + size_of_object);
|
||||
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{buffer(), this};
|
||||
for (const auto& p : tags) {
|
||||
tl_builder.add_tag(p.first, p.second);
|
||||
}
|
||||
}
|
||||
|
||||
}; // class OSMObjectBuilder
|
||||
|
||||
class NodeBuilder : public OSMObjectBuilder<NodeBuilder, Node> {
|
||||
|
||||
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<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};
|
||||
for (const auto& node_ref : nodes) {
|
||||
builder.add_node_ref(node_ref);
|
||||
}
|
||||
}
|
||||
|
||||
}; // class WayBuilder
|
||||
|
||||
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<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) {
|
||||
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
|
||||
|
||||
class ChangesetBuilder : public Builder {
|
||||
|
||||
using type = ChangesetBuilder;
|
||||
|
||||
constexpr static const std::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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a const 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.
|
||||
*/
|
||||
const Changeset& cobject() const noexcept {
|
||||
return static_cast<const 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(cobject().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);
|
||||
std::fill_n(reserve_space(space_needed), space_needed, 0);
|
||||
add_size(static_cast<uint32_t>(space_needed));
|
||||
}
|
||||
std::copy_n(user, length, object().data() + sizeof(Changeset));
|
||||
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
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_BUILDER_OSM_OBJECT_BUILDER_HPP
|
||||
Reference in New Issue
Block a user