1 #ifndef OSMIUM_BUILDER_ATTR_HPP
2 #define OSMIUM_BUILDER_ATTR_HPP
3 
4 /*
5 
6 This file is part of Osmium (https://osmcode.org/libosmium).
7 
8 Copyright 2013-2021 Jochen Topf <jochen@topf.org> and others (see README).
9 
10 Boost Software License - Version 1.0 - August 17th, 2003
11 
12 Permission is hereby granted, free of charge, to any person or organization
13 obtaining a copy of the software and accompanying documentation covered by
14 this license (the "Software") to use, reproduce, display, distribute,
15 execute, and transmit the Software, and to prepare derivative works of the
16 Software, and to permit third-parties to whom the Software is furnished to
17 do so, all subject to the following:
18 
19 The copyright notices in the Software and this entire statement, including
20 the above license grant, this restriction and the following disclaimer,
21 must be included in all copies of the Software, in whole or in part, and
22 all derivative works of the Software, unless such copies or derivative
23 works are solely in the form of machine-executable object code generated by
24 a source language processor.
25 
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
29 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
30 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
31 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32 DEALINGS IN THE SOFTWARE.
33 
34 */
35 
36 #include <osmium/builder/builder.hpp>
37 #include <osmium/builder/osm_object_builder.hpp>
38 #include <osmium/memory/buffer.hpp>
39 #include <osmium/osm/changeset.hpp>
40 #include <osmium/osm/item_type.hpp>
41 #include <osmium/osm/location.hpp>
42 #include <osmium/osm/node.hpp>
43 #include <osmium/osm/node_ref.hpp>
44 #include <osmium/osm/object.hpp>
45 #include <osmium/osm/relation.hpp>
46 #include <osmium/osm/timestamp.hpp>
47 #include <osmium/osm/types.hpp>
48 #include <osmium/util/string.hpp>
49 
50 #include <cstddef>
51 #include <cstdint>
52 #include <ctime>
53 #include <initializer_list>
54 #include <iterator>
55 #include <string>
56 #include <tuple>
57 #include <type_traits>
58 #include <utility>
59 
60 namespace osmium {
61 
62     namespace builder {
63 
64         namespace detail {
65 
66 #ifdef _MSC_VER
67             // workaround for bug in MSVC
68 
69             template <typename THandler, typename... TTypes>
70             struct is_handled_by;
71 
72             template <typename THandler>
73             struct is_handled_by<THandler> {
74                 static constexpr bool value = false;
75             };
76 
77             template <typename THandler, typename T, typename... TRest>
78             struct is_handled_by<THandler, T, TRest...> {
79                 static constexpr bool value = std::is_base_of<typename T::handler, THandler>::value ||
80                                               is_handled_by<THandler, TRest...>::value;
81             };
82 
83             template <typename THandler, typename... TTypes>
84             struct are_all_handled_by;
85 
86             template <typename THandler, typename T>
87             struct are_all_handled_by<THandler, T> {
88                 static constexpr bool value = std::is_base_of<typename T::handler, THandler>::value;
89             };
90 
91             template <typename THandler, typename T, typename... TRest>
92             struct are_all_handled_by<THandler, T, TRest...> {
93                 static constexpr bool value = std::is_base_of<typename T::handler, THandler>::value &&
94                                               are_all_handled_by<THandler, TRest...>::value;
95             };
96 #else
97             // True if Predicate matches for none of the types Ts
98             template <template <typename> class Predicate, typename... Ts>
99             struct static_none_of : std::is_same<std::tuple<std::false_type, typename Predicate<Ts>::type...>,
100                                                  std::tuple<typename Predicate<Ts>::type..., std::false_type>>
101             {};
102 
103             // True if Predicate matches for all of the types Ts
104             template <template <typename> class Predicate, typename... Ts>
105             struct static_all_of : std::is_same<std::tuple<std::true_type, typename Predicate<Ts>::type...>,
106                                                 std::tuple<typename Predicate<Ts>::type..., std::true_type>>
107             {};
108 
109             // True if THandler is derived from the handler for at least one of the types in TTypes
110             template <typename THandler, typename... TTypes>
111             struct is_handled_by {
112                 template <typename T>
113                 using HasHandler = std::is_base_of<typename T::handler, THandler>;
114 
115                 static constexpr bool value = !static_none_of<HasHandler, TTypes...>::value;
116             };
117 
118             // True if THandler is derived from the handlers of all the types in TTypes
119             template <typename THandler, typename... TTypes>
120             struct are_all_handled_by {
121                 template <typename T>
122                 using HasHandler = std::is_base_of<typename T::handler, THandler>;
123 
124                 static constexpr bool value = static_all_of<HasHandler, TTypes...>::value;
125             };
126 #endif
127 
128 
129             // Wraps any type, so that we can derive from it
130             template <typename TType>
131             struct type_wrapper {
132 
133                 using type = TType;
134 
135                 TType value;
136 
type_wrapperosmium::builder::detail::type_wrapper137                 constexpr explicit type_wrapper(const TType& v) :
138                     value(v) {
139                 }
140 
141             }; // struct type_wrapper
142 
143             // Small wrapper for begin/end iterator
144             template <typename TType>
145             struct iterator_wrapper {
146 
147                 using type = TType;
148 
149                 TType first;
150                 TType last;
151 
iterator_wrapperosmium::builder::detail::iterator_wrapper152                 constexpr iterator_wrapper(TType begin, TType end) :
153                     first(begin),
154                     last(end) {}
155 
beginosmium::builder::detail::iterator_wrapper156                 constexpr TType begin() const {
157                     return first;
158                 }
159 
endosmium::builder::detail::iterator_wrapper160                 constexpr TType end() const {
161                     return last;
162                 }
163 
164             }; // struct iterator_wrapper
165 
166 
167             struct entity_handler {};
168             struct object_handler;
169             struct node_handler;
170             struct tags_handler;
171             struct nodes_handler;
172             struct members_handler;
173             struct changeset_handler;
174             struct discussion_handler;
175             struct ring_handler;
176 
177         } // namespace detail
178 
179 #define OSMIUM_ATTRIBUTE(_handler, _name, _type) \
180     struct _name : public osmium::builder::detail::type_wrapper<_type> { \
181         using handler = osmium::builder::detail::_handler;
182 
183 #define OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(_handler, _name, _type) \
184     OSMIUM_ATTRIBUTE(_handler, _name, _type) \
185         constexpr explicit _name(std::add_const<_type>::type& value) : \
186             type_wrapper(value) {} \
187     }
188 
189 #define OSMIUM_ATTRIBUTE_ITER(_handler, _name) \
190     template <typename TIterator> \
191     struct _name : public osmium::builder::detail::iterator_wrapper<TIterator> { \
192         using handler = osmium::builder::detail::_handler; \
193         constexpr _name(TIterator first, TIterator last) : \
194             osmium::builder::detail::iterator_wrapper<TIterator>(first, last) {} \
195     }
196 
197         namespace attr {
198 
199             OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(object_handler, _id, osmium::object_id_type);
200             OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(object_handler, _version, osmium::object_version_type);
201             OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(entity_handler, _uid, osmium::user_id_type);
202             OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(entity_handler, _cid, osmium::changeset_id_type);
203 
OSMIUM_ATTRIBUTE(object_handler,_deleted,bool)204             OSMIUM_ATTRIBUTE(object_handler, _deleted, bool)
205                 constexpr explicit _deleted(bool value = true) noexcept :
206                     type_wrapper(value) {}
207             };
208 
OSMIUM_ATTRIBUTE(object_handler,_visible,bool)209             OSMIUM_ATTRIBUTE(object_handler, _visible, bool)
210                 constexpr explicit _visible(bool value = true) noexcept :
211                     type_wrapper(value) {}
212             };
213 
OSMIUM_ATTRIBUTE(object_handler,_timestamp,osmium::Timestamp)214             OSMIUM_ATTRIBUTE(object_handler, _timestamp, osmium::Timestamp)
215                 constexpr explicit _timestamp(const osmium::Timestamp& value) noexcept :
216                     type_wrapper(value) {}
_timestamp(time_t value)217                 constexpr explicit _timestamp(time_t value) noexcept :
218                     type_wrapper(osmium::Timestamp{value}) {}
_timestamp(uint32_t value)219                 constexpr explicit _timestamp(uint32_t value) noexcept :
220                     type_wrapper(osmium::Timestamp{value}) {}
_timestamp(const char * value)221                 explicit _timestamp(const char* value) :
222                     type_wrapper(osmium::Timestamp{value}) {}
_timestamp(const std::string & value)223                 explicit _timestamp(const std::string& value) :
224                     type_wrapper(osmium::Timestamp{value}) {}
225             };
226 
OSMIUM_ATTRIBUTE(node_handler,_location,osmium::Location)227             OSMIUM_ATTRIBUTE(node_handler, _location, osmium::Location)
228                 constexpr explicit _location(const osmium::Location& value) noexcept :
229                     type_wrapper(value) {}
_location(double lon,double lat)230                 explicit _location(double lon, double lat) :
231                     type_wrapper(osmium::Location{lon, lat}) {}
232             };
233 
234             OSMIUM_ATTRIBUTE(entity_handler, _user, const char*)
235                 constexpr explicit _user(const char* val) noexcept :
236                     type_wrapper(val) {}
237                 explicit _user(const std::string& val) noexcept :
238                     type_wrapper(val.c_str()) {}
239             };
240 
241             using pair_of_cstrings = std::pair<const char* const, const char* const>;
242             using pair_of_strings = std::pair<const std::string&, const std::string&>;
243 
244             class member_type {
245 
246                 osmium::item_type      m_type;
247                 osmium::object_id_type m_ref;
248                 const char*            m_role;
249 
250             public:
251 
252                 constexpr member_type(osmium::item_type type, osmium::object_id_type ref, const char* role = "") noexcept :
253                     m_type(type),
254                     m_ref(ref),
255                     m_role(role) {
256                 }
257 
258                 member_type(char type, osmium::object_id_type ref, const char* role = "") noexcept :
259                     member_type(osmium::char_to_item_type(type), ref, role) {
260                 }
261 
262                 constexpr osmium::item_type type() const noexcept {
263                     return m_type;
264                 }
265 
266                 constexpr osmium::object_id_type ref() const noexcept {
267                     return m_ref;
268                 }
269 
270                 constexpr const char* role() const noexcept {
271                     return m_role;
272                 }
273 
274             }; // class member_type
275 
276             class member_type_string {
277 
278                 osmium::item_type      m_type;
279                 osmium::object_id_type m_ref;
280                 std::string            m_role;
281 
282             public:
283 
284                 member_type_string(osmium::item_type type, osmium::object_id_type ref, std::string&& role) :
285                     m_type(type),
286                     m_ref(ref),
287                     m_role(std::move(role)) {
288                 }
289 
290                 member_type_string(char type, osmium::object_id_type ref, std::string&& role) noexcept :
291                     member_type_string(osmium::char_to_item_type(type), ref, std::move(role)) {
292                 }
293 
294                 osmium::item_type type() const noexcept {
295                     return m_type;
296                 }
297 
298                 osmium::object_id_type ref() const noexcept {
299                     return m_ref;
300                 }
301 
302                 const char* role() const noexcept {
303                     return m_role.c_str();
304                 }
305 
306             }; // class member_type_string
307 
308             class comment_type {
309 
310                 osmium::Timestamp    m_date;
311                 osmium::user_id_type m_uid;
312                 const char*          m_user;
313                 const char*          m_text;
314 
315             public:
316 
317                 constexpr comment_type(osmium::Timestamp date, osmium::user_id_type uid, const char* user, const char* text) noexcept :
318                     m_date(date),
319                     m_uid(uid),
320                     m_user(user),
321                     m_text(text) {
322                 }
323 
324                 constexpr osmium::Timestamp date() const noexcept {
325                     return m_date;
326                 }
327 
328                 constexpr osmium::user_id_type uid() const noexcept {
329                     return m_uid;
330                 }
331 
332                 constexpr const char* user() const noexcept {
333                     return m_user;
334                 }
335 
336                 constexpr const char* text() const noexcept {
337                     return m_text;
338                 }
339 
340             }; // class comment_type
341 
342             namespace detail {
343 
344                 OSMIUM_ATTRIBUTE_ITER(tags_handler, tags_from_iterator_pair);
345 
346                 OSMIUM_ATTRIBUTE_ITER(nodes_handler, nodes_from_iterator_pair);
347 
348                 OSMIUM_ATTRIBUTE_ITER(members_handler, members_from_iterator_pair);
349 
350                 OSMIUM_ATTRIBUTE_ITER(discussion_handler, comments_from_iterator_pair);
351 
352                 OSMIUM_ATTRIBUTE_ITER(ring_handler, outer_ring_from_iterator_pair);
353                 OSMIUM_ATTRIBUTE_ITER(ring_handler, inner_ring_from_iterator_pair);
354 
355             } // namespace detail
356 
357             OSMIUM_ATTRIBUTE(tags_handler, _tag, pair_of_cstrings)
358                 explicit _tag(const pair_of_cstrings& value) noexcept :
359                     type_wrapper(value) {}
360                 explicit _tag(const std::pair<const char* const, const char*>& value) :
361                     type_wrapper(pair_of_cstrings{value.first, value.second}) {}
362                 explicit _tag(const std::pair<const char*, const char* const>& value) :
363                     type_wrapper(pair_of_cstrings{value.first, value.second}) {}
364                 explicit _tag(const std::pair<const char*, const char*>& value) :
365                     type_wrapper(pair_of_cstrings{value.first, value.second}) {}
366                 explicit _tag(const pair_of_strings& value) :
367                     type_wrapper(std::make_pair(value.first.c_str(), value.second.c_str())) {}
368                 explicit _tag(const char* key, const char* val) :
369                     type_wrapper(std::make_pair(key, val)) {}
370                 explicit _tag(const std::string& key, const std::string& val) :
371                     type_wrapper(std::make_pair(key.c_str(), val.c_str())) {}
372                 explicit _tag(const char* const key_value) :
373                     type_wrapper(pair_of_cstrings{key_value, nullptr}) {}
374                 explicit _tag(const std::string& key_value) :
375                     type_wrapper(pair_of_cstrings{key_value.c_str(), nullptr}) {}
376             };
377 
378             OSMIUM_ATTRIBUTE(tags_handler, _t, const char*)
379                 explicit _t(const char *tags) :
380                     type_wrapper(tags) {}
381             };
382 
383             template <typename TTagIterator>
384             inline constexpr detail::tags_from_iterator_pair<TTagIterator> _tags(TTagIterator first, TTagIterator last) {
385                 return {first, last};
386             }
387 
388             template <typename TContainer>
389             inline detail::tags_from_iterator_pair<typename TContainer::const_iterator> _tags(const TContainer& container) {
390                 using std::begin;
391                 using std::end;
392                 return {begin(container), end(container)};
393             }
394 
395             using tag_ilist = std::initializer_list<std::pair<const char*, const char*>>;
396             inline detail::tags_from_iterator_pair<tag_ilist::const_iterator> _tags(const tag_ilist& container) {
397                 using std::begin;
398                 using std::end;
399                 return {begin(container), end(container)};
400             }
401 
402 
403 
404             OSMIUM_ATTRIBUTE(nodes_handler, _node, osmium::NodeRef)
405                 constexpr explicit _node(osmium::object_id_type value) noexcept :
406                     type_wrapper(NodeRef{value}) {}
407                 constexpr explicit _node(const NodeRef& value) noexcept :
408                     type_wrapper(value) {}
409             };
410 
411             template <typename TIdIterator>
412             inline constexpr detail::nodes_from_iterator_pair<TIdIterator> _nodes(TIdIterator first, TIdIterator last) {
413                 return {first, last};
414             }
415 
416             template <typename TContainer>
417             inline detail::nodes_from_iterator_pair<typename TContainer::const_iterator> _nodes(const TContainer& container) {
418                 using std::begin;
419                 using std::end;
420                 return {begin(container), end(container)};
421             }
422 
423             using object_id_ilist = std::initializer_list<osmium::object_id_type>;
424             inline detail::nodes_from_iterator_pair<object_id_ilist::const_iterator> _nodes(const object_id_ilist& container) {
425                 using std::begin;
426                 using std::end;
427                 return {begin(container), end(container)};
428             }
429 
430             using node_ref_ilist = std::initializer_list<osmium::NodeRef>;
431             inline detail::nodes_from_iterator_pair<node_ref_ilist::const_iterator> _nodes(const node_ref_ilist& container) {
432                 using std::begin;
433                 using std::end;
434                 return {begin(container), end(container)};
435             }
436 
437 
438             OSMIUM_ATTRIBUTE(members_handler, _member, member_type)
439                 constexpr explicit _member(const member_type& value) noexcept :
440                     type_wrapper(value) {}
441                 constexpr explicit _member(osmium::item_type type, osmium::object_id_type id) noexcept :
442                     type_wrapper({type, id}) {}
443                 constexpr explicit _member(osmium::item_type type, osmium::object_id_type id, const char* role) noexcept :
444                     type_wrapper({type, id, role}) {}
445                 explicit _member(osmium::item_type type, osmium::object_id_type id, const std::string& role) noexcept :
446                     type_wrapper({type, id, role.c_str()}) {}
447                 explicit _member(const osmium::RelationMember& member) noexcept :
448                     type_wrapper({member.type(), member.ref(), member.role()}) {}
449             };
450 
451             template <typename TMemberIterator>
452             inline constexpr detail::members_from_iterator_pair<TMemberIterator> _members(TMemberIterator first, TMemberIterator last) {
453                 return {first, last};
454             }
455 
456             template <typename TContainer>
457             inline detail::members_from_iterator_pair<typename TContainer::const_iterator> _members(const TContainer& container) {
458                 using std::begin;
459                 using std::end;
460                 return {begin(container), end(container)};
461             }
462 
463             using member_ilist = std::initializer_list<member_type>;
464             inline detail::members_from_iterator_pair<member_ilist::const_iterator> _members(const member_ilist& container) {
465                 using std::begin;
466                 using std::end;
467                 return {begin(container), end(container)};
468             }
469 
470 
471             OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(changeset_handler, _num_changes, osmium::num_changes_type);
472             OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(changeset_handler, _num_comments, osmium::num_comments_type);
473             OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(changeset_handler, _created_at, osmium::Timestamp);
474             OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR(changeset_handler, _closed_at, osmium::Timestamp);
475 
476             OSMIUM_ATTRIBUTE(discussion_handler, _comment, comment_type)
477                 constexpr explicit _comment(const comment_type& value) noexcept :
478                     type_wrapper(value) {}
479                 explicit _comment(const osmium::ChangesetComment& comment) noexcept :
480                     type_wrapper({comment.date(), comment.uid(), comment.user(), comment.text()}) {}
481             };
482 
483             template <typename TCommentIterator>
484             inline constexpr detail::comments_from_iterator_pair<TCommentIterator> _comments(TCommentIterator first, TCommentIterator last) {
485                 return {first, last};
486             }
487 
488             template <typename TContainer>
489             inline detail::comments_from_iterator_pair<typename TContainer::const_iterator> _comments(const TContainer& container) {
490                 using std::begin;
491                 using std::end;
492                 return {begin(container), end(container)};
493             }
494 
495             using comment_ilist = std::initializer_list<comment_type>;
496             inline detail::comments_from_iterator_pair<comment_ilist::const_iterator> _comments(const comment_ilist& container) {
497                 using std::begin;
498                 using std::end;
499                 return {begin(container), end(container)};
500             }
501 
502 
503             template <typename TIdIterator>
504             inline constexpr detail::outer_ring_from_iterator_pair<TIdIterator> _outer_ring(TIdIterator first, TIdIterator last) {
505                 return {first, last};
506             }
507 
508             template <typename TContainer>
509             inline detail::outer_ring_from_iterator_pair<typename TContainer::const_iterator> _outer_ring(const TContainer& container) {
510                 using std::begin;
511                 using std::end;
512                 return {begin(container), end(container)};
513             }
514 
515             using object_id_ilist = std::initializer_list<osmium::object_id_type>;
516             inline detail::outer_ring_from_iterator_pair<object_id_ilist::const_iterator> _outer_ring(const object_id_ilist& container) {
517                 using std::begin;
518                 using std::end;
519                 return {begin(container), end(container)};
520             }
521 
522             using node_ref_ilist = std::initializer_list<osmium::NodeRef>;
523             inline detail::outer_ring_from_iterator_pair<node_ref_ilist::const_iterator> _outer_ring(const node_ref_ilist& container) {
524                 using std::begin;
525                 using std::end;
526                 return {begin(container), end(container)};
527             }
528 
529             template <typename TIdIterator>
530             inline constexpr detail::inner_ring_from_iterator_pair<TIdIterator> _inner_ring(TIdIterator first, TIdIterator last) {
531                 return {first, last};
532             }
533 
534             template <typename TContainer>
535             inline detail::inner_ring_from_iterator_pair<typename TContainer::const_iterator> _inner_ring(const TContainer& container) {
536                 using std::begin;
537                 using std::end;
538                 return {begin(container), end(container)};
539             }
540 
541             using object_id_ilist = std::initializer_list<osmium::object_id_type>;
542             inline detail::inner_ring_from_iterator_pair<object_id_ilist::const_iterator> _inner_ring(const object_id_ilist& container) {
543                 using std::begin;
544                 using std::end;
545                 return {begin(container), end(container)};
546             }
547 
548             using node_ref_ilist = std::initializer_list<osmium::NodeRef>;
549             inline detail::inner_ring_from_iterator_pair<node_ref_ilist::const_iterator> _inner_ring(const node_ref_ilist& container) {
550                 using std::begin;
551                 using std::end;
552                 return {begin(container), end(container)};
553             }
554 
555 
556         } // namespace attr
557 
558 #undef OSMIUM_ATTRIBUTE_ITER
559 #undef OSMIUM_ATTRIBUTE_WITH_CONSTRUCTOR
560 #undef OSMIUM_ATTRIBUTE
561 
562         namespace detail {
563 
564             struct changeset_handler : public entity_handler {
565 
566                 template <typename TDummy>
567                 static void set_value(osmium::Changeset& /*changeset*/, const TDummy& /*dummy*/) noexcept {
568                 }
569 
570                 static void set_value(osmium::Changeset& changeset, attr::_cid id) noexcept {
571                     changeset.set_id(id.value);
572                 }
573 
574                 static void set_value(osmium::Changeset& changeset, attr::_num_changes num_changes) noexcept {
575                     changeset.set_num_changes(num_changes.value);
576                 }
577 
578                 static void set_value(osmium::Changeset& changeset, attr::_num_comments num_comments) noexcept {
579                     changeset.set_num_comments(num_comments.value);
580                 }
581 
582                 static void set_value(osmium::Changeset& changeset, attr::_created_at created_at) noexcept {
583                     changeset.set_created_at(created_at.value);
584                 }
585 
586                 static void set_value(osmium::Changeset& changeset, attr::_closed_at closed_at) noexcept {
587                     changeset.set_closed_at(closed_at.value);
588                 }
589 
590                 static void set_value(osmium::Changeset& changeset, attr::_uid uid) noexcept {
591                     changeset.set_uid(uid.value);
592                 }
593 
594             };
595 
596             struct object_handler : public entity_handler {
597 
598                 template <typename TDummy>
599                 static void set_value(osmium::OSMObject& /*object*/, const TDummy& /*dummy*/) noexcept {
600                 }
601 
602                 static void set_value(osmium::OSMObject& object, attr::_id id) noexcept {
603                     object.set_id(id.value);
604                 }
605 
606                 static void set_value(osmium::OSMObject& object, attr::_version version) noexcept {
607                     object.set_version(version.value);
608                 }
609 
610                 static void set_value(osmium::OSMObject& object, attr::_visible visible) noexcept {
611                     object.set_visible(visible.value);
612                 }
613 
614                 static void set_value(osmium::OSMObject& object, attr::_deleted deleted) noexcept {
615                     object.set_deleted(deleted.value);
616                 }
617 
618                 static void set_value(osmium::OSMObject& object, attr::_timestamp timestamp) noexcept {
619                     object.set_timestamp(timestamp.value);
620                 }
621 
622                 static void set_value(osmium::OSMObject& object, attr::_cid changeset) noexcept {
623                     object.set_changeset(changeset.value);
624                 }
625 
626                 static void set_value(osmium::OSMObject& object, attr::_uid uid) noexcept {
627                     object.set_uid(uid.value);
628                 }
629 
630             }; // object_handler
631 
632             struct node_handler : public object_handler {
633 
634                 using object_handler::set_value;
635 
636                 static void set_value(osmium::Node& node, attr::_location location) noexcept {
637                     node.set_location(location.value);
638                 }
639 
640             }; // node_handler
641 
642             template <typename THandler, typename TBuilder, typename... TArgs>
643             inline void add_basic(TBuilder& builder, const TArgs&... args) noexcept {
644                 (void)std::initializer_list<int>{
645                     (THandler::set_value(builder.object(), args), 0)...
646                 };
647             }
648 
649             // ==============================================================
650 
651             template <typename... TArgs>
652             inline constexpr const char* get_user(const attr::_user& user, const TArgs&... /*args*/) noexcept {
653                 return user.value;
654             }
655 
656             inline constexpr const char* get_user() noexcept {
657                 return "";
658             }
659 
660             template <typename TFirst, typename... TRest>
661             inline constexpr typename std::enable_if<!std::is_same<attr::_user, TFirst>::value, const char*>::type
662             get_user(const TFirst& /*first*/, const TRest&... args) noexcept {
663                 return get_user(args...);
664             }
665 
666             template <typename TBuilder, typename... TArgs>
667             inline void add_user(TBuilder& builder, const TArgs&... args) {
668                 builder.set_user(get_user(args...));
669             }
670 
671             // ==============================================================
672 
673             struct tags_handler {
674 
675                 template <typename TDummy>
676                 static void set_value(TagListBuilder& /*tlb*/, const TDummy& /*dummy*/) noexcept {
677                 }
678 
679                 static void set_value(TagListBuilder& builder, const attr::_tag& tag) {
680                     if (tag.value.second != nullptr) {
681                         builder.add_tag(tag.value);
682                         return;
683                     }
684                     const char* key = tag.value.first;
685                     const char* const equal_sign = std::strchr(key, '=');
686                     if (!equal_sign) {
687                         builder.add_tag(key, "");
688                         return;
689                     }
690                     const char* value = equal_sign + 1;
691                     builder.add_tag(key, equal_sign - key,
692                                     value, std::strlen(value));
693                 }
694 
695                 template <typename TIterator>
696                 static void set_value(TagListBuilder& builder, const attr::detail::tags_from_iterator_pair<TIterator>& tags) {
697                     for (const auto& tag : tags) {
698                         builder.add_tag(tag);
699                     }
700                 }
701 
702                 static void set_value(TagListBuilder& builder, const attr::_t& tags) {
703                     const auto taglist = osmium::split_string(tags.value, ',', true);
704                     for (const auto& tag : taglist) {
705                         const std::size_t pos = tag.find_first_of('=');
706                         if (pos == std::string::npos) {
707                             builder.add_tag(tag, "");
708                         } else {
709                             const char* value = tag.c_str() + pos + 1;
710                             builder.add_tag(tag.c_str(), pos,
711                                             value, tag.size() - pos - 1);
712                         }
713 
714                     }
715                 }
716 
717             }; // struct tags_handler
718 
719             struct nodes_handler {
720 
721                 template <typename TDummy>
722                 static void set_value(WayNodeListBuilder& /*wnlb*/, const TDummy& /*dummy*/) noexcept {
723                 }
724 
725                 static void set_value(WayNodeListBuilder& builder, const attr::_node& node_ref) {
726                     builder.add_node_ref(node_ref.value);
727                 }
728 
729                 template <typename TIterator>
730                 static void set_value(WayNodeListBuilder& builder, const attr::detail::nodes_from_iterator_pair<TIterator>& nodes) {
731                     for (const auto& ref : nodes) {
732                         builder.add_node_ref(ref);
733                     }
734                 }
735 
736             }; // struct nodes_handler
737 
738             struct members_handler {
739 
740                 template <typename TDummy>
741                 static void set_value(RelationMemberListBuilder& /*rmlb*/, const TDummy& /*dummy*/) noexcept {
742                 }
743 
744                 static void set_value(RelationMemberListBuilder& builder, const attr::_member& member) {
745                     builder.add_member(member.value.type(), member.value.ref(), member.value.role());
746                 }
747 
748                 template <typename TIterator>
749                 static void set_value(RelationMemberListBuilder& builder, const attr::detail::members_from_iterator_pair<TIterator>& members) {
750                     for (const auto& member : members) {
751                         builder.add_member(member.type(), member.ref(), member.role());
752                     }
753                 }
754 
755             }; // struct members_handler
756 
757             struct discussion_handler {
758 
759                 template <typename TDummy>
760                 static void set_value(ChangesetDiscussionBuilder& /*cdb*/, const TDummy& /*dummy*/) noexcept {
761                 }
762 
763                 static void set_value(ChangesetDiscussionBuilder& builder, const attr::_comment& comment) {
764                     builder.add_comment(comment.value.date(), comment.value.uid(), comment.value.user());
765                     builder.add_comment_text(comment.value.text());
766                 }
767 
768                 template <typename TIterator>
769                 static void set_value(ChangesetDiscussionBuilder& builder, const attr::detail::comments_from_iterator_pair<TIterator>& comments) {
770                     for (const auto& comment : comments) {
771                         builder.add_comment(comment.date(), comment.uid(), comment.user());
772                         builder.add_comment_text(comment.text());
773                     }
774                 }
775 
776             }; // struct discussion_handler
777 
778             struct ring_handler {
779 
780                 template <typename TDummy>
781                 static void set_value(AreaBuilder& /*ab*/, const TDummy& /*dummy*/) noexcept {
782                 }
783 
784                 template <typename TIterator>
785                 static void set_value(AreaBuilder& parent, const attr::detail::outer_ring_from_iterator_pair<TIterator>& nodes) {
786                     OuterRingBuilder builder(parent.buffer(), &parent);
787                     for (const auto& ref : nodes) {
788                         builder.add_node_ref(ref);
789                     }
790                 }
791 
792                 template <typename TIterator>
793                 static void set_value(AreaBuilder& parent, const attr::detail::inner_ring_from_iterator_pair<TIterator>& nodes) {
794                     InnerRingBuilder builder(parent.buffer(), &parent);
795                     for (const auto& ref : nodes) {
796                         builder.add_node_ref(ref);
797                     }
798                 }
799 
800             }; // struct ring_handler
801 
802             // ==============================================================
803 
804             template <typename TBuilder, typename THandler, typename... TArgs>
805             inline typename std::enable_if<!is_handled_by<THandler, TArgs...>::value>::type
806             add_list(osmium::builder::Builder& /*parent*/, const TArgs&... /*args*/) noexcept {
807             }
808 
809             template <typename TBuilder, typename THandler, typename... TArgs>
810             inline typename std::enable_if<is_handled_by<THandler, TArgs...>::value>::type
811             add_list(osmium::builder::Builder& parent, const TArgs&... args) {
812                 TBuilder builder{parent.buffer(), &parent};
813                 (void)std::initializer_list<int>{
814                     (THandler::set_value(builder, args), 0)...
815                 };
816             }
817 
818             struct any_node_handlers : public node_handler, public tags_handler {};
819             struct any_way_handlers : public object_handler, public tags_handler, public nodes_handler {};
820             struct any_relation_handlers : public object_handler, public tags_handler, public members_handler {};
821             struct any_area_handlers : public object_handler, public tags_handler, public ring_handler {};
822             struct any_changeset_handlers : public changeset_handler, public tags_handler, public discussion_handler {};
823 
824         } // namespace detail
825 
826 
827         /**
828          * Create a node using the given arguments and add it to the given buffer.
829          *
830          * @param buffer The buffer to which the node will be added.
831          * @param args The attributes of the node.
832          * @returns The position in the buffer where this node was added.
833          */
834         template <typename... TArgs>
835         inline size_t add_node(osmium::memory::Buffer& buffer, const TArgs&... args) {
836             static_assert(sizeof...(args) > 0, "add_node() must have buffer and at least one additional argument");
837             static_assert(detail::are_all_handled_by<detail::any_node_handlers, TArgs...>::value, "Attribute not allowed in add_node()");
838 
839             {
840                 NodeBuilder builder{buffer};
841 
842                 detail::add_basic<detail::node_handler>(builder, args...);
843                 detail::add_user(builder, args...);
844                 detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
845             }
846 
847             return buffer.commit();
848         }
849 
850         /**
851          * Create a way using the given arguments and add it to the given buffer.
852          *
853          * @param buffer The buffer to which the way will be added.
854          * @param args The attributes of the way.
855          * @returns The position in the buffer where this way was added.
856          */
857         template <typename... TArgs>
858         inline size_t add_way(osmium::memory::Buffer& buffer, const TArgs&... args) {
859             static_assert(sizeof...(args) > 0, "add_way() must have buffer and at least one additional argument");
860             static_assert(detail::are_all_handled_by<detail::any_way_handlers, TArgs...>::value, "Attribute not allowed in add_way()");
861 
862             {
863                 WayBuilder builder{buffer};
864 
865                 detail::add_basic<detail::object_handler>(builder, args...);
866                 detail::add_user(builder, args...);
867                 detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
868                 detail::add_list<WayNodeListBuilder, detail::nodes_handler>(builder, args...);
869             }
870 
871             return buffer.commit();
872         }
873 
874         /**
875          * Create a relation using the given arguments and add it to the given buffer.
876          *
877          * @param buffer The buffer to which the relation will be added.
878          * @param args The attributes of the relation.
879          * @returns The position in the buffer where this relation was added.
880          */
881         template <typename... TArgs>
882         inline size_t add_relation(osmium::memory::Buffer& buffer, const TArgs&... args) {
883             static_assert(sizeof...(args) > 0, "add_relation() must have buffer and at least one additional argument");
884             static_assert(detail::are_all_handled_by<detail::any_relation_handlers, TArgs...>::value, "Attribute not allowed in add_relation()");
885 
886             {
887                 RelationBuilder builder{buffer};
888 
889                 detail::add_basic<detail::object_handler>(builder, args...);
890                 detail::add_user(builder, args...);
891                 detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
892                 detail::add_list<RelationMemberListBuilder, detail::members_handler>(builder, args...);
893             }
894 
895             return buffer.commit();
896         }
897 
898         /**
899          * Create a changeset using the given arguments and add it to the given buffer.
900          *
901          * @param buffer The buffer to which the changeset will be added.
902          * @param args The attributes of the changeset.
903          * @returns The position in the buffer where this changeset was added.
904          */
905         template <typename... TArgs>
906         inline size_t add_changeset(osmium::memory::Buffer& buffer, const TArgs&... args) {
907             static_assert(sizeof...(args) > 0, "add_changeset() must have buffer and at least one additional argument");
908             static_assert(detail::are_all_handled_by<detail::any_changeset_handlers, TArgs...>::value, "Attribute not allowed in add_changeset()");
909 
910             {
911                 ChangesetBuilder builder{buffer};
912 
913                 detail::add_basic<detail::changeset_handler>(builder, args...);
914                 detail::add_user(builder, args...);
915                 detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
916                 detail::add_list<ChangesetDiscussionBuilder, detail::discussion_handler>(builder, args...);
917             }
918 
919             return buffer.commit();
920         }
921 
922         /**
923          * Create a area using the given arguments and add it to the given buffer.
924          *
925          * @param buffer The buffer to which the area will be added.
926          * @param args The attributes of the area.
927          * @returns The position in the buffer where this area was added.
928          */
929         template <typename... TArgs>
930         inline size_t add_area(osmium::memory::Buffer& buffer, const TArgs&... args) {
931             static_assert(sizeof...(args) > 0, "add_area() must have buffer and at least one additional argument");
932             static_assert(detail::are_all_handled_by<detail::any_area_handlers, TArgs...>::value, "Attribute not allowed in add_area()");
933 
934             {
935                 AreaBuilder builder{buffer};
936 
937                 detail::add_basic<detail::object_handler>(builder, args...);
938                 detail::add_user(builder, args...);
939                 detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
940 
941                 (void)std::initializer_list<int>{
942                     (detail::ring_handler::set_value(builder, args), 0)...
943                 };
944             }
945 
946             return buffer.commit();
947         }
948 
949         /**
950          * Create a WayNodeList using the given arguments and add it to the given buffer.
951          *
952          * @param buffer The buffer to which the list will be added.
953          * @param args The contents of the list.
954          * @returns The position in the buffer where this list was added.
955          */
956         template <typename... TArgs>
957         inline size_t add_way_node_list(osmium::memory::Buffer& buffer, const TArgs&... args) {
958             static_assert(sizeof...(args) > 0, "add_way_node_list() must have buffer and at least one additional argument");
959             static_assert(detail::are_all_handled_by<detail::nodes_handler, TArgs...>::value, "Attribute not allowed in add_way_node_list()");
960 
961             {
962                 WayNodeListBuilder builder{buffer};
963                 (void)std::initializer_list<int>{
964                     (detail::nodes_handler::set_value(builder, args), 0)...
965                 };
966             }
967 
968             return buffer.commit();
969         }
970 
971         /**
972          * Create a TagList using the given arguments and add it to the given buffer.
973          *
974          * @param buffer The buffer to which the list will be added.
975          * @param args The contents of the list.
976          * @returns The position in the buffer where this list was added.
977          */
978         template <typename... TArgs>
979         inline size_t add_tag_list(osmium::memory::Buffer& buffer, const TArgs&... args) {
980             static_assert(sizeof...(args) > 0, "add_tag_list() must have buffer and at least one additional argument");
981             static_assert(detail::are_all_handled_by<detail::tags_handler, TArgs...>::value, "Attribute not allowed in add_tag_list()");
982 
983             {
984                 TagListBuilder builder{buffer};
985                 (void)std::initializer_list<int>{
986                     (detail::tags_handler::set_value(builder, args), 0)...
987                 };
988             }
989 
990             return buffer.commit();
991         }
992 
993     } // namespace builder
994 
995 } // namespace osmium
996 
997 #endif // OSMIUM_BUILDER_ATTR_HPP
998