jaulib v1.3.0
Jau Support Library (C++, Java, ..)
cow_iterator.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#ifndef JAU_COW_ITERATOR_HPP_
26#define JAU_COW_ITERATOR_HPP_
27
28#include <cstddef>
29#include <limits>
30#include <mutex>
31
32#include <type_traits>
33
34#include <jau/cpp_lang_util.hpp>
35#include <jau/debug.hpp>
36#include <jau/basic_types.hpp>
37
38namespace jau {
39
40 /** \addtogroup DataStructs
41 *
42 * @{
43 */
44
45 // forward declaration for friendship with cow_rw_iterator
46 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
47 class cow_ro_iterator;
48
49 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
50 class cow_rw_iterator;
51
52 /****************************************************************************************
53 ****************************************************************************************/
54
55 /**
56 * Implementation of a Copy-On-Write (CoW) read-write iterator over mutable value_type storage.<br>
57 * Instance holds a copy of the parents' CoW storage and locks its write mutex until
58 * write_back() or destruction.
59 * <p>
60 * Implementation complies with Type Traits iterator_category 'random_access_iterator_tag'
61 * </p>
62 * <p>
63 * This iterator wraps the native iterator of type 'iterator_type'
64 * and manages the CoW related resource lifecycle.
65 * </p>
66 * <p>
67 * After completing all mutable operations but before this iterator's destruction,
68 * the user might want to write back this iterators' storage to its parents' CoW
69 * using write_back()
70 * </p>
71 * <p>
72 * Due to the costly nature of mutable CoW resource management,
73 * consider using jau::cow_ro_iterator if elements won't get mutated
74 * or any changes can be discarded.
75 * </p>
76 * <p>
77 * To allow data-race free operations on this iterator's data copy from a potentially mutated CoW,
78 * only one begin iterator should be retrieved from CoW and all further operations shall use
79 * jau::cow_rw_iterator::size(), jau::cow_rw_iterator::begin() and jau::cow_rw_iterator::end().
80 * </p>
81 * @see jau::cow_rw_iterator::write_back()
82 * @see jau::for_each_fidelity
83 * @see jau::cow_darray
84 */
85 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
88 template<typename, typename, typename, bool, bool> friend class cow_darray;
89 template<typename, typename> friend class cow_vector;
90
91 public:
92 typedef Storage_type storage_t;
93 typedef Storage_ref_type storage_ref_t;
94 typedef CoW_container cow_container_t;
95
96 /** Actual iterator type of the contained native iterator, probably a simple pointer. */
97 typedef typename storage_t::iterator iterator_type;
98
99 private:
100 typedef std::iterator_traits<iterator_type> sub_traits_t;
101
102 cow_container_t& cow_parent_;
103 std::unique_lock<std::recursive_mutex> lock_; // can move and swap
104 storage_ref_t store_ref_;
105 iterator_type iterator_;
106
107 constexpr explicit cow_rw_iterator(cow_container_t& cow_parent, storage_ref_t store, iterator_type iter) noexcept
108 : cow_parent_(cow_parent), lock_(cow_parent_.get_write_mutex()), store_ref_(std::move(store)),
109 iterator_(iter) { }
110
111 constexpr explicit cow_rw_iterator(cow_container_t& cow_parent)
112 : cow_parent_(cow_parent), lock_(cow_parent_.get_write_mutex()),
113 store_ref_(cow_parent.copy_store()), iterator_(store_ref_->begin()) { }
114
115 public:
116 typedef typename sub_traits_t::iterator_category iterator_category; // random_access_iterator_tag
117
118 typedef typename storage_t::size_type size_type; // using our template overload Size_type
119 typedef typename storage_t::difference_type difference_type; // derived from our Size_type
120 // typedef typename storage_t::value_type value_type; // OK
121 // typedef typename storage_t::reference reference; //
122 // typedef typename storage_t::pointer pointer; //
123 typedef typename sub_traits_t::value_type value_type; // OK
124 typedef typename sub_traits_t::reference reference; // 'value_type &'
125 typedef typename sub_traits_t::pointer pointer; // 'value_type *'
126
127// FIXME
128#if __cplusplus > 201703L && __cpp_lib_concepts && 0
129 using iterator_concept = std::__detail::__iter_concept<iterator_type>;
130 #endif
131
132 public:
133
134 /**
135 * Replace the parent's current store with this iterators' instance,
136 * unlock the CoW parents' write lock and discard all storage references.
137 * <p>
138 * After calling write_back(), this iterator is invalidated and no more operational.
139 * </p>
140 * <p>
141 * It is the user's responsibility to issue call this method
142 * to update the CoW parents' storage.
143 * </p>
144 * <p>
145 * It is not feasible nor effective to automatically earmark a dirty state
146 * on mutable operations.<br>
147 * This is due to the ambiguous semantics of like <code>operator*()</code>.<br>
148 * Also usage of multiple iterators to one CoW instance during a mutable operation
149 * complicates such an automated task, especially as we wish to only realize one
150 * storage replacement at the end.<br>
151 * Lastly, the user probably wants to issue the CoW storage sync
152 * in a programmatic deterministic fashion at the end.
153 * </p>
154 * @see jau::cow_darray::set_store()
155 */
156 void write_back() noexcept {
157 if( nullptr != store_ref_ ) {
158 cow_parent_.set_store(std::move(store_ref_));
159
160 lock_ = std::unique_lock<std::recursive_mutex>(); // force-dtor-unlock-null
161 store_ref_ = nullptr;
162 iterator_ = iterator_type();
163 }
164 }
165
166 /**
167 * C++ named requirements: LegacyIterator: CopyConstructible
168 */
169 constexpr cow_rw_iterator(const cow_rw_iterator& o) noexcept
170 : cow_parent_(o.cow_parent_), lock_(cow_parent_.get_write_mutex()),
171 store_ref_(o.store_ref_), iterator_(o.iterator_) { }
172
173 /**
174 * Assigns content of other mutable iterator to this one,
175 * if they are not identical.
176 * <p>
177 * C++ named requirements: LegacyIterator: CopyAssignable
178 * </p>
179 * @param o the new identity value to be copied into this iterator
180 * @return reference to this
181 */
182 constexpr cow_rw_iterator& operator=(const cow_rw_iterator& o) noexcept {
183 if( this != &o ) {
184 cow_parent_ = o.cow_parent_;
185 lock_ = std::unique_lock<std::recursive_mutex>( cow_parent_.get_write_mutex() );
186 store_ref_ = o.store_ref_;
187 iterator_ = o.iterator_;
188 }
189 return *this;
190 }
191
192
193 /**
194 * C++ named requirements: LegacyIterator: MoveConstructable
195 */
196 constexpr cow_rw_iterator(cow_rw_iterator && o) noexcept
197 : cow_parent_( o.cow_parent_ ), lock_( std::move( o.lock_ ) ),
198 store_ref_( std::move( o.store_ref_ ) ),
199 iterator_( std::move(o.iterator_ ) ) {
200 // Moved source has been disowned semantically and source's dtor will release resources!
201 }
202
203 /**
204 * Assigns identity of given mutable iterator,
205 * if they are not identical.
206 * <p>
207 * C++ named requirements: LegacyIterator: MoveAssignable
208 * </p>
209 * @param o the new identity to be taken
210 * @return reference to this
211 */
212 constexpr cow_rw_iterator& operator=(cow_rw_iterator&& o) noexcept {
213 if( this != &o ) {
214 cow_parent_ = o.cow_parent_;
215 lock_ = std::move(o.lock_);
216 store_ref_ = std::move(o.store_ref_);
217 iterator_ = std::move(o.iterator_);
218 // Moved source has been disowned semantically and source's dtor will release resources!
219 }
220 return *this;
221 }
222
223 /**
224 * C++ named requirements: LegacyIterator: Swappable
225 */
226 void swap(cow_rw_iterator& o) noexcept {
227 std::swap( cow_parent_, o.cow_parent_);
228 std::swap( lock_, o.lock_);
229 std::swap( store_ref_, o.store_ref_);
230 std::swap( iterator_, o.iterator_);
231 }
232
233 /**
234 * Returns a new const_iterator pointing to the current position.<br>
235 * This is the only explicit conversion operation of mutable -> immutable iterator, see below.
236 * <p>
237 * Be aware that the resulting cow_ro_iterator points to transient storage
238 * of this immutable iterator. In case write_back() won't be called
239 * and this iterator destructs, the returned immutable iterator is invalidated.
240 * </p>
241 * @see size()
242 * @see end()
243 */
245 { return cow_ro_iterator<Storage_type, Storage_ref_type, CoW_container>( store_ref_, iterator_ ); }
246
247 /**
248 * Returns a new iterator pointing to the first element, aka begin.
249 * <p>
250 * This is an addition API entry, allowing data-race free operations on
251 * this iterator's data snapshot from a potentially mutated CoW.
252 * </p>
253 * @see size()
254 * @see end()
255 */
256 constexpr cow_rw_iterator begin() const noexcept
257 { return cow_rw_iterator( cow_parent_, store_ref_, store_ref_->begin()); }
258
259 /**
260 * Returns a new iterator pointing to the <i>element following the last element</i>, aka end.<br>
261 * <p>
262 * This is an addition API entry, allowing data-race free operations on
263 * this iterator's data snapshot from a potentially mutated CoW.
264 * </p>
265 * @see size()
266 * @see begin()
267 */
268 constexpr cow_rw_iterator end() const noexcept
269 { return cow_rw_iterator( cow_parent_, store_ref_, store_ref_->end() ); }
270
271 /**
272 * Returns true if storage is empty().
273 */
274 constexpr bool empty() const noexcept { return store_ref_->empty(); }
275
276 /**
277 * Returns true if storage capacity has been reached and the next push_back()
278 * will grow the storage and invalidates all iterators and references.
279 */
280 constexpr bool capacity_reached() const noexcept { return store_ref_->capacity_reached(); }
281
282 /**
283 * Return the size of the underlying value_type store.
284 * <p>
285 * This is an addition API entry, allowing data-race free arithmetic on
286 * this iterator's data snapshot from a potentially mutated CoW.
287 * </p>
288 * @see begin()
289 * @see end()
290 */
291 constexpr size_type size() const noexcept { return store_ref_->size(); }
292
293 /**
294 * Returns this instances' underlying shared storage by reference.
295 */
296 constexpr storage_t& storage() const noexcept {
297 return *store_ref_;
298 }
299
300 /**
301 * Returns the distance to_end() using zero as first index. A.k.a the remaining elements iterable.
302 */
303 constexpr difference_type dist_end() const noexcept { return store_ref_->end() - iterator_; }
304
305 /**
306 * Returns true, if this iterator points to end().
307 */
308 constexpr bool is_end() const noexcept { return iterator_ == store_ref_->end(); }
309
310 /**
311 * This iterator is set to the last element, end(). Returns *this;
312 */
313 constexpr cow_rw_iterator& to_end() noexcept
314 { iterator_ = store_ref_->end(); return *this; }
315
316 /**
317 * Returns the distance to_begin() using zero as first index. A.k.a the index from start.
318 */
319 constexpr difference_type dist_begin() const noexcept { return iterator_ - store_ref_->begin(); }
320
321 /**
322 * Returns true, if this iterator points to begin().
323 */
324 constexpr bool is_begin() const noexcept { return iterator_ == store_ref_->begin(); }
325
326 /**
327 * This iterator is set to the first element, begin(). Returns *this;
328 */
329 constexpr cow_rw_iterator& to_begin() noexcept
330 { iterator_ = store_ref_->begin(); return *this; }
331
332 /**
333 * Returns a copy of the underlying storage iterator.
334 */
335 constexpr iterator_type base() const noexcept { return iterator_; }
336
337 // Multipass guarantee equality
338
339 /**
340 * Returns signum or three-way comparison value
341 * <pre>
342 * 0 if equal (both, store and iteratore),
343 * -1 if this->iterator_ < rhs_iter and
344 * 1 if this->iterator_ > rhs_iter (otherwise)
345 * </pre>
346 * @param rhs_store right-hand side store
347 * @param rhs_iter right-hand side iterator
348 */
349 constexpr int compare(const cow_rw_iterator& rhs) const noexcept {
350 return store_ref_ == rhs.store_ref_ && iterator_ == rhs.iterator_ ? 0
351 : ( iterator_ < rhs.iterator_ ? -1 : 1);
352 }
353
354 constexpr bool operator==(const cow_rw_iterator& rhs) const noexcept
355 { return compare(rhs) == 0; }
356
357 constexpr bool operator!=(const cow_rw_iterator& rhs) const noexcept
358 { return compare(rhs) != 0; }
359
360 // Relation
361
362 constexpr bool operator<=(const cow_rw_iterator& rhs) const noexcept
363 { return compare(rhs) <= 0; }
364
365 constexpr bool operator<(const cow_rw_iterator& rhs) const noexcept
366 { return compare(rhs) < 0; }
367
368 constexpr bool operator>=(const cow_rw_iterator& rhs) const noexcept
369 { return compare(rhs) >= 0; }
370
371 constexpr bool operator>(const cow_rw_iterator& rhs) const noexcept
372 { return compare(rhs) > 0; }
373
374 // Forward iterator requirements
375
376 /**
377 * Dereferencing iterator to value_type reference
378 * @return immutable reference to value_type
379 */
380 constexpr const reference operator*() const noexcept {
381 return *iterator_;
382 }
383
384 /**
385 * Pointer to member access.
386 * @return immutable pointer to value_type
387 */
388 constexpr const pointer operator->() const noexcept {
389 return &(*iterator_); // just in case iterator_type is a class, trick via dereference
390 }
391
392 /**
393 * Dereferencing iterator to value_type reference.
394 * @return mutable reference to value_type
395 */
396 constexpr reference operator*() noexcept { return *iterator_; }
397
398 /**
399 * Pointer to member access.
400 * @return mutable pointer to value_type
401 */
402 constexpr pointer operator->() noexcept {
403 return &(*iterator_); // just in case iterator_type is a class, trick via dereference
404 }
405
406 /** Pre-increment; Well performing, return *this. */
407 constexpr cow_rw_iterator& operator++() noexcept {
408 ++iterator_;
409 return *this;
410 }
411
412 /** Post-increment; Try to avoid: Low performance due to returning copy-ctor. */
413 constexpr cow_rw_iterator operator++(int) noexcept
414 { return cow_rw_iterator(cow_parent_, store_ref_, iterator_++); }
415
416 // Bidirectional iterator requirements
417
418 /** Pre-decrement; Well performing, return *this. */
419 constexpr cow_rw_iterator& operator--() noexcept {
420 --iterator_;
421 return *this;
422 }
423
424 /** Post-decrement; Try to avoid: Low performance due to returning copy-ctor. */
425 constexpr cow_rw_iterator operator--(int) noexcept
426 { return cow_rw_iterator(cow_parent_, store_ref_, iterator_--); }
427
428 // Random access iterator requirements
429
430 /** Subscript of 'element_index', returning immutable Value_type reference. */
431 constexpr const reference operator[](difference_type i) const noexcept
432 { return iterator_[i]; }
433
434 /**
435 * Subscript of 'element_index', returning mutable Value_type reference.
436 */
437 constexpr reference operator[](difference_type i) noexcept {
438 return iterator_[i];
439 }
440
441 /** Addition-assignment of 'element_count'; Well performing, return *this. */
443 { iterator_ += i; return *this; }
444
445 /** Binary 'iterator + element_count'; Try to avoid: Low performance due to returning copy-ctor. */
446 constexpr cow_rw_iterator operator+(difference_type rhs) const noexcept
447 { return cow_rw_iterator(cow_parent_, store_ref_, iterator_ + rhs); }
448
449 /** Subtraction-assignment of 'element_count'; Well performing, return *this. */
451 { iterator_ -= i; return *this; }
452
453 /** Binary 'iterator - element_count'; Try to avoid: Low performance due to returning copy-ctor. */
454 constexpr cow_rw_iterator operator-(difference_type rhs) const noexcept
455 { return cow_rw_iterator(cow_parent_, store_ref_, iterator_ - rhs); }
456
457 // Distance or element count, binary subtraction of two iterator.
458
459 /** Binary 'iterator - iterator -> element_count'; Well performing, return element_count of type difference_type. */
460 constexpr difference_type operator-(const cow_rw_iterator& rhs) const noexcept
461 { return iterator_ - rhs.iterator_; }
462
463 inline std::string toString() const noexcept {
464 return jau::to_string(iterator_);
465 }
466#if 0
467 inline operator std::string() const noexcept {
468 return toString();
469 }
470#endif
471 std::string get_info() const noexcept {
472 return "cow_rw_iterator[this "+jau::to_hexstring(this)+", CoW "+jau::to_hexstring(&cow_parent_)+
473 ", store "+jau::to_hexstring(&store_ref_)+
474 ", "+jau::to_string(iterator_)+"]";
475 }
476
477 /**
478 * Removes the last element and sets this iterator to end()
479 */
480 constexpr void pop_back() noexcept {
481 store_ref_->pop_back();
482 iterator_ = store_ref_->end();
483 }
484
485 /**
486 * Erases the element at the current position.
487 * <p>
488 * This iterator is set to the element following the last removed element.
489 * </p>
490 */
491 constexpr void erase () {
492 iterator_ = store_ref_->erase(iterator_);
493 }
494
495 /**
496 * Like std::vector::erase(), removes the elements in the range [current, current+count).
497 * <p>
498 * This iterator is set to the element following the last removed element.
499 * </p>
500 */
501 constexpr void erase (size_type count) {
502 iterator_ = store_ref_->erase(iterator_, iterator_+count);
503 }
504
505 /**
506 * Inserts the element before the current position
507 * and moves all elements from there to the right beforehand.
508 * <p>
509 * size will be increased by one.
510 * </p>
511 * <p>
512 * This iterator is set to the inserted element.
513 * </p>
514 */
515 constexpr void insert(const value_type& x) {
516 iterator_ = store_ref_->insert(iterator_, x);
517 }
518
519 /**
520 * Inserts the element before the current position (std::move operation)
521 * and moves all elements from there to the right beforehand.
522 * <p>
523 * size will be increased by one.
524 * </p>
525 * <p>
526 * This iterator is set to the inserted element.
527 * </p>
528 */
529 constexpr void insert(value_type&& x) {
530 iterator_ = store_ref_->insert(iterator_, std::move(x));
531 }
532
533 /**
534 * Like std::vector::emplace(), construct a new element in place.
535 * <p>
536 * Constructs the element before the current position using placement new
537 * and moves all elements from there to the right beforehand.
538 * </p>
539 * <p>
540 * size will be increased by one.
541 * </p>
542 * <p>
543 * This iterator is set to the inserted element.
544 * </p>
545 * @param args arguments to forward to the constructor of the element
546 */
547 template<typename... Args>
548 constexpr void emplace(Args&&... args) {
549 iterator_ = store_ref_->emplace(iterator_, std::forward<Args>(args)... );
550 }
551
552 /**
553 * Like std::vector::insert(), inserting the value_type range [first, last).
554 * <p>
555 * This iterator is set to the first element inserted, or pos if first==last.
556 * </p>
557 * @tparam InputIt foreign input-iterator to range of value_type [first, last)
558 * @param first first foreign input-iterator to range of value_type [first, last)
559 * @param last last foreign input-iterator to range of value_type [first, last)
560 */
561 template< class InputIt >
562 constexpr void insert( InputIt first, InputIt last ) {
563 iterator_ = store_ref_->insert(iterator_, first, last);
564 }
565
566 /**
567 * Like std::vector::push_back(), copy
568 * <p>
569 * This iterator is set to the end.
570 * </p>
571 * @param x the value to be added at the tail.
572 */
573 constexpr void push_back(const value_type& x) {
574 store_ref_->push_back(x);
575 iterator_ = store_ref_->end();
576 }
577
578 /**
579 * Like std::vector::push_back(), move
580 * <p>
581 * This iterator is set to the end.
582 * </p>
583 * @param x the value to be added at the tail.
584 */
585 constexpr void push_back(value_type&& x) {
586 store_ref_->push_back(std::move(x));
587 iterator_ = store_ref_->end();
588 }
589
590 /**
591 * Like std::vector::emplace_back(), construct a new element in place at the end().
592 * <p>
593 * Constructs the element at the end() using placement new.
594 * </p>
595 * <p>
596 * size will be increased by one.
597 * </p>
598 * <p>
599 * This iterator is set to the end.
600 * </p>
601 * @param args arguments to forward to the constructor of the element
602 */
603 template<typename... Args>
604 constexpr reference emplace_back(Args&&... args) {
605 reference res = store_ref_->emplace_back(std::forward<Args>(args)...);
606 iterator_ = store_ref_->end();
607 return res;
608 }
609
610 /**
611 * Like std::vector::push_back(), but appends the value_type range [first, last).
612 * <p>
613 * This iterator is set to the end.
614 * </p>
615 * @tparam InputIt foreign input-iterator to range of value_type [first, last)
616 * @param first first foreign input-iterator to range of value_type [first, last)
617 * @param last last foreign input-iterator to range of value_type [first, last)
618 */
619 template< class InputIt >
620 constexpr void push_back( InputIt first, InputIt last ) {
621 store_ref_->push_back(first, last);
622 iterator_ = store_ref_->end();
623 }
624 };
625
626 /**
627 * Implementation of a Copy-On-Write (CoW) read-onlu iterator over immutable value_type storage.<br>
628 * Instance holds a shared storage snapshot of the parents' CoW storage until destruction.
629 * <p>
630 * Implementation complies with Type Traits iterator_category 'random_access_iterator_tag'
631 * </p>
632 * <p>
633 * Implementation simply wraps the native iterator of type 'iterator_type'
634 * and manages the CoW related resource lifecycle.
635 * </p>
636 * <p>
637 * This iterator is the preferred choice if no mutations are made to the elements state
638 * itself, or all changes can be discarded after the iterator's destruction.<br>
639 * This avoids the costly mutex lock and storage copy of jau::cow_rw_iterator.<br>
640 * Also see jau::for_each_fidelity to iterate through in this good faith fashion.
641 * </p>
642 * <p>
643 * To allow data-race free operations on this iterator's data snapshot from a potentially mutated CoW,
644 * only one begin iterator should be retrieved from CoW and all further operations shall use
645 * jau::cow_ro_iterator::size(), jau::cow_ro_iterator::begin() and jau::cow_ro_iterator::end().
646 * </p>
647 * @see jau::cow_ro_iterator::size()
648 * @see jau::cow_ro_iterator::begin()
649 * @see jau::cow_ro_iterator::end()
650 * @see jau::for_each_fidelity
651 * @see jau::cow_darray
652 */
653 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
656 template<typename, typename, typename, bool, bool> friend class cow_darray;
657 template<typename, typename> friend class cow_vector;
658
659 public:
660 typedef Storage_type storage_t;
661 typedef Storage_ref_type storage_ref_t;
662 typedef CoW_container cow_container_t;
663
664 /** Actual const iterator type of the contained native iterator, probably a simple pointer. */
665 typedef typename storage_t::const_iterator iterator_type;
666
667 private:
668 typedef std::iterator_traits<iterator_type> sub_traits_t;
669
670 storage_ref_t store_ref_;
671 iterator_type iterator_;
672
673 constexpr cow_ro_iterator(storage_ref_t store, iterator_type it) noexcept
674 : store_ref_(std::move(store)), iterator_(std::move(it)) { }
675
676 public:
677 typedef typename sub_traits_t::iterator_category iterator_category; // random_access_iterator_tag
678
679 typedef typename storage_t::size_type size_type; // using our template overload Size_type
680 typedef typename storage_t::difference_type difference_type; // derived from our Size_type
681 // typedef typename storage_t::value_type value_type; // OK
682 // typedef typename storage_t::reference reference; // storage_t is not 'const'
683 // typedef typename storage_t::pointer pointer; // storage_t is not 'const'
684 typedef typename sub_traits_t::value_type value_type; // OK
685 typedef typename sub_traits_t::reference reference; // 'const value_type &'
686 typedef typename sub_traits_t::pointer pointer; // 'const value_type *'
687
688// FIXME
689#if __cplusplus > 201703L && __cpp_lib_concepts && 0
690 using iterator_concept = std::__detail::__iter_concept<iterator_type>;
691#endif
692
693 public:
694 constexpr cow_ro_iterator() noexcept
695 : store_ref_(nullptr), iterator_() { }
696
697 // C++ named requirements: LegacyIterator: CopyConstructible
698 constexpr cow_ro_iterator(const cow_ro_iterator& o) noexcept
699 : store_ref_(o.store_ref_), iterator_(o.iterator_) {}
700
701 // C++ named requirements: LegacyIterator: CopyAssignable
702 constexpr cow_ro_iterator& operator=(const cow_ro_iterator& o) noexcept {
703 if( this != &o ) {
704 store_ref_ = o.store_ref_;
705 iterator_ = o.iterator_;
706 }
707 return *this;
708 }
709
710 // C++ named requirements: LegacyIterator: MoveConstructable
711 constexpr cow_ro_iterator(cow_ro_iterator && o) noexcept
712 : store_ref_(std::move(o.store_ref_)), iterator_(std::move(o.iterator_)) {
713 // Moved source has been disowned semantically and source's dtor will release resources!
714 }
715
716 // C++ named requirements: LegacyIterator: MoveAssignable
717 constexpr cow_ro_iterator& operator=(cow_ro_iterator&& o) noexcept {
718 if( this != &o ) {
719 store_ref_ = std::move(o.store_ref_);
720 iterator_ = std::move(o.iterator_);
721 // Moved source has been disowned semantically and source's dtor will release resources!
722 }
723 return *this;
724 }
725
726 // C++ named requirements: LegacyIterator: Swappable
727 void swap(cow_ro_iterator& o) noexcept {
728 std::swap( store_ref_, o.store_ref_);
729 std::swap( iterator_, o.iterator_);
730 }
731
732 /**
733 * Returns a new const_iterator pointing to the first element, aka begin.
734 * <p>
735 * This is an addition API entry, allowing data-race free operations on
736 * this iterator's data snapshot from a potentially mutated CoW.
737 * </p>
738 * @see size()
739 * @see end()
740 */
741 constexpr cow_ro_iterator cbegin() const noexcept
742 { return cow_ro_iterator( store_ref_, store_ref_->cbegin() ); }
743
744 /**
745 * Returns a new const_iterator pointing to the <i>element following the last element</i>, aka end.<br>
746 * <p>
747 * This is an addition API entry, allowing data-race free operations on
748 * this iterator's data snapshot from a potentially mutated CoW.
749 * </p>
750 * @see size()
751 * @see begin()
752 */
753 constexpr cow_ro_iterator cend() const noexcept
754 { return cow_ro_iterator( store_ref_, store_ref_->cend() ); }
755
756 /**
757 * Returns true if storage is empty().
758 */
759 constexpr bool empty() const noexcept { return store_ref_->empty(); }
760
761 /**
762 * Returns true if storage capacity has been reached and the next push_back()
763 * will grow the storage and invalidates all iterators and references.
764 */
765 constexpr bool capacity_reached() const noexcept { return store_ref_->capacity_reached(); }
766
767 /**
768 * Return the size of the underlying value_type store.
769 * <p>
770 * This is an addition API entry, allowing data-race free arithmetic on
771 * this iterator's data snapshot from a potentially mutated CoW.
772 * </p>
773 * @see begin()
774 * @see end()
775 */
776 constexpr size_type size() const noexcept { return store_ref_->size(); }
777
778 /**
779 * Returns this instances' underlying shared storage by reference.
780 */
781 constexpr storage_t& storage() const noexcept {
782 return *store_ref_;
783 }
784
785 /**
786 * Returns the distance to_end() using zero as first index. A.k.a the remaining elements iterable.
787 */
788 constexpr difference_type dist_end() const noexcept { return store_ref_->cend() - iterator_; }
789
790 /**
791 * Returns true, if this iterator points to cend().
792 */
793 constexpr bool is_end() const noexcept { return iterator_ == store_ref_->cend(); }
794
795 /**
796 * This iterator is set to the last element, cend(). Returns *this;
797 */
798 constexpr cow_ro_iterator& to_end() noexcept
799 { iterator_ = store_ref_->cend(); return *this; }
800
801 /**
802 * Returns the distance to_begin() using zero as first index. A.k.a the index from start.
803 */
804 constexpr difference_type dist_begin() const noexcept { return iterator_ - store_ref_->cbegin(); }
805
806 /**
807 * Returns true, if this iterator points to cbegin().
808 */
809 constexpr bool is_begin() const noexcept { return iterator_ == store_ref_->cbegin(); }
810
811 /**
812 * This iterator is set to the first element, cbegin(). Returns *this;
813 */
814 constexpr cow_ro_iterator& to_begin() noexcept
815 { iterator_ = store_ref_->cbegin(); return *this; }
816
817 /**
818 * Returns a copy of the underlying storage const_iterator.
819 * <p>
820 * This is an addition API entry, inspired by the STL std::normal_iterator.
821 * </p>
822 */
823 constexpr iterator_type base() const noexcept { return iterator_; };
824
825 // Multipass guarantee equality
826
827 /**
828 * Returns signum or three-way comparison value
829 * <pre>
830 * 0 if equal (both, store and iteratore),
831 * -1 if this->iterator_ < rhs_iter and
832 * 1 if this->iterator_ > rhs_iter (otherwise)
833 * </pre>
834 * @param rhs_store right-hand side store
835 * @param rhs_iter right-hand side iterator
836 */
837 constexpr int compare(const cow_ro_iterator& rhs) const noexcept {
838 return store_ref_ == rhs.store_ref_ && iterator_ == rhs.iterator_ ? 0
839 : ( iterator_ < rhs.iterator_ ? -1 : 1);
840 }
841
843 return store_ref_ == rhs.store_ref_ && iterator_ == rhs.iterator_ ? 0
844 : ( iterator_ < rhs.iterator_ ? -1 : 1);
845 }
846
847 constexpr bool operator==(const cow_ro_iterator& rhs) const noexcept
848 { return compare(rhs) == 0; }
849
850 constexpr bool operator!=(const cow_ro_iterator& rhs) const noexcept
851 { return compare(rhs) != 0; }
852
853 // Relation
854
855 constexpr bool operator<=(const cow_ro_iterator& rhs) const noexcept
856 { return compare(rhs) <= 0; }
857
858 constexpr bool operator<(const cow_ro_iterator& rhs) const noexcept
859 { return compare(rhs) < 0; }
860
861 constexpr bool operator>=(const cow_ro_iterator& rhs) const noexcept
862 { return compare(rhs) >= 0; }
863
864 constexpr bool operator>(const cow_ro_iterator& rhs) const noexcept
865 { return compare(rhs) > 0; }
866
867 // Forward iterator requirements
868
869 constexpr const reference operator*() const noexcept {
870 return *iterator_;
871 }
872
873 constexpr const pointer operator->() const noexcept {
874 return &(*iterator_); // just in case iterator_type is a class, trick via dereference
875 }
876
877 /** Pre-increment; Well performing, return *this. */
878 constexpr cow_ro_iterator& operator++() noexcept {
879 ++iterator_;
880 return *this;
881 }
882
883 /** Post-increment; Try to avoid: Low performance due to returning copy-ctor. */
884 constexpr cow_ro_iterator operator++(int) noexcept
885 { return cow_ro_iterator(store_ref_, iterator_++); }
886
887 // Bidirectional iterator requirements
888
889 /** Pre-decrement; Well performing, return *this. */
890 constexpr cow_ro_iterator& operator--() noexcept {
891 --iterator_;
892 return *this;
893 }
894
895 /** Post-decrement; Try to avoid: Low performance due to returning copy-ctor. */
896 constexpr cow_ro_iterator operator--(int) noexcept
897 { return cow_ro_iterator(store_ref_, iterator_--); }
898
899 // Random access iterator requirements
900
901 /** Subscript of 'element_index', returning immutable Value_type reference. */
902 constexpr const reference operator[](difference_type i) const noexcept
903 { return iterator_[i]; }
904
905 /** Addition-assignment of 'element_count'; Well performing, return *this. */
907 { iterator_ += i; return *this; }
908
909 /** Binary 'iterator + element_count'; Try to avoid: Low performance due to returning copy-ctor. */
910 constexpr cow_ro_iterator operator+(difference_type rhs) const noexcept
911 { return cow_ro_iterator(store_ref_, iterator_ + rhs); }
912
913 /** Subtraction-assignment of 'element_count'; Well performing, return *this. */
915 { iterator_ -= i; return *this; }
916
917 /** Binary 'iterator - element_count'; Try to avoid: Low performance due to returning copy-ctor. */
918 constexpr cow_ro_iterator operator-(difference_type rhs) const noexcept
919 { return cow_ro_iterator(store_ref_, iterator_ - rhs); }
920
921 // Distance or element count, binary subtraction of two iterator.
922
923 /** Binary 'iterator - iterator -> element_count'; Well performing, return element_count of type difference_type. */
924 constexpr difference_type operator-(const cow_ro_iterator& rhs) const noexcept
925 { return iterator_ - rhs.iterator_; }
926
928 { return iterator_ - rhs.iterator_; }
929
930 inline std::string toString() const noexcept {
931 return jau::to_string(iterator_);
932 }
933#if 0
934 inline operator std::string() const noexcept {
935 return toString();
936 }
937#endif
938 std::string get_info() const noexcept {
939 return "cow_ro_iterator[this "+jau::to_hexstring(this)+
940 ", store "+jau::to_hexstring(&store_ref_)+
941 ", "+jau::to_string(iterator_)+"]";
942 }
943 };
944
945 /****************************************************************************************
946 ****************************************************************************************/
947
948 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
950 out << c.toString();
951 return out;
952 }
953
954 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
956 out << c.toString();
957 return out;
958 }
959
960 /****************************************************************************************
961 ****************************************************************************************/
962
963 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
966 { return lhs.compare(rhs) == 0; }
967
968 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
971 { return lhs.compare(rhs) != 0; }
972
973 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
976 { return rhs.compare(lhs) == 0; }
977
978 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
981 { return rhs.compare(lhs) != 0; }
982
983 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
986 { return lhs.compare(rhs) <= 0; }
987
988 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
991 { return rhs.compare(lhs) > 0; }
992
993 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
996 { return lhs.compare(rhs) < 0; }
997
998 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
1001 { return rhs.compare(lhs) >= 0; }
1002
1003 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
1006 { return lhs.compare(rhs) >= 0; }
1007
1008 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
1011 { return rhs.compare(lhs) < 0; }
1012
1013 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
1016 { return lhs.compare(rhs) > 0; }
1017
1018 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
1021 { return rhs.compare(lhs) <= 0; }
1022
1023 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
1024 constexpr typename Storage_type::difference_type operator-
1027 { return lhs.distance(rhs); }
1028
1029 template <typename Storage_type, typename Storage_ref_type, typename CoW_container>
1030 constexpr typename Storage_type::difference_type operator-
1033 { return rhs.distance(lhs) * -1; }
1034
1035 /****************************************************************************************
1036 ****************************************************************************************/
1037
1038 /**
1039 * <code>template< class T > is_cow_type<T>::value</code> compile-time Type Trait,
1040 * determining whether the given template class is a CoW type, e.g. jau::cow_darray,
1041 * jau::cow_vector or any of their iterator.
1042 */
1043 template< class, class = void >
1044 struct is_cow_type : std::false_type { };
1045
1046 /**
1047 * <code>template< class T > is_cow_type<T>::value</code> compile-time Type Trait,
1048 * determining whether the given template class is a CoW type, e.g. jau::cow_darray,
1049 * jau::cow_vector or any of their iterator.
1050 */
1051 template< class T >
1052 struct is_cow_type<T, std::void_t<typename T::cow_container_t>> : std::true_type { };
1053
1054 /****************************************************************************************
1055 ****************************************************************************************/
1056
1057 /**@}*/
1058
1059} /* namespace jau */
1060
1061
1062#endif /* JAU_COW_ITERATOR_HPP_ */
Implementation of a Copy-On-Write (CoW) using jau::darray as the underlying storage,...
Definition: cow_darray.hpp:127
Implementation of a Copy-On-Write (CoW) read-onlu iterator over immutable value_type storage.
constexpr bool operator>=(const cow_ro_iterator &rhs) const noexcept
Storage_type storage_t
constexpr bool operator!=(const cow_ro_iterator &rhs) const noexcept
constexpr difference_type dist_end() const noexcept
Returns the distance to_end() using zero as first index.
constexpr cow_ro_iterator(const cow_ro_iterator &o) noexcept
constexpr cow_ro_iterator & to_end() noexcept
This iterator is set to the last element, cend().
constexpr const reference operator[](difference_type i) const noexcept
Subscript of 'element_index', returning immutable Value_type reference.
constexpr bool operator==(const cow_ro_iterator &rhs) const noexcept
constexpr difference_type dist_begin() const noexcept
Returns the distance to_begin() using zero as first index.
constexpr cow_ro_iterator cbegin() const noexcept
Returns a new const_iterator pointing to the first element, aka begin.
constexpr int compare(const cow_rw_iterator< storage_t, storage_ref_t, cow_container_t > &rhs) const noexcept
Storage_ref_type storage_ref_t
constexpr difference_type distance(const cow_rw_iterator< storage_t, storage_ref_t, cow_container_t > &rhs) const noexcept
constexpr iterator_type base() const noexcept
Returns a copy of the underlying storage const_iterator.
constexpr cow_ro_iterator operator++(int) noexcept
Post-increment; Try to avoid: Low performance due to returning copy-ctor.
constexpr cow_ro_iterator & operator-=(difference_type i) noexcept
Subtraction-assignment of 'element_count'; Well performing, return *this.
storage_t::difference_type difference_type
constexpr cow_ro_iterator(cow_ro_iterator &&o) noexcept
constexpr size_type size() const noexcept
Return the size of the underlying value_type store.
sub_traits_t::reference reference
constexpr const reference operator*() const noexcept
constexpr difference_type operator-(const cow_ro_iterator &rhs) const noexcept
Binary 'iterator - iterator -> element_count'; Well performing, return element_count of type differen...
std::string toString() const noexcept
constexpr bool is_begin() const noexcept
Returns true, if this iterator points to cbegin().
storage_t::size_type size_type
sub_traits_t::value_type value_type
storage_t::const_iterator iterator_type
Actual const iterator type of the contained native iterator, probably a simple pointer.
constexpr cow_ro_iterator & operator++() noexcept
Pre-increment; Well performing, return *this.
constexpr bool operator>(const cow_ro_iterator &rhs) const noexcept
sub_traits_t::iterator_category iterator_category
constexpr bool is_end() const noexcept
Returns true, if this iterator points to cend().
constexpr const pointer operator->() const noexcept
constexpr cow_ro_iterator & operator=(cow_ro_iterator &&o) noexcept
constexpr bool capacity_reached() const noexcept
Returns true if storage capacity has been reached and the next push_back() will grow the storage and ...
sub_traits_t::pointer pointer
CoW_container cow_container_t
constexpr cow_ro_iterator() noexcept
std::string get_info() const noexcept
constexpr cow_ro_iterator & operator=(const cow_ro_iterator &o) noexcept
constexpr cow_ro_iterator operator+(difference_type rhs) const noexcept
Binary 'iterator + element_count'; Try to avoid: Low performance due to returning copy-ctor.
constexpr cow_ro_iterator & to_begin() noexcept
This iterator is set to the first element, cbegin().
void swap(cow_ro_iterator &o) noexcept
constexpr bool operator<=(const cow_ro_iterator &rhs) const noexcept
constexpr cow_ro_iterator operator-(difference_type rhs) const noexcept
Binary 'iterator - element_count'; Try to avoid: Low performance due to returning copy-ctor.
constexpr storage_t & storage() const noexcept
Returns this instances' underlying shared storage by reference.
constexpr cow_ro_iterator & operator--() noexcept
Pre-decrement; Well performing, return *this.
constexpr int compare(const cow_ro_iterator &rhs) const noexcept
Returns signum or three-way comparison value.
constexpr bool empty() const noexcept
Returns true if storage is empty().
constexpr cow_ro_iterator cend() const noexcept
Returns a new const_iterator pointing to the element following the last element, aka end.
constexpr bool operator<(const cow_ro_iterator &rhs) const noexcept
constexpr cow_ro_iterator operator--(int) noexcept
Post-decrement; Try to avoid: Low performance due to returning copy-ctor.
constexpr cow_ro_iterator & operator+=(difference_type i) noexcept
Addition-assignment of 'element_count'; Well performing, return *this.
Implementation of a Copy-On-Write (CoW) read-write iterator over mutable value_type storage.
constexpr void erase(size_type count)
Like std::vector::erase(), removes the elements in the range [current, current+count).
sub_traits_t::value_type value_type
constexpr cow_rw_iterator begin() const noexcept
Returns a new iterator pointing to the first element, aka begin.
storage_t::difference_type difference_type
constexpr void pop_back() noexcept
Removes the last element and sets this iterator to end()
constexpr void emplace(Args &&... args)
Like std::vector::emplace(), construct a new element in place.
constexpr void insert(InputIt first, InputIt last)
Like std::vector::insert(), inserting the value_type range [first, last).
constexpr bool operator==(const cow_rw_iterator &rhs) const noexcept
constexpr reference operator[](difference_type i) noexcept
Subscript of 'element_index', returning mutable Value_type reference.
constexpr cow_rw_iterator operator+(difference_type rhs) const noexcept
Binary 'iterator + element_count'; Try to avoid: Low performance due to returning copy-ctor.
constexpr iterator_type base() const noexcept
Returns a copy of the underlying storage iterator.
storage_t::iterator iterator_type
Actual iterator type of the contained native iterator, probably a simple pointer.
constexpr void push_back(const value_type &x)
Like std::vector::push_back(), copy.
constexpr void insert(value_type &&x)
Inserts the element before the current position (std::move operation) and moves all elements from the...
constexpr void push_back(value_type &&x)
Like std::vector::push_back(), move.
sub_traits_t::iterator_category iterator_category
constexpr cow_rw_iterator & to_begin() noexcept
This iterator is set to the first element, begin().
constexpr reference emplace_back(Args &&... args)
Like std::vector::emplace_back(), construct a new element in place at the end().
constexpr bool operator<(const cow_rw_iterator &rhs) const noexcept
constexpr bool is_begin() const noexcept
Returns true, if this iterator points to begin().
constexpr pointer operator->() noexcept
Pointer to member access.
constexpr difference_type dist_begin() const noexcept
Returns the distance to_begin() using zero as first index.
Storage_type storage_t
std::string toString() const noexcept
constexpr cow_rw_iterator & operator++() noexcept
Pre-increment; Well performing, return *this.
Storage_ref_type storage_ref_t
constexpr cow_rw_iterator & operator-=(difference_type i) noexcept
Subtraction-assignment of 'element_count'; Well performing, return *this.
constexpr cow_ro_iterator< Storage_type, Storage_ref_type, CoW_container > immutable() const noexcept
Returns a new const_iterator pointing to the current position.
constexpr cow_rw_iterator & operator=(const cow_rw_iterator &o) noexcept
Assigns content of other mutable iterator to this one, if they are not identical.
constexpr cow_rw_iterator & operator+=(difference_type i) noexcept
Addition-assignment of 'element_count'; Well performing, return *this.
constexpr cow_rw_iterator & operator--() noexcept
Pre-decrement; Well performing, return *this.
sub_traits_t::pointer pointer
constexpr difference_type operator-(const cow_rw_iterator &rhs) const noexcept
Binary 'iterator - iterator -> element_count'; Well performing, return element_count of type differen...
constexpr storage_t & storage() const noexcept
Returns this instances' underlying shared storage by reference.
constexpr reference operator*() noexcept
Dereferencing iterator to value_type reference.
constexpr void push_back(InputIt first, InputIt last)
Like std::vector::push_back(), but appends the value_type range [first, last).
constexpr cow_rw_iterator operator-(difference_type rhs) const noexcept
Binary 'iterator - element_count'; Try to avoid: Low performance due to returning copy-ctor.
std::string get_info() const noexcept
storage_t::size_type size_type
constexpr cow_rw_iterator(const cow_rw_iterator &o) noexcept
C++ named requirements: LegacyIterator: CopyConstructible.
constexpr size_type size() const noexcept
Return the size of the underlying value_type store.
constexpr bool is_end() const noexcept
Returns true, if this iterator points to end().
constexpr cow_rw_iterator(cow_rw_iterator &&o) noexcept
C++ named requirements: LegacyIterator: MoveConstructable.
CoW_container cow_container_t
constexpr void insert(const value_type &x)
Inserts the element before the current position and moves all elements from there to the right before...
void swap(cow_rw_iterator &o) noexcept
C++ named requirements: LegacyIterator: Swappable.
constexpr cow_rw_iterator end() const noexcept
Returns a new iterator pointing to the element following the last element, aka end.
void write_back() noexcept
Replace the parent's current store with this iterators' instance, unlock the CoW parents' write lock ...
constexpr cow_rw_iterator & to_end() noexcept
This iterator is set to the last element, end().
constexpr const pointer operator->() const noexcept
Pointer to member access.
constexpr difference_type dist_end() const noexcept
Returns the distance to_end() using zero as first index.
constexpr cow_rw_iterator operator--(int) noexcept
Post-decrement; Try to avoid: Low performance due to returning copy-ctor.
constexpr void erase()
Erases the element at the current position.
constexpr const reference operator*() const noexcept
Dereferencing iterator to value_type reference.
constexpr const reference operator[](difference_type i) const noexcept
Subscript of 'element_index', returning immutable Value_type reference.
constexpr cow_rw_iterator & operator=(cow_rw_iterator &&o) noexcept
Assigns identity of given mutable iterator, if they are not identical.
sub_traits_t::reference reference
constexpr bool operator<=(const cow_rw_iterator &rhs) const noexcept
constexpr int compare(const cow_rw_iterator &rhs) const noexcept
Returns signum or three-way comparison value.
constexpr cow_rw_iterator operator++(int) noexcept
Post-increment; Try to avoid: Low performance due to returning copy-ctor.
constexpr bool empty() const noexcept
Returns true if storage is empty().
constexpr bool operator!=(const cow_rw_iterator &rhs) const noexcept
constexpr bool operator>(const cow_rw_iterator &rhs) const noexcept
constexpr bool operator>=(const cow_rw_iterator &rhs) const noexcept
constexpr bool capacity_reached() const noexcept
Returns true if storage capacity has been reached and the next push_back() will grow the storage and ...
Implementation of a Copy-On-Write (CoW) using std::vector as the underlying storage,...
Definition: cow_vector.hpp:108
std::string to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
std::ostream & operator<<(std::ostream &out, const cow_darray< Value_type, Size_type, Alloc_type > &c)
bool operator>=(const cow_darray< Value_type, Size_type, Alloc_type > &rhs, const cow_darray< Value_type, Size_type, Alloc_type > &lhs)
bool operator>(const cow_darray< Value_type, Size_type, Alloc_type > &rhs, const cow_darray< Value_type, Size_type, Alloc_type > &lhs)
bool operator<(const cow_darray< Value_type, Size_type, Alloc_type > &rhs, const cow_darray< Value_type, Size_type, Alloc_type > &lhs)
void swap(cow_darray< Value_type, Size_type, Alloc_type > &rhs, cow_darray< Value_type, Size_type, Alloc_type > &lhs) noexcept
bool operator<=(const cow_darray< Value_type, Size_type, Alloc_type > &rhs, const cow_darray< Value_type, Size_type, Alloc_type > &lhs)
std::string to_hexstring(value_type const &v) noexcept
Produce a lower-case hexadecimal string representation of the given pointer.
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
bool operator==(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
Definition: callocator.hpp:150
bool operator!=(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
Definition: callocator.hpp:163
STL namespace.
template< class T > is_cow_type<T>::value compile-time Type Trait, determining whether the given temp...