Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_dynArray.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
43#ifndef TPL_DYNARRAY_H
44#define TPL_DYNARRAY_H
45
46#include <cmath>
47
48#include <string>
49#include <concepts>
50#include <type_traits>
51#include <aleph.H>
52#include <ahIterator.H>
53#include <array_utils.H>
54#include <ahDry.H>
55#include <tpl_dynDlist.H>
56#include <ah-args-ctor.H>
57#include <htlist.H>
58#include <ah-dry.H>
59#include <ah-errors.H>
60#include <tpl_array.H>
61
62namespace Aleph {
63class BitArray; // forward needed
64
202template <typename T>
203class DynArray : public LocateFunctions<DynArray<T>, T>,
204 public FunctionalMethods<DynArray<T>, T>,
205 public GenericKeys<DynArray<T>, T>,
206 public EqualSequenceMethod<DynArray<T>>,
207 public StlAlephIterator<DynArray<T>>
208{
209 friend class BitArray; // for access to __traversal() method
210
211 // look at the end of this file for seeing the values
212public:
213 using Item_Type = T;
214 using Key_Type = T;
215
216 static const size_t Default_Pow_Dir;
217 static const size_t Default_Pow_Seg;
218 static const size_t Default_Pow_Block;
219
220private:
221 static const size_t Max_Bits_Allowed;
222
223public:
225 static const unsigned long long Max_Dim_Allowed;
226
227private:
228 static const size_t Max_Pow_Block;
229
230 mutable size_t pow_dir = Default_Pow_Dir;
231 mutable size_t pow_seg = Default_Pow_Seg;
232 mutable size_t pow_block = std::min(Default_Pow_Block, Max_Pow_Block);
235 mutable size_t dir_size = two_raised(pow_dir); // = 2^pow_dir
236 mutable size_t seg_size = two_raised(pow_seg); // = 2^pow_seg
237 mutable size_t block_size = two_raised(pow_block); // = 2^pow_block
238
239 // 2^(pow_dir + pow_seg + pow_block) - 1
241
242 static size_t two_raised(const size_t n) noexcept
243 {
244 ah_overflow_error_if(n >= Max_Bits_Allowed) << "two_raised: exponent " << n << " is too large";
245 return static_cast<size_t>(1) << n;
246 }
247
248 static size_t compute_dim(size_t d, size_t s, size_t b) noexcept
249 {
250 return two_raised(d) * two_raised(s) * two_raised(b);
251 }
252
253public:
262 static void compute_sizes(const size_t n, size_t &d, size_t &s, size_t &b) noexcept
263 {
264 d = Default_Pow_Dir;
265 s = Default_Pow_Seg;
267 if (compute_dim(d, s, b) >= n)
268 return;
269
270 while (true)
271 {
272 if (compute_dim(++d, s, b) >= n)
273 break;
274
275 if (compute_dim(d, ++s, b) >= n)
276 break;
277
278 if (compute_dim(d, s, ++b) >= n)
279 break;
280 }
281 }
282
289 static std::tuple<size_t, size_t, size_t> compute_sizes(const size_t n) noexcept
290 {
291 size_t d, s, b;
292 compute_sizes(n, d, s, b);
293 return std::make_tuple(d, s, b);
294 }
295
296private:
297 size_t mask_seg = seg_size - 1;
298 size_t mask_block = block_size - 1;
299
300 size_t index_in_dir(const size_t i) const noexcept
301 {
305
306 return i >> seg_plus_block_pow;
307 }
308
309 size_t modulus_from_index_in_dir(const size_t i) const noexcept
310 {
313
314 return (i & mask_seg_plus_block);
315 }
316
317 size_t index_in_seg(const size_t &i) const noexcept
318 {
321
323 }
324
325 size_t index_in_block(const size_t i) const noexcept
326 {
329 ((i % (seg_size * block_size)) % block_size));
330
332 }
333
335 size_t num_segs = 0;
336 size_t num_blocks = 0;
337 T ***dir = nullptr;
338
340 {
341 assert(dir != nullptr);
342
343 for (size_t i = 0; i < dir_size; ++i)
344 dir[i] = nullptr;
345 }
346
347 void fill_seg_to_null(T **seg) noexcept
348 {
349 assert(seg != nullptr);
350
351 for (size_t i = 0; i < seg_size; ++i)
352 seg[i] = nullptr;
353 }
354
356 {
357 dir = static_cast<T ***>(malloc(dir_size * sizeof(T **)));
358 ah_bad_alloc_unless(dir != nullptr);
359
361 }
362
363 void resize_dir(const size_t i) // resize dir to fit index i
364 {
365 assert(i >= max_dim);
366
367 size_t new_pow_dir = pow_dir + 1;
369 ++new_pow_dir;
370
371 const size_t new_dir_sz = two_raised(new_pow_dir);
372 T ***new_dir = static_cast<T ***>(realloc(dir, new_dir_sz * sizeof(T **)));
373 ah_bad_alloc_unless(new_dir != nullptr);
374
375 dir = new_dir;
376 for (size_t k = dir_size; k < new_dir_sz; ++k)
377 dir[k] = nullptr;
378
381
383 }
384
385 void allocate_segment(T **&seg)
386 {
387 assert(seg == nullptr);
388
389 seg = new T *[seg_size];
390 fill_seg_to_null(seg);
391 ++num_segs;
392 }
393
396
397 void allocate_block(T *&block)
398 {
399 assert(block == nullptr);
400
401 block = new T[block_size];
402 ++num_blocks;
403
404 if (default_initial_value_ptr == nullptr)
405 return;
406
407 for (size_t i = 0; i < block_size; ++i)
408 block[i] = *default_initial_value_ptr;
409 }
410
411 void release_segment(T **&seg) noexcept
412 {
413 assert(seg != nullptr);
414
415 delete[] seg;
416 seg = nullptr;
417 --num_segs;
418 }
419
420 void release_block(T *&block) noexcept
421 {
422 assert(block != nullptr);
423
424 delete[] block;
425 block = nullptr;
426 --num_blocks;
427 }
428
429 void release_blocks_and_segment(T **&seg) noexcept
430 {
431 assert(seg != nullptr);
432
433 for (size_t i = 0; i < seg_size; ++i)
434 if (seg[i] != nullptr)
435 release_block(seg[i]);
436
437 release_segment(seg);
438 }
439
440 void ensure_not_empty(const char *context) const
441 {
442 ah_underflow_error_if(is_empty()) << context;
443 }
444
446 {
447 assert(dir != nullptr);
448
449 for (size_t i = 0; i < dir_size; ++i)
450 if (dir[i] != nullptr)
452
453 current_dim = 0;
454 }
455
457 {
458 if (dir == nullptr)
459 return;
460
462 if (dir != nullptr)
463 free(dir);
464
465 dir = nullptr;
466 current_dim = 0;
467 }
468
469 static size_t next2Pow(const size_t number) noexcept
470 {
471 return static_cast<size_t>(ceil(log(static_cast<float>(number)) / log(2.0)));
472 }
473
474 size_t divide_by_block_size(const size_t number) const noexcept
475 {
476 assert(number / block_size == number >> pow_block);
477
478 return number >> pow_block;
479 }
480
481 size_t modulus_by_block_size(const size_t number) const noexcept
482 {
483 assert((number % block_size) == (number & mask_block));
484
485 return number & mask_block;
486 }
487
488 void allocate_block(T *&block, T *src_block)
489 {
490 allocate_block(block);
491 for (size_t i = 0; i < block_size; i++)
492 block[i] = src_block[i];
493 }
494
495 void allocate_segment(T **&seg, T **src_seg)
496 {
497 allocate_segment(seg);
498 for (size_t i = 0; i < seg_size; i++)
499 if (src_seg[i] != nullptr)
500 allocate_block(seg[i], src_seg[i]);
501 }
502
504 {
505 allocate_dir();
506 for (size_t i = 0; i < dir_size; i++)
507 if (src_dir[i] != nullptr)
509 }
510
511 class Proxy
512 {
513 size_t index;
520
521 public:
523 : index(i), pos_in_dir(_array.index_in_dir(index)), pos_in_seg(_array.index_in_seg(index)),
524 pos_in_block(_array.index_in_block(index)), ref_seg(_array.dir[pos_in_dir]), block(nullptr),
526 {
527 if (ref_seg != nullptr)
528 block = ref_seg[pos_in_seg]; // Entry block already exists
529 }
530
531 operator T &()
532 {
533 ah_invalid_argument_if(block == nullptr) << "accessed entry not been still written";
534 return block[pos_in_block];
535 }
536
538 {
540
541 if (ref_seg == nullptr) // Is there a segment?
542 { // No ==> allocate it!
545 }
546
547 if (block == nullptr) // test if block is allocated
548 {
549 try
550 {
553
555 }
556 catch (...)
557 {
560
561 throw;
562 }
563 }
564
565 if (index >= array.current_dim)
566 array.current_dim = index + 1;
567
568 return &block[pos_in_block];
569 }
570
571 Proxy &operator = (const T &data)
572 {
574 if (ref_seg == nullptr) // Is there a segment?
575 { // No ==> allocate ii!
578 }
579
580 if (block == nullptr) // test if block is allocated
581 {
582 try
583 {
586
588 }
589 catch (...)
590 {
593
594 throw;
595 }
596 }
597
598 if (index >= array.current_dim)
599 array.current_dim = index + 1;
600
601 block[pos_in_block] = data;
602
603 return *this;
604 }
605
607 {
608 ah_domain_error_if(proxy.block == nullptr) << "right entry has not been still written";
609
610 if (&proxy == this)
611 return *this;
612
614 if (ref_seg == nullptr) // Is there a segment?
615 { // No ==> allocate it!
618 }
619
620 if (block == nullptr) // test if block is allocated
621 {
622 try
623 {
626
628 }
629 catch (...)
630 {
633
634 throw;
635 }
636 }
637
638 if (index >= array.current_dim)
639 array.current_dim = index + 1;
640
641 block[pos_in_block] = proxy.block[proxy.pos_in_block];
642
643 return *this;
644 }
645 };
646
647public:
650 {
651 return dir_size;
652 }
653
656 {
657 return seg_size;
658 }
659
662 {
663 return block_size;
664 }
665
670 {
671 return current_dim;
672 }
673
679 {
680 return max_dim;
681 }
682
685 {
686 return num_blocks;
687 }
688
701
708
724 DynArray(const size_t _pow_dir, const size_t _pow_seg, const size_t _pow_block)
731 {
732 static_assert(std::is_copy_constructible_v<T>, "No copy constructor for T");
733 static_assert(std::is_move_constructible_v<T>, "No move constructor for T");
734 static_assert(std::is_copy_assignable_v<T>, "No copy assign for T");
735 static_assert(std::is_move_assignable_v<T>, "No move assign for T");
737
738 ah_length_error_if(max_dim > Max_Dim_Allowed) << "Dimension too large";
739
740 allocate_dir();
741 }
742
751 DynArray(const size_t dim = 0) : current_dim(dim)
752 {
753 static_assert(std::is_default_constructible_v<T>, "No default constructor for T");
754 static_assert(std::is_copy_constructible_v<T>, "No copy constructor for T");
755 static_assert(std::is_move_constructible_v<T>, "No move constructor for T");
756 static_assert(std::is_copy_assignable_v<T>, "No copy assign for T");
757 static_assert(std::is_move_assignable_v<T>, "No move assign for T");
759
760 ah_length_error_if(max_dim > Max_Dim_Allowed) << "Dimension too large";
761
762 allocate_dir();
763 }
764
766
768 {
769 release_dir();
770 }
771
777 {
778 for (size_t i = 0; i < src_array.current_dim; ++i)
779 if (src_array.exist(i))
780 (*this)[i] = src_array.access(i);
781 }
782
799
806 {
807 if (this == &array)
808 return *this;
809
810 copy_array(array);
811
812 if (array.current_dim < current_dim)
813 cut(array.current_dim);
814
815 current_dim = array.current_dim;
816
817 return *this;
818 }
819
825 void swap(DynArray<T> &array) noexcept
826 {
827 std::swap(dir, array.dir);
828 std::swap(pow_dir, array.pow_dir);
829 std::swap(pow_seg, array.pow_seg);
830 std::swap(pow_block, array.pow_block);
831 std::swap(seg_plus_block_pow, array.seg_plus_block_pow);
832 std::swap(mask_seg_plus_block, array.mask_seg_plus_block);
833 std::swap(dir_size, array.dir_size);
834 std::swap(seg_size, array.seg_size);
835 std::swap(block_size, array.block_size);
836 std::swap(mask_seg, array.mask_seg);
837 std::swap(mask_block, array.mask_block);
838 std::swap(max_dim, array.max_dim);
839 std::swap(current_dim, array.current_dim);
840 std::swap(num_segs, array.num_segs);
841 std::swap(num_blocks, array.num_blocks);
842
843 std::swap(default_initial_value, array.default_initial_value);
844
846 array.default_initial_value_ptr = &array.default_initial_value;
847 }
848
861
864 {
865 swap(other);
866 return *this;
867 }
868
877 T &access(const size_t i) const noexcept
878 {
879 assert(dir[index_in_dir(i)] != nullptr);
880 assert(dir[index_in_dir(i)][index_in_seg(i)] != nullptr);
881
882 return dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
883 }
884
886 T &operator () (const size_t i) const noexcept
887 {
888 return access(i);
889 }
890
898 bool exist(const size_t i) const
899 {
900 if (i >= max_dim)
901 return false;
902
903 const size_t pos_in_dir = index_in_dir(i);
904
905 assert(pos_in_dir < dir_size);
906
907 if (dir[pos_in_dir] == nullptr)
908 return false;
909
910 const size_t pos_in_seg = index_in_seg(i);
911
912 assert(pos_in_seg < seg_size);
913
914 if (dir[pos_in_dir][pos_in_seg] == nullptr)
915 return false;
916
917 return true;
918 }
919
930 T *test(const size_t i) const noexcept
931 {
932 if (i >= max_dim)
933 return nullptr;
934
935 const size_t pos_in_dir = index_in_dir(i);
936 if (dir[pos_in_dir] == nullptr)
937 return nullptr;
938
939 const size_t pos_in_seg = index_in_seg(i);
940 if (dir[pos_in_dir][pos_in_seg] == nullptr)
941 return nullptr;
942
943 return &dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
944 }
945
961 T &touch(const size_t i)
962 {
963 if (i >= max_dim)
964 resize_dir(i);
965
966 const size_t pos_in_dir = index_in_dir(i);
967 bool new_segment = false;
968 if (dir[pos_in_dir] == nullptr)
969 {
970 allocate_segment(dir[pos_in_dir]);
971 new_segment = true;
972 }
973
974 const size_t pos_in_seg = index_in_seg(i);
975 if (dir[pos_in_dir][pos_in_seg] == nullptr)
976 {
977 try
978 {
979 allocate_block(dir[pos_in_dir][pos_in_seg]);
980 }
981 catch (...)
982 {
983 if (new_segment && dir[pos_in_dir] != nullptr)
984 release_segment(dir[pos_in_dir]);
985 throw;
986 }
987 }
988
989 if (i >= current_dim)
990 current_dim = i + 1;
991
992 return dir[pos_in_dir][pos_in_seg][index_in_block(i)];
993 }
994
1011 void reserve(const size_t l, const size_t r)
1012 {
1013 ah_domain_error_if(l > r) << "invalid range";
1014
1015 if (r >= max_dim)
1016 resize_dir(r);
1017
1018 const size_t first_seg = index_in_dir(l);
1019 const size_t last_seg = index_in_dir(r);
1020 const size_t first_block = index_in_seg(l);
1021 const size_t last_block = index_in_seg(r);
1022
1023 // First pass: count the segments and blocks this call must allocate.
1024 // It keeps the common case, where the whole range already exists, free
1025 // of heap allocations, and it lets the rollback bookkeeping be sized
1026 // before anything is allocated. Recording an allocation then never
1027 // allocates, so it cannot fail and leave an allocation out of the
1028 // rollback.
1029 size_t missing_segs = 0;
1030 size_t missing_blocks = 0;
1031 for (size_t seg_idx = first_seg; seg_idx <= last_seg; ++seg_idx)
1032 {
1033 const size_t lo = (seg_idx == first_seg) ? first_block : 0;
1034 const size_t hi = (seg_idx == last_seg) ? last_block : seg_size - 1;
1035 if (dir[seg_idx] == nullptr)
1036 {
1037 ++missing_segs;
1038 missing_blocks += hi - lo + 1;
1039 }
1040 else
1041 for (size_t block_idx = lo; block_idx <= hi; ++block_idx)
1042 if (dir[seg_idx][block_idx] == nullptr)
1044 }
1045
1046 if (missing_blocks == 0) // a missing segment always implies missing blocks
1047 {
1048 if (r + 1 > current_dim)
1049 current_dim = r + 1;
1050 return;
1051 }
1052
1057
1058 try
1059 {
1060 for (size_t seg_idx = first_seg; seg_idx <= last_seg; ++seg_idx)
1061 {
1062 if (dir[seg_idx] == nullptr)
1063 {
1064 allocate_segment(dir[seg_idx]);
1065 new_segments.append(seg_idx);
1066 }
1067
1068 size_t block_idx = (seg_idx == first_seg) ? first_block : 0;
1069 const size_t final_block = (seg_idx == last_seg) ? last_block : seg_size - 1;
1070
1071 while (block_idx <= final_block)
1072 {
1073 if (dir[seg_idx][block_idx] == nullptr)
1074 {
1075 allocate_block(dir[seg_idx][block_idx]);
1076 new_blocks.append(std::make_pair(seg_idx, block_idx));
1077 }
1078
1079 ++block_idx;
1080 }
1081 } // end for (...)
1082 }
1083 catch (...)
1084 {
1085 for (size_t k = new_blocks.size(); k > 0; --k)
1086 {
1087 const auto [seg_idx, block_idx] = new_blocks(k - 1);
1088 if (dir[seg_idx] != nullptr and dir[seg_idx][block_idx] != nullptr)
1089 release_block(dir[seg_idx][block_idx]);
1090 }
1091
1092 for (size_t k = new_segments.size(); k > 0; --k)
1093 if (const size_t seg_idx = new_segments(k - 1); dir[seg_idx] != nullptr)
1094 release_segment(dir[seg_idx]);
1095
1096 throw;
1097 }
1098
1099 if (r + 1 > current_dim)
1100 current_dim = r + 1;
1101 }
1102
1108 void reserve(const size_t dim)
1109 {
1110 if (dim > 0)
1111 reserve(0, dim - 1);
1112 }
1113
1114 void cut_ne(const size_t new_dim = 0)
1115 {
1116 if (new_dim == 0)
1117 {
1119 current_dim = 0;
1120 return;
1121 }
1122
1123 const size_t old_dim = current_dim; // old dimension
1124
1125 // segment and block first indexes
1126 const long idx_first_seg = index_in_dir(old_dim - 1);
1127 const long idx_first_block = index_in_seg(old_dim - 1);
1128
1129 // segment and block last indexes
1130 const long idx_last_seg = index_in_dir(new_dim - 1);
1131 const long idx_last_block = index_in_seg(new_dim - 1);
1132 for (long idx_seg = index_in_dir(old_dim - 1); idx_seg >= idx_last_seg;
1133 --idx_seg) // recorre descendentemente los segmentos
1134 {
1135 if (dir[idx_seg] == nullptr) // ¿hay un segmento?
1136 continue; // no ==> Advance to the next
1137
1138 long idx_block = // First block to be released
1140
1141 // Libera descendentemente los bloques reservados del segmento
1142 while ((idx_seg > idx_last_seg and idx_block >= 0) or
1144 {
1145 if (dir[idx_seg][idx_block] != nullptr) // ¿Hay un bloque aquí?
1147
1148 --idx_block;
1149 }
1150
1151 if (idx_block < 0)
1153 }
1154
1155 current_dim = new_dim; // Updates New Dimension
1156 }
1157
1164 void cut(const size_t new_dim = 0)
1165 {
1166 // Only shrinking is allowed; growing must be done via adjust().
1167 // If new_dim equals current_dim, this is a no-op and we return early.
1168 ah_length_error_if(new_dim > current_dim) << "new dimension greater than current dimension";
1169
1170 if (new_dim == current_dim)
1171 return;
1172
1173 cut_ne(new_dim);
1174 }
1175
1184 void adjust(const size_t dim)
1185 {
1186 if (dim > current_dim)
1187 reserve(dim);
1188 else
1189 cut(dim);
1190 }
1191
1195 {
1196 cut(0);
1197 }
1198
1205 {
1206 empty();
1207 }
1208
1209 Proxy operator [] (const size_t i) const
1210 {
1211 ah_out_of_range_error_if(i >= max_dim) << "index out of maximum range";
1212
1213 return Proxy(const_cast<DynArray<T> &>(*this), i);
1214 }
1215
1216 Proxy operator [] (const size_t i)
1217 {
1218 if (i >= max_dim)
1219 resize_dir(i);
1220
1221 return Proxy(const_cast<DynArray<T> &>(*this), i);
1222 }
1223
1227 {
1228 return touch(this->size());
1229 }
1230
1233 T &append(const T &data)
1234 {
1235 T &ref = this->append();
1236 ref = data;
1237 return ref;
1238 }
1239
1242 T &append(T &&data)
1243 {
1244 T &ref = this->append();
1245 ref = std::move(data);
1246 return ref;
1247 }
1248
1249 T &insert(const T &item)
1250 {
1251 this->append();
1252 open_gap(*this, current_dim);
1253 T &ret = access(0);
1254 ret = item;
1255 return ret;
1256 }
1257
1258 T &insert(T &&item)
1259 {
1260 this->append();
1261 open_gap(*this, current_dim);
1262 T &ret = access(0);
1263 ret = std::forward<T>(item);
1264 return ret;
1265 }
1266
1268 void push(const T &data)
1269 {
1270 this->append(data);
1271 }
1272
1274 T &push(T &&data)
1275 {
1276 return this->append(std::forward<T>(data));
1277 }
1278
1280 void put(const T &data)
1281 {
1282 this->append(data);
1283 }
1284
1286 T &put(T &&data)
1287 {
1288 return this->append(std::forward<T>(data));
1289 }
1290
1296 void remove(T &item)
1297 {
1298 ensure_not_empty("DynArray::remove(): empty array");
1299 std::swap(item, this->access(this->size() - 1));
1300 this->cut_ne(this->size() - 1);
1301 }
1302
1304 void erase(T &item)
1305 {
1306 remove(item);
1307 }
1308
1311 {
1312 return this->size() == 0;
1313 }
1314
1318 {
1319 Array<T> ret;
1320 ret.reserve(this->size());
1321 for (size_t i = 0; i < this->size(); ++i)
1322 ret.append(this->access(i));
1323 return ret;
1324 }
1325
1328 {
1329 if (current_dim < 2)
1330 return *this;
1331
1332 for (size_t i = 0, j = current_dim - 1; i < j; ++i, --j)
1333 std::swap(touch(i), touch(j));
1334
1335 return *this;
1336 }
1337
1340 {
1341 ensure_not_empty("DynArray::pop(): empty array");
1342 T ret_val = std::move(this->access(this->size() - 1));
1343 cut(size() - 1);
1344
1345 return ret_val;
1346 }
1347
1349 T &top() const
1350 {
1351 ensure_not_empty("DynArray::top(): empty array");
1352 return (*this)[size() - 1];
1353 }
1354
1357 T &get_first() const
1358 {
1359 ensure_not_empty("DynArray::get_first(): empty array");
1360 return (*this)[0];
1361 }
1362
1365 T &get_last() const
1366 {
1367 ensure_not_empty("DynArray::get_last(): empty array");
1368 return (*this)[size() - 1];
1369 }
1370
1382 {
1383 protected:
1385 long curr_idx = 0;
1386
1387 public:
1389
1396
1399
1402 {
1403 // empty
1404 }
1405
1413 {
1414 return array_ptr != nullptr and curr_idx >= 0 and
1415 static_cast<size_t>(curr_idx) < array_ptr->size();
1416 }
1417
1424 {
1425 const long n = array_ptr == nullptr ? 0 : static_cast<long>(array_ptr->size());
1426 return has_curr() and curr_idx == n - 1;
1427 }
1428
1431 {
1432 return array_ptr->access(curr_idx);
1433 }
1434
1441 T &get_curr() const
1442 {
1443 ah_underflow_error_if(curr_idx < 0) << "not current item in iterator";
1445 static_cast<size_t>(curr_idx) >= array_ptr->size())
1446 << "not current item in iterator";
1447 return get_curr_ne();
1448 }
1449
1452 {
1453 return curr_idx;
1454 }
1455
1459 {
1460 ++curr_idx;
1461 }
1462
1468 void next()
1469 {
1471 (curr_idx >= 0 and
1472 static_cast<size_t>(curr_idx) >= array_ptr->size()))
1473 << "not current item in iterator";
1474 next_ne();
1475 }
1476
1477 // Move the iterator one position backward guaranteeing no
1480 {
1481 --curr_idx;
1482 }
1483
1486 void prev()
1487 {
1488 ah_underflow_error_if(curr_idx == -1) << "not current item in iterator";
1489 prev_ne();
1490 }
1491
1494 {
1495 curr_idx = array_ptr == nullptr ? -1 : static_cast<long>(array_ptr->size()) - 1;
1496 }
1497
1500 {
1501 curr_idx = array_ptr == nullptr ? 0 : static_cast<long>(array_ptr->size());
1502 }
1503
1506 {
1507 curr_idx = 0;
1508 }
1509
1510 void set_pos(const long pos) noexcept
1511 {
1512 curr_idx = pos;
1513 }
1514 };
1515
1517 {
1518 return Iterator(*this);
1519 }
1520
1522 {
1523 return Iterator(*this);
1524 }
1525
1526 Iterator get_it(const size_t pos)
1527 {
1528 ah_out_of_range_error_if(pos >= size()) << "DynArray::get_it(pos): pos >= size()";
1529 Iterator it(*this);
1530 it.set_pos(static_cast<long>(pos));
1531 return it;
1532 }
1533
1534 Iterator get_it(const size_t pos) const
1535 {
1536 return const_cast<DynArray *>(this)->get_it(pos);
1537 }
1538
1539private:
1540 // superfast array traversal
1541 template <class Operation>
1543 {
1544 size_t dir_idx = 0, seg_idx = 0, block_idx = 0;
1545 for (size_t i = 0; i < current_dim; ++i)
1546 {
1547 if (not operation(dir[dir_idx][seg_idx][block_idx]))
1548 return false;
1549
1550 if (++block_idx == block_size)
1551 {
1552 block_idx = 0;
1553 if (++seg_idx == seg_size)
1554 {
1555 seg_idx = 0;
1556 ++dir_idx;
1557 }
1558 }
1559 }
1560 return true;
1561 }
1562
1563public:
1577 template <class Operation>
1579 {
1580 return const_cast<DynArray &>(*this).__traverse(operation);
1581 }
1582
1584 template <class Operation>
1586 {
1587 return __traverse(operation);
1588 }
1589
1591 template <class Operation>
1593 {
1595 }
1596
1598 template <class Operation>
1600 {
1602 }
1603};
1604
1605template <typename T>
1606const size_t DynArray<T>::Default_Pow_Dir = 6; /* 64 */
1607
1608template <typename T>
1609const size_t DynArray<T>::Default_Pow_Seg = 8; /* 256 */
1610
1611template <typename T>
1612const size_t DynArray<T>::Default_Pow_Block = 12; /* 4096 */
1613
1614template <typename T>
1615const size_t DynArray<T>::Max_Bits_Allowed = 8 * sizeof(size_t);
1616
1617template <typename T>
1618const unsigned long long DynArray<T>::Max_Dim_Allowed = 256 * 1024 * 1024 * 1024ull; // 256 Gb
1619
1620template <typename T>
1621const size_t DynArray<T>::Max_Pow_Block = (Max_Bits_Allowed - Default_Pow_Dir - Default_Pow_Seg - 1);
1622} // end namespace Aleph
1623
1624#endif /* TPL_DYNARRAY_H */
Variadic constructor macros for containers.
Container traversal and functional operation mixins.
Exception handling system with formatted messages for Aleph-w.
#define ah_length_error_if(C)
Throws std::length_error if condition holds.
Definition ah-errors.H:703
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
Definition ah-errors.H:584
#define ah_underflow_error_if(C)
Throws std::underflow_error if condition holds.
Definition ah-errors.H:373
#define ah_bad_alloc_unless(C)
Throws std::bad_alloc if condition does NOT hold.
Definition ah-errors.H:442
#define ah_overflow_error_if(C)
Throws std::overflow_error if condition holds.
Definition ah-errors.H:468
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:527
#define ah_invalid_argument_if(C)
Throws std::invalid_argument if condition holds.
Definition ah-errors.H:644
DRY (Don't Repeat Yourself) utilities and macros.
#define Special_Ctors(Set_Type, Type)
Generates special constructors for containers.
Definition ahDry.H:113
Iterator traits and STL-compatible iterator wrappers.
Core header for the Aleph-w library.
Utility functions for array manipulation.
size_t size_t int32_t value
Definition ca-c-api.h:116
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
void reserve(size_t cap)
Reserves cap cells into the array.
Definition tpl_array.H:320
Contiguous array of bits.
Definition bitArray.H:201
Iterator on the items of array.
void reset_last() noexcept
Reset the iterator to the last item.
long get_pos() const noexcept
Return the ordinal position of current item.
void set_pos(const long pos) noexcept
void reset_first() noexcept
Reset the iterator to the first item.
void prev()
Move the current a position backward.
T & get_curr_ne() const noexcept
Return the current link guaranteeing no exception. Be careful.
bool is_last() const noexcept
Check whether the current item is the last item.
void next()
Advance one position, from the last item to the end if needed.
void end() noexcept
Put the iterator in the end state.
Iterator() noexcept=default
Default constructor creates an "end" iterator.
bool has_curr() const noexcept
Check whether the iterator refers to an item.
void next_ne() noexcept
Move the iterator one position forward guaranteeing no exception.
T & get_curr() const
Return the current item.
void prev_ne() noexcept
exception. Be careful.
Proxy(DynArray< T > &_array, const size_t i) noexcept
Proxy & operator=(const T &data)
bool traverse(Operation &operation)
DynArray(const DynArray< T > &array)
Copy constructor.
void allocate_dir(T ***src_dir)
void release_block(T *&block) noexcept
void allocate_block(T *&block, T *src_block)
T * test(const size_t i) const noexcept
Test if the i-th entry es writable,.
size_t get_block_size() const noexcept
Return the block size.
bool __traverse(Operation &operation)
size_t index_in_dir(const size_t i) const noexcept
size_t index_in_seg(const size_t &i) const noexcept
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 ...
DynArray & reverse()
Reverse the order of items in an array.
size_t modulus_from_index_in_dir(const size_t i) const noexcept
void swap(DynArray< T > &array) noexcept
Swap in constant time array with this
Array< T > to_array() const
Copy contents into Aleph::Array (requires copyable elements).
T & put(T &&data)
size_t get_dir_size() const noexcept
Return the directory size.
void remove(T &item)
Given a valid reference to an item in the array, it removes it and decrease the dimension.
unsigned long long max_dim
static size_t compute_dim(size_t d, size_t s, size_t b) noexcept
void release_dir() noexcept
T Key_Type
The type of element stored in the array.
bool traverse(Operation &&operation)
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)
size_t seg_plus_block_pow
static size_t next2Pow(const size_t number) noexcept
Proxy operator[](const size_t i) const
void cut_ne(const size_t new_dim=0)
Iterator get_it(const size_t pos) const
T & get_first() const
Return a modifiable reference to the first item of array (as if this was a queue)
DynArray(const size_t _pow_dir, const size_t _pow_seg, const size_t _pow_block)
Construct a dynamic array given directory, segment and block sizes.
void reserve(const size_t dim)
Assure that the range between 0 and dim is allocated.
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 & append(const T &data)
Copy data to the end of array, increase the dimension and return a modifiable reference to the copied...
void copy_array(const DynArray< T > &src_array)
Copy the items of src_array to this
static const size_t Default_Pow_Seg
Default two power for directory size.
T & touch(const size_t i)
Touch the entry i.
size_t size() const noexcept
Return the current dimension of array.
void release_blocks_and_segment(T **&seg) noexcept
void allocate_segment(T **&seg)
Iterator get_it() const
static const size_t Max_Pow_Block
T pop()
Remove the last item of array (as if this was a stack)
bool traverse(Operation &&operation) const
T & access(const size_t i) const noexcept
Fast access without checking allocation and bound_min_clock checking.
static const size_t Default_Pow_Dir
The type of element stored in the array.
T * default_initial_value_ptr
DynArray(const size_t dim=0)
Default constructor.
void fill_dir_to_null() noexcept
void set_default_initial_value(T &&value=T())
static const size_t Default_Pow_Block
Default two power for segment size.
size_t max_size() const noexcept
Return the maximum allowed dimension (or the maximum number of elements that could have the array tre...
void resize_dir(const size_t i)
T & push(T &&data)
void release_all_segments_and_blocks() noexcept
bool exist(const size_t i) const
Return true if the i-th entry is accessible.
size_t modulus_by_block_size(const size_t number) const noexcept
size_t divide_by_block_size(const size_t number) const noexcept
static void compute_sizes(const size_t n, size_t &d, size_t &s, size_t &b) noexcept
Given a dimension n, it proposes values for the directory, segment and block sizes.
size_t mask_seg_plus_block
bool traverse(Operation &operation) const
Traverse all the array and execute a conditioned operation must have the signature:
static const unsigned long long Max_Dim_Allowed
Maximum dimension allowed.
T & append(T &&data)
Move data to the end of array, increase the dimension and return a modifiable reference to the copied...
size_t get_seg_size() const noexcept
Return the segment size.
T & top() const
Return a modifiable reference to the last item of stack.
void allocate_segment(T **&seg, T **src_seg)
void allocate_block(T *&block)
DynArray< T > & operator=(const DynArray< T > &array)
Copy assignment.
void release_segment(T **&seg) noexcept
T & insert(T &&item)
Iterator get_it(const size_t pos)
static std::tuple< size_t, size_t, size_t > compute_sizes(const size_t n) noexcept
Given a dimension n, it proposes values for the directory, segment and block sizes.
void ensure_not_empty(const char *context) const
void put(const T &data)
size_t index_in_block(const size_t i) const noexcept
T & append()
Allocate a new entry to the end of array.
static const size_t Max_Bits_Allowed
Default two power for block size.
bool is_empty() const noexcept
Return true if the array is empty.
void fill_seg_to_null(T **seg) noexcept
next_permutation for DynArray
void empty() noexcept
Empty the array.
DynArray(DynArray &&other) noexcept
Move constructor.
static size_t two_raised(const size_t n) noexcept
void reserve(const size_t l, const size_t r)
Allocate a range of entries.
void erase(T &item)
T & operator()(const size_t i) const noexcept
Mixin providing equality comparison for sequence containers.
Definition ah-dry.H:1891
Common methods to the Aleph-w ( ) containers.
Definition ah-dry.H:658
and
Conditional mapping of the elements of the container.
Definition ah-dry.H:1137
Common sequential searching methods on containers.
Definition ah-dry.H:200
Mixin that adds STL begin()/end() and cbegin()/cend() to Aleph containers.
__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
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_log_function > > log(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4074
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_ceil_function > > ceil(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4067
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.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
void open_gap(Tarray &ptr, size_t n, size_t pos=0, size_t num_entries=1)
Open a gap in an array by shifting elements right.
Definition array_utils.H:96
STL namespace.
Generic list of items stored in a container.
Definition ah-dry.H:1846
static int * k
gsl_rng * r
Dynamic array container with automatic resizing.
Dynamic doubly linked list implementation.
DynList< int > l