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 <concepts>
52# include <aleph.H>
53# include <ahIterator.H>
54# include <array_utils.H>
55# include <ahDry.H>
56# include <tpl_dynDlist.H>
57# include <ah-args-ctor.H>
58# include <htlist.H>
59# include <ah-dry.H>
60# include <ah-errors.H>
61# include <ah-errors.H>
62# include <tpl_array.H>
63
64namespace Aleph
65{
66 class BitArray; // forward needed
67
201 template <typename T>
202 class DynArray : public LocateFunctions<DynArray<T>, T>,
203 public FunctionalMethods<DynArray<T>, T>,
204 public GenericKeys<DynArray<T>, T>,
205 public EqualSequenceMethod<DynArray<T>>,
206 public StlAlephIterator<DynArray<T>>
207 {
208 friend class BitArray; // for access to __traversal() method
209
210 // look at the end of this file for seeing the values
211 public:
212 using Item_Type = T;
213 using Key_Type = T;
214
215 static const size_t Default_Pow_Dir;
216 static const size_t Default_Pow_Seg;
217 static const size_t Default_Pow_Block;
218
219 private:
220 static const size_t Max_Bits_Allowed;
221
222 public:
224 static const unsigned long long Max_Dim_Allowed;
225
226 private:
227 static const size_t Max_Pow_Block;
228
229 mutable size_t pow_dir = Default_Pow_Dir;
230 mutable size_t pow_seg = Default_Pow_Seg;
231 mutable size_t 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 {
245 << "two_raised: exponent " << n << " is too large";
246 return static_cast<size_t>(1) << n;
247 }
248
249 static size_t compute_dim(size_t d, size_t s, size_t b) noexcept
250 {
251 return two_raised(d) * two_raised(s) * two_raised(b);
252 }
253
254 public:
263 static void compute_sizes(const size_t n, size_t & d, size_t & s, size_t & b)
264 noexcept
265 {
266 d = Default_Pow_Dir;
267 s = Default_Pow_Seg;
269 if (compute_dim(d, s, b) >= n)
270 return;
271
272 while (true)
273 {
274 if (compute_dim(++d, s, b) >= n)
275 break;
276
277 if (compute_dim(d, ++s, b) >= n)
278 break;
279
280 if (compute_dim(d, s, ++b) >= n)
281 break;
282 }
283 }
284
291 static std::tuple<size_t, size_t, size_t> compute_sizes(const size_t n)
292 noexcept
293 {
294 size_t d, s, b;
295 compute_sizes(n, d, s, b);
296 return std::make_tuple(d, s, b);
297 }
298
299 private:
300 size_t mask_seg = seg_size - 1;
301 size_t mask_block = block_size - 1;
302
303 size_t index_in_dir(const size_t i) const noexcept
304 {
308
309 return i >> seg_plus_block_pow;
310 }
311
312 size_t modulus_from_index_in_dir(const size_t i) const noexcept
313 {
316
317 return (i & mask_seg_plus_block);
318 }
319
320 size_t index_in_seg(const size_t & i) const noexcept
321 {
325
327 }
328
329 size_t index_in_block(const size_t i) const noexcept
330 {
334
336 }
337
339 size_t num_segs = 0;
340 size_t num_blocks = 0;
341 T ***dir = nullptr;
342
344 {
345 assert(dir != nullptr);
346
347 for (size_t i = 0; i < dir_size; ++i)
348 dir[i] = nullptr;
349 }
350
351 void fill_seg_to_null(T **seg) noexcept
352 {
353 assert(seg != nullptr);
354
355 for (size_t i = 0; i < seg_size; ++i)
356 seg[i] = nullptr;
357 }
358
360 {
361 dir = static_cast<T ***>(malloc(dir_size * sizeof(T **)));
362 ah_bad_alloc_unless(dir != nullptr);
363
365 }
366
367 void resize_dir(const size_t i) // resize dir to fit index i
368 {
369 assert(i >= max_dim);
370
371 size_t new_pow_dir = pow_dir + 1;
373 ++new_pow_dir;
374
375 const size_t new_dir_sz = two_raised(new_pow_dir);
376 T ***new_dir = static_cast<T ***>(realloc(dir, new_dir_sz * sizeof(T **)));
377 ah_bad_alloc_unless(new_dir != nullptr);
378
379 dir = new_dir;
380 for (size_t k = dir_size; k < new_dir_sz; ++k)
381 dir[k] = nullptr;
382
385
387 }
388
389 void allocate_segment(T **& seg)
390 {
391 assert(seg == nullptr);
392
393 seg = new T *[seg_size];
394 fill_seg_to_null(seg);
395 ++num_segs;
396 }
397
400
401 void allocate_block(T *& block)
402 {
403 assert(block == nullptr);
404
405 block = new T [block_size];
406 ++num_blocks;
407
408 if (default_initial_value_ptr == nullptr)
409 return;
410
411 for (size_t i = 0; i < block_size; ++i)
412 block[i] = *default_initial_value_ptr;
413 }
414
415 void release_segment(T **& seg) noexcept
416 {
417 assert(seg != nullptr);
418
419 delete [] seg;
420 seg = nullptr;
421 --num_segs;
422 }
423
424 void release_block(T *& block) noexcept
425 {
426 assert(block != nullptr);
427
428 delete [] block;
429 block = nullptr;
430 --num_blocks;
431 }
432
433 void release_blocks_and_segment(T ** & seg) noexcept
434 {
435 assert(seg != nullptr);
436
437 for (size_t i = 0; i < seg_size; ++i)
438 if (seg[i] != nullptr)
439 release_block(seg[i]);
440
441 release_segment(seg);
442 }
443
444 void ensure_not_empty(const char *context) const
445 {
447 }
448
450 {
451 assert(dir != nullptr);
452
453 for (size_t i = 0; i < dir_size; ++i)
454 if (dir[i] != nullptr)
456
457 current_dim = 0;
458 }
459
461 {
462 if (dir == nullptr)
463 return;
464
466 if (dir != nullptr)
467 free(dir);
468
469 dir = nullptr;
470 current_dim = 0;
471 }
472
473 static size_t next2Pow(const size_t number) noexcept
474 {
475 return static_cast<size_t>(ceil(log(static_cast<float>(number)) / log(2.0)));
476 }
477
478 size_t divide_by_block_size(const size_t number) const noexcept
479 {
480 assert(number/block_size == number >> pow_block);
481
482 return number >> pow_block;
483 }
484
485 size_t modulus_by_block_size(const size_t number) const noexcept
486 {
487 assert((number%block_size) == (number & mask_block));
488
489 return number & mask_block;
490 }
491
493 const size_t len) const noexcept
494 {
495 if (block_index + len < block_size)
496 {
497 block_index += len;
498 return;
499 }
500
503 }
504
505 void allocate_block(T *& block, T *src_block)
506 {
507 allocate_block(block);
508 for (size_t i = 0; i < block_size; i++)
509 block[i] = src_block[i];
510 }
511
512 void allocate_segment(T **& seg, T **src_seg)
513 {
514 allocate_segment(seg);
515 for (size_t i = 0; i < seg_size; i++)
516 if (src_seg[i] != nullptr)
517 allocate_block(seg[i], src_seg[i]);
518 }
519
521 {
522 allocate_dir();
523 for (size_t i = 0; i < dir_size; i++)
524 if (src_dir[i] != nullptr)
526 }
527
528 class Proxy
529 {
530 size_t index;
537
538 public:
539 Proxy(DynArray<T> & _array, const size_t i) noexcept
540 : index(i), pos_in_dir(_array.index_in_dir(index)),
541 pos_in_seg(_array.index_in_seg(index)),
542 pos_in_block(_array.index_in_block(index)),
543 ref_seg(_array.dir[pos_in_dir]), block(nullptr), array(_array)
544 {
545 if (ref_seg != nullptr)
546 block = ref_seg[pos_in_seg]; // Entry block already exists
547 }
548
549 operator T &()
550 {
551 ah_invalid_argument_if(block == nullptr) << "accessed entry not been still written";
552 return block[pos_in_block];
553 }
554
556 {
558
559 if (ref_seg == nullptr) // Is there a segment?
560 { // No ==> allocate it!
563 }
564
565 if (block == nullptr) // test if block is allocated
566 {
567 try
568 {
571
573 }
574 catch (...)
575 {
578
579 throw;
580 }
581 }
582
583 if (index >= array.current_dim)
584 array.current_dim = index + 1;
585
586 return &block[pos_in_block];
587 }
588
589 Proxy &operator =(const T & data)
590 {
592 if (ref_seg == nullptr) // Is there a segment?
593 { // No ==> allocate ii!
596 }
597
598 if (block == nullptr) // test if block is allocated
599 {
600 try
601 {
604
606 }
607 catch (...)
608 {
611
612 throw;
613 }
614 }
615
616 if (index >= array.current_dim)
617 array.current_dim = index + 1;
618
619 block[pos_in_block] = data;
620
621 return *this;
622 }
623
625 {
626 ah_domain_error_if(proxy.block == nullptr) << "right entry has not been still written";
627
628 if (&proxy == this)
629 return *this;
630
632 if (ref_seg == nullptr) // Is there a segment?
633 { // No ==> allocate it!
636 }
637
638 if (block == nullptr) // test if block is allocated
639 {
640 try
641 {
644
646 }
647 catch (...)
648 {
651
652 throw;
653 }
654 }
655
656 if (index >= array.current_dim)
657 array.current_dim = index + 1;
658
659 block[pos_in_block] = proxy.block[proxy.pos_in_block];
660
661 return *this;
662 }
663 };
664
665 public:
667 size_t get_dir_size() const noexcept { return dir_size; }
668
670 size_t get_seg_size() const noexcept { return seg_size; }
671
674
678 size_t size() const noexcept { return current_dim; }
679
684 size_t max_size() const noexcept { return max_dim; }
685
688
696 void set_default_initial_value(const T & value) noexcept
697 {
698 default_initial_value = value;
700 }
701
703 void set_default_initial_value(T && value = T())
704 {
705 std::swap(default_initial_value, value);
707 }
708
724 DynArray(const size_t _pow_dir, const size_t _pow_seg, const size_t _pow_block)
725 : pow_dir(_pow_dir),
734 mask_seg(seg_size - 1),
736 current_dim(0),
737 num_segs(0),
738 num_blocks(0)
739 {
740 static_assert(std::is_copy_constructible_v<T>, "No copy constructor for T");
741 static_assert(std::is_move_constructible_v<T>, "No move constructor for T");
742 static_assert(std::is_copy_assignable_v<T>, "No copy assign for T");
743 static_assert(std::is_move_assignable_v<T>, "No move assign for T");
745
746 ah_length_error_if(max_dim > Max_Dim_Allowed) << "Dimension too large";
747
748 allocate_dir();
749 }
750
759 DynArray(const size_t dim = 0)
761 {
762 static_assert(std::is_default_constructible_v<T>, "No default constructor for T");
763 static_assert(std::is_copy_constructible_v<T>, "No copy constructor for T");
764 static_assert(std::is_move_constructible_v<T>, "No move constructor for T");
765 static_assert(std::is_copy_assignable_v<T>, "No copy assign for T");
766 static_assert(std::is_move_assignable_v<T>, "No move assign for T");
768
769 ah_length_error_if(max_dim > Max_Dim_Allowed) << "Dimension too large";
770
771 allocate_dir();
772 }
773
775
777 {
778 release_dir();
779 }
780
786 {
787 for (size_t i = 0; i < src_array.current_dim; ++i)
788 if (src_array.exist(i))
789 (*this)[i] = src_array.access(i);
790 }
791
797 DynArray(const DynArray<T> & array)
798 : pow_dir(array.pow_dir),
799 pow_seg(array.pow_seg),
800 pow_block(array.pow_block),
803 dir_size(array.dir_size),
804 seg_size(array.seg_size),
805 block_size(array.block_size),
806 max_dim(array.max_dim),
807 mask_seg(array.mask_seg),
808 mask_block(array.mask_block),
809 current_dim(0),
810 num_segs(0),
811 num_blocks(0),
812 dir(nullptr),
815 {
816 allocate_dir(array.dir);
817 copy_array(array);
818 }
819
826 {
827 if (this == &array)
828 return *this;
829
830 copy_array(array);
831
832 if (array.current_dim < current_dim)
833 cut(array.current_dim);
834
835 current_dim = array.current_dim;
836
837 return *this;
838 }
839
845 void swap(DynArray<T> & array) noexcept
846 {
847 std::swap(dir, array.dir);
848 std::swap(pow_dir, array.pow_dir);
849 std::swap(pow_seg, array.pow_seg);
850 std::swap(pow_block, array.pow_block);
851 std::swap(seg_plus_block_pow, array.seg_plus_block_pow);
852 std::swap(mask_seg_plus_block, array.mask_seg_plus_block);
853 std::swap(dir_size, array.dir_size);
854 std::swap(seg_size, array.seg_size);
855 std::swap(block_size, array.block_size);
856 std::swap(mask_seg, array.mask_seg);
857 std::swap(mask_block, array.mask_block);
858 std::swap(max_dim, array.max_dim);
859 std::swap(current_dim, array.current_dim);
860 std::swap(num_segs, array.num_segs);
861 std::swap(num_blocks, array.num_blocks);
862
863 std::swap(default_initial_value, array.default_initial_value);
864
866 array.default_initial_value_ptr = &array.default_initial_value;
867 }
868
890
893 {
894 swap(other);
895 return *this;
896 }
897
906 T &access(const size_t i) const noexcept
907 {
908 assert(dir[index_in_dir(i)] != nullptr);
909 assert(dir[index_in_dir(i)][index_in_seg(i)] != nullptr);
910
911 return dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
912 }
913
915 T &operator ()(const size_t i) const noexcept
916 {
917 return access(i);
918 }
919
927 bool exist(const size_t i) const
928 {
929 if (i >= max_dim)
930 return false;
931
932 const size_t pos_in_dir = index_in_dir(i);
933
934 assert(pos_in_dir < dir_size);
935
936 if (dir[pos_in_dir] == nullptr)
937 return false;
938
939 const size_t pos_in_seg = index_in_seg(i);
940
941 assert(pos_in_seg < seg_size);
942
943 if (dir[pos_in_dir][pos_in_seg] == nullptr)
944 return false;
945
946 return true;
947 }
948
959 T * test(const size_t i) const noexcept
960 {
961 if (i >= max_dim)
962 return nullptr;
963
964 const size_t pos_in_dir = index_in_dir(i);
965 if (dir[pos_in_dir] == nullptr)
966 return nullptr;
967
968 const size_t pos_in_seg = index_in_seg(i);
969 if (dir[pos_in_dir][pos_in_seg] == nullptr)
970 return nullptr;
971
972 return &dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
973 }
974
990 T &touch(const size_t i)
991 {
992 if (i >= max_dim)
993 resize_dir(i);
994
995 const size_t pos_in_dir = index_in_dir(i);
996 bool new_segment = false;
997 if (dir[pos_in_dir] == nullptr)
998 {
999 allocate_segment(dir[pos_in_dir]);
1000 new_segment = true;
1001 }
1002
1003 const size_t pos_in_seg = index_in_seg(i);
1004 if (dir[pos_in_dir][pos_in_seg] == nullptr)
1005 {
1006 try
1007 {
1008 allocate_block(dir[pos_in_dir][pos_in_seg]);
1009 }
1010 catch (...)
1011 {
1012 if (new_segment && dir[pos_in_dir] != nullptr)
1013 release_segment(dir[pos_in_dir]);
1014 throw;
1015 }
1016 }
1017
1018 if (i >= current_dim)
1019 current_dim = i + 1;
1020
1021 return dir[pos_in_dir][pos_in_seg][index_in_block(i)];
1022 }
1023
1035 void reserve(const size_t l, const size_t r)
1036 {
1037 ah_domain_error_if(l > r) << "invalid range";
1038
1039 if (r >= max_dim)
1040 resize_dir(r);
1041
1042 const size_t first_seg = index_in_dir(l);
1043 const size_t last_seg = index_in_dir(r);
1044 const size_t first_block = index_in_seg(l);
1045 const size_t last_block = index_in_seg(r);
1046
1047 std::vector<size_t> new_segments;
1048 std::vector<std::pair<size_t, size_t>> new_blocks;
1049
1050 try
1051 {
1052 for (size_t seg_idx = first_seg; seg_idx <= last_seg; ++seg_idx)
1053 {
1054 if (dir[seg_idx] == nullptr)
1055 {
1056 allocate_segment(dir[seg_idx]);
1057 new_segments.push_back(seg_idx);
1058 }
1059
1060 size_t block_idx = (seg_idx == first_seg) ? first_block : 0;
1061 const size_t final_block =
1062 (seg_idx == last_seg) ? last_block : seg_size - 1;
1063
1064 while (block_idx <= final_block)
1065 {
1066 if (dir[seg_idx][block_idx] == nullptr)
1067 {
1068 allocate_block(dir[seg_idx][block_idx]);
1069 new_blocks.emplace_back(seg_idx, block_idx);
1070 }
1071
1072 ++block_idx;
1073 }
1074 } // end for (...)
1075 }
1076 catch (...)
1077 {
1078 for (auto it = new_blocks.rbegin(); it != new_blocks.rend(); ++it)
1079 {
1080 const auto [seg_idx, block_idx] = *it;
1081 if (dir[seg_idx] != nullptr and dir[seg_idx][block_idx] != nullptr)
1082 release_block(dir[seg_idx][block_idx]);
1083 }
1084
1085 for (auto it = new_segments.rbegin(); it != new_segments.rend(); ++it)
1086 {
1087 const auto seg_idx = *it;
1088 if (dir[seg_idx] != nullptr)
1089 release_segment(dir[seg_idx]);
1090 }
1091
1092 throw;
1093 }
1094
1095 if (r + 1 > current_dim)
1096 current_dim = r + 1;
1097 }
1098
1104 void reserve(const size_t dim)
1105 {
1106 if (dim > 0)
1107 reserve(0, dim - 1);
1108 }
1109
1110 void cut_ne(const size_t new_dim = 0)
1111 {
1112 if (new_dim == 0)
1113 {
1115 current_dim = 0;
1116 return;
1117 }
1118
1119 const size_t old_dim = current_dim; // old dimension
1120
1121 // segment and block first indexes
1122 const long idx_first_seg = index_in_dir(old_dim - 1);
1123 const long idx_first_block = index_in_seg(old_dim - 1);
1124
1125 // segment and block last indexes
1126 const long idx_last_seg = index_in_dir(new_dim - 1);
1127 const long idx_last_block = index_in_seg(new_dim - 1);
1128 for (long idx_seg = index_in_dir(old_dim - 1); idx_seg >= idx_last_seg;
1129 --idx_seg) // recorre descendentemente los segmentos
1130 {
1131 if (dir[idx_seg] == nullptr) // ¿hay un segmento?
1132 continue; // no ==> Advance to the next
1133
1134 long idx_block = // First block to be released
1136
1137 // Libera descendentemente los bloques reservados del segmento
1138 while ((idx_seg > idx_last_seg and idx_block >= 0) or
1140 {
1141 if (dir[idx_seg][idx_block] != nullptr) // ¿Hay un bloque aquí?
1143
1144 --idx_block;
1145 }
1146
1147 if (idx_block < 0)
1149 }
1150
1151 current_dim = new_dim; // Updates New Dimension
1152 }
1153
1160 void cut(const size_t new_dim = 0)
1161 {
1162 // Only shrinking is allowed; growing must be done via adjust().
1163 // If new_dim equals current_dim, this is a no-op and we return early.
1165 << "new dimension greater than current dimension";
1166
1167 if (new_dim == current_dim)
1168 return;
1169
1170 cut_ne(new_dim);
1171 }
1172
1181 void adjust(const size_t dim)
1182 {
1183 if (dim > current_dim)
1184 reserve(dim);
1185 else
1186 cut(dim);
1187 }
1188
1191 void empty() noexcept { cut(0); }
1192
1198 void clear() noexcept { empty(); }
1199
1200 Proxy operator [](const size_t i) const
1201 {
1202 ah_out_of_range_error_if(i >= max_dim) << "index out of maximum range";
1203
1204 return Proxy(const_cast<DynArray<T> &>(*this), i);
1205 }
1206
1207 Proxy operator [](const size_t i)
1208 {
1209 if (i >= max_dim)
1210 resize_dir(i);
1211
1212 return Proxy(const_cast<DynArray<T> &>(*this), i);
1213 }
1214
1218 {
1219 return touch(this->size());
1220 }
1221
1224 T &append(const T & data)
1225 {
1226 T & ref = this->append();
1227 ref = data;
1228 return ref;
1229 }
1230
1233 T &append(T && data)
1234 {
1235 T & ref = this->append();
1236 ref = std::move(data);
1237 return ref;
1238 }
1239
1240 T &insert(const T & item)
1241 {
1242 this->append();
1243 open_gap(*this, current_dim);
1244 T & ret = access(0);
1245 ret = item;
1246 return ret;
1247 }
1248
1249 T &insert(T && item)
1250 {
1251 this->append();
1252 open_gap(*this, current_dim);
1253 T & ret = access(0);
1254 ret = std::forward<T>(item);
1255 return ret;
1256 }
1257
1259 void push(const T & data) { this->append(data); }
1260
1262 T &push(T && data) { return this->append(std::forward<T>(data)); }
1263
1265 void put(const T & data) { this->append(data); }
1266
1268 T &put(T && data) { return this->append(std::forward<T>(data)); }
1269
1275 void remove(T & item)
1276 {
1277 ensure_not_empty("DynArray::remove(): empty array");
1278 std::swap(item, this->access(this->size() - 1));
1279 this->cut_ne(this->size() - 1);
1280 }
1281
1283 void erase(T & item) { remove(item); }
1284
1286 bool is_empty() const noexcept { return this->size() == 0; }
1287
1290 {
1291 Array<T> ret;
1292 ret.reserve(this->size());
1293 for (size_t i = 0; i < this->size(); ++i)
1294 ret.append(this->access(i));
1295 return ret;
1296 }
1297
1300 {
1301 for (size_t i = 0, j = current_dim - 1; i < j; ++i, --j)
1302 swap(touch(i), touch(j));
1303
1304 return *this;
1305 }
1306
1309 {
1310 ensure_not_empty("DynArray::pop(): empty array");
1311 T ret_val = std::move(this->access(this->size() - 1));
1312 cut(size() - 1);
1313
1314 return ret_val;
1315 }
1316
1318 T &top() const
1319 {
1320 ensure_not_empty("DynArray::top(): empty array");
1321 return (*this)[size() - 1];
1322 }
1323
1326 T &get_first() const
1327 {
1328 ensure_not_empty("DynArray::get_first(): empty array");
1329 return (*this)[0];
1330 }
1331
1334 T &get_last() const
1335 {
1336 ensure_not_empty("DynArray::get_last(): empty array");
1337 return (*this)[size() - 1];
1338 }
1339
1351 {
1352 protected:
1354 long curr_idx = 0;
1355
1356 public:
1358
1361
1364 : array_ptr(const_cast<DynArray *>(&array))
1365 {
1366 // empty
1367 }
1368
1371 {
1372 return curr_idx >= 0 and curr_idx < array_ptr->size();
1373 }
1374
1375 [[nodiscard]] bool is_last() const noexcept { return curr_idx == array_ptr->size() - 1; }
1376
1379
1384 T &get_curr() const
1385 {
1386 ah_overflow_error_if(curr_idx == array_ptr->size()) << "not current item in iterator";
1387 return get_curr_ne();
1388 }
1389
1391 [[nodiscard]] long get_pos() const noexcept { return curr_idx; }
1392
1396
1399 void next()
1400 {
1401 ah_overflow_error_if(curr_idx == array_ptr->size()) << "not current item in iterator";
1402 next_ne();
1403 }
1404
1405 // Move the iterator one position backward guaranteeing no
1408
1411 void prev()
1412 {
1413 ah_underflow_error_if(curr_idx == -1) << "not current item in iterator";
1414 prev_ne();
1415 }
1416
1419
1422
1425
1426 void set_pos(const long pos) noexcept { curr_idx = pos; }
1427 };
1428
1430 {
1431 return Iterator(*this);
1432 }
1433
1435 {
1436 return Iterator(*this);
1437 }
1438
1439 Iterator get_it(const size_t pos)
1440 {
1441 ah_out_of_range_error_if(pos >= size()) << "DynArray::get_it(pos): pos >= size()";
1442 Iterator it(*this);
1443 it.set_pos(static_cast<long>(pos));
1444 return it;
1445 }
1446
1447 Iterator get_it(const size_t pos) const
1448 {
1449 return const_cast<DynArray *>(this)->get_it(pos);
1450 }
1451
1452 private:
1453 // superfast array traversal
1454 template <class Operation>
1456 {
1457 size_t dir_idx = 0, seg_idx = 0, block_idx = 0;
1458 for (size_t i = 0; i < current_dim; ++i)
1459 {
1460 if (not operation(dir[dir_idx][seg_idx][block_idx]))
1461 return false;
1462
1463 if (++block_idx == block_size)
1464 {
1465 block_idx = 0;
1466 if (++seg_idx == seg_size)
1467 {
1468 seg_idx = 0;
1469 ++dir_idx;
1470 }
1471 }
1472 }
1473 return true;
1474 }
1475
1476 public:
1490 template <class Operation>
1492 {
1493 return const_cast<DynArray &>(*this).__traverse(operation);
1494 }
1495
1497 template <class Operation>
1499 {
1500 return __traverse(operation);
1501 }
1502
1504 template <class Operation>
1506 {
1508 }
1509
1511 template <class Operation>
1513 {
1515 }
1516 };
1517
1518 template <typename T>
1519 const size_t DynArray<T>::Default_Pow_Dir = 6; /* 64 */
1520
1521 template <typename T>
1522 const size_t DynArray<T>::Default_Pow_Seg = 8; /* 256 */
1523
1524 template <typename T>
1525 const size_t DynArray<T>::Default_Pow_Block = 12; /* 4096 */
1526
1527 template <typename T>
1528 const size_t DynArray<T>::Max_Bits_Allowed = 8 * sizeof(size_t);
1529
1530 template <typename T>
1531 const unsigned long long DynArray<T>::Max_Dim_Allowed =
1532 256 * 1024 * 1024 * 1024ull; // 256 Gb
1533
1534 template <typename T>
1535 const size_t DynArray<T>::Max_Pow_Block =
1536 (Max_Bits_Allowed - Default_Pow_Dir - Default_Pow_Seg - 1);
1537} // end namespace Aleph
1538
1539# 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.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
void reserve(size_t cap)
Reserves cap cells into the array.
Definition tpl_array.H:315
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 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
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.
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:1756
Common methods to the Aleph-w ( ) containers.
Definition ah-dry.H:642
Common sequential searching methods on containers.
Definition ah-dry.H:196
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
and
Check uniqueness with explicit hash + equality functors.
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.
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:1714
static int * k
gsl_rng * r
Dynamic array container with automatic resizing.
Dynamic doubly linked list implementation.
DynList< int > l