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
31
44# ifndef TPL_DYNARRAY_H
45# define TPL_DYNARRAY_H
46
47# include <cmath>
48
49# include <string>
50# include <vector>
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 <ah-errors.H>
61
62namespace Aleph
63{
64 class BitArray; // forward needed
65
199 template <typename T>
200 class DynArray : public LocateFunctions<DynArray<T>, T>,
201 public FunctionalMethods<DynArray<T>, T>,
202 public GenericKeys<DynArray<T>, T>,
203 public EqualToMethod<DynArray<T>>,
204 public StlAlephIterator<DynArray<T>>
205 {
206 friend class BitArray; // for access to __traversal() method
207
208 // look at the end of this file for seeing the values
209 public:
210 using Item_Type = T;
211 using Key_Type = T;
212
213 static const size_t Default_Pow_Dir;
214 static const size_t Default_Pow_Seg;
215 static const size_t Default_Pow_Block;
216
217 private:
218 static const size_t Max_Bits_Allowed;
219
220 public:
222 static const unsigned long long Max_Dim_Allowed;
223
224 private:
225 static const size_t Max_Pow_Block;
226
227 mutable size_t pow_dir = Default_Pow_Dir;
228 mutable size_t pow_seg = Default_Pow_Seg;
229 mutable size_t pow_block =
233 mutable size_t dir_size = two_raised(pow_dir); // = 2^pow_dir
234 mutable size_t seg_size = two_raised(pow_seg); // = 2^pow_seg
235 mutable size_t block_size = two_raised(pow_block); // = 2^pow_block
236
237 // 2^(pow_dir + pow_seg + pow_block) - 1
239
240 static size_t two_raised(const size_t n) noexcept
241 {
243 << "two_raised: exponent " << n << " is too large";
244 return static_cast<size_t>(1) << n;
245 }
246
247 static size_t compute_dim(size_t d, size_t s, size_t b) noexcept
248 {
249 return two_raised(d) * two_raised(s) * two_raised(b);
250 }
251
252 public:
261 static void compute_sizes(const size_t n, size_t & d, size_t & s, size_t & b)
262 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)
290 noexcept
291 {
292 size_t d, s, b;
293 compute_sizes(n, d, s, b);
294 return std::make_tuple(d, s, b);
295 }
296
297 private:
298 size_t mask_seg = seg_size - 1;
299 size_t mask_block = block_size - 1;
300
301 size_t index_in_dir(const size_t i) const noexcept
302 {
306
307 return i >> seg_plus_block_pow;
308 }
309
310 size_t modulus_from_index_in_dir(const size_t i) const noexcept
311 {
314
315 return (i & mask_seg_plus_block);
316 }
317
318 size_t index_in_seg(const size_t & i) const noexcept
319 {
323
325 }
326
327 size_t index_in_block(const size_t i) const noexcept
328 {
332
334 }
335
337 size_t num_segs = 0;
338 size_t num_blocks = 0;
339 T ***dir = nullptr;
340
342 {
343 assert(dir != nullptr);
344
345 for (size_t i = 0; i < dir_size; ++i)
346 dir[i] = nullptr;
347 }
348
349 void fill_seg_to_null(T **seg) noexcept
350 {
351 assert(seg != nullptr);
352
353 for (size_t i = 0; i < seg_size; ++i)
354 seg[i] = nullptr;
355 }
356
358 {
359 dir = static_cast<T ***>(malloc(dir_size * sizeof(T **)));
360 ah_bad_alloc_unless(dir != nullptr);
361
363 }
364
365 void resize_dir(const size_t i) // resize dir to fit index i
366 {
367 assert(i >= max_dim);
368
369 size_t new_pow_dir = pow_dir + 1;
371 ++new_pow_dir;
372
373 const size_t new_dir_sz = two_raised(new_pow_dir);
374 T ***new_dir = static_cast<T ***>(realloc(dir, new_dir_sz * sizeof(T **)));
375 ah_bad_alloc_unless(new_dir != nullptr);
376
377 dir = new_dir;
378 for (size_t k = dir_size; k < new_dir_sz; ++k)
379 dir[k] = nullptr;
380
383
385 }
386
388 {
389 assert(seg == nullptr);
390
391 seg = new T *[seg_size];
393 ++num_segs;
394 }
395
398
399 void allocate_block(T *& block)
400 {
401 assert(block == nullptr);
402
403 block = new T [block_size];
404 ++num_blocks;
405
406 if (default_initial_value_ptr == nullptr)
407 return;
408
409 for (size_t i = 0; i < block_size; ++i)
410 block[i] = *default_initial_value_ptr;
411 }
412
413 void release_segment(T **& seg) noexcept
414 {
415 assert(seg != nullptr);
416
417 delete [] seg;
418 seg = nullptr;
419 --num_segs;
420 }
421
422 void release_block(T *& block) noexcept
423 {
424 assert(block != nullptr);
425
426 delete [] block;
427 block = nullptr;
428 --num_blocks;
429 }
430
431 void release_blocks_and_segment(T ** & seg) noexcept
432 {
433 assert(seg != nullptr);
434
435 for (size_t i = 0; i < seg_size; ++i)
436 if (seg[i] != nullptr)
437 release_block(seg[i]);
438
440 }
441
442 void ensure_not_empty(const char *context) const
443 {
445 }
446
448 {
449 assert(dir != nullptr);
450
451 for (size_t i = 0; i < dir_size; ++i)
452 if (dir[i] != nullptr)
454
455 current_dim = 0;
456 }
457
459 {
460 if (dir == nullptr)
461 return;
462
464 if (dir != nullptr)
465 free(dir);
466
467 dir = nullptr;
468 current_dim = 0;
469 }
470
471 static size_t next2Pow(const size_t number) noexcept
472 {
473 return static_cast<size_t>(ceil(log(static_cast<float>(number)) / log(2.0)));
474 }
475
476 size_t divide_by_block_size(const size_t number) const noexcept
477 {
478 assert(number/block_size == number >> pow_block);
479
480 return number >> pow_block;
481 }
482
483 size_t modulus_by_block_size(const size_t number) const noexcept
484 {
485 assert((number%block_size) == (number & mask_block));
486
487 return number & mask_block;
488 }
489
491 const size_t len) const noexcept
492 {
493 if (block_index + len < block_size)
494 {
495 block_index += len;
496 return;
497 }
498
501 }
502
503 void allocate_block(T *& block, T *src_block)
504 {
505 allocate_block(block);
506 for (size_t i = 0; i < block_size; i++)
507 block[i] = src_block[i];
508 }
509
511 {
513 for (size_t i = 0; i < seg_size; i++)
514 if (src_seg[i] != nullptr)
515 allocate_block(seg[i], src_seg[i]);
516 }
517
519 {
520 allocate_dir();
521 for (size_t i = 0; i < dir_size; i++)
522 if (src_dir[i] != nullptr)
524 }
525
526 class Proxy
527 {
528 size_t index;
535
536 public:
537 Proxy(DynArray<T> & _array, const size_t i) noexcept
538 : index(i), pos_in_dir(_array.index_in_dir(index)),
539 pos_in_seg(_array.index_in_seg(index)),
540 pos_in_block(_array.index_in_block(index)),
541 ref_seg(_array.dir[pos_in_dir]), block(nullptr), array(_array)
542 {
543 if (ref_seg != nullptr)
544 block = ref_seg[pos_in_seg]; // Entry block already exists
545 }
546
547 operator T &()
548 {
549 ah_invalid_argument_if(block == nullptr) << "accessed entry not been still written";
550 return block[pos_in_block];
551 }
552
554 {
556
557 if (ref_seg == nullptr) // Is there a segment?
558 { // No ==> allocate it!
561 }
562
563 if (block == nullptr) // test if block is allocated
564 {
565 try
566 {
569
571 }
572 catch (...)
573 {
576
577 throw;
578 }
579 }
580
581 if (index >= array.current_dim)
582 array.current_dim = index + 1;
583
584 return &block[pos_in_block];
585 }
586
587 Proxy &operator =(const T & data)
588 {
590 if (ref_seg == nullptr) // Is there a segment?
591 { // No ==> allocate ii!
594 }
595
596 if (block == nullptr) // test if block is allocated
597 {
598 try
599 {
602
604 }
605 catch (...)
606 {
609
610 throw;
611 }
612 }
613
614 if (index >= array.current_dim)
615 array.current_dim = index + 1;
616
617 block[pos_in_block] = data;
618
619 return *this;
620 }
621
623 {
624 ah_domain_error_if(proxy.block == nullptr) << "right entry has not been still written";
625
626 if (&proxy == this)
627 return *this;
628
630 if (ref_seg == nullptr) // Is there a segment?
631 { // No ==> allocate it!
634 }
635
636 if (block == nullptr) // test if block is allocated
637 {
638 try
639 {
642
644 }
645 catch (...)
646 {
649
650 throw;
651 }
652 }
653
654 if (index >= array.current_dim)
655 array.current_dim = index + 1;
656
657 block[pos_in_block] = proxy.block[proxy.pos_in_block];
658
659 return *this;
660 }
661 };
662
663 public:
665 size_t get_dir_size() const noexcept { return dir_size; }
666
668 size_t get_seg_size() const noexcept { return seg_size; }
669
672
676 size_t size() const noexcept { return current_dim; }
677
682 size_t max_size() const noexcept { return max_dim; }
683
686
694 void set_default_initial_value(const T & value) noexcept
695 {
696 default_initial_value = value;
698 }
699
701 void set_default_initial_value(T && value = T())
702 {
703 std::swap(default_initial_value, value);
705 }
706
722 DynArray(const size_t _pow_dir, const size_t _pow_seg, const size_t _pow_block)
723 : pow_dir(_pow_dir),
732 mask_seg(seg_size - 1),
734 current_dim(0),
735 num_segs(0),
736 num_blocks(0)
737 {
738 static_assert(std::is_copy_constructible_v<T>, "No copy constructor for T");
739 static_assert(std::is_move_constructible_v<T>, "No move constructor for T");
740 static_assert(std::is_copy_assignable_v<T>, "No copy assign for T");
741 static_assert(std::is_move_assignable_v<T>, "No move assign for T");
743
744 ah_length_error_if(max_dim > Max_Dim_Allowed) << "Dimension too large";
745
746 allocate_dir();
747 }
748
757 DynArray(const size_t dim = 0)
759 {
760 static_assert(std::is_default_constructible_v<T>, "No default constructor for T");
761 static_assert(std::is_copy_constructible_v<T>, "No copy constructor for T");
762 static_assert(std::is_move_constructible_v<T>, "No move constructor for T");
763 static_assert(std::is_copy_assignable_v<T>, "No copy assign for T");
764 static_assert(std::is_move_assignable_v<T>, "No move assign for T");
766
767 ah_length_error_if(max_dim > Max_Dim_Allowed) << "Dimension too large";
768
769 allocate_dir();
770 }
771
773
775 {
776 release_dir();
777 }
778
784 {
785 for (size_t i = 0; i < src_array.current_dim; ++i)
786 if (src_array.exist(i))
787 (*this)[i] = src_array.access(i);
788 }
789
795 DynArray(const DynArray<T> & array)
796 : pow_dir(array.pow_dir),
797 pow_seg(array.pow_seg),
798 pow_block(array.pow_block),
801 dir_size(array.dir_size),
802 seg_size(array.seg_size),
803 block_size(array.block_size),
804 max_dim(array.max_dim),
805 mask_seg(array.mask_seg),
806 mask_block(array.mask_block),
807 current_dim(0),
808 num_segs(0),
809 num_blocks(0),
810 dir(nullptr),
813 {
814 allocate_dir(array.dir);
815 copy_array(array);
816 }
817
824 {
825 if (this == &array)
826 return *this;
827
828 copy_array(array);
829
830 if (array.current_dim < current_dim)
831 cut(array.current_dim);
832
833 current_dim = array.current_dim;
834
835 return *this;
836 }
837
843 void swap(DynArray<T> & array) noexcept
844 {
845 std::swap(dir, array.dir);
846 std::swap(pow_dir, array.pow_dir);
847 std::swap(pow_seg, array.pow_seg);
848 std::swap(pow_block, array.pow_block);
849 std::swap(seg_plus_block_pow, array.seg_plus_block_pow);
850 std::swap(mask_seg_plus_block, array.mask_seg_plus_block);
851 std::swap(dir_size, array.dir_size);
852 std::swap(seg_size, array.seg_size);
853 std::swap(block_size, array.block_size);
854 std::swap(mask_seg, array.mask_seg);
855 std::swap(mask_block, array.mask_block);
856 std::swap(max_dim, array.max_dim);
857 std::swap(current_dim, array.current_dim);
858 std::swap(num_segs, array.num_segs);
859 std::swap(num_blocks, array.num_blocks);
860
861 std::swap(default_initial_value, array.default_initial_value);
862
864 array.default_initial_value_ptr = &array.default_initial_value;
865 }
866
888
891 {
892 swap(other);
893 return *this;
894 }
895
904 T &access(const size_t i) const noexcept
905 {
906 assert(dir[index_in_dir(i)] != nullptr);
907 assert(dir[index_in_dir(i)][index_in_seg(i)] != nullptr);
908
909 return dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
910 }
911
913 T &operator ()(const size_t i) const noexcept
914 {
915 return access(i);
916 }
917
925 bool exist(const size_t i) const
926 {
927 if (i >= max_dim)
928 return false;
929
930 const size_t pos_in_dir = index_in_dir(i);
931
932 assert(pos_in_dir < dir_size);
933
934 if (dir[pos_in_dir] == nullptr)
935 return false;
936
937 const size_t pos_in_seg = index_in_seg(i);
938
939 assert(pos_in_seg < seg_size);
940
941 if (dir[pos_in_dir][pos_in_seg] == nullptr)
942 return false;
943
944 return true;
945 }
946
957 T * test(const size_t i) const noexcept
958 {
959 if (i >= max_dim)
960 return nullptr;
961
962 const size_t pos_in_dir = index_in_dir(i);
963 if (dir[pos_in_dir] == nullptr)
964 return nullptr;
965
966 const size_t pos_in_seg = index_in_seg(i);
967 if (dir[pos_in_dir][pos_in_seg] == nullptr)
968 return nullptr;
969
970 return &dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
971 }
972
988 T &touch(const size_t i)
989 {
990 if (i >= max_dim)
991 resize_dir(i);
992
993 const size_t pos_in_dir = index_in_dir(i);
994 bool new_segment = false;
995 if (dir[pos_in_dir] == nullptr)
996 {
997 allocate_segment(dir[pos_in_dir]);
998 new_segment = true;
999 }
1000
1001 const size_t pos_in_seg = index_in_seg(i);
1002 if (dir[pos_in_dir][pos_in_seg] == nullptr)
1003 {
1004 try
1005 {
1006 allocate_block(dir[pos_in_dir][pos_in_seg]);
1007 }
1008 catch (...)
1009 {
1010 if (new_segment && dir[pos_in_dir] != nullptr)
1011 release_segment(dir[pos_in_dir]);
1012 throw;
1013 }
1014 }
1015
1016 if (i >= current_dim)
1017 current_dim = i + 1;
1018
1019 return dir[pos_in_dir][pos_in_seg][index_in_block(i)];
1020 }
1021
1033 void reserve(const size_t l, const size_t r)
1034 {
1035 ah_domain_error_if(l > r) << "invalid range";
1036
1037 if (r >= max_dim)
1038 resize_dir(r);
1039
1040 const size_t first_seg = index_in_dir(l);
1041 const size_t last_seg = index_in_dir(r);
1042 const size_t first_block = index_in_seg(l);
1043 const size_t last_block = index_in_seg(r);
1044
1045 std::vector<size_t> new_segments;
1046 std::vector<std::pair<size_t, size_t>> new_blocks;
1047
1048 try
1049 {
1050 for (size_t seg_idx = first_seg; seg_idx <= last_seg; ++seg_idx)
1051 {
1052 if (dir[seg_idx] == nullptr)
1053 {
1055 new_segments.push_back(seg_idx);
1056 }
1057
1058 size_t block_idx = (seg_idx == first_seg) ? first_block : 0;
1059 const size_t final_block =
1060 (seg_idx == last_seg) ? last_block : seg_size - 1;
1061
1062 while (block_idx <= final_block)
1063 {
1064 if (dir[seg_idx][block_idx] == nullptr)
1065 {
1067 new_blocks.emplace_back(seg_idx, block_idx);
1068 }
1069
1070 ++block_idx;
1071 }
1072 } // end for (...)
1073 }
1074 catch (...)
1075 {
1076 for (auto it = new_blocks.rbegin(); it != new_blocks.rend(); ++it)
1077 {
1078 const auto [seg_idx, block_idx] = *it;
1079 if (dir[seg_idx] != nullptr and dir[seg_idx][block_idx] != nullptr)
1081 }
1082
1083 for (auto it = new_segments.rbegin(); it != new_segments.rend(); ++it)
1084 {
1085 const auto seg_idx = *it;
1086 if (dir[seg_idx] != nullptr)
1088 }
1089
1090 throw;
1091 }
1092
1093 if (r + 1 > current_dim)
1094 current_dim = r + 1;
1095 }
1096
1102 void reserve(const size_t dim)
1103 {
1104 if (dim > 0)
1105 reserve(0, dim - 1);
1106 }
1107
1108 void cut_ne(const size_t new_dim = 0)
1109 {
1110 if (new_dim == 0)
1111 {
1113 current_dim = 0;
1114 return;
1115 }
1116
1117 const size_t old_dim = current_dim; // old dimension
1118
1119 // segment and block first indexes
1120 const long idx_first_seg = index_in_dir(old_dim - 1);
1121 const long idx_first_block = index_in_seg(old_dim - 1);
1122
1123 // segment and block last indexes
1124 const long idx_last_seg = index_in_dir(new_dim - 1);
1125 const long idx_last_block = index_in_seg(new_dim - 1);
1126 for (long idx_seg = index_in_dir(old_dim - 1); idx_seg >= idx_last_seg;
1127 --idx_seg) // recorre descendentemente los segmentos
1128 {
1129 if (dir[idx_seg] == nullptr) // ¿hay un segmento?
1130 continue; // no ==> Advance to the next
1131
1132 long idx_block = // First block to be released
1134
1135 // Libera descendentemente los bloques reservados del segmento
1136 while ((idx_seg > idx_last_seg and idx_block >= 0) or
1138 {
1139 if (dir[idx_seg][idx_block] != nullptr) // ¿Hay un bloque aquí?
1141
1142 --idx_block;
1143 }
1144
1145 if (idx_block < 0)
1147 }
1148
1149 current_dim = new_dim; // Updates New Dimension
1150 }
1151
1158 void cut(const size_t new_dim = 0)
1159 {
1160 // Only shrinking is allowed; growing must be done via adjust().
1161 // If new_dim equals current_dim, this is a no-op and we return early.
1163 << "new dimension greater than current dimension";
1164
1165 if (new_dim == current_dim)
1166 return;
1167
1168 cut_ne(new_dim);
1169 }
1170
1179 void adjust(const size_t dim)
1180 {
1181 if (dim > current_dim)
1182 reserve(dim);
1183 else
1184 cut(dim);
1185 }
1186
1189 void empty() noexcept { cut(0); }
1190
1191 Proxy operator [](const size_t i) const
1192 {
1193 ah_out_of_range_error_if(i >= max_dim) << "index out of maximum range";
1194
1195 return Proxy(const_cast<DynArray<T> &>(*this), i);
1196 }
1197
1198 Proxy operator [](const size_t i)
1199 {
1200 if (i >= max_dim)
1201 resize_dir(i);
1202
1203 return Proxy(const_cast<DynArray<T> &>(*this), i);
1204 }
1205
1209 {
1210 return touch(this->size());
1211 }
1212
1215 T &append(const T & data)
1216 {
1217 T & ref = this->append();
1218 ref = data;
1219 return ref;
1220 }
1221
1224 T &append(T && data)
1225 {
1226 T & ref = this->append();
1227 ref = std::move(data);
1228 return ref;
1229 }
1230
1231 T &insert(const T & item)
1232 {
1233 this->append();
1234 open_gap(*this, current_dim);
1235 T & ret = access(0);
1236 ret = item;
1237 return ret;
1238 }
1239
1240 T &insert(T && item)
1241 {
1242 this->append();
1243 open_gap(*this, current_dim);
1244 T & ret = access(0);
1245 ret = std::forward<T>(item);
1246 return ret;
1247 }
1248
1250 void push(const T & data) { this->append(data); }
1251
1253 T &push(T && data) { return this->append(std::forward<T>(data)); }
1254
1256 void put(const T & data) { this->append(data); }
1257
1259 T &put(T && data) { return this->append(std::forward<T>(data)); }
1260
1266 void remove(T & item)
1267 {
1268 ensure_not_empty("DynArray::remove(): empty array");
1269 std::swap(item, this->access(this->size() - 1));
1270 this->cut_ne(this->size() - 1);
1271 }
1272
1274 void erase(T & item) { remove(item); }
1275
1277 bool is_empty() const noexcept { return this->size() == 0; }
1278
1281 {
1282 for (size_t i = 0, j = current_dim - 1; i < j; ++i, --j)
1283 swap(touch(i), touch(j));
1284
1285 return *this;
1286 }
1287
1290 {
1291 ensure_not_empty("DynArray::pop(): empty array");
1292 T ret_val = std::move(this->access(this->size() - 1));
1293 cut(size() - 1);
1294
1295 return ret_val;
1296 }
1297
1299 T &top() const
1300 {
1301 ensure_not_empty("DynArray::top(): empty array");
1302 return (*this)[size() - 1];
1303 }
1304
1307 T &get_first() const
1308 {
1309 ensure_not_empty("DynArray::get_first(): empty array");
1310 return (*this)[0];
1311 }
1312
1315 T &get_last() const
1316 {
1317 ensure_not_empty("DynArray::get_last(): empty array");
1318 return (*this)[size() - 1];
1319 }
1320
1332 {
1333 protected:
1335 long curr_idx = 0;
1336
1337 public:
1339
1342
1345 : array_ptr(const_cast<DynArray *>(&array))
1346 {
1347 // empty
1348 }
1349
1352 {
1353 return curr_idx >= 0 and curr_idx < array_ptr->size();
1354 }
1355
1356 [[nodiscard]] bool is_last() const noexcept { return curr_idx == array_ptr->size() - 1; }
1357
1360
1365 T &get_curr() const
1366 {
1367 ah_overflow_error_if(curr_idx == array_ptr->size()) << "not current item in iterator";
1368 return get_curr_ne();
1369 }
1370
1372 [[nodiscard]] long get_pos() const noexcept { return curr_idx; }
1373
1377
1380 void next()
1381 {
1382 ah_overflow_error_if(curr_idx == array_ptr->size()) << "not current item in iterator";
1383 next_ne();
1384 }
1385
1386 // Move the iterator one position backward guaranteeing no
1389
1392 void prev()
1393 {
1394 ah_underflow_error_if(curr_idx == -1) << "not current item in iterator";
1395 prev_ne();
1396 }
1397
1400
1403
1406
1407 void set_pos(const long pos) noexcept { curr_idx = pos; }
1408 };
1409
1411 {
1412 return Iterator(*this);
1413 }
1414
1416 {
1417 return Iterator(*this);
1418 }
1419
1420 Iterator get_it(const size_t pos)
1421 {
1422 ah_out_of_range_error_if(pos >= size()) << "DynArray::get_it(pos): pos >= size()";
1423 Iterator it(*this);
1424 it.set_pos(static_cast<long>(pos));
1425 return it;
1426 }
1427
1428 Iterator get_it(const size_t pos) const
1429 {
1430 return const_cast<DynArray *>(this)->get_it(pos);
1431 }
1432
1433 private:
1434 // superfast array traversal
1435 template <class Operation>
1437 {
1438 size_t dir_idx = 0, seg_idx = 0, block_idx = 0;
1439 for (size_t i = 0; i < current_dim; ++i)
1440 {
1442 return false;
1443
1444 if (++block_idx == block_size)
1445 {
1446 block_idx = 0;
1447 if (++seg_idx == seg_size)
1448 {
1449 seg_idx = 0;
1450 ++dir_idx;
1451 }
1452 }
1453 }
1454 return true;
1455 }
1456
1457 public:
1471 template <class Operation>
1473 {
1474 return const_cast<DynArray &>(*this).__traverse(operation);
1475 }
1476
1478 template <class Operation>
1480 {
1481 return __traverse(operation);
1482 }
1483
1485 template <class Operation>
1487 {
1489 }
1490
1492 template <class Operation>
1494 {
1496 }
1497 };
1498
1499 template <typename T>
1500 const size_t DynArray<T>::Default_Pow_Dir = 6; /* 64 */
1501
1502 template <typename T>
1503 const size_t DynArray<T>::Default_Pow_Seg = 8; /* 256 */
1504
1505 template <typename T>
1506 const size_t DynArray<T>::Default_Pow_Block = 12; /* 4096 */
1507
1508 template <typename T>
1509 const size_t DynArray<T>::Max_Bits_Allowed = 8 * sizeof(size_t);
1510
1511 template <typename T>
1512 const unsigned long long DynArray<T>::Max_Dim_Allowed =
1513 256 * 1024 * 1024 * 1024ull; // 256 Gb
1514
1515 template <typename T>
1516 const size_t DynArray<T>::Max_Pow_Block =
1517 (Max_Bits_Allowed - Default_Pow_Dir - Default_Pow_Seg - 1);
1518} // end namespace Aleph
1519
1520# 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:698
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
Definition ah-errors.H:579
#define ah_underflow_error_if(C)
Throws std::underflow_error if condition holds.
Definition ah-errors.H:368
#define ah_bad_alloc_unless(C)
Throws std::bad_alloc if condition does NOT hold.
Definition ah-errors.H:437
#define ah_overflow_error_if(C)
Throws std::overflow_error if condition holds.
Definition ah-errors.H:463
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
#define ah_invalid_argument_if(C)
Throws std::invalid_argument if condition holds.
Definition ah-errors.H:639
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.
Contiguous array of bits.
Definition bitArray.H:189
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
void next()
Move the current a position forward.
void end() noexcept
Put the iterator in the end state.
Iterator() noexcept=default
Default constructor creates an "end" iterator.
bool has_curr() const noexcept
Return true if there is current 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 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
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
void advance_block_index(size_t block_index, size_t seg_index, const size_t len) const 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.
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
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
Equality test for containers.
Definition ah-dry.H:1534
Common methods to the Aleph-w ( ) containers.
Definition ah-dry.H:548
Aleph::DynList< __T > maps(Operation &op) const
Map the elements of the container.
Definition ah-dry.H:904
Common sequential searching methods on containers.
Definition ah-dry.H:164
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:4052
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_log_function > > log(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4063
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_ceil_function > > ceil(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4056
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:107
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
DynList< T > maps(const C &c, Op op)
Classic map operation.
Generic list of items stored in a container.
Definition ah-dry.H:1501
Dynamic doubly linked list implementation.
DynList< int > l