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