Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
dynarray.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
38#include <gtest/gtest.h>
39
40#include <tpl_dynArray.H>
41#include <ah-unique.H>
42
43#include <new>
44#include <stdexcept>
45
46using namespace Aleph;
47using namespace std;
48
49namespace {
50
52{
53 DynArray<int> arr;
54 EXPECT_TRUE(arr.is_empty());
55 EXPECT_EQ(arr.size(), 0u);
56
57 arr.append(42);
58 EXPECT_EQ(arr.size(), 1u);
60 EXPECT_EQ(arr.access(0), 42);
61
62 arr.append(7);
63 EXPECT_EQ(arr.size(), 2u);
64 EXPECT_EQ(arr.access(1), 7);
65}
66
68{
69 DynArray<int> src;
70 for (int v : {3, 6, 9})
71 src.append(v);
72
73 auto copy = src.to_array();
74
75 ASSERT_EQ(copy.size(), src.size());
76 for (size_t i = 0; i < copy.size(); ++i)
77 EXPECT_EQ(copy(i), src(i));
78}
79
81{
82 DynArray<int> arr;
84
85 arr.reserve(0, 3);
86 ASSERT_EQ(arr.size(), 4u);
87 for (size_t i = 0; i < arr.size(); ++i)
88 EXPECT_EQ(arr.access(i), 123);
89
90 arr.access(2) = 77;
91 EXPECT_EQ(arr.access(2), 77);
92
93 auto & ref = arr.touch(10);
94 ref = 99;
95 EXPECT_EQ(arr.size(), 11u);
96 EXPECT_EQ(arr.access(10), 99);
97}
98
100{
101 DynArray<int> arr;
102 arr.append(1);
103 arr.append(2);
104 arr.append(1);
105 arr.append(3);
106 arr.append(2);
107 arr.append(4);
108 arr.append(4);
109
110 in_place_unique(arr);
111
112 ASSERT_EQ(arr.size(), 4u);
113 EXPECT_EQ(arr.access(0), 1);
114 EXPECT_EQ(arr.access(1), 2);
115 EXPECT_EQ(arr.access(2), 3);
116 EXPECT_EQ(arr.access(3), 4);
117}
118
120{
121 DynArray<int> arr;
122
123 EXPECT_THROW(arr.pop(), std::underflow_error);
124 EXPECT_THROW(arr.top(), std::underflow_error);
125 EXPECT_THROW(arr.get_first(), std::underflow_error);
126 EXPECT_THROW(arr.get_last(), std::underflow_error);
127
128 int dummy = 0;
129 EXPECT_THROW(arr.remove(dummy), std::underflow_error);
130}
131
133{
134 DynArray<int> arr;
135 EXPECT_THROW(arr.reserve(5, 4), std::domain_error);
136}
137
139{
140 DynArray<int> arr;
141 arr.reserve(5);
142 ASSERT_EQ(arr.size(), 5u);
143 for (size_t i = 0; i < arr.size(); ++i)
144 arr.access(i) = static_cast<int>(i * 2);
145 for (size_t i = 0; i < arr.size(); ++i)
146 EXPECT_EQ(arr.access(i), static_cast<int>(i * 2));
147}
148
150{
151 DynArray<int> arr;
152 for (int i = 0; i < 6; ++i)
153 arr.append(i);
154
155 auto it = arr.get_it(3);
156 ASSERT_TRUE(it.has_curr());
157 EXPECT_EQ(it.get_curr(), 3);
158 it.next();
159 EXPECT_EQ(it.get_curr(), 4);
160
161 const auto & carr = arr;
162 auto cit = carr.get_it(5);
163 EXPECT_EQ(cit.get_curr(), 5);
164 EXPECT_THROW(carr.get_it(6), std::out_of_range);
165}
166
168{
170 EXPECT_FALSE(singular.is_last());
171 singular.reset_last();
172 EXPECT_FALSE(singular.has_curr());
173 EXPECT_FALSE(singular.is_last());
174
175 DynArray<int> empty;
176 auto it = empty.get_it();
177 it.reset_last();
178 EXPECT_FALSE(it.has_curr());
179 EXPECT_FALSE(it.is_last());
180
181 empty.append(7);
182 it.reset_last();
183 EXPECT_TRUE(it.has_curr());
184 EXPECT_TRUE(it.is_last());
185 it.end();
186 EXPECT_FALSE(it.is_last());
187}
188
190{
192 EXPECT_THROW(singular.get_curr(), std::overflow_error);
193 EXPECT_THROW(singular.next(), std::overflow_error);
194 singular.reset_last();
195 EXPECT_THROW(singular.get_curr(), std::underflow_error);
196 EXPECT_THROW(singular.next(), std::overflow_error);
197
198 DynArray<int> arr;
199 auto it = arr.get_it();
200 EXPECT_THROW(it.get_curr(), std::overflow_error);
201 EXPECT_THROW(it.next(), std::overflow_error);
202 it.reset_last();
203 EXPECT_THROW(it.get_curr(), std::underflow_error);
204
205 arr.append(42);
206 it.reset_first();
207 EXPECT_EQ(it.get_curr(), 42);
208 it.next();
209 EXPECT_THROW(it.get_curr(), std::overflow_error);
210 EXPECT_THROW(it.next(), std::overflow_error);
211 it.set_pos(-1);
212 EXPECT_THROW(it.get_curr(), std::underflow_error);
213 it.next();
214 EXPECT_EQ(it.get_curr(), 42);
215}
216
218{
219 DynArray<int> arr;
220 arr.adjust(10);
221 EXPECT_EQ(arr.size(), 10u);
222 arr.cut(3);
223 EXPECT_EQ(arr.size(), 3u);
224 arr.empty();
225 EXPECT_TRUE(arr.is_empty());
226 arr.append(1);
227 arr.append(2);
228 arr.cut(2);
229 EXPECT_EQ(arr.size(), 2u);
230
231 arr.clear();
232 EXPECT_TRUE(arr.is_empty());
233 EXPECT_EQ(arr.size(), 0u);
234
235 arr.append(10);
236 EXPECT_TRUE(arr.contains(10));
237 EXPECT_FALSE(arr.contains(20));
238}
239
241{
242 DynArray<int> arr;
243 EXPECT_THROW(arr.reserve(4, 3), std::domain_error);
244 EXPECT_EQ(arr.size(), 0u);
245}
246
248{
249 DynArray<int> arr;
250 arr.reserve(2, 5);
251 ASSERT_EQ(arr.size(), 6u);
252 arr.touch(20) = 100;
253 EXPECT_EQ(arr.size(), 21u);
254 arr.cut(6);
255 EXPECT_EQ(arr.size(), 6u);
256}
257
258// Default constructor that throws std::bad_alloc once `budget` constructions
259// have succeeded. A negative budget never fails. Used to make a block
260// allocation fail at a chosen point inside DynArray::reserve().
261struct Fails_After_Budget
262{
263 static inline long budget = -1;
264 int value = 0;
265
266 Fails_After_Budget()
267 {
268 if (budget == 0)
269 throw std::bad_alloc();
270 if (budget > 0)
271 --budget;
272 }
273};
274
275// Restores the unlimited budget even if an ASSERT leaves the test early.
276struct Budget_Guard
277{
278 ~Budget_Guard() { Fails_After_Budget::budget = -1; }
279};
280
282{
283 DynArray<int> arr(4, 2, 2); // segments of 4 blocks of 4 entries
284 arr.touch(0) = 7; // segment 0 exists, but only its block 0
285 ASSERT_EQ(arr.get_num_blocks(), 1u);
286
287 arr.reserve(0, 15); // must allocate blocks 1..3 of the existing segment
288 EXPECT_EQ(arr.get_num_blocks(), 4u);
289 EXPECT_EQ(arr.size(), 16u);
290 for (size_t i = 0; i <= 15; ++i)
291 EXPECT_TRUE(arr.exist(i)) << "entry " << i;
292 EXPECT_EQ(arr.access(0), 7); // existing data is preserved
293}
294
296{
297 Budget_Guard guard;
298 // 16 segments of 4 blocks of 4 entries: [0, 47] spans segments 0, 1 and 2.
299 DynArray<Fails_After_Budget> arr(4, 2, 2);
300 const size_t block = arr.get_block_size();
301 ASSERT_EQ(block, 4u);
302
303 arr.touch(0); // segment 0 and its block 0 exist before the reserve
304 ASSERT_EQ(arr.get_num_blocks(), 1u);
305
306 // Blocks 1..3 of segment 0 and block 0 of segment 1 succeed; block 1 of
307 // segment 1 fails, after a whole new segment has been allocated.
308 Fails_After_Budget::budget = static_cast<long>(4 * block);
309 EXPECT_THROW(arr.reserve(0, 47), std::bad_alloc);
310 Fails_After_Budget::budget = -1;
311
312 EXPECT_EQ(arr.get_num_blocks(), 1u);
313 EXPECT_EQ(arr.size(), 1u);
314 for (size_t i = 0; i < block; ++i)
315 EXPECT_TRUE(arr.exist(i)) << "pre-existing entry " << i;
316 for (size_t i = block; i <= 47; ++i)
317 EXPECT_FALSE(arr.exist(i)) << "entry " << i << " was not rolled back";
318
319 arr.reserve(0, 47); // the array remains fully usable
320 EXPECT_EQ(arr.get_num_blocks(), 12u);
321 EXPECT_EQ(arr.size(), 48u);
322 for (size_t i = 0; i <= 47; ++i)
323 EXPECT_TRUE(arr.exist(i));
324}
325
327{
328 Budget_Guard guard;
329 DynArray<Fails_After_Budget> arr(4, 2, 2);
330
331 Fails_After_Budget::budget = 0; // the very first block allocation fails
332 EXPECT_THROW(arr.reserve(20, 40), std::bad_alloc);
333 Fails_After_Budget::budget = -1;
334
335 EXPECT_EQ(arr.get_num_blocks(), 0u);
336 EXPECT_EQ(arr.size(), 0u);
337 for (size_t i = 0; i <= 47; ++i)
338 EXPECT_FALSE(arr.exist(i));
339}
340
342{
343 Budget_Guard guard;
344 DynArray<Fails_After_Budget> arr(4, 2, 2);
345 arr.reserve(0, 47);
346 ASSERT_EQ(arr.get_num_blocks(), 12u);
347
348 Fails_After_Budget::budget = 0; // any element construction would throw
349 EXPECT_NO_THROW(arr.reserve(0, 47));
350 EXPECT_NO_THROW(arr.reserve(5, 30));
351 EXPECT_EQ(arr.get_num_blocks(), 12u);
352 EXPECT_EQ(arr.size(), 48u);
353}
354
356{
357 DynArray<int> arr;
358 for (int i = 0; i < 5; ++i)
359 arr.push(i);
360 EXPECT_EQ(arr.get_first(), 0);
361 EXPECT_EQ(arr.get_last(), 4);
362
363 arr.insert(-1);
364 EXPECT_EQ(arr.get_first(), -1);
365
366 EXPECT_EQ(arr.pop(), 4);
367 EXPECT_EQ(arr.size(), 5u);
368 EXPECT_EQ(arr.top(), arr.get_last());
369}
370
371} // namespace
Deduplicate sequential Aleph containers in-place.
size_t size_t int32_t value
Definition ca-c-api.h:116
Iterator on the items of array.
void reset_last() noexcept
Reset the iterator to the last item.
size_t get_block_size() const noexcept
Return the block size.
void push(const T &data)
void adjust(const size_t dim)
Set a new dimension.
Iterator get_it()
void cut(const size_t new_dim=0)
Cut the array to a new dimension; that is, it reduces the dimension of array and frees the remaining ...
Array< T > to_array() const
Copy contents into Aleph::Array (requires copyable elements).
void remove(T &item)
Given a valid reference to an item in the array, it removes it and decrease the dimension.
T & insert(const T &item)
T & get_last() const
Return a modifiable reference to the last item of array (as if this was a queue)
T & get_first() const
Return a modifiable reference to the first item of array (as if this was a queue)
size_t get_num_blocks() const noexcept
Return the number of blocks consumed by the array.
void set_default_initial_value(const T &value) noexcept
Set the default value.
void clear() noexcept
Empties the container.
T & touch(const size_t i)
Touch the entry i.
size_t size() const noexcept
Return the current dimension of array.
T pop()
Remove the last item of array (as if this was a stack)
T & access(const size_t i) const noexcept
Fast access without checking allocation and bound_min_clock checking.
bool exist(const size_t i) const
Return true if the i-th entry is accessible.
T & top() const
Return a modifiable reference to the last item of stack.
T & append()
Allocate a new entry to the end of array.
bool is_empty() const noexcept
Return true if the array is empty.
void empty() noexcept
Empty the array.
void reserve(const size_t l, const size_t r)
Allocate a range of entries.
bool contains(const Type &item) const
Test if an item is present in the container using equality.
Definition ah-dry.H:574
#define TEST(name)
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
Compiler_SSA_Block & block(Compiler_SSA_Function &function, const Compiler_SSA_Block_Id id)
Definition SSA.H:636
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
void in_place_unique(Container &c, Compare cmp={})
Remove duplicates in-place preserving first occurrence order.
Definition ah-unique.H:74
Itor2 copy(Itor1 sourceBeg, const Itor1 &sourceEnd, Itor2 destBeg)
Copy elements from one range to another.
Definition ahAlgo.H:584
STL namespace.
Lazy and scalable dynamic array implementation.