Stroika Library 3.0d21
 
Loading...
Searching...
No Matches
Samples/Containers/Sources/Collection.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Foundation/StroikaPreComp.h"
5
8#include "Stroika/Foundation/Containers/Collection.h"
11
12// Not generally included, but you can include these if you want to select a particular backend implementation
16
18
19#include "Collection.h"
20
21using namespace std;
22
23using namespace Stroika::Foundation;
26
27using Characters::CompareOptions;
28
29namespace {
30 void SimplestCollectionTest_ ()
31 {
32 /*
33 * A Collection is the simplest form of Stroika container. You can add things, and remove them, and iterate over them.
34 * The order items appear (in iteration) is undefined.
35 * There are almost no requirements on the type of things you can add to a collection (except that it must be copyable). In particular,
36 * there is no need for comparison operators etc to be defined.
37 * View the class declaration, with all the methods well documented, must with examples of usage.
38 */
40 c.Add (3);
41 c += 13;
42 for ([[maybe_unused]] int i : c) {
43 Assert (i == 3 or i == 13);
44 }
45 Assert (c.size () == 2);
46 }
47}
48
49namespace {
50 void UseParticularConcreteRepresentation_ ()
51 {
52 {
53 Collection<int> c{3, 5, 19, 3040, 34, 1, 33, 33, 4, 19};
54
55 // Unclear what the performance characteristics of this will be - with a linked list - O(1), but with array, O(N) worst case.
56 c += 4;
57
58 // 'c' will now operate identically (same API) - but use a different backend datastructure for storage,
59 // always showing O(1) worst case addition time
61 c += 4;
62 }
63 {
65 Collection<String> fruits;
66 fruits += "apple";
67 fruits += "bananas";
68 fruits += "cherries";
69 fruits += "APPLE";
70 // Print (to debugger/tracelog) the fruits - but now they could come out in any order
71 DbgTrace ("fruits={}"_f, fruits);
72 Assert (fruits.size () == 4); // they are all there
73
74 // Like changing the backend. But this still respects all the rules of a Collection (no order specified) -
75 // except now it will happen to be ordered (using the default compare function)
76 fruits = SortedCollection<String>{fruits};
77 DbgTrace ("sorted fruits={}"_f, fruits);
78 Assert (fruits.size () == 4); // only one apple or the other (case squished)
79 // note they must now be in alphabetic order
80 Assert (fruits.SequentialEquals (initializer_list<String>{"APPLE", "apple", "bananas", "cherries"}));
81
82 // But, we can do the same thing with a compare function that sorts case insensitively
83 fruits = SortedCollection<String>{String::LessComparer{CompareOptions::eCaseInsensitive}, fruits};
84 DbgTrace ("sorted case insensitive fruits={}"_f, fruits);
85 Assert (fruits.SequentialEquals (initializer_list<String>{"apple", "APPLE", "bananas", "cherries"}) or
86 fruits.SequentialEquals (initializer_list<String>{"APPLE", "apple", "bananas", "cherries"}));
87 }
88 }
89}
90
91namespace {
92 void InterfaceWithSTLContainers_ ()
93 {
94 vector<int> aVector{1, 3, 5, 7, 9, 11};
95 Collection<int> c{aVector};
96
97 // CANNOT guarantee the ordering is the same, as Collection guarantees it keeps all the same elements,
98 // but does not guarantee maintaining order.
99 Assert (c.SetEquals (aVector));
100 Assert (c.SequentialEquals (aVector) or not c.SequentialEquals (aVector));
101
102 vector<int> v2 = c.As<vector<int>> ();
103 // V will contain all the same elements as aVector, but maybe not in the same order.
104 // it will be in the order the 'c' collection happened to produce
105 }
106}
107
108namespace {
109 void PrintTheContentsOfAContainerToTheTraceLog_ ()
110 {
111 /*
112 * Use DbgTrace (and often implicitly Characters::ToString ()) to echo objects to a tracelog file (and/or debugger output under windows)
113 */
114 Debug::TraceContextBumper ctx{L"PrintTheContentsOfAContainerToTheTraceLog_"};
115 Collection<int> tmp{1, 3, 5, 7, 9};
116 DbgTrace ("tmp={}"_f, tmp);
117 }
118}
119
120namespace {
121 void UseLinqLikeFunctionalAPIs_ ()
122 {
123 Debug::TraceContextBumper ctx{L"PrintTheContentsOfAContainerToTheTraceLog_"};
124 /*
125 * See the Iterable<> template in Iterable.h - for a ton more of this functional style linq-like operations
126 * you can do on any Stroika container.
127 *
128 * While most of these 'linq like' APIs are also present in STL as '<algorithms>' - those algorithms
129 * are much hard to use (due to how templates work, and how you must pass 2 iterators, and they aren't
130 * member functions of the container).
131 */
132 {
133 Collection<int> tmp{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
134 auto whereTestResult = tmp.Where ([] (int i) { return i % 2 == 1; });
135 DbgTrace ("whereTestResult={}"_f, whereTestResult);
136 }
137 {
138 Collection<int> tmp{1, 2, 3, 4, 5, 1, 2, 3, 4, 5};
139 auto d = tmp.Distinct ();
140 DbgTrace ("d={}"_f, d);
141 Assert (d.SetEquals (initializer_list<int>{1, 2, 3, 4, 5}));
142 }
143 {
144 using Characters::String;
145 Collection<String> fruits;
146 fruits += "apple";
147 fruits += "APPLE";
148 fruits += "bananas";
149 fruits += "cherries";
150 DbgTrace ("fruits={}"_f, fruits.Distinct (String::EqualsComparer{CompareOptions::eCaseInsensitive}));
151 Assert (fruits.Distinct (String::EqualsComparer{CompareOptions::eCaseInsensitive}).size () == 3); // only one apple or the other (case squished)
152 }
153 }
154}
155
156namespace {
157 void CollectionOfThingsWithNoOpEqualsAndNotDefaultConstructibleEtc_ ()
158 {
159 struct MyFunnyObject_ {
160 MyFunnyObject_ () = delete; // no need to be default constructible
161 MyFunnyObject_ (int /*n*/)
162 {
163 // need some constructor to test
164 }
165 MyFunnyObject_ (const MyFunnyObject_&) = default; // OK, but you do need to be copyable
166 };
168 myObjects.Add (MyFunnyObject_{3});
169 myObjects += MyFunnyObject_{4}; // use whatever add syntax you want
170
171 // THIS WONT WORK, because no operator== defined
172 // myObjects.Remove (MyFunnyObject_{3});
173 // but this will remove the first object found
174 Assert (myObjects.size () == 2);
175 myObjects.Remove (MyFunnyObject_{3}, [] (const MyFunnyObject_&, const MyFunnyObject_&) { return true; });
176 Assert (myObjects.size () == 1);
177 }
178}
179
180namespace {
181 /*
182 * This is just like STL containers. You cannot (generally) update a container while iterating,
183 * except that some APIs allow the iterators to be updated as part of the update process (like erase).
184 *
185 * Unlike STL (generally - some implementations may offer this) - in DEBUG builds, Stroika will detect use
186 * of an invalid iterator and trigger an assertion.
187 */
188 void UpdatingContainerWhileIterating_ ()
189 {
190 using Characters::String;
191 Collection<String> fruits;
192 fruits += "apple";
193 fruits += "APPLE";
194 fruits += "bananas";
195 fruits += "cherries";
196
197 {
198 // Note how Stroika iterators have a type that depends on the type of thing you are iterating over, but
199 // UNLIKE STL containers, their type does NOT depend on the type of the underlying container you are iterating over.
200 // This is a great simplication of APIs (passing iterators to functions no longer requires templates), but
201 // comes at a slight cost (operator++ involves a virtual function call to get the next item).
202 Iterator<String> i = fruits.Find ([] (String i) { return i == "apple"; });
203 Assert (i != fruits.end ());
204 Assert (fruits.size () == 4);
205 }
206 for (Iterator<String> i = fruits.begin (); i != fruits.end ();) {
207 if (String::EqualsComparer{CompareOptions::eCaseInsensitive}(*i, "apple")) {
208 fruits.Remove (i, &i); // 'i' has already been updated to refer to the next element, regardless of how the Collection<> represents its data
209 // If you forget to pass in &i and continue iterating, this is a DETECTED bug (in debug builds)
210 // And stroika will assert out when you next use the iterator (i++).
211 }
212 else {
213 ++i;
214 }
215 }
216 Assert (fruits.size () == 2);
217 }
218}
219
220void Samples::Containers::Collection::RunDemo ()
221{
222 SimplestCollectionTest_ ();
223 UseParticularConcreteRepresentation_ ();
224 InterfaceWithSTLContainers_ ();
225 PrintTheContentsOfAContainerToTheTraceLog_ ();
226 UseLinqLikeFunctionalAPIs_ ();
227 CollectionOfThingsWithNoOpEqualsAndNotDefaultConstructibleEtc_ ();
228 UpdatingContainerWhileIterating_ ();
229}
#define DbgTrace
Definition Trace.h:309
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
A Collection<T> is a container to manage an un-ordered collection of items, without equality defined ...
nonvirtual void Remove(ArgByValueType< value_type > item, EQUALS_COMPARER &&equalsComparer={})
Remove () the argument value (which must exist)
nonvirtual RESULT_CONTAINER Where(INCLUDE_PREDICATE &&includeIfTrue) const
return a subset of the Collection for which includeIfTrue returns true.
nonvirtual void Add(ArgByValueType< value_type > item)
Collection_stdforward_list<T> is an std::forward_list (singly linked list)-based concrete implementat...
A SortedCollection is a Collection<T> which remains sorted (iteration produces items sorted) even as ...
nonvirtual Iterator< T > Find(THAT_FUNCTION &&that, Execution::SequencePolicy seq=Execution::SequencePolicy::eDEFAULT) const
Run the argument bool-returning function (or lambda) on each element of the container,...
nonvirtual Iterable< T > Distinct(EQUALS_COMPARER &&equalsComparer=EQUALS_COMPARER{}) const
nonvirtual size_t size() const
Returns the number of items contained.
Definition Iterable.inl:302
nonvirtual Iterator< T > begin() const
Support for ranged for, and STL syntax in general.
static bool SequentialEquals(const LHS_CONTAINER_TYPE &lhs, const RHS_CONTAINER_TYPE &rhs, EQUALS_COMPARER &&equalsComparer=EQUALS_COMPARER{}, bool useIterableSize=false)
Definition Iterable.inl:398
static constexpr default_sentinel_t end() noexcept
Support for ranged for, and STL syntax in general.
An Iterator<T> is a copyable object which allows traversing the contents of some container....
Definition Iterator.h:225
Create a format-string (see std::wformat_string or Stroika FormatString, or python 'f' strings.
STL namespace.
very similar to ThreeWayComparer but returns true if less
Definition String.h:1867