Stroika Library 3.0d18
 
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 template <typename T, typename DATASTRUCTURE_CONTAINER>
56 struct IteratorImplHelper_DefaultTraits {
57 static_assert (not is_reference_v<T>);
58 static_assert (not is_reference_v<DATASTRUCTURE_CONTAINER>);
59 using DataStructureT = DATASTRUCTURE_CONTAINER;
60 using DataStructureIteratorT = typename DATASTRUCTURE_CONTAINER::ForwardIterator;
61 using DataStructureContainerValueT = typename DATASTRUCTURE_CONTAINER::value_type; // I THINK WE CAN LOSE THIS DEFINE
62 // static constexpr bool kConvertDataStructureIterationResult2ContainerIteratorResult = false;
63 // see if can use auto in place of explict XX
64 //template <typename XX>
65 static constexpr T ConvertDataStructureIterationResult2ContainerIteratorResult (const DataStructureContainerValueT& t)
66 //requires (Common::explicitly_convertible_to<DataStructureContainerValueT, T>)
67 {
68 static_assert (Common::explicitly_convertible_to<DataStructureContainerValueT, T>,
69 "dont use the default traits, but provide your own - see KeyedCollection_HashTable as example");
70 return static_cast<T> (t);
71 }
72 };
73
74 /**
75 * \brief helper to wrap a low level 'DataStructure Container Iterator' into a 'Stroika' Iterator::IRep iterator.
76 *
77 * There is no requirement that Stroika concrete containers use this class. However, it
78 * so far has appeared a handy code sharing utility.
79 *
80 * Plus, its details are intimately tied to how the Stroika containers manage lifetime, so
81 * its not likely well suited for use elsewhere.
82 *
83 * \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
84 * good compiler error messages - maybe use more/better concepts usage; low priority since private impl helper method;
85 * -- LGP 2024-09-05
86 */
87 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS = IteratorImplHelper_DefaultTraits<T, DATASTRUCTURE_CONTAINER>>
88 class IteratorImplHelper_ : public Iterator<T>::IRep,
89 public Memory::UseBlockAllocationIfAppropriate<IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS>> {
90 private:
91 using inherited = typename Iterator<T>::IRep;
92
93 //backward compat names
94 private:
95 using DATASTRUCTURE_CONTAINER_ITERATOR = typename TRAITS::DataStructureIteratorT;
96 using DATASTRUCTURE_CONTAINER_VALUE = typename TRAITS::DataStructureContainerValueT;
97
98 public:
99 using DataStructureImplValueType_ = DATASTRUCTURE_CONTAINER_VALUE;
100
101 public:
102 IteratorImplHelper_ () = delete;
103 IteratorImplHelper_ (IteratorImplHelper_&&) noexcept = default;
104 IteratorImplHelper_ (const IteratorImplHelper_&) = default;
105 template <typename... ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS>
106 explicit IteratorImplHelper_ (const DATASTRUCTURE_CONTAINER* data, const ContainerDebugChangeCounts_* changeCounter = nullptr,
107 ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS&&... args)
108 requires (constructible_from<DATASTRUCTURE_CONTAINER_ITERATOR, const DATASTRUCTURE_CONTAINER*, ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS...>);
109 template <typename... ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS>
110 explicit IteratorImplHelper_ (const ContainerDebugChangeCounts_* changeCounter = nullptr, ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS&&... args)
111 requires (constructible_from<DATASTRUCTURE_CONTAINER_ITERATOR, ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS...>);
112
113 public:
114 virtual ~IteratorImplHelper_ () = default;
115
116 // Iterator<T>::IRep
117 public:
118 virtual unique_ptr<typename Iterator<T>::IRep> Clone () const override;
119 virtual void More (optional<T>* result, bool advance) override;
120 virtual bool Equals (const typename Iterator<T>::IRep* rhs) const override;
121#if qStroika_Foundation_Debug_AssertionsChecked
122 /**
123 */
124 virtual void Invariant () const noexcept override;
125#endif
126
127 public:
128 /**
129 * rarely used but in special cases when returning new derived/pathed iterator*
130 */
131 nonvirtual void UpdateChangeCount ();
132
133 public:
134 /**
135 * This is used internally by Stroika to assure iterators are not used after the container they iterate over
136 * has been changed.
137 */
138 nonvirtual void ValidateChangeCount () const;
139
140 public:
141 mutable DATASTRUCTURE_CONTAINER_ITERATOR fIterator{};
142#if qStroika_Foundation_Debug_AssertionsChecked
143 const ContainerDebugChangeCounts_* fChangeCounter{nullptr};
144 ContainerDebugChangeCounts_::ChangeCountType fLastCapturedChangeCount{};
145#endif
146 };
147
148}
149
150/*
151 ********************************************************************************
152 ***************************** Implementation Details ***************************
153 ********************************************************************************
154 */
155#include "IteratorImplHelper.inl"
156
157#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