998 lines
42 KiB
C++
998 lines
42 KiB
C++
#ifndef OSMIUM_BUILDER_ATTR_HPP
|
|
#define OSMIUM_BUILDER_ATTR_HPP
|
|
|
|
/*
|
|
|
|
This file is part of Osmium (https://osmcode.org/libosmium).
|
|
|
|
Copyright 2013-2022 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 <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>
|
|
#include <osmium/util/string.hpp>
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <ctime>
|
|
#include <initializer_list>
|
|
#include <iterator>
|
|
#include <string>
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
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 lon, double lat) :
|
|
type_wrapper(osmium::Location{lon, lat}) {}
|
|
};
|
|
|
|
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) {
|
|
}
|
|
|
|
member_type(char type, osmium::object_id_type ref, const char* role = "") noexcept :
|
|
member_type(osmium::char_to_item_type(type), ref, 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)) {
|
|
}
|
|
|
|
member_type_string(char type, osmium::object_id_type ref, std::string&& role) noexcept :
|
|
member_type_string(osmium::char_to_item_type(type), ref, 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())) {}
|
|
explicit _tag(const char* const key_value) :
|
|
type_wrapper(pair_of_cstrings{key_value, nullptr}) {}
|
|
explicit _tag(const std::string& key_value) :
|
|
type_wrapper(pair_of_cstrings{key_value.c_str(), nullptr}) {}
|
|
};
|
|
|
|
OSMIUM_ATTRIBUTE(tags_handler, _t, const char*)
|
|
explicit _t(const char *tags) :
|
|
type_wrapper(tags) {}
|
|
};
|
|
|
|
template <typename TTagIterator>
|
|
inline constexpr detail::tags_from_iterator_pair<TTagIterator> _tags(TTagIterator first, TTagIterator last) {
|
|
return {first, last};
|
|
}
|
|
|
|
template <typename TContainer>
|
|
inline detail::tags_from_iterator_pair<typename TContainer::const_iterator> _tags(const TContainer& container) {
|
|
using std::begin;
|
|
using std::end;
|
|
return {begin(container), 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) {
|
|
using std::begin;
|
|
using std::end;
|
|
return {begin(container), 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 {first, last};
|
|
}
|
|
|
|
template <typename TContainer>
|
|
inline detail::nodes_from_iterator_pair<typename TContainer::const_iterator> _nodes(const TContainer& container) {
|
|
using std::begin;
|
|
using std::end;
|
|
return {begin(container), 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) {
|
|
using std::begin;
|
|
using std::end;
|
|
return {begin(container), 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) {
|
|
using std::begin;
|
|
using std::end;
|
|
return {begin(container), 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 {first, last};
|
|
}
|
|
|
|
template <typename TContainer>
|
|
inline detail::members_from_iterator_pair<typename TContainer::const_iterator> _members(const TContainer& container) {
|
|
using std::begin;
|
|
using std::end;
|
|
return {begin(container), 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) {
|
|
using std::begin;
|
|
using std::end;
|
|
return {begin(container), 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 {first, last};
|
|
}
|
|
|
|
template <typename TContainer>
|
|
inline detail::comments_from_iterator_pair<typename TContainer::const_iterator> _comments(const TContainer& container) {
|
|
using std::begin;
|
|
using std::end;
|
|
return {begin(container), 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) {
|
|
using std::begin;
|
|
using std::end;
|
|
return {begin(container), end(container)};
|
|
}
|
|
|
|
|
|
template <typename TIdIterator>
|
|
inline constexpr detail::outer_ring_from_iterator_pair<TIdIterator> _outer_ring(TIdIterator first, TIdIterator last) {
|
|
return {first, last};
|
|
}
|
|
|
|
template <typename TContainer>
|
|
inline detail::outer_ring_from_iterator_pair<typename TContainer::const_iterator> _outer_ring(const TContainer& container) {
|
|
using std::begin;
|
|
using std::end;
|
|
return {begin(container), 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) {
|
|
using std::begin;
|
|
using std::end;
|
|
return {begin(container), 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) {
|
|
using std::begin;
|
|
using std::end;
|
|
return {begin(container), end(container)};
|
|
}
|
|
|
|
template <typename TIdIterator>
|
|
inline constexpr detail::inner_ring_from_iterator_pair<TIdIterator> _inner_ring(TIdIterator first, TIdIterator last) {
|
|
return {first, last};
|
|
}
|
|
|
|
template <typename TContainer>
|
|
inline detail::inner_ring_from_iterator_pair<typename TContainer::const_iterator> _inner_ring(const TContainer& container) {
|
|
using std::begin;
|
|
using std::end;
|
|
return {begin(container), 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) {
|
|
using std::begin;
|
|
using std::end;
|
|
return {begin(container), 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) {
|
|
using std::begin;
|
|
using std::end;
|
|
return {begin(container), 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& /*changeset*/, const TDummy& /*dummy*/) 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& /*object*/, const TDummy& /*dummy*/) 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&... /*args*/) 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& /*first*/, 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& /*tlb*/, const TDummy& /*dummy*/) noexcept {
|
|
}
|
|
|
|
static void set_value(TagListBuilder& builder, const attr::_tag& tag) {
|
|
if (tag.value.second != nullptr) {
|
|
builder.add_tag(tag.value);
|
|
return;
|
|
}
|
|
const char* key = tag.value.first;
|
|
const char* const equal_sign = std::strchr(key, '=');
|
|
if (!equal_sign) {
|
|
builder.add_tag(key, "");
|
|
return;
|
|
}
|
|
const char* value = equal_sign + 1;
|
|
builder.add_tag(key, equal_sign - key,
|
|
value, std::strlen(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);
|
|
}
|
|
}
|
|
|
|
static void set_value(TagListBuilder& builder, const attr::_t& tags) {
|
|
const auto taglist = osmium::split_string(tags.value, ',', true);
|
|
for (const auto& tag : taglist) {
|
|
const std::size_t pos = tag.find_first_of('=');
|
|
if (pos == std::string::npos) {
|
|
builder.add_tag(tag, "");
|
|
} else {
|
|
const char* value = tag.c_str() + pos + 1;
|
|
builder.add_tag(tag.c_str(), pos,
|
|
value, tag.size() - pos - 1);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}; // struct tags_handler
|
|
|
|
struct nodes_handler {
|
|
|
|
template <typename TDummy>
|
|
static void set_value(WayNodeListBuilder& /*wnlb*/, const TDummy& /*dummy*/) 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& /*rmlb*/, const TDummy& /*dummy*/) 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& /*cdb*/, const TDummy& /*dummy*/) 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& /*ab*/, const TDummy& /*dummy*/) 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& /*parent*/, const TArgs&... /*args*/) 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
|