Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Sequence.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Containers_Sequence_h_
5#define _Stroika_Foundation_Containers_Sequence_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <compare>
10#include <limits>
11
12#include "Stroika/Foundation/Common/Common.h"
14#include "Stroika/Foundation/Common/Concepts.h"
15#include "Stroika/Foundation/Containers/Common.h"
19
20/*
21 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
22 *
23 * TODO:
24 * @todo Add/FIX three-way-comparer support - operator<=> etc - for Sequence. I Think it can be
25 * easily defined as operator<> on ELT, followed by operator<> on value and then as a string
26 * of those operations.
27 *
28 * @todo Provide Slice () overload to mask inherited one from Iterable, but more efficient, and return
29 * sequence. Mention alias 'SubSequence' from older todo.
30 *
31 * @todo Stroika v1 had REVERSE_ITERATORS - and so does STL. At least for sequences, we need reverse iterators!
32 * NOTE - this is NOT a special TYPE of iterator (unlike STL). Its just iterator returned from rbegin(), rend().
33 *
34 * @todo Sequence<> must support RandomAccessIterator<>
35 *
36 * @todo Where() and probably other things should use new EmptyClone() strategy - so cheaper and
37 * returns something of same underlying data structure type.
38 *
39 * @todo Add insert(Iterator<T>,T) overload (so works with Mapping<..>::As<...> ()
40 *
41 * @todo Must support Iterator<T>::operator-(Iterator<T>) or some-such so that SequenceIterator must work with qsort().
42 * In other words, must act as random-access iterator so it can be used in algorithms that use STL
43 * random-access iterators. (FOLLOW RULES OF RANDOM ACCESS ITERAOTRS)
44 *
45 * std::iterator<input_iterator_tag, T> versus ?? other iterator tag?
46 *
47 * @todo Maybe add (back) SequenceIterator - with support for operator- (difference), and UpdateCurrent, and GetIndex()
48 * Maybe also AdvanceBy(), BackBy() methods. Though All these COULD be methods of the underlying Sequence object.
49 *
50 * @todo Implement stuff like Contains () using ApplyUntil.... and lambdas, so locking works cheaply, and
51 * so no virtual references to operator== - so can always create Sequence<T> even if no operator== defined
52 * for T.
53 *
54 * @todo Document and Consider that though iterator compares with CONTAINER.end () work fine with Stroika iterators,
55 * other comparisons fail. For example, i < it.end (); and more importantly, constructs like i-s.begin() fail.
56 *
57 * Consider if we can make this work, or document why and that we cannot. Maybe we need a concept of
58 * SequenceIterator (like we had in Stroika 1) - which adds operator-?
59 *
60 * @todo Add Sequence_SparseArray<T> - using btree implementation
61 * it requires there is an empty T CTOR. But then uses btree to store values when they differ from T()
62 * (implement using redback tree or using stl map<>)
63 *
64 * @todo Add backend implementation of Sequence<T> using and Sequence_stdlist<>
65 *
66 * @todo Make sure that Sequence<T> (vector<T>) CTOR reserves the appropriate size before appending,
67 * by using type_traits logic to figure out of legal to compare - and see length. Same for
68 * Sequence<T> (ITER iFrom, ITER iTo) - do re-allocate size if appropriate - can do diff
69 * iTo-iFrom.
70 */
71
73
75 using Common::IPotentiallyComparer;
76 using Traversal::IInputIterator;
77 using Traversal::IIterableOfTo;
78 using Traversal::Iterable;
79 using Traversal::Iterator;
80
81 /**
82 * \brief A generalization of a vector: a container whose elements are keyed by the natural numbers.
83 *
84 * SmallTalk book page 153
85 *
86 * TODO:
87 *
88 * -> At some point in the near future we may add the ability to start at an
89 * arbitrary point in a sequence, and end at an arbitrary point. This
90 * requires more thought though. That functionality is probably not too
91 * important in light of being able to compute the current index easily
92 * in an iteration. Also, it requires more thought how to fit in with
93 * the sequenceDirection. Do we have a separate constructor specifying
94 * two start and endpoints and use their relative order to decide a
95 * direction? Do we just add the two start and end values to the end of
96 * the param list? How hard is this todo with Sequence_DLL?? If this
97 * functionality is subsumed by smart-iterators, does it make sense to
98 * wait to we provide that functionality?
99 *
100 * -> Figure out exactly what we will do about sorting/lookup function
101 * specification. Stroustrup like class param with somehow defaulting
102 * to op==????
103 *
104 * -> Add SetLength() method. Make sure it is optimally efficient, but try
105 * to avoid introducing a virtual function. Probably overload, and 1 arg
106 * version will use T default CTOR. If done non-virtually with templates
107 * then we only require no arg CTOR when this function called - GOOD.
108 * Cannot really do with GenClass (would need to compile in separate .o,
109 * even that wont work - need to not compile except when called).
110 *
111 * -> Consider patching iterators on insertions??? If not, document more
112 * clearly why not. Document exact details of patching in SEQUENCE as
113 * part of API!!!!
114 *
115 * Notes:
116 *
117 * Note: the decision on arguments to a Sort() function was difficult.
118 * Making the arg default to op <= would not work since for type int it
119 * wouldn't be defined, and sometimes people define it as a member function,
120 * or taking const T& args. Thus the function pointer type would not match.
121 * The other alternative is to overload, and have the no arg function just
122 * have a static private CompareFunction that calls op<=. This does work
123 * pretty well, BUT it fails in cases like Sequence(Picture) where there
124 * is no op<= defined. Here, we could force the definition of this function,
125 * but that would be generally awkward and was judged not worth the trouble.
126 * Just define your own little compare function that does op <=. That simple.
127 *
128 * The other approach sterl's been pushing is that of functional objects
129 * described in Coplain, and the latest Stroustrup book (Nov 91). I haven't
130 * looked closely enuf to decide.
131 *
132 * Another important addition was the CurrentIndex method. This was
133 * decided since it allowed for easy filtering (like only third thru eight
134 * elements, or only odd elements) without keeping an extra index variable
135 * which was often very awkward. This feature will probably be seldom used,
136 * and is seldom needed, but is one of the few things that differentiate
137 * a SequenceForEach from a Sequence (ie SequenceIterator from
138 * CollectionIterator). This statement really comes down to our really only
139 * needing sequence iterators rarely, and mostly using CollectionIterators.
140 *
141 * \note \em Iterators
142 * Note that iterators always run in Sequence order, from smallest index
143 * to largest. Items inserted before the current iterator index will not
144 * be encountered, and items inserted after the current index will be encountered.
145 * Items inserted at the current index remain undefined if they will
146 * be encountered or not.
147 *
148 * \em Concrete Implementations:
149 * o @see Concrete::Sequence_Array<>
150 * o @see Concrete::Sequence_DoublyLinkedList<>
151 * o @see Concrete::Sequence_LinkedList<>
152 * o @see Concrete::Sequence_stdvector<>
153 *
154 * \em Factory:
155 * @see Sequence_Factory<> to see default implementations.
156 *
157 * \note \em Thread-Safety <a href="Thread-Safety.md#C++-Standard-Thread-Safety">C++-Standard-Thread-Safety</a>
158 *
159 * \note Design Note - TRAITS for equals versus COMPARER template param to methods that need it
160 * We experimented (until Stroika 2.0a20 apx) with using TRAITS that were optional
161 * with Sequence<> - and had the equals comparer. This worked OK. The advantage of
162 * having the 'equals' method in the TRAITS was that it assured (for a given instance of Sequence)
163 * that all comparisons/notions of equality were tied to the instance.
164 *
165 * The idea WAS that you could even have a comparer that stored data in the instance (we never implemented that).
166 *
167 * But this notion of equals has problems for defining Sequence<>::Equals() - do you use the
168 * one from the RHS or LHS?
169 *
170 * Plus - making it a template param just added to the syntactic garbage in the template
171 * names (like in the debugger how the names printed out). This is no biggie, but
172 * it wasn't a plus.
173 *
174 * So now (as of v2.0a20) - we just have the EQUALS_COMPARER be a templated param to the
175 * methods that need it.
176 *
177 * \note See <a href="./ReadMe.md">ReadMe.md</a> for common features of all Stroika containers (especially
178 * constructors, iterators, etc)
179 *
180 * \note <a href="Design-Overview.md#Comparisons">Comparisons</a>:
181 * o static_assert (equality_comparable<T> ==> equality_comparable<Sequence<T>>);
182 * o static_assert (totally_ordered<T> ==> totally_ordered<Sequence<T>>);
183 * o using EqualsComparer = typename Iterable<T>::template SequentialEqualsComparer<T_EQUALS_COMPARER>;
184 * o using ThreeWayComparer = typename Iterable<T>::template SequentialThreeWayComparer<T_EQUALS_COMPARER>;
185 */
186 template <typename T>
187 class [[nodiscard]] Sequence : public Iterable<T> {
188 private:
189 using inherited = Iterable<T>;
190
191 protected:
192 class _IRep;
193
194 public:
195 /**
196 * @see inherited::value_type
197 */
199
200 public:
201 /**
202 * Use this typedef in templates to recover the basic functional container pattern of concrete types.
203 */
205
206 public:
207 /**
208 * For the CTOR overload with ITERABLE_OF_ADDABLE, its anything that supports c.begin(), c.end () to find
209 * all the elements.
210 *
211 * \note <a href="ReadMe.md#Container Constructors">See general information about container constructors that applies here</a>
212 *
213 * \par Example Usage
214 * \code
215 * Collection<int> c;
216 * std::vector<int> v;
217 *
218 * Sequence<int> s1 = {1, 2, 3};
219 * Sequence<int> s2 = s1;
220 * Sequence<int> s3{ s1 };
221 * Sequence<int> s4{ s1.begin (), s1.end () };
222 * Sequence<int> s5{ c };
223 * Sequence<int> s6{ v };
224 * Sequence<int> s7{ v.begin (), v.end () };
225 * Sequence<int> s8{ move (s1) };
226 * \endcode
227 */
228 Sequence ();
229 Sequence (Sequence&&) noexcept = default;
230 Sequence (const Sequence&) noexcept = default;
231 Sequence (const initializer_list<value_type>& src);
232 template <IIterableOfTo<T> ITERABLE_OF_ADDABLE>
233 requires (not derived_from<remove_cvref_t<ITERABLE_OF_ADDABLE>, Sequence<T>>)
234 explicit Sequence (ITERABLE_OF_ADDABLE&& src)
235#if qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
236 : Sequence{}
237 {
238 AppendAll (forward<ITERABLE_OF_ADDABLE> (src));
239 _AssertRepValidType ();
240 }
241#endif
242 ;
243 template <IInputIterator<T> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
244 Sequence (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end);
245
246 protected:
247 explicit Sequence (shared_ptr<_IRep>&& rep) noexcept;
248 explicit Sequence (const shared_ptr<_IRep>& rep) noexcept;
249
250 public:
251 /**
252 */
253 nonvirtual Sequence& operator= (Sequence&&) noexcept = default;
254 nonvirtual Sequence& operator= (const Sequence&) = default;
255
256 public:
257 /**
258 * \brief 'override' Iterable<>::Map () function so RESULT_CONTAINER defaults to Sequence, and improve that case to clone properties from this rep (such is rep type, etc).
259 */
260 template <typename RESULT_CONTAINER = Sequence<T>, invocable<T> ELEMENT_MAPPER>
261 nonvirtual RESULT_CONTAINER Map (ELEMENT_MAPPER&& elementMapper) const
262 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, typename RESULT_CONTAINER::value_type> or
263 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>);
264
265 public:
266 /**
267 * Apply the function function to each element, and return all the ones for which it was true.
268 *
269 * @see Iterable<T>::Where
270 */
271 template <derived_from<Iterable<T>> RESULT_CONTAINER = Sequence<T>, predicate<T> INCLUDE_PREDICATE>
272 nonvirtual RESULT_CONTAINER Where (INCLUDE_PREDICATE&& includeIfTrue) const;
273
274 public:
275 /**
276 *
277 * \par Example Usage
278 * \code
279 * Sequence<int> c { 3, 5, 9, 38, 3, 5 };
280 * EXPECT_TRUE (c.OrderBy () == Sequence<int> { 3, 3, 5, 5, 9, 38 });
281 * \endcode
282 *
283 * \par Example Usage
284 * \code
285 * Sequence<int> c { 3, 5, 9, 38, 3, 5 };
286 * EXPECT_TRUE (c.OrderBy ([](int lhs, int rhs) -> bool { return lhs < rhs; }) == Sequence<int> { 3, 3, 5, 5, 9, 38 });
287 * \endcode
288 *
289 * \note hides Iterable<T>::OrderBy since provides more specific types
290 *
291 * \note This performs a stable sort (preserving the relative order of items that compare equal).
292 * That maybe less performant than a regular (e.g. quicksort) but works better as a default, in most cases, as it allows combining multi-level sorts.
293 *
294 * @aliases Sort ()
295 *
296 * \note Should be of type IInOrderComparer, but not required - for convenience of use (so can be used with any lambda functor)
297 */
298 template <IPotentiallyComparer<T> INORDER_COMPARER_TYPE = less<T>>
299 nonvirtual Sequence OrderBy (INORDER_COMPARER_TYPE&& inorderComparer = INORDER_COMPARER_TYPE{}) const;
300
301 public:
302 /**
303 * simply indirect to @Iterable<T>::SequentialEqualsComparer
304 *
305 * A Sequence<T> doesn't generally require a comparison for individual elements
306 * be be defined, but obviously to compare if the containers are equal, you must
307 * compare the individual elements (at least sometimes).
308 *
309 * If operator==(T,T) is predefined, you can just call:
310 * \par Example Usage
311 * \code
312 * Sequence<int> a, b;
313 * if (a == b) {
314 * }
315 * \endcode
316 *
317 * or
318 * \code
319 * Sequence<int> a, b;
320 * if (Sequence<int>::EqualsComparer{eltComparer} (a, b)) {
321 * }
322 * \endcode
323 *
324 * to compare with an alternative comparer.
325 */
326 template <Common::IEqualsComparer<T> T_EQUALS_COMPARER = equal_to<T>>
328
329 public:
330 /**
331 */
332 template <typename ELEMENT_COMPARER = compare_three_way>
334
335 public:
336 /**
337 * simply indirect to @Sequence<>::EqualsComparer
338 */
339 nonvirtual bool operator== (const Sequence& rhs) const
340 requires (equality_comparable<T>);
341
342 public:
343 /**
344 * simply indirect to @Sequence<>::operator
345 */
346 nonvirtual auto operator<=> (const Sequence& rhs) const
347 requires (three_way_comparable<T>);
348
349 public:
350 /**
351 * \brief RemoveAll removes all, or all matching (predicate, iterator range, equals comparer or whatever) items.
352 *
353 * The no-arg overload removes all (quickly).
354 *
355 * The overloads that remove some subset of the items returns the number of items so removed.
356 *
357 * \note mutates container
358 */
359 nonvirtual void RemoveAll ();
360 template <predicate<T> PREDICATE>
361 nonvirtual size_t RemoveAll (PREDICATE&& p);
362
363 public:
364 /**
365 * \pre i < size ()
366 */
367 nonvirtual value_type GetAt (size_t i) const;
368
369 public:
370 /**
371 * \pre i < size ()
372 *
373 * \note mutates container
374 */
375 nonvirtual void SetAt (size_t i, ArgByValueType<value_type> item);
376
377 private:
378 struct TemporaryElementReference_;
379
380 public:
381 /**
382 * \brief alias for GetAt (i) - but returning const T
383 *
384 * @aliases GetAt
385 *
386 * \pre i < size ().
387 *
388 * \note this returns const value_type, so you cannot accidentally assign to the result
389 * a[3] = 4; // wont compile because return type const
390 *
391 * \note - we investigated having operator[] (int) return TemporaryElementReference_, but the trouble
392 * is that, though this almost works, the COST of TemporaryElementReference_ is much higher than
393 * returning the cost value_type, and its not super obvious at call point that you are getting the
394 * expensive or inexpensive version (depends on constness of this pointer).
395 *
396 * Also considered having this return T&, the way you would with std c++ vector (etc). This would avoid a lot
397 * of issues. BUT - it would BREAK the COW (copy-on-write) semantics. Consider if we had a single
398 * reference to a sequence. And we grab the value_type& (to update it; this doesn't increase refCnt for container). Then in another thread,
399 * we access the sequence (incrementing its reps ref count). We could be updating through that saved
400 * reference to T while the other thread is looking at the sequence - a dangerous race.
401 *
402 * So because all of this, use the syntax a(3) instead of a[3] if you want a modifiable reference
403 * (to call non-const methods on or to assign to).
404 */
405 nonvirtual const value_type operator[] (size_t i) const;
406
407 public:
408 /**
409 * \brief operator() is similar to operator[] - but returning TemporaryElementReference_, and so is updatable/writable
410 *
411 * See the notes on operator[]. The semantics of this method are similar to operator[],
412 * except that it returns a proxy object which allows (immediately) updating the element of the sequence.
413 *
414 * \par Example Usage
415 * \code
416 * Sequence<T> s = ...;
417 * s(2) = 4; // s[2] = 4; WONT COMPILE
418 * \endcode
419 *
420 * is equivalent to
421 * \code
422 * auto t = s.GetAt (2);
423 * t = 4;
424 * s.SetAt (2, i); // note when using operator() - this SetAt() dont even if t not updated so wasteful unless updating
425 * \endcode
426 *
427 * \pre i < size ()
428 *
429 * \note mutates container
430 */
431 nonvirtual TemporaryElementReference_ operator() (size_t i);
432
433 public:
434 /**
435 * Search the sequence and see if the given item is contained in
436 * it, and return the index of that item. Comparison is done with
437 * TRAITS::EqualsCompareFunctionType (which defaults to operator== (T, T))
438 * for first two overloads - third taking iterator always works)
439 *
440 * Note that the IndexOf(Iterator<T>) overload ignores the EQUALS_COMPARER
441 * but still must be a template method because non-template methods
442 * cannot be overloaded with template members.
443 *
444 * If not found for the by value overloads, IndexOf () return {};
445 * For the IndexOf(Iterator<T>) - \pre it is found/legal iterator
446 */
447 template <Common::IEqualsComparer<T> EQUALS_COMPARER = equal_to<T>>
448 nonvirtual optional<size_t> IndexOf (ArgByValueType<value_type> i, EQUALS_COMPARER&& equalsComparer = {}) const;
449 template <Common::IEqualsComparer<T> EQUALS_COMPARER = equal_to<T>>
450 nonvirtual optional<size_t> IndexOf (const Sequence& s, EQUALS_COMPARER&& equalsComparer = {}) const;
451 template <typename IGNORED = void>
452 nonvirtual size_t IndexOf (const Iterator<value_type>& i) const;
453
454 public:
455 /**
456 * Insert the given item into the sequence at the given index.
457 * Any active iterators will encounter the given item if their
458 * cursor encounters the new index in the course of iteration.
459 * Put another way, If you are iterating forwards, and you add an
460 * item after what you are up to you will hit it - if you are iterating
461 * backwards and you add an item before where you are, you will hit it -
462 * otherwise you will miss the added item during iteration.
463 *
464 * NB: Adding an item at the CURRENT index has no effect on
465 * what the iterator says is the current item.
466 *
467 * \note mutates container
468 */
469 nonvirtual void Insert (size_t i, ArgByValueType<value_type> item);
470 nonvirtual void Insert (const Iterator<value_type>& i, ArgByValueType<value_type> item);
471
472 public:
473 /**
474 * \brief Insert all the given items into this sequence, starting at offset 'i'.
475 *
476 * \pre IInputIterator<ITERATOR_OF_ADDABLE, T> or IIterableOfTo<ITERABLE_OF_ADDABLE, T>
477 */
478 template <IInputIterator<T> ITERATOR_OF_ADDABLE, sentinel_for<ITERATOR_OF_ADDABLE> ITERATOR_OF_ADDABLE2>
479 nonvirtual void InsertAll (size_t i, ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end);
480 template <IIterableOfTo<T> ITERABLE_OF_ADDABLE>
481 nonvirtual void InsertAll (size_t i, ITERABLE_OF_ADDABLE&& s);
482
483 public:
484 /**
485 * \note mutates container
486 */
487 nonvirtual void Prepend (ArgByValueType<value_type> item);
488
489 public:
490 /**
491 * \pre IInputIterator<ITERATOR_OF_ADDABLE, T> or IIterableOfTo<ITERABLE_OF_ADDABLE, T>
492 *
493 * \note mutates container
494 */
495 template <IIterableOfTo<T> ITERABLE_OF_ADDABLE>
496 nonvirtual void PrependAll (ITERABLE_OF_ADDABLE&& s);
497 template <IInputIterator<T> ITERATOR_OF_ADDABLE>
498 nonvirtual void PrependAll (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE&& end);
499
500 public:
501 /**
502 * This is roughly Insert (size(), item), except that there is a race after you call size, and before
503 * Insert, which calling Append () avoids.
504 *
505 * \note mutates container
506 */
507 nonvirtual void Append (ArgByValueType<value_type> item);
508
509 public:
510 /**
511 * This is roughly AppendAll (size(), s), except that there is a race after you call size,
512 * and before Insert, which calling Append () avoids. Also note - if used in a multithreaded environment,
513 * the appended items wont necessarily all get appended at once, since other threads could make
514 * changes in between.
515 *
516 * \note mutates container
517 */
518 template <IIterableOfTo<T> ITERABLE_OF_ADDABLE>
519 nonvirtual void AppendAll (ITERABLE_OF_ADDABLE&& s);
520 template <IInputIterator<T> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
521 nonvirtual void AppendAll (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end);
522
523 public:
524 /**
525 * This function requires that the iterator 'i' came from this container.
526 *
527 * The value pointed to by 'i' is updated - replaced with the value 'newValue'.
528 *
529 * \param nextI - if provided (not null) - will be filled in with a valid iterator pointing where i is pointing - since i is invalidated by changing the container)
530 *
531 * \note - this differs from Collection::Update() (which advances *nextI); since for a sequence, there is no need to ever
532 * invalidate the current item on a removal (order doesnt change on update to a Sequence).
533 *
534 * \note mutates container
535 */
536 nonvirtual void Update (const Iterator<value_type>& i, ArgByValueType<value_type> newValue, Iterator<value_type>* nextI = nullptr);
537
538 public:
539 /**
540 * This function requires that the iterator 'i' came from this container.
541 *
542 * The value pointed to by 'i' is removed.
543 *
544 * Remove the item at the given position of the sequence. Make sure
545 * that iteration is not disturbed by this removal. In particular, any
546 * items (other than the one at index) that would have been seen, will
547 * still be, and no new items will be seen that wouldn't have been.
548 *
549 * \note mutates container
550 */
551 nonvirtual void Remove (size_t i);
552 nonvirtual void Remove (size_t start, size_t end);
553 nonvirtual void Remove (const Iterator<value_type>& i, Iterator<value_type>* nextI = nullptr);
554
555 public:
556 /*
557 * Convert Sequence<T> losslessly into a standard supported C++ type.
558 * Supported types include:
559 * o vector<T>
560 * o list<T>
561 * (maybe any container that takes CTOR (IT BEGIN, IT END) - but don't count on that yet...
562 */
563 template <typename CONTAINER_OF_ADDABLE>
564 nonvirtual CONTAINER_OF_ADDABLE As () const;
565 template <typename CONTAINER_OF_ADDABLE>
566 nonvirtual void As (CONTAINER_OF_ADDABLE* into) const;
567
568 public:
569 /**
570 * @see Iterable<T>::First ()
571 */
572 nonvirtual optional<value_type> First () const;
573 nonvirtual optional<value_type> First (const function<bool (ArgByValueType<value_type>)>& that) const;
574
575 public:
576 /**
577 * @see Iterable<T>::FirstValue ()
578 */
579 nonvirtual value_type FirstValue (ArgByValueType<value_type> defaultValue = {}) const;
580
581 public:
582 /**
583 * @see Iterable<T>::Last ()
584 */
585 nonvirtual optional<value_type> Last () const;
586 nonvirtual optional<value_type> Last (const function<bool (ArgByValueType<value_type>)>& that) const;
587
588 public:
589 /**
590 * @see Iterable<T>::LastValue ()
591 */
592 nonvirtual value_type LastValue (ArgByValueType<value_type> defaultValue = {}) const;
593
594 public:
595 /**
596 * @aliases Append
597 *
598 * \note mutates container
599 */
600 nonvirtual void push_back (ArgByValueType<value_type> item);
601
602 public:
603 /**
604 * Read the last element (GetLast()). Requires not empty.
605 */
606 nonvirtual value_type back () const;
607
608 public:
609 /**
610 */
611 nonvirtual value_type front () const;
612
613 public:
614 /**
615 * @aliases RemoveAll ().
616 */
617 nonvirtual void clear ();
618
619 public:
620 /**
621 * @aliases Remove ().
622 *
623 * \note mutates container
624 */
625 nonvirtual void erase (size_t i);
626 nonvirtual Iterator<value_type> erase (const Iterator<value_type>& i);
627
628 public:
629 /**
630 * \brief Alias for Append/AppendAll ().
631 */
632 nonvirtual Sequence& operator+= (ArgByValueType<value_type> item);
633 nonvirtual Sequence& operator+= (const Sequence& items);
634
635 protected:
636 /**
637 * \brief Utility to get WRITABLE underlying shared_ptr (replacement for what we normally do - _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ())
638 * but where we also handle the cloning/patching of the associated iterator
639 *
640 * When you have a non-const operation (such as Remove) with an argument of an Iterator<>, then due to COW,
641 * you may end up cloning the container rep, and yet the Iterator<> contains a pointer to the earlier rep (and so maybe unusable).
642 *
643 * Prior to Stroika 2.1b14, this was handled elegantly, and automatically, by the iterator patching mechanism. But that was deprecated (due to cost, and
644 * rarity of use), in favor of this more restricted feature, where we just patch the iterators on an as-needed basis.
645 *
646 * \todo @todo - could be smarter about moves and avoid some copies here - I think, and this maybe performance sensitive enough to look into that... (esp for COMMON case where no COW needed)
647 */
648 nonvirtual tuple<_IRep*, Iterator<value_type>> _GetWritableRepAndPatchAssociatedIterator (const Iterator<value_type>& i);
649
650 protected:
651 /**
652 */
653 template <typename T2>
654 using _SafeReadRepAccessor = typename inherited::template _SafeReadRepAccessor<T2>;
655
656 protected:
657 /**
658 */
659 template <typename T2>
660 using _SafeReadWriteRepAccessor = typename inherited::template _SafeReadWriteRepAccessor<T2>;
661
662 protected:
663 nonvirtual void _AssertRepValidType () const;
664 };
665
666 /**
667 * \brief Implementation detail for Sequence<T> implementors.
668 *
669 * Protected abstract interface to support concrete implementations of
670 * the Sequence<T> container API.
671 */
672 template <typename T>
673 class Sequence<T>::_IRep : public Iterable<T>::_IRep {
674 private:
675 using inherited = typename Iterable<T>::_IRep;
676
677 protected:
678 _IRep () = default;
679
680 public:
681 virtual ~_IRep () = default;
682
683 protected:
684 static constexpr size_t _kSentinelLastItemIndex = numeric_limits<size_t>::max ();
685
686 public:
687 virtual shared_ptr<_IRep> CloneEmpty () const = 0;
688 virtual shared_ptr<_IRep> CloneAndPatchIterator (Iterator<value_type>* i) const = 0;
689 // 'i' argument to GetAt MAYBE kBadSequenceIndex - indicating last element
690 virtual value_type GetAt (size_t i) const = 0;
691 virtual void SetAt (size_t i, ArgByValueType<value_type> item) = 0;
692 virtual size_t IndexOf (const Iterator<value_type>& i) const = 0;
693 virtual void Remove (const Iterator<value_type>& i, Iterator<value_type>* nextI) = 0;
694 virtual void Update (const Iterator<value_type>& i, ArgByValueType<value_type> newValue, Iterator<value_type>* nextI) = 0;
695 // 'at' argument to Insert MAYBE kBadSequenceIndex - indicating append
696 virtual void Insert (size_t at, const value_type* from, const value_type* to) = 0;
697 virtual void Remove (size_t from, size_t to) = 0;
698
699 private:
700 friend Sequence<T>;
701 };
702
703 /**
704 * Basic operator overload with the obvious meaning (Sequence<T> copy and Sequence<T>::AppendAll)
705 */
706 template <typename T>
707 Sequence<T> operator+ (const Iterable<T>& lhs, const Sequence<T>& rhs);
708 template <typename T>
709 Sequence<T> operator+ (const Sequence<T>& lhs, const Iterable<T>& rhs);
710 template <typename T>
711 Sequence<T> operator+ (const Sequence<T>& lhs, const Sequence<T>& rhs);
712
713}
714
715/*
716 ********************************************************************************
717 ******************************* Implementation Details *************************
718 ********************************************************************************
719 */
720#include "Sequence.inl"
721
722#endif /*_Stroika_Foundation_Containers_Sequence_h_ */
Implementation detail for Sequence<T> implementors.
Definition Sequence.h:673
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Definition Sequence.h:187
nonvirtual void InsertAll(size_t i, ITERATOR_OF_ADDABLE &&start, ITERATOR_OF_ADDABLE2 &&end)
Insert all the given items into this sequence, starting at offset 'i'.
nonvirtual void PrependAll(ITERABLE_OF_ADDABLE &&s)
typename Iterable< value_type >::template SequentialEqualsComparer< T_EQUALS_COMPARER > EqualsComparer
Definition Sequence.h:327
typename inherited::value_type value_type
Definition Sequence.h:198
nonvirtual void Insert(size_t i, ArgByValueType< value_type > item)
Definition Sequence.inl:281
nonvirtual optional< size_t > IndexOf(ArgByValueType< value_type > i, EQUALS_COMPARER &&equalsComparer={}) const
nonvirtual void SetAt(size_t i, ArgByValueType< value_type > item)
Definition Sequence.inl:244
nonvirtual value_type GetAt(size_t i) const
Definition Sequence.inl:237
nonvirtual void Update(const Iterator< value_type > &i, ArgByValueType< value_type > newValue, Iterator< value_type > *nextI=nullptr)
Definition Sequence.inl:351
nonvirtual void AppendAll(ITERABLE_OF_ADDABLE &&s)
Implementation detail for iterator implementors.
Definition Iterable.h:1569
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237
T value_type
value_type is an alias for the type iterated over - like vector<T>::value_type
Definition Iterable.h:248
An Iterator<T> is a copyable object which allows traversing the contents of some container....
Definition Iterator.h:225
conditional_t<(sizeof(CHECK_T)<=2 *sizeof(void *)) and is_trivially_copyable_v< CHECK_T >, CHECK_T, const CHECK_T & > ArgByValueType
This is an alias for 'T' - but how we want to pass it on stack as formal parameter.
Definition TypeHints.h:32
Collection< T > operator+(const Iterable< T > &lhs, const Collection< T > &rhs)