Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
IteratorImplHelper.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Containers_Private_IteratorImplHelper_h_
5#define _Stroika_Foundation_Containers_Private_IteratorImplHelper_h_
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include "Stroika/Foundation/Common/Common.h"
10#include "Stroika/Foundation/Containers/Common.h"
11
12/**
13 * Private utility to support building of Traversal::Iterator<> objects for concrete Containers.
14 *
15 * TODO:
16 * @todo Crazy temphack cuz current code assumes you must call++ before starting iteration! Crazy!
17 * Issue is way we implemented the 'CURRENT' stuff with iterators - filling in after the first
18 * More()...
19 *
20 * At this point - this appears to be restricted to ALL BACKEND support Iterator (ForwardIterator) classes.
21 * The Stroika Iterator API doesn't appear to have this quirk.
22 *
23 *
24 * Notes:
25 *
26 */
27
29
30 /**
31 */
32 struct ContainerDebugChangeCounts_ {
33 using ChangeCountType = unsigned int;
34#if qStroika_Foundation_Debug_AssertionsChecked
35 static ChangeCountType mkInitial_ ();
36#endif
37
38 ContainerDebugChangeCounts_ ();
39 ContainerDebugChangeCounts_ (const ContainerDebugChangeCounts_& src);
40 ~ContainerDebugChangeCounts_ ();
41
42#if qStroika_Foundation_Debug_AssertionsChecked
43 // NOTE - might want to use weakly_shared_ptr (weakref) as safer 'debugging' check than this, but only
44 // for debug checking, so not strictly needed (and might cost too much). CONSIDER going forward just
45 // for DEBUG mode -- LGP 2021-11-11
46 bool fDeleted{false};
47 atomic<ChangeCountType> fChangeCount{0}; // overwritten with random# in CTOR
48#endif
49
50 /**
51 */
52 nonvirtual void PerformedChange ();
53 };
54
55 /**
56 * \brief helper to wrap a low level 'DataStructure Container Iterator' into a 'Stroika' Iterator::IRep iterator.
57 *
58 * There is no requirement that Stroika concrete containers use this class. However, it
59 * so far has appeared a handy code sharing utility.
60 *
61 * Plus, its details are intimately tied to how the Stroika containers manage lifetime, so
62 * its not likely well suited for use elsewhere.
63 *
64 * \todo This class is a bit kludgy/fragile. (e.g. the cases where you have to override More needing to also override Clone). Maybe use CRTP? And not
65 * good compiler error messages - maybe use more/better concepts usage; low priority since private impl helper method;
66 * -- LGP 2024-09-05
67 */
68 template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR = typename DATASTRUCTURE_CONTAINER::ForwardIterator, typename DATASTRUCTURE_CONTAINER_VALUE = T>
70 : public Iterator<T>::IRep,
71 public Memory::UseBlockAllocationIfAppropriate<IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>> {
72 private:
73 using inherited = typename Iterator<T>::IRep;
74
75 public:
76 using DataStructureImplValueType_ = DATASTRUCTURE_CONTAINER_VALUE;
77
78 public:
79 IteratorImplHelper_ () = delete;
80 IteratorImplHelper_ (IteratorImplHelper_&&) noexcept = default;
82 template <typename... ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS>
83 explicit IteratorImplHelper_ (const DATASTRUCTURE_CONTAINER* data, const ContainerDebugChangeCounts_* changeCounter = nullptr,
84 ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS&&... args)
85 requires (constructible_from<DATASTRUCTURE_CONTAINER_ITERATOR, const DATASTRUCTURE_CONTAINER*, ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS...>);
86 template <typename... ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS>
87 explicit IteratorImplHelper_ (const ContainerDebugChangeCounts_* changeCounter = nullptr, ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS&&... args)
88 requires (constructible_from<DATASTRUCTURE_CONTAINER_ITERATOR, ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS...>);
89
90 public:
91 virtual ~IteratorImplHelper_ () = default;
92
93 // Iterator<T>::IRep
94 public:
95 virtual unique_ptr<typename Iterator<T>::IRep> Clone () const override;
96 virtual void More (optional<T>* result, bool advance) override;
97 virtual bool Equals (const typename Iterator<T>::IRep* rhs) const override;
98#if qStroika_Foundation_Debug_AssertionsChecked
99 /**
100 */
101 virtual void Invariant () const noexcept override;
102#endif
103
104 public:
105 /**
106 * rarely used but in special cases when returning new derived/pathed iterator*
107 */
108 nonvirtual void UpdateChangeCount ();
109
110 public:
111 /**
112 * This is used internally by Stroika to assure iterators are not used after the container they iterate over
113 * has been changed.
114 */
115 nonvirtual void ValidateChangeCount () const;
116
117 public:
118 mutable DATASTRUCTURE_CONTAINER_ITERATOR fIterator{};
119#if qStroika_Foundation_Debug_AssertionsChecked
120 const ContainerDebugChangeCounts_* fChangeCounter{nullptr};
121 ContainerDebugChangeCounts_::ChangeCountType fLastCapturedChangeCount{};
122#endif
123 };
124
125}
126
127/*
128 ********************************************************************************
129 ***************************** Implementation Details ***************************
130 ********************************************************************************
131 */
132#include "IteratorImplHelper.inl"
133
134#endif /*_Stroika_Foundation_Containers_Private_IteratorImplHelper_h_ */
conditional_t< qStroika_Foundation_Memory_PreferBlockAllocation and andTrueCheck, BlockAllocationUseHelper< T >, Common::Empty > UseBlockAllocationIfAppropriate
Use this to enable block allocation for a particular class. Beware of subclassing.
helper to wrap a low level 'DataStructure Container Iterator' into a 'Stroika' Iterator::IRep iterato...
virtual void More(optional< T > *result, bool advance) override
virtual unique_ptr< typename Iterator< T >::IRep > Clone() const override
Implementation detail for iterator implementors.
Definition Iterator.h:599
An Iterator<T> is a copyable object which allows traversing the contents of some container....
Definition Iterator.h:225