318
+ − 1 // Copyright Toru Niina 2019.
+ − 2 // Distributed under the MIT License.
+ − 3 #ifndef TOML11_COMMENTS_HPP
+ − 4 #define TOML11_COMMENTS_HPP
+ − 5 #include <initializer_list>
+ − 6 #include <iterator>
+ − 7 #include <stdexcept>
+ − 8 #include <string>
+ − 9 #include <type_traits>
+ − 10 #include <utility>
+ − 11 #include <vector>
+ − 12
+ − 13 #ifdef TOML11_PRESERVE_COMMENTS_BY_DEFAULT
+ − 14 # define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::preserve_comments
+ − 15 #else
+ − 16 # define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::discard_comments
+ − 17 #endif
+ − 18
+ − 19 // This file provides mainly two classes, `preserve_comments` and `discard_comments`.
+ − 20 // Those two are a container that have the same interface as `std::vector<std::string>`
+ − 21 // but bahaves in the opposite way. `preserve_comments` is just the same as
+ − 22 // `std::vector<std::string>` and each `std::string` corresponds to a comment line.
+ − 23 // Conversely, `discard_comments` discards all the strings and ignores everything
+ − 24 // assigned in it. `discard_comments` is always empty and you will encounter an
+ − 25 // error whenever you access to the element.
+ − 26 namespace toml
+ − 27 {
+ − 28 struct discard_comments; // forward decl
+ − 29
+ − 30 // use it in the following way
+ − 31 //
+ − 32 // const toml::basic_value<toml::preserve_comments> data =
+ − 33 // toml::parse<toml::preserve_comments>("example.toml");
+ − 34 //
+ − 35 // the interface is almost the same as std::vector<std::string>.
+ − 36 struct preserve_comments
+ − 37 {
+ − 38 // `container_type` is not provided in discard_comments.
+ − 39 // do not use this inner-type in a generic code.
+ − 40 using container_type = std::vector<std::string>;
+ − 41
+ − 42 using size_type = container_type::size_type;
+ − 43 using difference_type = container_type::difference_type;
+ − 44 using value_type = container_type::value_type;
+ − 45 using reference = container_type::reference;
+ − 46 using const_reference = container_type::const_reference;
+ − 47 using pointer = container_type::pointer;
+ − 48 using const_pointer = container_type::const_pointer;
+ − 49 using iterator = container_type::iterator;
+ − 50 using const_iterator = container_type::const_iterator;
+ − 51 using reverse_iterator = container_type::reverse_iterator;
+ − 52 using const_reverse_iterator = container_type::const_reverse_iterator;
+ − 53
+ − 54 preserve_comments() = default;
+ − 55 ~preserve_comments() = default;
+ − 56 preserve_comments(preserve_comments const&) = default;
+ − 57 preserve_comments(preserve_comments &&) = default;
+ − 58 preserve_comments& operator=(preserve_comments const&) = default;
+ − 59 preserve_comments& operator=(preserve_comments &&) = default;
+ − 60
+ − 61 explicit preserve_comments(const std::vector<std::string>& c): comments(c){}
+ − 62 explicit preserve_comments(std::vector<std::string>&& c)
+ − 63 : comments(std::move(c))
+ − 64 {}
+ − 65 preserve_comments& operator=(const std::vector<std::string>& c)
+ − 66 {
+ − 67 comments = c;
+ − 68 return *this;
+ − 69 }
+ − 70 preserve_comments& operator=(std::vector<std::string>&& c)
+ − 71 {
+ − 72 comments = std::move(c);
+ − 73 return *this;
+ − 74 }
+ − 75
+ − 76 explicit preserve_comments(const discard_comments&) {}
+ − 77
+ − 78 explicit preserve_comments(size_type n): comments(n) {}
+ − 79 preserve_comments(size_type n, const std::string& x): comments(n, x) {}
+ − 80 preserve_comments(std::initializer_list<std::string> x): comments(x) {}
+ − 81 template<typename InputIterator>
+ − 82 preserve_comments(InputIterator first, InputIterator last)
+ − 83 : comments(first, last)
+ − 84 {}
+ − 85
+ − 86 template<typename InputIterator>
+ − 87 void assign(InputIterator first, InputIterator last) {comments.assign(first, last);}
+ − 88 void assign(std::initializer_list<std::string> ini) {comments.assign(ini);}
+ − 89 void assign(size_type n, const std::string& val) {comments.assign(n, val);}
+ − 90
+ − 91 // Related to the issue #97.
+ − 92 //
+ − 93 // It is known that `std::vector::insert` and `std::vector::erase` in
+ − 94 // the standard library implementation included in GCC 4.8.5 takes
+ − 95 // `std::vector::iterator` instead of `std::vector::const_iterator`.
+ − 96 // Because of the const-correctness, we cannot convert a `const_iterator` to
+ − 97 // an `iterator`. It causes compilation error in GCC 4.8.5.
+ − 98 #if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && !defined(__clang__)
+ − 99 # if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= 40805
+ − 100 # define TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION
+ − 101 # endif
+ − 102 #endif
+ − 103
+ − 104 #ifdef TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION
+ − 105 iterator insert(iterator p, const std::string& x)
+ − 106 {
+ − 107 return comments.insert(p, x);
+ − 108 }
+ − 109 iterator insert(iterator p, std::string&& x)
+ − 110 {
+ − 111 return comments.insert(p, std::move(x));
+ − 112 }
+ − 113 void insert(iterator p, size_type n, const std::string& x)
+ − 114 {
+ − 115 return comments.insert(p, n, x);
+ − 116 }
+ − 117 template<typename InputIterator>
+ − 118 void insert(iterator p, InputIterator first, InputIterator last)
+ − 119 {
+ − 120 return comments.insert(p, first, last);
+ − 121 }
+ − 122 void insert(iterator p, std::initializer_list<std::string> ini)
+ − 123 {
+ − 124 return comments.insert(p, ini);
+ − 125 }
+ − 126
+ − 127 template<typename ... Ts>
+ − 128 iterator emplace(iterator p, Ts&& ... args)
+ − 129 {
+ − 130 return comments.emplace(p, std::forward<Ts>(args)...);
+ − 131 }
+ − 132
+ − 133 iterator erase(iterator pos) {return comments.erase(pos);}
+ − 134 iterator erase(iterator first, iterator last)
+ − 135 {
+ − 136 return comments.erase(first, last);
+ − 137 }
+ − 138 #else
+ − 139 iterator insert(const_iterator p, const std::string& x)
+ − 140 {
+ − 141 return comments.insert(p, x);
+ − 142 }
+ − 143 iterator insert(const_iterator p, std::string&& x)
+ − 144 {
+ − 145 return comments.insert(p, std::move(x));
+ − 146 }
+ − 147 iterator insert(const_iterator p, size_type n, const std::string& x)
+ − 148 {
+ − 149 return comments.insert(p, n, x);
+ − 150 }
+ − 151 template<typename InputIterator>
+ − 152 iterator insert(const_iterator p, InputIterator first, InputIterator last)
+ − 153 {
+ − 154 return comments.insert(p, first, last);
+ − 155 }
+ − 156 iterator insert(const_iterator p, std::initializer_list<std::string> ini)
+ − 157 {
+ − 158 return comments.insert(p, ini);
+ − 159 }
+ − 160
+ − 161 template<typename ... Ts>
+ − 162 iterator emplace(const_iterator p, Ts&& ... args)
+ − 163 {
+ − 164 return comments.emplace(p, std::forward<Ts>(args)...);
+ − 165 }
+ − 166
+ − 167 iterator erase(const_iterator pos) {return comments.erase(pos);}
+ − 168 iterator erase(const_iterator first, const_iterator last)
+ − 169 {
+ − 170 return comments.erase(first, last);
+ − 171 }
+ − 172 #endif
+ − 173
+ − 174 void swap(preserve_comments& other) {comments.swap(other.comments);}
+ − 175
+ − 176 void push_back(const std::string& v) {comments.push_back(v);}
+ − 177 void push_back(std::string&& v) {comments.push_back(std::move(v));}
+ − 178 void pop_back() {comments.pop_back();}
+ − 179
+ − 180 template<typename ... Ts>
+ − 181 void emplace_back(Ts&& ... args) {comments.emplace_back(std::forward<Ts>(args)...);}
+ − 182
+ − 183 void clear() {comments.clear();}
+ − 184
+ − 185 size_type size() const noexcept {return comments.size();}
+ − 186 size_type max_size() const noexcept {return comments.max_size();}
+ − 187 size_type capacity() const noexcept {return comments.capacity();}
+ − 188 bool empty() const noexcept {return comments.empty();}
+ − 189
+ − 190 void reserve(size_type n) {comments.reserve(n);}
+ − 191 void resize(size_type n) {comments.resize(n);}
+ − 192 void resize(size_type n, const std::string& c) {comments.resize(n, c);}
+ − 193 void shrink_to_fit() {comments.shrink_to_fit();}
+ − 194
+ − 195 reference operator[](const size_type n) noexcept {return comments[n];}
+ − 196 const_reference operator[](const size_type n) const noexcept {return comments[n];}
+ − 197 reference at(const size_type n) {return comments.at(n);}
+ − 198 const_reference at(const size_type n) const {return comments.at(n);}
+ − 199 reference front() noexcept {return comments.front();}
+ − 200 const_reference front() const noexcept {return comments.front();}
+ − 201 reference back() noexcept {return comments.back();}
+ − 202 const_reference back() const noexcept {return comments.back();}
+ − 203
+ − 204 pointer data() noexcept {return comments.data();}
+ − 205 const_pointer data() const noexcept {return comments.data();}
+ − 206
+ − 207 iterator begin() noexcept {return comments.begin();}
+ − 208 iterator end() noexcept {return comments.end();}
+ − 209 const_iterator begin() const noexcept {return comments.begin();}
+ − 210 const_iterator end() const noexcept {return comments.end();}
+ − 211 const_iterator cbegin() const noexcept {return comments.cbegin();}
+ − 212 const_iterator cend() const noexcept {return comments.cend();}
+ − 213
+ − 214 reverse_iterator rbegin() noexcept {return comments.rbegin();}
+ − 215 reverse_iterator rend() noexcept {return comments.rend();}
+ − 216 const_reverse_iterator rbegin() const noexcept {return comments.rbegin();}
+ − 217 const_reverse_iterator rend() const noexcept {return comments.rend();}
+ − 218 const_reverse_iterator crbegin() const noexcept {return comments.crbegin();}
+ − 219 const_reverse_iterator crend() const noexcept {return comments.crend();}
+ − 220
+ − 221 friend bool operator==(const preserve_comments&, const preserve_comments&);
+ − 222 friend bool operator!=(const preserve_comments&, const preserve_comments&);
+ − 223 friend bool operator< (const preserve_comments&, const preserve_comments&);
+ − 224 friend bool operator<=(const preserve_comments&, const preserve_comments&);
+ − 225 friend bool operator> (const preserve_comments&, const preserve_comments&);
+ − 226 friend bool operator>=(const preserve_comments&, const preserve_comments&);
+ − 227
+ − 228 friend void swap(preserve_comments&, std::vector<std::string>&);
+ − 229 friend void swap(std::vector<std::string>&, preserve_comments&);
+ − 230
+ − 231 private:
+ − 232
+ − 233 container_type comments;
+ − 234 };
+ − 235
+ − 236 inline bool operator==(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments == rhs.comments;}
+ − 237 inline bool operator!=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments != rhs.comments;}
+ − 238 inline bool operator< (const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments < rhs.comments;}
+ − 239 inline bool operator<=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments <= rhs.comments;}
+ − 240 inline bool operator> (const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments > rhs.comments;}
+ − 241 inline bool operator>=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments >= rhs.comments;}
+ − 242
+ − 243 inline void swap(preserve_comments& lhs, preserve_comments& rhs)
+ − 244 {
+ − 245 lhs.swap(rhs);
+ − 246 return;
+ − 247 }
+ − 248 inline void swap(preserve_comments& lhs, std::vector<std::string>& rhs)
+ − 249 {
+ − 250 lhs.comments.swap(rhs);
+ − 251 return;
+ − 252 }
+ − 253 inline void swap(std::vector<std::string>& lhs, preserve_comments& rhs)
+ − 254 {
+ − 255 lhs.swap(rhs.comments);
+ − 256 return;
+ − 257 }
+ − 258
+ − 259 template<typename charT, typename traits>
+ − 260 std::basic_ostream<charT, traits>&
+ − 261 operator<<(std::basic_ostream<charT, traits>& os, const preserve_comments& com)
+ − 262 {
+ − 263 for(const auto& c : com)
+ − 264 {
+ − 265 os << '#' << c << '\n';
+ − 266 }
+ − 267 return os;
+ − 268 }
+ − 269
+ − 270 namespace detail
+ − 271 {
+ − 272
+ − 273 // To provide the same interface with `preserve_comments`, `discard_comments`
+ − 274 // should have an iterator. But it does not contain anything, so we need to
+ − 275 // add an iterator that points nothing.
+ − 276 //
+ − 277 // It always points null, so DO NOT unwrap this iterator. It always crashes
+ − 278 // your program.
+ − 279 template<typename T, bool is_const>
+ − 280 struct empty_iterator
+ − 281 {
+ − 282 using value_type = T;
+ − 283 using reference_type = typename std::conditional<is_const, T const&, T&>::type;
+ − 284 using pointer_type = typename std::conditional<is_const, T const*, T*>::type;
+ − 285 using difference_type = std::ptrdiff_t;
+ − 286 using iterator_category = std::random_access_iterator_tag;
+ − 287
+ − 288 empty_iterator() = default;
+ − 289 ~empty_iterator() = default;
+ − 290 empty_iterator(empty_iterator const&) = default;
+ − 291 empty_iterator(empty_iterator &&) = default;
+ − 292 empty_iterator& operator=(empty_iterator const&) = default;
+ − 293 empty_iterator& operator=(empty_iterator &&) = default;
+ − 294
+ − 295 // DO NOT call these operators.
+ − 296 reference_type operator*() const noexcept {std::terminate();}
+ − 297 pointer_type operator->() const noexcept {return nullptr;}
+ − 298 reference_type operator[](difference_type) const noexcept {return this->operator*();}
+ − 299
+ − 300 // These operators do nothing.
+ − 301 empty_iterator& operator++() noexcept {return *this;}
+ − 302 empty_iterator operator++(int) noexcept {return *this;}
+ − 303 empty_iterator& operator--() noexcept {return *this;}
+ − 304 empty_iterator operator--(int) noexcept {return *this;}
+ − 305
+ − 306 empty_iterator& operator+=(difference_type) noexcept {return *this;}
+ − 307 empty_iterator& operator-=(difference_type) noexcept {return *this;}
+ − 308
+ − 309 empty_iterator operator+(difference_type) const noexcept {return *this;}
+ − 310 empty_iterator operator-(difference_type) const noexcept {return *this;}
+ − 311 };
+ − 312
+ − 313 template<typename T, bool C>
+ − 314 bool operator==(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return true;}
+ − 315 template<typename T, bool C>
+ − 316 bool operator!=(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return false;}
+ − 317 template<typename T, bool C>
+ − 318 bool operator< (const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return false;}
+ − 319 template<typename T, bool C>
+ − 320 bool operator<=(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return true;}
+ − 321 template<typename T, bool C>
+ − 322 bool operator> (const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return false;}
+ − 323 template<typename T, bool C>
+ − 324 bool operator>=(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return true;}
+ − 325
+ − 326 template<typename T, bool C>
+ − 327 typename empty_iterator<T, C>::difference_type
+ − 328 operator-(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return 0;}
+ − 329
+ − 330 template<typename T, bool C>
+ − 331 empty_iterator<T, C>
+ − 332 operator+(typename empty_iterator<T, C>::difference_type, const empty_iterator<T, C>& rhs) noexcept {return rhs;}
+ − 333 template<typename T, bool C>
+ − 334 empty_iterator<T, C>
+ − 335 operator+(const empty_iterator<T, C>& lhs, typename empty_iterator<T, C>::difference_type) noexcept {return lhs;}
+ − 336
+ − 337 } // detail
+ − 338
+ − 339 // The default comment type. It discards all the comments. It requires only one
+ − 340 // byte to contain, so the memory footprint is smaller than preserve_comments.
+ − 341 //
+ − 342 // It just ignores `push_back`, `insert`, `erase`, and any other modifications.
+ − 343 // IT always returns size() == 0, the iterator taken by `begin()` is always the
+ − 344 // same as that of `end()`, and accessing through `operator[]` or iterators
+ − 345 // always causes a segmentation fault. DO NOT access to the element of this.
+ − 346 //
+ − 347 // Why this is chose as the default type is because the last version (2.x.y)
+ − 348 // does not contain any comments in a value. To minimize the impact on the
+ − 349 // efficiency, this is chosen as a default.
+ − 350 //
+ − 351 // To reduce the memory footprint, later we can try empty base optimization (EBO).
+ − 352 struct discard_comments
+ − 353 {
+ − 354 using size_type = std::size_t;
+ − 355 using difference_type = std::ptrdiff_t;
+ − 356 using value_type = std::string;
+ − 357 using reference = std::string&;
+ − 358 using const_reference = std::string const&;
+ − 359 using pointer = std::string*;
+ − 360 using const_pointer = std::string const*;
+ − 361 using iterator = detail::empty_iterator<std::string, false>;
+ − 362 using const_iterator = detail::empty_iterator<std::string, true>;
+ − 363 using reverse_iterator = detail::empty_iterator<std::string, false>;
+ − 364 using const_reverse_iterator = detail::empty_iterator<std::string, true>;
+ − 365
+ − 366 discard_comments() = default;
+ − 367 ~discard_comments() = default;
+ − 368 discard_comments(discard_comments const&) = default;
+ − 369 discard_comments(discard_comments &&) = default;
+ − 370 discard_comments& operator=(discard_comments const&) = default;
+ − 371 discard_comments& operator=(discard_comments &&) = default;
+ − 372
+ − 373 explicit discard_comments(const std::vector<std::string>&) noexcept {}
+ − 374 explicit discard_comments(std::vector<std::string>&&) noexcept {}
+ − 375 discard_comments& operator=(const std::vector<std::string>&) noexcept {return *this;}
+ − 376 discard_comments& operator=(std::vector<std::string>&&) noexcept {return *this;}
+ − 377
+ − 378 explicit discard_comments(const preserve_comments&) noexcept {}
+ − 379
+ − 380 explicit discard_comments(size_type) noexcept {}
+ − 381 discard_comments(size_type, const std::string&) noexcept {}
+ − 382 discard_comments(std::initializer_list<std::string>) noexcept {}
+ − 383 template<typename InputIterator>
+ − 384 discard_comments(InputIterator, InputIterator) noexcept {}
+ − 385
+ − 386 template<typename InputIterator>
+ − 387 void assign(InputIterator, InputIterator) noexcept {}
+ − 388 void assign(std::initializer_list<std::string>) noexcept {}
+ − 389 void assign(size_type, const std::string&) noexcept {}
+ − 390
+ − 391 iterator insert(const_iterator, const std::string&) {return iterator{};}
+ − 392 iterator insert(const_iterator, std::string&&) {return iterator{};}
+ − 393 iterator insert(const_iterator, size_type, const std::string&) {return iterator{};}
+ − 394 template<typename InputIterator>
+ − 395 iterator insert(const_iterator, InputIterator, InputIterator) {return iterator{};}
+ − 396 iterator insert(const_iterator, std::initializer_list<std::string>) {return iterator{};}
+ − 397
+ − 398 template<typename ... Ts>
+ − 399 iterator emplace(const_iterator, Ts&& ...) {return iterator{};}
+ − 400 iterator erase(const_iterator) {return iterator{};}
+ − 401 iterator erase(const_iterator, const_iterator) {return iterator{};}
+ − 402
+ − 403 void swap(discard_comments&) {return;}
+ − 404
+ − 405 void push_back(const std::string&) {return;}
+ − 406 void push_back(std::string&& ) {return;}
+ − 407 void pop_back() {return;}
+ − 408
+ − 409 template<typename ... Ts>
+ − 410 void emplace_back(Ts&& ...) {return;}
+ − 411
+ − 412 void clear() {return;}
+ − 413
+ − 414 size_type size() const noexcept {return 0;}
+ − 415 size_type max_size() const noexcept {return 0;}
+ − 416 size_type capacity() const noexcept {return 0;}
+ − 417 bool empty() const noexcept {return true;}
+ − 418
+ − 419 void reserve(size_type) {return;}
+ − 420 void resize(size_type) {return;}
+ − 421 void resize(size_type, const std::string&) {return;}
+ − 422 void shrink_to_fit() {return;}
+ − 423
+ − 424 // DO NOT access to the element of this container. This container is always
+ − 425 // empty, so accessing through operator[], front/back, data causes address
+ − 426 // error.
+ − 427
+ − 428 reference operator[](const size_type) noexcept {never_call("toml::discard_comment::operator[]");}
+ − 429 const_reference operator[](const size_type) const noexcept {never_call("toml::discard_comment::operator[]");}
+ − 430 reference at(const size_type) {throw std::out_of_range("toml::discard_comment is always empty.");}
+ − 431 const_reference at(const size_type) const {throw std::out_of_range("toml::discard_comment is always empty.");}
+ − 432 reference front() noexcept {never_call("toml::discard_comment::front");}
+ − 433 const_reference front() const noexcept {never_call("toml::discard_comment::front");}
+ − 434 reference back() noexcept {never_call("toml::discard_comment::back");}
+ − 435 const_reference back() const noexcept {never_call("toml::discard_comment::back");}
+ − 436
+ − 437 pointer data() noexcept {return nullptr;}
+ − 438 const_pointer data() const noexcept {return nullptr;}
+ − 439
+ − 440 iterator begin() noexcept {return iterator{};}
+ − 441 iterator end() noexcept {return iterator{};}
+ − 442 const_iterator begin() const noexcept {return const_iterator{};}
+ − 443 const_iterator end() const noexcept {return const_iterator{};}
+ − 444 const_iterator cbegin() const noexcept {return const_iterator{};}
+ − 445 const_iterator cend() const noexcept {return const_iterator{};}
+ − 446
+ − 447 reverse_iterator rbegin() noexcept {return iterator{};}
+ − 448 reverse_iterator rend() noexcept {return iterator{};}
+ − 449 const_reverse_iterator rbegin() const noexcept {return const_iterator{};}
+ − 450 const_reverse_iterator rend() const noexcept {return const_iterator{};}
+ − 451 const_reverse_iterator crbegin() const noexcept {return const_iterator{};}
+ − 452 const_reverse_iterator crend() const noexcept {return const_iterator{};}
+ − 453
+ − 454 private:
+ − 455
+ − 456 [[noreturn]] static void never_call(const char *const this_function)
+ − 457 {
+ − 458 #ifdef __has_builtin
+ − 459 # if __has_builtin(__builtin_unreachable)
+ − 460 __builtin_unreachable();
+ − 461 # endif
+ − 462 #endif
+ − 463 throw std::logic_error{this_function};
+ − 464 }
+ − 465 };
+ − 466
+ − 467 inline bool operator==(const discard_comments&, const discard_comments&) noexcept {return true;}
+ − 468 inline bool operator!=(const discard_comments&, const discard_comments&) noexcept {return false;}
+ − 469 inline bool operator< (const discard_comments&, const discard_comments&) noexcept {return false;}
+ − 470 inline bool operator<=(const discard_comments&, const discard_comments&) noexcept {return true;}
+ − 471 inline bool operator> (const discard_comments&, const discard_comments&) noexcept {return false;}
+ − 472 inline bool operator>=(const discard_comments&, const discard_comments&) noexcept {return true;}
+ − 473
+ − 474 inline void swap(const discard_comments&, const discard_comments&) noexcept {return;}
+ − 475
+ − 476 template<typename charT, typename traits>
+ − 477 std::basic_ostream<charT, traits>&
+ − 478 operator<<(std::basic_ostream<charT, traits>& os, const discard_comments&)
+ − 479 {
+ − 480 return os;
+ − 481 }
+ − 482
+ − 483 } // toml11
+ − 484 #endif// TOML11_COMMENTS_HPP