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 <memory>
43
44using namespace std;
45using namespace testing;
46using namespace Aleph;
47
48bool is_power_of_two(size_t x)
49{
50 return ((x != 0) && !(x & (x - 1))) != 0;
51}
52
53struct Default_MemArray : public Test
54{
55 const size_t n = 64;
57};
58
60{
63 {
64 for (size_t i = 0; i < 30; ++i)
65 m.append(i);
66 }
67};
68
70{
71 {
73 EXPECT_TRUE(is_power_of_two(m1.capacity()));
74 EXPECT_EQ(m1.size(), 0);
75 EXPECT_TRUE(m1.is_empty());
76 EXPECT_THROW(m1.get(), underflow_error);
77 }
78
79 {
80 MemArray<int> m1(32);
81 EXPECT_TRUE(is_power_of_two(m1.capacity()));
82 EXPECT_EQ(m1.size(), 0);
83 EXPECT_TRUE(m1.is_empty());
84 EXPECT_THROW(m1.get(), underflow_error);
85
86 MemArray<int> m2(31);
87 MemArray<int> m3(17);
88 EXPECT_TRUE(is_power_of_two(m2.capacity()));
89 EXPECT_TRUE(m2.is_empty());
90 EXPECT_TRUE(m3.is_empty());
91 EXPECT_EQ(m2.size(), 0);
92 EXPECT_EQ(m3.size(), 0);
93 EXPECT_EQ(m1.capacity(), m2.capacity());
94 EXPECT_EQ(m1.capacity(), m3.capacity());
95 }
96
97 {
98 MemArray<int> m1(512);
99 EXPECT_TRUE(is_power_of_two(m1.capacity()));
100 EXPECT_EQ(m1.size(), 0);
101 EXPECT_TRUE(m1.is_empty());
102 EXPECT_THROW(m1.get(), underflow_error);
103
104 MemArray<int> m2(257);
105 MemArray<int> m3(316);
106 EXPECT_TRUE(is_power_of_two(m2.capacity()));
107 EXPECT_TRUE(m2.is_empty());
108 EXPECT_TRUE(m3.is_empty());
109 EXPECT_EQ(m2.size(), 0);
110 EXPECT_EQ(m3.size(), 0);
111 EXPECT_EQ(m1.capacity(), m2.capacity());
112 EXPECT_EQ(m1.capacity(), m3.capacity());
113 }
114
115 {
116 MemArray<int> m1(4096);
117 EXPECT_TRUE(is_power_of_two(m1.capacity()));
118 EXPECT_EQ(m1.size(), 0);
119 EXPECT_TRUE(m1.is_empty());
120 EXPECT_THROW(m1.get(), underflow_error);
121
122 MemArray<int> m2(2049);
123 MemArray<int> m3(3000);
124 EXPECT_TRUE(is_power_of_two(m2.capacity()));
125 EXPECT_TRUE(m2.is_empty());
126 EXPECT_TRUE(m3.is_empty());
127 EXPECT_EQ(m2.size(), 0);
128 EXPECT_EQ(m3.size(), 0);
129 EXPECT_EQ(m1.capacity(), m2.capacity());
130 EXPECT_EQ(m1.capacity(), m3.capacity());
131 }
132}
133
135{
136 const size_t n = m.capacity();
137 for (size_t i = 0; i < n; ++i)
138 m.append(i);
139
140 EXPECT_EQ(m.size(), n);
141 EXPECT_EQ(m.capacity(), n);
142
143 m.append(n); // this append would cause expansion
144 EXPECT_EQ(m.capacity(), 2 * n);
145 EXPECT_EQ(m.size(), n + 1);
146 EXPECT_EQ(m.get_first(), 0);
147 EXPECT_EQ(m.get_last(), n);
148
149 // testing gap opening
150 m.insert(-1);
151 EXPECT_EQ(m.get_first(), -1);
152 EXPECT_EQ(m.get_last(), n);
153
154 EXPECT_THROW(m[m.size()], out_of_range);
155 EXPECT_THROW(m[m.capacity()], out_of_range);
156
157 { // Testing operator [] in read mode
158 int k = -1;
159 for (size_t i = 0; i < m.size(); ++i, ++k)
160 EXPECT_EQ(m[i], k);
161 EXPECT_EQ(k, n + 1);
162 }
163
164 { // Testing operator [] in write mode
165 for (size_t i = 0; i < m.size(); ++i)
166 m[i]++;
167
168 int k = 0;
169 for (size_t i = 0; i < m.size(); ++i, ++k)
170 EXPECT_EQ(m[i], k);
171 EXPECT_EQ(k, n + 2);
172 }
173}
174
176{
177 const size_t dim = m.capacity();
178
179 m.putn(dim + 1); // This will cause expansion
180
181 EXPECT_EQ(m.capacity(), 2 * dim); // Verify expansion
183 EXPECT_EQ(m.size(), dim + 1);
184
185 for (size_t i = 0; i < m.size(); ++i)
186 {
187 EXPECT_NO_THROW(m[i]);
188 m[i] = i;
189 }
190
191 EXPECT_THROW(m[m.size()], out_of_range);
192 EXPECT_THROW(m.get(m.size() + 1), underflow_error);
193
194 size_t k = 0;
195 EXPECT_NE(m.size(), k);
196 for (size_t i = 0; i < m.size(); ++i, ++k)
197 EXPECT_EQ(m[i], i);
198 EXPECT_EQ(k, m.size()); // TEST that loop has been executed
199
200 const size_t curr_cap = m.capacity();
201 const size_t avail = m.capacity() - m.size();
202 m.putn(avail); // this shouldn't cause expansion
203
205 EXPECT_EQ(m.size(), m.capacity());
206
207 int item;
208 EXPECT_NO_THROW(item = m.get(m.size())); // it must take out all items
209
210 EXPECT_EQ(item, 0);
212 EXPECT_EQ(m.size(), 0);
213}
214
216{
218
219 auto p1 = std::make_unique<int>(5);
220 auto p2 = std::make_unique<int>(7);
221
222 m.append(std::move(p1));
223 m.append(std::move(p2));
224
225 ASSERT_EQ(m.size(), 2u);
226 EXPECT_EQ(*m[0], 5);
227 EXPECT_EQ(*m[1], 7);
228
229 auto last = m.remove_last();
230 EXPECT_EQ(*last, 7);
231 EXPECT_EQ(m.size(), 1u);
232
233 auto first = m.remove_first();
234 EXPECT_EQ(*first, 5);
236}
237
239{
241 EXPECT_EQ(m.size(), 0);
242 EXPECT_NE(m.capacity(), 0);
243
244 const size_t cap1 = m.capacity();
245
246 // Test invalid accesses without insertion neither expansion
247 size_t k = 0;
248 for (size_t i = 0; i < m.capacity(); ++i, ++k)
249 EXPECT_THROW(m[i], out_of_range);
250 EXPECT_EQ(k, m.capacity());
251 EXPECT_EQ(m.capacity(), cap1); // capacity has not changed
253 EXPECT_EQ(m.size(), 0);
254
255 // Insert until capacity (no expansion)
256 k = 0;
257 for (size_t i = 0; i < m.capacity(); ++i, ++k)
258 m.append(i);
259 EXPECT_EQ(k, m.capacity());
260 EXPECT_EQ(m.size(), m.capacity());
261
262 // Test that item were inserted
263 k = 0;
264 for (size_t i = 0; i < m.capacity(); ++i, ++k)
265 {
266 EXPECT_NO_THROW(m[i]);
267 EXPECT_EQ(m[i], i);
268 }
269 EXPECT_EQ(k, m.capacity());
270
271 // Now we cause an expansion
272 k = 0;
273 for (size_t i = m.size(); i < 2 * cap1; ++i, ++k)
274 m.append(i);
275
276 EXPECT_EQ(k, cap1);
277 EXPECT_EQ(m.capacity(), 2 * cap1);
278 EXPECT_EQ(m.size(), 2 * cap1);
279
280 k = 0;
281 for (size_t i = 0; i < m.size(); ++i, ++k)
282 {
283 EXPECT_NO_THROW(m[i]);
284 EXPECT_EQ(m[i], i);
285 }
286 EXPECT_EQ(k, m.capacity());
287}
288
290{
291 const size_t cap = m.capacity();
293 EXPECT_NE(m.capacity(), 0);
294 EXPECT_EQ(m.size(), 0);
295
296 m.reserve(2 * cap + 1); // this should expand to 4*cap
297 EXPECT_EQ(m.capacity(), 4 * cap);
298}
299
301{
303 EXPECT_EQ(m.size(), 30);
304 EXPECT_EQ(m.capacity(), 32);
305 size_t k = 0;
306 for (size_t i = 0; i < m.size(); ++i, ++k)
307 EXPECT_EQ(m[i], i);
308 EXPECT_EQ(k, m.size());
309
310 { // Copy constructor
311 MemArray<int> aux = m;
312 EXPECT_FALSE(aux.is_empty());
313 EXPECT_EQ(aux.size(), 30);
314 EXPECT_EQ(aux.capacity(), 32);
315 size_t k = 0;
316 for (size_t i = 0; i < m.size(); ++i, ++k)
317 EXPECT_EQ(aux[i], i);
318 EXPECT_EQ(k, m.size());
319 EXPECT_NE(m.get_ptr(), aux.get_ptr());
320 }
321
322 { // move constructor
323 auto ptr = m.get_ptr();
324 MemArray<int> aux = move(m);
325 EXPECT_EQ(aux.get_ptr(), ptr);
326 EXPECT_FALSE(aux.is_empty());
327 EXPECT_EQ(aux.size(), 30);
328 EXPECT_EQ(aux.capacity(), 32);
330 EXPECT_EQ(m.size(), 0);
331 EXPECT_EQ(m.capacity(), 0);
332 EXPECT_EQ(m.get_ptr(), nullptr); // array of zero must be nullptr
333 size_t k = 0;
334 for (size_t i = 0; i < m.size(); ++i, ++k)
335 EXPECT_EQ(aux[i], i);
336 EXPECT_EQ(k, m.size());
337 EXPECT_NE(m.get_ptr(), aux.get_ptr());
338
339 m.swap(aux); // restore m to previous initialized state
340 EXPECT_EQ(m.get_ptr(), ptr);
341 EXPECT_TRUE(aux.is_empty());
342 EXPECT_EQ(aux.size(), 0);
343 EXPECT_EQ(aux.capacity(), 0);
345 EXPECT_EQ(m.size(), 30);
346 EXPECT_EQ(m.capacity(), 32);
347 k = 0;
348 for (size_t i = 0; i < m.size(); ++i, ++k)
349 EXPECT_EQ(m[i], i);
350 EXPECT_EQ(k, m.size());
351 }
352
353 // copy assigment
354 MemArray<int> aux;
355 EXPECT_TRUE(aux.is_empty());
356 EXPECT_EQ(aux.size(), 0);
357 EXPECT_NE(aux.capacity(), 0);
358 EXPECT_NE(aux.get_ptr(), nullptr);
359
360 aux = m;
361 EXPECT_FALSE(aux.is_empty());
362 EXPECT_NE(m.size(), 0);
363 EXPECT_EQ(aux.size(), m.size());
364 EXPECT_EQ(aux.capacity(), m.capacity());
366 EXPECT_NE(m.size(), 0);
367 EXPECT_NE(m.capacity(), 0);
368 EXPECT_NE(m.get_ptr(), aux.get_ptr()); // array of zero must be nullptr
369 k = 0;
370 for (size_t i = 0; i < m.size(); ++i, ++k)
371 EXPECT_EQ(aux[i], m[i]);
372 EXPECT_EQ(k, m.size());
373
374 // TODO move assigment
375}
376
378{
379 MemArray<int> m(0);
380 EXPECT_NE(m.capacity(), 0);
381 EXPECT_EQ(m.size(), 0);
382 EXPECT_NE(m.get_ptr(), nullptr);
384}
385
387{
389 EXPECT_EQ(m.size(), 0);
391
392 size_t N = 0;
393 for (size_t i = 0; i < 10; ++i)
394 {
397 for (size_t k = 0; k < 10; ++k, ++N)
398 l.append(N);
400 m.insert(move(l));
402 }
403
404 size_t n = 0;
405 for (long i = 9; i >= 0; --i) // descending for matching values of N
406 {
407 const DynList<int> &l = m[i];
409 for (auto it = l.get_it(); it.has_curr(); it.next(), ++n)
410 EXPECT_EQ(it.get_curr(), n);
411 }
412}
413
415{
416 constexpr size_t num_items = 10;
418 size_t N = 0;
419 for (size_t i = 0; i < num_items; ++i)
420 {
423 for (size_t k = 0; k < num_items; ++k, ++N)
424 l.insert(N);
426 m.insert(move(l));
428 }
429
430 size_t n = N - 1;
431 for (size_t i = 0; i < num_items; ++i)
432 {
433 DynList<int> l = m.remove_first();
434 auto it = l.get_it();
435 for (size_t k = 0; k < 10; ++k, it.next(), --n)
436 EXPECT_EQ(it.get_curr(), n);
437 assert(num_items - i < m.capacity()); // hard assert. Better leave it!
438 EXPECT_TRUE(m(num_items - i - 1).is_empty()); // verify moving
439 }
440}
441
443{
444 for (size_t i = 0; i < n; ++i)
445 m.append(i);
446
447 EXPECT_EQ(m.capacity(), n);
448 EXPECT_EQ(m.capacity(), m.size());
449
450 size_t N = m.capacity();
451 for (size_t i = 0; i < n; ++i)
452 {
453 EXPECT_EQ(m.remove_last(), n - i - 1);
454 if (m.size() == N / 4 - 1 and m.size() > m.contract_threshold)
455 {
456 N /= 2;
457 EXPECT_EQ(m.capacity(), N); // valid if contraction was done!
458 }
459 }
460}
461
463{
464 EXPECT_THROW(m.remove_last(), underflow_error);
465 EXPECT_THROW(m.remove_first(), underflow_error);
466 EXPECT_THROW(m.get(), underflow_error);
467 EXPECT_THROW(m.get(2), underflow_error);
468}
469
471{
473
474 EXPECT_THROW(m.top(), underflow_error);
475
476 for (size_t i = 0; i < 100; ++i)
477 EXPECT_EQ(m.push(i), i);
478
479 for (size_t i = 100; i > 0; --i)
480 EXPECT_EQ(m.pop(), i - 1);
481
483 ASSERT_EQ(m.size(), 0);
484 EXPECT_THROW(m.top(), underflow_error);
485 EXPECT_THROW(m.pop(), underflow_error);
486}
487
489{
493 EXPECT_THROW(it.get_curr(), overflow_error);
494 EXPECT_THROW(it.next(), overflow_error);
495 EXPECT_THROW(it.prev(), underflow_error);
496 it.reset();
498 EXPECT_THROW(it.get_curr(), overflow_error);
499 EXPECT_THROW(it.next(), overflow_error);
500 EXPECT_THROW(it.prev(), underflow_error);
501 it.reset_last();
503 EXPECT_THROW(it.get_curr(), underflow_error);
504 EXPECT_THROW(it.next(), overflow_error);
505 EXPECT_THROW(it.prev(), underflow_error);
506}
507
509{
510 int i = 0;
511 for (MemArray<int>::Iterator it = m; it.has_curr(); it.next(), ++i)
512 EXPECT_EQ(it.get_curr(), i);
513
515 it.reset_last();
516 i = n - 1;
517 for (MemArray<int>::Iterator it = m; it.has_curr(); it.prev(), --i)
518 EXPECT_EQ(it.get_curr(), i);
519}
520
522{
524 size_t n = 0;
525 auto ret = m.traverse([&n](int)
526 {
527 ++n;
528 return true;
529 });
531 EXPECT_EQ(n, 0);
532}
533
535{
536 const size_t cap = m.capacity();
537
538 // Test 1: clear on empty
540 EXPECT_EQ(m.size(), 0);
541
542 static_assert(noexcept(m.clear()), "clear() must be noexcept");
543 m.clear();
544
546 EXPECT_EQ(m.size(), 0);
547 EXPECT_EQ(m.capacity(), cap);
548 EXPECT_NE(m.get_ptr(), nullptr);
549
550 // Test 2: clear on populated
551 for (size_t i = 0; i < 10; ++i)
552 m.append(i);
553
555 EXPECT_EQ(m.size(), 10);
556 const size_t cap_before = m.capacity();
557 const int* ptr_before = m.get_ptr();
558
559 m.clear();
560
562 EXPECT_EQ(m.size(), 0);
564 EXPECT_EQ(m.get_ptr(), ptr_before);
565
566 // Verify it can be reused
567 m.append(100);
568 EXPECT_EQ(m.size(), 1);
569 EXPECT_EQ(m[0], 100);
570}
571
573{
574 int N = 0;
575 auto ret = m.traverse([&N, this](int i)
576 {
577 ++N;
578 return i == n / 2;
579 }); // m is empty
581 EXPECT_EQ(N, 0);
582
583 for (size_t i = 0; i < n; ++i)
584 m.append(i);
585
586 EXPECT_EQ(N, 0);
587 EXPECT_TRUE(m.size() > 0);
588 EXPECT_EQ(m.size(), n);
589 ret = m.traverse([&N, this](int i)
590 {
591 ++N;
592 return i < n / 2;
593 });
595 EXPECT_EQ(N, n / 2 + 1);
596}
T & get_curr() const
Get the current item with bounds checking.
Definition array_it.H:245
void reset_last() noexcept
Reset the iterator to the last item.
Definition array_it.H:307
void reset() noexcept
Reset the iterator to the first item.
Definition array_it.H:297
void prev()
Move to the previous item with bounds checking.
Definition array_it.H:289
void next()
Advance to the next item with bounds checking.
Definition array_it.H:269
bool has_curr() const noexcept
Check if there is a current valid item.
Definition array_it.H:219
Dynamic singly linked list with functional programming support.
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:222
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:4052
Singly linked list implementations with head-tail access.
bool is_power_of_two(size_t x)
Definition memarray.cc:48
TEST_F(Default_MemArray, growing_in_2_powers)
Definition memarray.cc:134
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
bool traverse(Node *root, Op op)
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
STL namespace.
Simple iterator on elements of array.
const size_t n
Definition memarray.cc:55
MemArray< int > m
Definition memarray.cc:56
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:97
MemArray< int > m
Definition memarray.cc:61
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
Dnode< int > Test
Definition testDnode.C:37
static int * k
Simple, scalable, contiguous dynamic array.
DynList< int > l