Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
memarray.cc
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
33
38# include <gtest/gtest.h>
39
40# include <tpl_memArray.H>
41# include <htlist.H>
42# include <limits>
43# include <memory>
44
45using namespace std;
46using namespace testing;
47using namespace Aleph;
48
49bool is_power_of_two(size_t x)
50{
51 return ((x != 0) && !(x & (x - 1))) != 0;
52}
53
54struct Default_MemArray : public Test
55{
56 const size_t n = 64;
58};
59
61{
64 {
65 for (size_t i = 0; i < 30; ++i)
66 m.append(i);
67 }
68};
69
71{
72 {
74 EXPECT_TRUE(is_power_of_two(m1.capacity()));
75 EXPECT_EQ(m1.size(), 0);
76 EXPECT_TRUE(m1.is_empty());
77 EXPECT_THROW(m1.get(), underflow_error);
78 }
79
80 {
81 MemArray<int> m1(32);
82 EXPECT_TRUE(is_power_of_two(m1.capacity()));
83 EXPECT_EQ(m1.size(), 0);
84 EXPECT_TRUE(m1.is_empty());
85 EXPECT_THROW(m1.get(), underflow_error);
86
87 MemArray<int> m2(31);
88 MemArray<int> m3(17);
89 EXPECT_TRUE(is_power_of_two(m2.capacity()));
90 EXPECT_TRUE(m2.is_empty());
91 EXPECT_TRUE(m3.is_empty());
92 EXPECT_EQ(m2.size(), 0);
93 EXPECT_EQ(m3.size(), 0);
94 EXPECT_EQ(m1.capacity(), m2.capacity());
95 EXPECT_EQ(m1.capacity(), m3.capacity());
96 }
97
98 {
99 MemArray<int> m1(512);
100 EXPECT_TRUE(is_power_of_two(m1.capacity()));
101 EXPECT_EQ(m1.size(), 0);
102 EXPECT_TRUE(m1.is_empty());
103 EXPECT_THROW(m1.get(), underflow_error);
104
105 MemArray<int> m2(257);
106 MemArray<int> m3(316);
107 EXPECT_TRUE(is_power_of_two(m2.capacity()));
108 EXPECT_TRUE(m2.is_empty());
109 EXPECT_TRUE(m3.is_empty());
110 EXPECT_EQ(m2.size(), 0);
111 EXPECT_EQ(m3.size(), 0);
112 EXPECT_EQ(m1.capacity(), m2.capacity());
113 EXPECT_EQ(m1.capacity(), m3.capacity());
114 }
115
116 {
117 MemArray<int> m1(4096);
118 EXPECT_TRUE(is_power_of_two(m1.capacity()));
119 EXPECT_EQ(m1.size(), 0);
120 EXPECT_TRUE(m1.is_empty());
121 EXPECT_THROW(m1.get(), underflow_error);
122
123 MemArray<int> m2(2049);
124 MemArray<int> m3(3000);
125 EXPECT_TRUE(is_power_of_two(m2.capacity()));
126 EXPECT_TRUE(m2.is_empty());
127 EXPECT_TRUE(m3.is_empty());
128 EXPECT_EQ(m2.size(), 0);
129 EXPECT_EQ(m3.size(), 0);
130 EXPECT_EQ(m1.capacity(), m2.capacity());
131 EXPECT_EQ(m1.capacity(), m3.capacity());
132 }
133}
134
136{
137 const size_t n = m.capacity();
138 for (size_t i = 0; i < n; ++i)
139 m.append(i);
140
141 EXPECT_EQ(m.size(), n);
142 EXPECT_EQ(m.capacity(), n);
143
144 m.append(n); // this append would cause expansion
145 EXPECT_EQ(m.capacity(), 2 * n);
146 EXPECT_EQ(m.size(), n + 1);
147 EXPECT_EQ(m.get_first(), 0);
148 EXPECT_EQ(m.get_last(), n);
149
150 // testing gap opening
151 m.insert(-1);
152 EXPECT_EQ(m.get_first(), -1);
153 EXPECT_EQ(m.get_last(), n);
154
155 EXPECT_THROW(m[m.size()], out_of_range);
156 EXPECT_THROW(m[m.capacity()], out_of_range);
157
158 { // Testing operator [] in read mode
159 int k = -1;
160 for (size_t i = 0; i < m.size(); ++i, ++k)
161 EXPECT_EQ(m[i], k);
162 EXPECT_EQ(k, n + 1);
163 }
164
165 { // Testing operator [] in write mode
166 for (size_t i = 0; i < m.size(); ++i)
167 m[i]++;
168
169 int k = 0;
170 for (size_t i = 0; i < m.size(); ++i, ++k)
171 EXPECT_EQ(m[i], k);
172 EXPECT_EQ(k, n + 2);
173 }
174}
175
177{
178 const size_t dim = m.capacity();
179
180 m.putn(dim + 1); // This will cause expansion
181
182 EXPECT_EQ(m.capacity(), 2 * dim); // Verify expansion
184 EXPECT_EQ(m.size(), dim + 1);
185
186 for (size_t i = 0; i < m.size(); ++i)
187 {
188 EXPECT_NO_THROW(m[i]);
189 m[i] = i;
190 }
191
192 EXPECT_THROW(m[m.size()], out_of_range);
193 EXPECT_THROW(m.get(m.size() + 1), underflow_error);
194
195 size_t k = 0;
196 EXPECT_NE(m.size(), k);
197 for (size_t i = 0; i < m.size(); ++i, ++k)
198 EXPECT_EQ(m[i], i);
199 EXPECT_EQ(k, m.size()); // TEST that loop has been executed
200
201 const size_t curr_cap = m.capacity();
202 const size_t avail = m.capacity() - m.size();
203 m.putn(avail); // this shouldn't cause expansion
204
206 EXPECT_EQ(m.size(), m.capacity());
207
208 int item;
209 EXPECT_NO_THROW(item = m.get(m.size())); // it must take out all items
210
211 EXPECT_EQ(item, 0);
213 EXPECT_EQ(m.size(), 0);
214}
215
217{
219
220 auto p1 = std::make_unique<int>(5);
221 auto p2 = std::make_unique<int>(7);
222
223 m.append(std::move(p1));
224 m.append(std::move(p2));
225
226 ASSERT_EQ(m.size(), 2u);
227 EXPECT_EQ(*m[0], 5);
228 EXPECT_EQ(*m[1], 7);
229
230 auto last = m.remove_last();
231 EXPECT_EQ(*last, 7);
232 EXPECT_EQ(m.size(), 1u);
233
234 auto first = m.remove_first();
235 EXPECT_EQ(*first, 5);
237}
238
240{
242 EXPECT_EQ(m.size(), 0);
243 EXPECT_NE(m.capacity(), 0);
244
245 const size_t cap1 = m.capacity();
246
247 // Test invalid accesses without insertion neither expansion
248 size_t k = 0;
249 for (size_t i = 0; i < m.capacity(); ++i, ++k)
250 EXPECT_THROW(m[i], out_of_range);
251 EXPECT_EQ(k, m.capacity());
252 EXPECT_EQ(m.capacity(), cap1); // capacity has not changed
254 EXPECT_EQ(m.size(), 0);
255
256 // Insert until capacity (no expansion)
257 k = 0;
258 for (size_t i = 0; i < m.capacity(); ++i, ++k)
259 m.append(i);
260 EXPECT_EQ(k, m.capacity());
261 EXPECT_EQ(m.size(), m.capacity());
262
263 // Test that item were inserted
264 k = 0;
265 for (size_t i = 0; i < m.capacity(); ++i, ++k)
266 {
267 EXPECT_NO_THROW(m[i]);
268 EXPECT_EQ(m[i], i);
269 }
270 EXPECT_EQ(k, m.capacity());
271
272 // Now we cause an expansion
273 k = 0;
274 for (size_t i = m.size(); i < 2 * cap1; ++i, ++k)
275 m.append(i);
276
277 EXPECT_EQ(k, cap1);
278 EXPECT_EQ(m.capacity(), 2 * cap1);
279 EXPECT_EQ(m.size(), 2 * cap1);
280
281 k = 0;
282 for (size_t i = 0; i < m.size(); ++i, ++k)
283 {
284 EXPECT_NO_THROW(m[i]);
285 EXPECT_EQ(m[i], i);
286 }
287 EXPECT_EQ(k, m.capacity());
288}
289
291{
292 const size_t cap = m.capacity();
294 EXPECT_NE(m.capacity(), 0);
295 EXPECT_EQ(m.size(), 0);
296
297 m.reserve(2 * cap + 1); // this should expand to 4*cap
298 EXPECT_EQ(m.capacity(), 4 * cap);
299}
300
302{
304 EXPECT_EQ(m.size(), 30);
305 EXPECT_EQ(m.capacity(), 32);
306 size_t k = 0;
307 for (size_t i = 0; i < m.size(); ++i, ++k)
308 EXPECT_EQ(m[i], i);
309 EXPECT_EQ(k, m.size());
310
311 { // Copy constructor
312 MemArray<int> aux = m;
313 EXPECT_FALSE(aux.is_empty());
314 EXPECT_EQ(aux.size(), 30);
315 EXPECT_EQ(aux.capacity(), 32);
316 size_t k = 0;
317 for (size_t i = 0; i < m.size(); ++i, ++k)
318 EXPECT_EQ(aux[i], i);
319 EXPECT_EQ(k, m.size());
320 EXPECT_NE(m.get_ptr(), aux.get_ptr());
321 }
322
323 { // move constructor
324 auto ptr = m.get_ptr();
325 MemArray<int> aux = move(m);
326 EXPECT_EQ(aux.get_ptr(), ptr);
327 EXPECT_FALSE(aux.is_empty());
328 EXPECT_EQ(aux.size(), 30);
329 EXPECT_EQ(aux.capacity(), 32);
331 EXPECT_EQ(m.size(), 0);
332 EXPECT_EQ(m.capacity(), 0);
333 EXPECT_EQ(m.get_ptr(), nullptr); // array of zero must be nullptr
334 size_t k = 0;
335 for (size_t i = 0; i < m.size(); ++i, ++k)
336 EXPECT_EQ(aux[i], i);
337 EXPECT_EQ(k, m.size());
338 EXPECT_NE(m.get_ptr(), aux.get_ptr());
339
340 m.swap(aux); // restore m to previous initialized state
341 EXPECT_EQ(m.get_ptr(), ptr);
342 EXPECT_TRUE(aux.is_empty());
343 EXPECT_EQ(aux.size(), 0);
344 EXPECT_EQ(aux.capacity(), 0);
346 EXPECT_EQ(m.size(), 30);
347 EXPECT_EQ(m.capacity(), 32);
348 k = 0;
349 for (size_t i = 0; i < m.size(); ++i, ++k)
350 EXPECT_EQ(m[i], i);
351 EXPECT_EQ(k, m.size());
352 }
353
354 // copy assigment
355 MemArray<int> aux;
356 EXPECT_TRUE(aux.is_empty());
357 EXPECT_EQ(aux.size(), 0);
358 EXPECT_NE(aux.capacity(), 0);
359 EXPECT_NE(aux.get_ptr(), nullptr);
360
361 aux = m;
362 EXPECT_FALSE(aux.is_empty());
363 EXPECT_NE(m.size(), 0);
364 EXPECT_EQ(aux.size(), m.size());
365 EXPECT_EQ(aux.capacity(), m.capacity());
367 EXPECT_NE(m.size(), 0);
368 EXPECT_NE(m.capacity(), 0);
369 EXPECT_NE(m.get_ptr(), aux.get_ptr()); // array of zero must be nullptr
370 k = 0;
371 for (size_t i = 0; i < m.size(); ++i, ++k)
372 EXPECT_EQ(aux[i], m[i]);
373 EXPECT_EQ(k, m.size());
374
375 // TODO move assigment
376}
377
379{
380 MemArray<int> m(0);
381 EXPECT_NE(m.capacity(), 0);
382 EXPECT_EQ(m.size(), 0);
383 EXPECT_NE(m.get_ptr(), nullptr);
385}
386
388{
390 EXPECT_EQ(m.size(), 0);
392
393 size_t N = 0;
394 for (size_t i = 0; i < 10; ++i)
395 {
398 for (size_t k = 0; k < 10; ++k, ++N)
399 l.append(N);
401 m.insert(move(l));
403 }
404
405 size_t n = 0;
406 for (long i = 9; i >= 0; --i) // descending for matching values of N
407 {
408 const DynList<int> &l = m[i];
410 for (auto it = l.get_it(); it.has_curr(); it.next(), ++n)
411 EXPECT_EQ(it.get_curr(), n);
412 }
413}
414
416{
417 constexpr size_t num_items = 10;
419 size_t N = 0;
420 for (size_t i = 0; i < num_items; ++i)
421 {
424 for (size_t k = 0; k < num_items; ++k, ++N)
425 l.insert(N);
427 m.insert(move(l));
429 }
430
431 size_t n = N - 1;
432 for (size_t i = 0; i < num_items; ++i)
433 {
434 DynList<int> l = m.remove_first();
435 auto it = l.get_it();
436 for (size_t k = 0; k < 10; ++k, it.next(), --n)
437 EXPECT_EQ(it.get_curr(), n);
438 assert(num_items - i < m.capacity()); // hard assert. Better leave it!
439 EXPECT_TRUE(m(num_items - i - 1).is_empty()); // verify moving
440 }
441}
442
444{
445 for (size_t i = 0; i < n; ++i)
446 m.append(i);
447
448 EXPECT_EQ(m.capacity(), n);
449 EXPECT_EQ(m.capacity(), m.size());
450
451 size_t N = m.capacity();
452 for (size_t i = 0; i < n; ++i)
453 {
454 EXPECT_EQ(m.remove_last(), n - i - 1);
455 if (m.size() == N / 4 - 1 and m.size() > m.contract_threshold)
456 {
457 N /= 2;
458 EXPECT_EQ(m.capacity(), N); // valid if contraction was done!
459 }
460 }
461}
462
464{
465 EXPECT_THROW(m.remove_last(), underflow_error);
466 EXPECT_THROW(m.remove_first(), underflow_error);
467 EXPECT_THROW(m.get(0), underflow_error);
468 EXPECT_THROW(m.get(), underflow_error);
469 EXPECT_THROW(m.get(2), underflow_error);
470}
471
473{
475 EXPECT_NO_THROW(m.reverse());
477
478 m.append(7);
479 EXPECT_NO_THROW(m.reverse());
480 EXPECT_EQ(m.size(), 1u);
481 EXPECT_EQ(m[0], 7);
482}
483
485{
487 EXPECT_THROW(m.putn(std::numeric_limits<size_t>::max()), overflow_error);
488}
489
491{
493
494 EXPECT_THROW(m.top(), underflow_error);
495
496 for (size_t i = 0; i < 100; ++i)
497 EXPECT_EQ(m.push(i), i);
498
499 for (size_t i = 100; i > 0; --i)
500 EXPECT_EQ(m.pop(), i - 1);
501
503 ASSERT_EQ(m.size(), 0);
504 EXPECT_THROW(m.top(), underflow_error);
505 EXPECT_THROW(m.pop(), underflow_error);
506}
507
509{
513 EXPECT_THROW(it.get_curr(), overflow_error);
514 EXPECT_THROW(it.next(), overflow_error);
515 EXPECT_THROW(it.prev(), underflow_error);
516 it.reset();
518 EXPECT_THROW(it.get_curr(), overflow_error);
519 EXPECT_THROW(it.next(), overflow_error);
520 EXPECT_THROW(it.prev(), underflow_error);
521 it.reset_last();
523 EXPECT_THROW(it.get_curr(), underflow_error);
524 EXPECT_THROW(it.next(), overflow_error);
525 EXPECT_THROW(it.prev(), underflow_error);
526}
527
529{
530 int i = 0;
531 for (MemArray<int>::Iterator it = m; it.has_curr(); it.next(), ++i)
532 EXPECT_EQ(it.get_curr(), i);
533
535 it.reset_last();
536 i = n - 1;
537 for (MemArray<int>::Iterator it = m; it.has_curr(); it.prev(), --i)
538 EXPECT_EQ(it.get_curr(), i);
539}
540
542{
544 size_t n = 0;
545 auto ret = m.traverse([&n](int)
546 {
547 ++n;
548 return true;
549 });
551 EXPECT_EQ(n, 0);
552}
553
555{
556 const size_t cap = m.capacity();
557
558 // Test 1: clear on empty
560 EXPECT_EQ(m.size(), 0);
561
562 static_assert(noexcept(m.clear()), "clear() must be noexcept");
563 m.clear();
564
566 EXPECT_EQ(m.size(), 0);
567 EXPECT_EQ(m.capacity(), cap);
568 EXPECT_NE(m.get_ptr(), nullptr);
569
570 // Test 2: clear on populated
571 for (size_t i = 0; i < 10; ++i)
572 m.append(i);
573
575 EXPECT_EQ(m.size(), 10);
576 const size_t cap_before = m.capacity();
577 const int* ptr_before = m.get_ptr();
578
579 m.clear();
580
582 EXPECT_EQ(m.size(), 0);
584 EXPECT_EQ(m.get_ptr(), ptr_before);
585
586 // Verify it can be reused
587 m.append(100);
588 EXPECT_EQ(m.size(), 1);
589 EXPECT_EQ(m[0], 100);
590}
591
593{
594 int N = 0;
595 auto ret = m.traverse([&N, this](int i)
596 {
597 ++N;
598 return i == n / 2;
599 }); // m is empty
601 EXPECT_EQ(N, 0);
602
603 for (size_t i = 0; i < n; ++i)
604 m.append(i);
605
606 EXPECT_EQ(N, 0);
607 EXPECT_TRUE(m.size() > 0);
608 EXPECT_EQ(m.size(), n);
609 ret = m.traverse([&N, this](int i)
610 {
611 ++N;
612 return i < n / 2;
613 });
615 EXPECT_EQ(N, n / 2 + 1);
616}
T & get_curr() const
Get the current item with bounds checking.
Definition array_it.H:268
void reset_last() noexcept
Reset the iterator to the last item.
Definition array_it.H:330
void reset() noexcept
Reset the iterator to the first item.
Definition array_it.H:317
void prev()
Move to the previous item with bounds checking.
Definition array_it.H:310
void next()
Advance to the next item with bounds checking.
Definition array_it.H:290
bool has_curr() const noexcept
Check if there is a current valid item.
Definition array_it.H:231
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
T & insert(const T &item)
Definition htlist.H:1220
T & append(const T &item)
Definition htlist.H:1271
constexpr bool is_empty() const noexcept
Definition htlist.H:419
Simple, scalable and fast dynamic array.
size_t size() const noexcept
Return the number of elements.
T & append(const T &item)
T * get_ptr() const noexcept
Return the current base of array.
constexpr size_t capacity() const noexcept
The type of element of array.
bool is_empty() const noexcept
Return true is the array is empty.
void swap(ODhashTable &other) noexcept
Definition tpl_odhash.H:420
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:228
Key * append(const Key &key)
Alias for insert() (copy version).
Definition hashDry.H:389
constexpr size_t size() const noexcept
Returns the number of entries in the table.
Definition hashDry.H:619
constexpr size_t capacity() const noexcept
Returns the current capacity of the table.
Definition hashDry.H:629
void clear()
Empties the container.
Definition hashDry.H:614
constexpr bool is_empty() const noexcept
Checks if the table is empty.
Definition hashDry.H:624
Key * insert(const Key &key)
Inserts a key into the hash table (copy version).
Definition hashDry.H:203
#define TEST(name)
#define N
Definition fib.C:294
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_dim_function > > dim(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4063
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Singly linked list implementations with head-tail access.
bool is_power_of_two(size_t x)
Definition memarray.cc:49
TEST_F(Default_MemArray, growing_in_2_powers)
Definition memarray.cc:135
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
bool traverse(Node *root, Op op)
and
Check uniqueness with explicit hash + equality functors.
STL namespace.
Simple iterator on elements of array.
const size_t n
Definition memarray.cc:56
MemArray< int > m
Definition memarray.cc:57
bool traverse(Operation &operation) noexcept(traverse_is_noexcept< Operation >())
Traverse the container via its iterator and performs a conditioned operation on each item.
Definition ah-dry.H:101
MemArray< int > m
Definition memarray.cc:62
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
Dnode< int > Test
Definition testDnode.C:42
static int * k
Simple, scalable, contiguous dynamic array.
DynList< int > l