Lumiera 0.pre.04
»edit your freedom«
Loading...
Searching...
No Matches
extent-family-test.cpp
Go to the documentation of this file.
1/*
2 ExtentFamily(Test) - verify cyclic extents allocation scheme
3
4 Copyright (C)
5 2023, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12* *****************************************************************/
13
19#include "lib/test/run.hpp"
21#include "lib/iter-explorer.hpp"
22#include "lib/util.hpp"
23
24#include <utility>
25
26using test::Test;
27using util::isnil;
29using lib::explore;
30
31
32namespace vault{
33namespace mem {
34namespace test {
35
37 using Extent = Extents::Extent;
38 using Iter = Extents::iterator;
39
40
41
42
43 /***************************************************************/
48 class ExtentFamily_test : public Test
49 {
50
51 virtual void
52 run (Arg)
53 {
54 seedRand();
57 iteration();
59 wrapAround();
60 }
61
62
65 void
67 {
68 Extents extents{5};
69 extents.openNew();
70 Extent& extent = *extents.begin();
71 CHECK (10 == extent.size());
72
73 int num = rani(1000);
74 extent[2] = num;
75 extent[5] = num+5;
76 CHECK (num == extent[2]);
77 CHECK (num+5 == extent[5]);
78 }
79
80
81
84 void
86 {
87 Extents extents{5};
88 CHECK ( 0 == watch(extents).first());
89 CHECK ( 0 == watch(extents).last());
90 CHECK ( 0 == watch(extents).active());
91 CHECK ( 5 == watch(extents).size());
92
93 extents.openNew(3);
94 CHECK ( 0 == watch(extents).first());
95 CHECK ( 3 == watch(extents).last());
96 CHECK ( 3 == watch(extents).active());
97 CHECK ( 5 == watch(extents).size());
98
99 extents.dropOld(2);
100 CHECK ( 2 == watch(extents).first());
101 CHECK ( 3 == watch(extents).last());
102 CHECK ( 1 == watch(extents).active());
103 CHECK ( 5 == watch(extents).size());
104 }
105
106
107
111 void
113 {
114 Extents extents{5};
115 CHECK (isnil (extents));
116 Iter it = extents.begin();
117 CHECK (isnil (it)); // no extents provided yet
118
119 extents.openNew(2); // allot two extents for active use
120 CHECK (it);
121 CHECK (0 == it.getIndex());
122 CHECK (isSameObject(*it, *extents.begin()));
123
124 Extent& extent{*it};
125 CHECK (10 == extent.size());
126
127 int num = rani(1000);
128 extent[2] = num;
129 CHECK (num == extent[2]);
130
131 ++it;
132 CHECK (it);
133 CHECK (1 == it.getIndex());
134 Extent& nextEx{*it};
135 CHECK (not isSameObject(extent, nextEx));
136 CHECK (isSameObject(nextEx, *extents.last()));
137 nextEx[5] = extent[2] + 1;
138 CHECK (num == extent[2]);
139 CHECK (num+1 == nextEx[5]);
140
141 ++it;
142 CHECK (it == extents.end());
143 CHECK (isnil (it)); // only two allocated
144 it.expandAlloc(); // but can expand allocation
145 CHECK (it);
146
147 // iterate again to verify we get the same memory blocks
148 it = extents.begin();
149 CHECK (isSameObject(*it, extent));
150 CHECK ((*it)[2] == num);
151 ++it;
152 CHECK (isSameObject(*it, nextEx));
153 CHECK ((*it)[5] == num+1);
154 }
155
156
157
161 void
163 {
164 struct Probe
165 {
166 short val;
167 Probe() : val(1 + rani(1000)) { }
168 ~Probe() { val = 0; }
169 };
170
171 using SpecialExtents = ExtentFamily<Probe, 1000>;
172
173 SpecialExtents spex{3};
174 spex.openNew(2);
175 CHECK ( 0 == watch(spex).first());
176 CHECK ( 2 == watch(spex).last());
177
178 // implant a new Probe object into each »slot« of the new extent
179 auto& extent = *spex.begin();
180 for (Probe& probe : extent)
181 new(&probe) Probe;
182
183 auto calcChecksum = [](SpecialExtents::Extent& extent) -> size_t
184 {
185 size_t sum{0};
186 for (Probe& probe : extent)
187 sum += probe.val;
188 return sum;
189 };
190
191 size_t checksum = calcChecksum (*spex.begin());
192
193 // discard first extent, i.e. mark it as unused
194 // while the underlying memory block remains allocated
195 // and data within this block is not touched
196 spex.dropOld(1);
197 CHECK ( 1 == watch(spex).first());
198 CHECK ( 2 == watch(spex).last());
199
200 // the »begin« (i.e. the first active extent is now another memory block
201 CHECK (not isSameObject (extent, *spex.begin()));
202 size_t checkSecond = calcChecksum (*spex.begin());
203 CHECK (checkSecond != checksum);
204
205 // but the random data generated above still sits in the original (first) memory block
206 CHECK (checksum == calcChecksum (extent));
207
208 // now let the actively allotted extents "wrap around"...
209 spex.dropOld(1);
210 CHECK ( 2 == watch(spex).first());
211 CHECK ( 2 == watch(spex).last());
212 spex.openNew(2);
213 CHECK ( 2 == watch(spex).first());
214 CHECK ( 1 == watch(spex).last());
215
216 auto iter = spex.begin();
217 CHECK ( 2 == iter.getIndex());
218 ++iter;
219 CHECK ( 0 == iter.getIndex());
220 CHECK (isSameObject(*iter, extent));
221
222 // and during all those allotting and dropping, data in the memory block was not touched,
223 // which also proves that constructors or destructors of the nominal "content" are not invoked
224 CHECK (checksum == calcChecksum (extent));
225 }
226
227
228
237 void
239 {
240 // Helper to capture the storage addresses of all currently active Extents
241 auto snapshotAdr = [](Extents& extents)
242 {
243 auto takeAdr = [](auto& x){ return &*x; };
244 return explore(extents).transform(takeAdr).effuse();
245 };
246 auto verifyAdr = [](auto snapshot, auto it)
247 {
248 for (auto oldAddr : snapshot)
249 {
250 if (not isSameObject(*oldAddr, *it))
251 return false;
252 ++it;
253 }
254 return true;
255 };
256
257
258 Extents extents{5};
259 CHECK ( extents.empty());
260 CHECK ( 0 == watch(extents).first());
261 CHECK ( 0 == watch(extents).last());
262 CHECK ( 0 == watch(extents).active());
263 CHECK ( 5 == watch(extents).size());
264
265 extents.openNew(4);
266 CHECK ( 0 == watch(extents).first());
267 CHECK ( 4 == watch(extents).last());
268 CHECK ( 4 == watch(extents).active());
269 CHECK ( 5 == watch(extents).size());
270
271 auto snapshot = snapshotAdr(extents); // capture *addresses* of currently active Extents
272 CHECK (4 == snapshot.size());
273
274 extents.openNew();
275 CHECK ( 0 == watch(extents).first());
276 CHECK ( 5 == watch(extents).last());
277 CHECK ( 5 == watch(extents).active());
278 CHECK (10 == watch(extents).size()); // Note: heuristics to over-allocate to some degree
279 CHECK (verifyAdr (snapshot, extents.begin()));
280
281 extents.dropOld(3); // place the active window such as to start on last snapshotted Extent
282 CHECK ( 3 == watch(extents).first());
283 CHECK ( 5 == watch(extents).last());
284 CHECK ( 2 == watch(extents).active());
285 CHECK (10 == watch(extents).size());
286 CHECK (isSameObject (*extents.begin(), *snapshot.back()));
287
288 extents.openNew(6); // now provoke a »wrapped« state of internal management of active Extents
289 CHECK ( 3 == watch(extents).first()); // ...Note: the position of the *first* active Extent...
290 CHECK ( 1 == watch(extents).last()); // ... is *behind* the position of the last active Extent
291 CHECK ( 8 == watch(extents).active()); // ... implying that the active strike wraps at allocation end
292 CHECK (10 == watch(extents).size());
293 snapshot = snapshotAdr (extents); // take a new snapshot; this also verifies proper iteration
294 CHECK (8 == snapshot.size());
295
296 extents.openNew(2); // ask for more than can be accommodated without ambiguity
297 CHECK ( 8 == watch(extents).first()); // ...Note: new allocation was inserted, existing tail shifted
298 CHECK ( 3 == watch(extents).last()); // ... allowing for the requested two »slots« to be accommodated
299 CHECK (10 == watch(extents).active());
300 CHECK (15 == watch(extents).size());
301 CHECK (verifyAdr (snapshot, extents.begin())); // ... yet all existing Extent addresses have been rotated transparently
302
303 extents.dropOld(10); // close out all active slots, wrapping the first-pos to approach last
304 CHECK ( 3 == watch(extents).first());
305 CHECK ( 3 == watch(extents).last());
306 CHECK ( 0 == watch(extents).active());
307 CHECK (15 == watch(extents).size());
308
309 extents.openNew(12); // provoke a special boundary situation, where the end is *just wrapped*
310 CHECK ( 3 == watch(extents).first());
311 CHECK ( 0 == watch(extents).last());
312 CHECK (12 == watch(extents).active());
313 CHECK (15 == watch(extents).size());
314
315 extents.dropOld(11); // and make this boundary situation even more nasty, just sitting on the rim
316 CHECK (14 == watch(extents).first());
317 CHECK ( 0 == watch(extents).last());
318 CHECK ( 1 == watch(extents).active());
319 CHECK (15 == watch(extents).size());
320
321 CHECK (14 == extents.begin().getIndex());
322 snapshot = snapshotAdr (extents); // verify iteration end just after wrapping properly detected
323 CHECK (1 == snapshot.size());
324 CHECK (isSameObject (*extents.begin(), *snapshot.front()));
325
326 extents.openNew(14); // and now provoke further expansion, adding new allocation right at start
327 CHECK (19 == watch(extents).first()); // ...Note: first must be relocated to sit again at the very rim
328 CHECK (14 == watch(extents).last()); // ... to allow last to sit at the index previously used by first
329 CHECK (15 == watch(extents).active());
330 CHECK (20 == watch(extents).size());
331
332 CHECK (19 == extents.begin().getIndex()); // ... yet address of the first Extent remains the same, just held in another slot
333 CHECK (isSameObject (*extents.begin(), *snapshot.front()));
334 }
335 };
336
337
339 LAUNCHER (ExtentFamily_test, "unit memory");
340
341
342
343}}} // namespace vault::mem::test
Abstract Base Class for all testcases.
Definition run.hpp:54
void seedRand()
draw a new random seed from a common nucleus, and re-seed the default-Gen.
Definition suite.cpp:211
Memory manager to provide a sequence of Extents for cyclic usage.
void openNew(size_t cnt=1)
claim next cnt extents, possibly allocate.
Memory management scheme for cyclically used memory extents.
Building tree expanding and backtracking evaluations within hierarchical scopes.
auto explore(IT &&srcSeq)
start building a IterExplorer by suitably wrapping the given iterable source.
Test runner and basic definitions for tests.
bool isSameObject(A const &a, B const &b)
compare plain object identity, based directly on the referee's memory identities.
Definition util.hpp:421
bool isnil(lib::time::Duration const &dur)
ExtentFamily< int, 10 > Extents
Extents::Extent Extent
Extents::iterator Iter
ExtentDiagnostic< T, siz > watch(ExtentFamily< T, siz > &extentFamily)
Vault-Layer implementation namespace root.
Simplistic test class runner.
#define LAUNCHER(_TEST_CLASS_, _GROUPS_)
Definition run.hpp:116
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...