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