1 #ifndef OSMIUM_OSM_CHANGESET_HPP 2 #define OSMIUM_OSM_CHANGESET_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/memory/collection.hpp> 37 #include <osmium/memory/item.hpp> 38 #include <osmium/osm/box.hpp> 39 #include <osmium/osm/entity.hpp> 40 #include <osmium/osm/item_type.hpp> 41 #include <osmium/osm/tag.hpp> 42 #include <osmium/osm/timestamp.hpp> 43 #include <osmium/osm/types.hpp> 44 #include <osmium/osm/types_from_string.hpp> 45 46 #include <cstdint> 47 #include <cstring> 48 #include <iterator> 49 50 namespace osmium { 51 52 namespace builder { 53 class ChangesetDiscussionBuilder; 54 class ChangesetBuilder; 55 } // namespace builder 56 57 class Changeset; 58 59 class ChangesetComment : public osmium::memory::detail::ItemHelper { 60 61 friend class osmium::builder::ChangesetDiscussionBuilder; 62 63 osmium::Timestamp m_date; 64 osmium::user_id_type m_uid = 0; 65 changeset_comment_size_type m_text_size; 66 string_size_type m_user_size; 67 endpos()68 unsigned char* endpos() { 69 return data() + osmium::memory::padded_length(sizeof(ChangesetComment) + m_user_size + m_text_size); 70 } 71 endpos() const72 const unsigned char* endpos() const { 73 return data() + osmium::memory::padded_length(sizeof(ChangesetComment) + m_user_size + m_text_size); 74 } 75 76 template <typename TMember> 77 friend class osmium::memory::CollectionIterator; 78 next()79 unsigned char* next() { 80 return endpos(); 81 } 82 next() const83 const unsigned char* next() const { 84 return endpos(); 85 } 86 set_user_size(string_size_type size)87 void set_user_size(string_size_type size) noexcept { 88 m_user_size = size; 89 } 90 set_text_size(changeset_comment_size_type size)91 void set_text_size(changeset_comment_size_type size) noexcept { 92 m_text_size = size; 93 } 94 95 public: 96 97 static constexpr item_type collection_type = item_type::changeset_discussion; 98 ChangesetComment(osmium::Timestamp date,osmium::user_id_type uid)99 ChangesetComment(osmium::Timestamp date, osmium::user_id_type uid) noexcept : 100 m_date(date), 101 m_uid(uid), 102 m_text_size(0), 103 m_user_size(0) { 104 } 105 106 ChangesetComment(const ChangesetComment&) = delete; 107 ChangesetComment& operator=(const ChangesetComment&) = delete; 108 109 ChangesetComment(ChangesetComment&&) = delete; 110 ChangesetComment& operator=(ChangesetComment&&) = delete; 111 112 ~ChangesetComment() noexcept = default; 113 date() const114 osmium::Timestamp date() const noexcept { 115 return m_date; 116 } 117 uid() const118 osmium::user_id_type uid() const noexcept { 119 return m_uid; 120 } 121 user() const122 const char* user() const noexcept { 123 return reinterpret_cast<const char*>(data() + sizeof(ChangesetComment)); 124 } 125 text() const126 const char* text() const noexcept { 127 return reinterpret_cast<const char*>(data() + sizeof(ChangesetComment) + m_user_size); 128 } 129 130 }; // class ChangesetComment 131 132 class ChangesetDiscussion : public osmium::memory::Collection<ChangesetComment, osmium::item_type::changeset_discussion> { 133 134 public: 135 136 ChangesetDiscussion() noexcept = default; 137 138 }; // class ChangesetDiscussion 139 140 static_assert(sizeof(ChangesetDiscussion) % osmium::memory::align_bytes == 0, "Class osmium::ChangesetDiscussion has wrong size to be aligned properly!"); 141 142 /** 143 * \brief An OSM Changeset, a group of changes made by a single user over 144 * a short period of time. 145 * 146 * You can not create Changeset objects directly. Use the ChangesetBuilder 147 * class to create Changesets in a Buffer. 148 */ 149 class Changeset : public osmium::OSMEntity { 150 151 friend class osmium::builder::ChangesetBuilder; 152 153 osmium::Box m_bounds; 154 osmium::Timestamp m_created_at; 155 osmium::Timestamp m_closed_at; 156 changeset_id_type m_id = 0; 157 num_changes_type m_num_changes = 0; 158 num_comments_type m_num_comments = 0; 159 user_id_type m_uid = 0; 160 string_size_type m_user_size = 0; 161 int16_t m_padding1 = 0; 162 int32_t m_padding2 = 0; 163 Changeset()164 Changeset() : 165 OSMEntity(sizeof(Changeset), osmium::item_type::changeset) { 166 } 167 set_user_size(string_size_type size)168 void set_user_size(string_size_type size) noexcept { 169 m_user_size = size; 170 } 171 user_size() const172 string_size_type user_size() const noexcept { 173 return m_user_size; 174 } 175 subitems_position()176 unsigned char* subitems_position() { 177 return data() + osmium::memory::padded_length(sizeof(Changeset) + m_user_size); 178 } 179 subitems_position() const180 const unsigned char* subitems_position() const { 181 return data() + osmium::memory::padded_length(sizeof(Changeset) + m_user_size); 182 } 183 184 public: 185 186 static constexpr osmium::item_type itemtype = osmium::item_type::changeset; 187 is_compatible_to(osmium::item_type t)188 constexpr static bool is_compatible_to(osmium::item_type t) noexcept { 189 return t == itemtype; 190 } 191 192 // Dummy to avoid warning because of unused private fields. Do not use. do_not_use() const193 int32_t do_not_use() const noexcept { 194 return m_padding1 + m_padding2; 195 } 196 197 /// Get ID of this changeset id() const198 changeset_id_type id() const noexcept { 199 return m_id; 200 } 201 202 /** 203 * Set ID of this changeset 204 * 205 * @param id The id. 206 * @returns Reference to changeset to make calls chainable. 207 */ set_id(changeset_id_type id)208 Changeset& set_id(changeset_id_type id) noexcept { 209 m_id = id; 210 return *this; 211 } 212 213 /** 214 * Set ID of this changeset. 215 * 216 * @param id The id. 217 * @returns Reference to object to make calls chainable. 218 */ set_id(const char * id)219 Changeset& set_id(const char* id) { 220 return set_id(osmium::string_to_changeset_id(id)); 221 } 222 223 /// Get user id. uid() const224 user_id_type uid() const noexcept { 225 return m_uid; 226 } 227 228 /** 229 * Set user id. 230 * 231 * @param uid The user id. 232 * @returns Reference to changeset to make calls chainable. 233 */ set_uid(user_id_type uid)234 Changeset& set_uid(user_id_type uid) noexcept { 235 m_uid = uid; 236 return *this; 237 } 238 239 /** 240 * Set user id to given uid or to 0 (anonymous user) if the given 241 * uid is smaller than 0. 242 * 243 * @param uid The user id. 244 * @returns Reference to changeset to make calls chainable. 245 */ set_uid_from_signed(signed_user_id_type uid)246 Changeset& set_uid_from_signed(signed_user_id_type uid) noexcept { 247 m_uid = uid < 0 ? 0 : static_cast<user_id_type>(uid); 248 return *this; 249 } 250 251 /** 252 * Set user id to given uid or to 0 (anonymous user) if the given 253 * uid is smaller than 0. 254 * 255 * @returns Reference to changeset to make calls chainable. 256 */ set_uid(const char * uid)257 Changeset& set_uid(const char* uid) { 258 m_uid = string_to_uid(uid); 259 return *this; 260 } 261 262 /// Is this user anonymous? user_is_anonymous() const263 bool user_is_anonymous() const noexcept { 264 return m_uid == 0; 265 } 266 267 /// Get timestamp when this changeset was created. created_at() const268 osmium::Timestamp created_at() const noexcept { 269 return m_created_at; 270 } 271 272 /** 273 * Get timestamp when this changeset was closed. 274 * 275 * @returns Timestamp. Will return the empty Timestamp when the 276 * changeset is not yet closed. 277 */ closed_at() const278 osmium::Timestamp closed_at() const noexcept { 279 return m_closed_at; 280 } 281 282 /// Is this changeset open? open() const283 bool open() const noexcept { 284 return m_closed_at == osmium::Timestamp(); 285 } 286 287 /// Is this changeset closed? closed() const288 bool closed() const noexcept { 289 return !open(); 290 } 291 292 /** 293 * Set the timestamp when this changeset was created. 294 * 295 * @param timestamp Timestamp 296 * @returns Reference to changeset to make calls chainable. 297 */ set_created_at(const osmium::Timestamp & timestamp)298 Changeset& set_created_at(const osmium::Timestamp& timestamp) { 299 m_created_at = timestamp; 300 return *this; 301 } 302 303 /** 304 * Set the timestamp when this changeset was closed. 305 * 306 * @param timestamp Timestamp 307 * @returns Reference to changeset to make calls chainable. 308 */ set_closed_at(const osmium::Timestamp & timestamp)309 Changeset& set_closed_at(const osmium::Timestamp& timestamp) { 310 m_closed_at = timestamp; 311 return *this; 312 } 313 314 /// Get the number of changes in this changeset num_changes() const315 num_changes_type num_changes() const noexcept { 316 return m_num_changes; 317 } 318 319 /// Set the number of changes in this changeset set_num_changes(num_changes_type num_changes)320 Changeset& set_num_changes(num_changes_type num_changes) noexcept { 321 m_num_changes = num_changes; 322 return *this; 323 } 324 325 /// Set the number of changes in this changeset set_num_changes(const char * num_changes)326 Changeset& set_num_changes(const char* num_changes) { 327 return set_num_changes(osmium::string_to_num_changes(num_changes)); 328 } 329 330 /// Get the number of comments in this changeset num_comments() const331 num_comments_type num_comments() const noexcept { 332 return m_num_comments; 333 } 334 335 /// Set the number of comments in this changeset set_num_comments(num_comments_type num_comments)336 Changeset& set_num_comments(num_comments_type num_comments) noexcept { 337 m_num_comments = num_comments; 338 return *this; 339 } 340 341 /// Set the number of comments in this changeset set_num_comments(const char * num_comments)342 Changeset& set_num_comments(const char* num_comments) { 343 return set_num_comments(osmium::string_to_num_comments(num_comments)); 344 } 345 346 /** 347 * Get the bounding box of this changeset. 348 * 349 * @returns Bounding box. Can be empty. 350 */ bounds()351 osmium::Box& bounds() noexcept { 352 return m_bounds; 353 } 354 355 /** 356 * Get the bounding box of this changeset. 357 * 358 * @returns Bounding box. Can be empty. 359 */ bounds() const360 const osmium::Box& bounds() const noexcept { 361 return m_bounds; 362 } 363 364 /// Get user name. user() const365 const char* user() const { 366 return reinterpret_cast<const char*>(data() + sizeof(Changeset)); 367 } 368 369 /// Clear user name. clear_user()370 void clear_user() noexcept { 371 std::memset(data() + sizeof(Changeset), 0, user_size()); 372 } 373 374 /// Get the list of tags. tags() const375 const TagList& tags() const { 376 return osmium::detail::subitem_of_type<const TagList>(cbegin(), cend()); 377 } 378 379 /** 380 * Set named attribute. 381 * 382 * @param attr Name of the attribute (must be one of "id", "version", 383 * "changeset", "timestamp", "uid", "visible") 384 * @param value Value of the attribute 385 */ set_attribute(const char * attr,const char * value)386 void set_attribute(const char* attr, const char* value) { 387 if (!std::strcmp(attr, "id")) { 388 set_id(value); 389 } else if (!std::strcmp(attr, "num_changes")) { 390 set_num_changes(value); 391 } else if (!std::strcmp(attr, "comments_count")) { 392 set_num_comments(value); 393 } else if (!std::strcmp(attr, "created_at")) { 394 set_created_at(osmium::Timestamp(value)); 395 } else if (!std::strcmp(attr, "closed_at")) { 396 set_closed_at(osmium::Timestamp(value)); 397 } else if (!std::strcmp(attr, "uid")) { 398 set_uid(value); 399 } 400 } 401 402 using iterator = osmium::memory::CollectionIterator<Item>; 403 using const_iterator = osmium::memory::CollectionIterator<const Item>; 404 begin()405 iterator begin() { 406 return iterator(subitems_position()); 407 } 408 end()409 iterator end() { 410 return iterator(data() + padded_size()); 411 } 412 cbegin() const413 const_iterator cbegin() const { 414 return const_iterator(subitems_position()); 415 } 416 cend() const417 const_iterator cend() const { 418 return const_iterator(data() + padded_size()); 419 } 420 begin() const421 const_iterator begin() const { 422 return cbegin(); 423 } 424 end() const425 const_iterator end() const { 426 return cend(); 427 } 428 discussion()429 ChangesetDiscussion& discussion() { 430 return osmium::detail::subitem_of_type<ChangesetDiscussion>(begin(), end()); 431 } 432 discussion() const433 const ChangesetDiscussion& discussion() const { 434 return osmium::detail::subitem_of_type<const ChangesetDiscussion>(cbegin(), cend()); 435 } 436 437 }; // class Changeset 438 439 static_assert(sizeof(Changeset) % osmium::memory::align_bytes == 0, "Class osmium::Changeset has wrong size to be aligned properly!"); 440 441 /** 442 * Changesets are equal if their IDs are equal. 443 */ operator ==(const Changeset & lhs,const Changeset & rhs)444 inline bool operator==(const Changeset& lhs, const Changeset& rhs) { 445 return lhs.id() == rhs.id(); 446 } 447 operator !=(const Changeset & lhs,const Changeset & rhs)448 inline bool operator!=(const Changeset& lhs, const Changeset& rhs) { 449 return !(lhs == rhs); 450 } 451 452 /** 453 * Changesets can be ordered by id. 454 */ operator <(const Changeset & lhs,const Changeset & rhs)455 inline bool operator<(const Changeset& lhs, const Changeset& rhs) { 456 return lhs.id() < rhs.id(); 457 } 458 operator >(const Changeset & lhs,const Changeset & rhs)459 inline bool operator>(const Changeset& lhs, const Changeset& rhs) { 460 return rhs < lhs; 461 } 462 operator <=(const Changeset & lhs,const Changeset & rhs)463 inline bool operator<=(const Changeset& lhs, const Changeset& rhs) { 464 return !(rhs < lhs); 465 } 466 operator >=(const Changeset & lhs,const Changeset & rhs)467 inline bool operator>=(const Changeset& lhs, const Changeset& rhs) { 468 return !(lhs < rhs); 469 } 470 471 } // namespace osmium 472 473 #endif // OSMIUM_OSM_CHANGESET_HPP 474