2 # ifndef TPL_DYNARRAY_H
3 # define TPL_DYNARRAY_H
14 using namespace Aleph;
80 static const size_t Default_Pow_Dir;
81 static const size_t Default_Pow_Seg;
82 static const size_t Default_Pow_Block;
84 static const size_t Max_Bits_Allowed;
86 static const unsigned long long Max_Dim_Allowed;
90 static const size_t Max_Pow_Block;
92 mutable size_t pow_dir = Default_Pow_Dir;
93 mutable size_t pow_seg = Default_Pow_Seg;
94 mutable size_t pow_block =
95 std::min(Default_Pow_Block, Max_Pow_Block);
96 mutable size_t seg_plus_block_pow = pow_seg + pow_block;
97 mutable size_t mask_seg_plus_block = two_raised(seg_plus_block_pow) - 1;
98 mutable size_t dir_size = two_raised(pow_dir);
99 mutable size_t seg_size = two_raised(pow_seg);
100 mutable size_t block_size = two_raised(pow_block);
103 unsigned long long max_dim = two_raised(seg_plus_block_pow + pow_dir);
105 static size_t two_raised(
const size_t n)
107 if (n >= Max_Bits_Allowed)
108 throw std::overflow_error (
"number of bits exceeds maximum allowed");
113 static size_t compute_dim(
size_t d,
size_t s,
size_t b)
115 return two_raised(d)*two_raised(s)*two_raised(b);
123 static void compute_sizes(
const size_t n,
size_t & d,
size_t & s,
size_t & b)
127 b = Default_Pow_Block;
128 if (compute_dim(d, s, b) >= n)
133 if (compute_dim(++d, s, b) >= n)
136 if (compute_dim(d, ++s, b) >= n)
139 if (compute_dim(d, s, ++b) >= n)
146 size_t mask_seg = seg_size - 1;
147 size_t mask_block = block_size - 1;
149 size_t index_in_dir(
const size_t i)
const
151 I( (pow_block + pow_seg) == seg_plus_block_pow );
152 I( seg_size * block_size == two_raised(seg_plus_block_pow) );
153 I( i >> seg_plus_block_pow == i/(seg_size*block_size) );
155 return i >> seg_plus_block_pow;
158 size_t modulus_from_index_in_dir(
const size_t i)
const
160 I( mask_seg_plus_block == seg_size*block_size - 1 );
161 I( (i & mask_seg_plus_block) == i%(seg_size*block_size) );
163 return (i & mask_seg_plus_block);
166 size_t index_in_seg(
const size_t & i)
const
168 I( two_raised(pow_block) == block_size );
169 I( (modulus_from_index_in_dir(i) >> pow_block) ==
170 (i%(seg_size*block_size))/block_size );
172 return modulus_from_index_in_dir(i) >> pow_block;
175 size_t index_in_block(
const size_t i)
const
177 I( mask_block == block_size - 1 );
178 I( (modulus_from_index_in_dir(i) & mask_block) ==
179 ((i%(seg_size*block_size))%block_size) );
181 return modulus_from_index_in_dir(i) & mask_block;
186 size_t num_blocks = 0;
189 void fill_dir_to_null()
193 for (
size_t i = 0; i < dir_size; ++i)
197 void fill_seg_to_null(T ** seg)
201 for (
size_t i = 0; i < seg_size; ++i)
207 dir = (T***) malloc(dir_size*
sizeof(T**));
209 throw std::bad_alloc();
214 void resize_dir(
const size_t i)
218 size_t new_pow_dir = pow_dir + 1;
219 while (compute_dim(new_pow_dir, pow_seg, pow_block) <= i)
222 const size_t new_dir_sz = two_raised(new_pow_dir);
223 T *** new_dir = (T***) realloc(dir, new_dir_sz*
sizeof(T**));
225 throw std::bad_alloc();
228 for (
size_t k = dir_size; k < new_dir_sz; ++k)
231 pow_dir = new_pow_dir;
232 dir_size = new_dir_sz;
234 max_dim = compute_dim(pow_dir, pow_seg, pow_block);
237 void allocate_segment(T **& seg)
241 seg =
new T* [seg_size];
242 fill_seg_to_null(seg);
246 T default_initial_value = T();
247 T * default_initial_value_ptr = &default_initial_value;
249 void allocate_block(T *& block)
253 block =
new T [block_size];
256 if (default_initial_value_ptr == NULL)
259 for (
size_t i = 0; i < block_size; ++i)
260 block[i] = *default_initial_value_ptr;
263 void release_segment(T **& seg)
272 void release_block(T *& block)
281 void release_blocks_and_segment(T ** & seg)
285 for(
size_t i = 0; i < seg_size ; ++i)
287 release_block(seg[i]);
289 release_segment(seg);
292 void release_all_segments_and_blocks()
296 for(
size_t i = 0; i < dir_size ; ++i)
298 release_blocks_and_segment(dir[i]);
308 release_all_segments_and_blocks();
316 static size_t next2Pow(
const size_t number)
318 return (
size_t) ceil( log((
float) number)/ log(2.0) );
321 size_t divide_by_block_size(
const size_t number)
const
323 I(number/block_size == number >> pow_block);
325 return number >> pow_block;
328 size_t modulus_by_block_size(
const size_t number)
const
330 I((number%block_size) == (number & mask_block));
332 return number & mask_block;
335 void advance_block_index(
size_t block_index,
size_t seg_index,
336 const size_t len)
const
338 if (block_index + len < block_size)
344 seg_index += divide_by_block_size(len);
345 block_index = modulus_by_block_size(len);
348 void allocate_block(T *& block, T * src_block)
350 allocate_block(block);
351 for (
int i = 0; i < block_size; i++)
352 block[i] = src_block[i];
355 void allocate_segment(T **& seg, T ** src_seg)
357 allocate_segment(seg);
358 for (
int i = 0; i < seg_size; i++)
359 if (src_seg[i] != NULL)
360 allocate_block(seg[i], src_seg[i]);
363 void allocate_dir(T *** src_dir)
366 for (
int i = 0; i < dir_size; i++)
367 if (src_dir[i] != NULL)
368 allocate_segment(dir[i], src_dir[i]);
384 index(i), pos_in_dir(_array.index_in_dir(index)),
385 pos_in_seg(_array.index_in_seg(index)),
386 pos_in_block(_array.index_in_block(index)),
387 ref_seg(_array.dir[pos_in_dir]), block (NULL), array(_array)
390 block = ref_seg[pos_in_seg];
396 throw std::invalid_argument(
"accessed entry not been still written");
397 return block[pos_in_block];
402 bool seg_was_allocated_in_current_call =
false;
406 array.allocate_segment(ref_seg);
407 seg_was_allocated_in_current_call =
true;
414 array.allocate_block(block);
415 ref_seg[pos_in_seg] = block;
417 I(array.dir[pos_in_dir] == ref_seg);
421 if (seg_was_allocated_in_current_call)
422 array.release_segment(ref_seg);
428 if (index >= array.current_dim)
429 array.current_dim = index + 1;
431 return &block[pos_in_block];
434 Proxy & operator = (
const T & data)
436 bool seg_was_allocated_in_current_call =
false;
439 array.allocate_segment(ref_seg);
440 seg_was_allocated_in_current_call =
true;
447 array.allocate_block(block);
448 ref_seg[pos_in_seg] = block;
450 I(array.dir[pos_in_dir] == ref_seg);
454 if (seg_was_allocated_in_current_call)
455 array.release_segment(ref_seg);
461 if (index >= array.current_dim)
462 array.current_dim = index + 1;
464 block[pos_in_block] = data;
469 Proxy & operator = (
const Proxy & proxy)
471 if (proxy.block == NULL)
472 throw std::domain_error(
"right entry has not been still written");
477 bool seg_was_allocated_in_current_call =
false;
480 array.allocate_segment(ref_seg);
481 seg_was_allocated_in_current_call =
true;
488 array.allocate_block(block);
489 ref_seg[pos_in_seg] = block;
491 I(array.dir[pos_in_dir] == ref_seg);
495 if (seg_was_allocated_in_current_call)
496 array.release_segment(ref_seg);
502 if (index >= array.current_dim)
503 array.current_dim = index + 1;
505 block[pos_in_block] = proxy.block[proxy.pos_in_block];
523 size_t size()
const {
return current_dim; }
543 default_initial_value = value;
544 default_initial_value_ptr = &default_initial_value;
547 void set_default_initial_value(T && value = T())
549 std::swap(default_initial_value, value);
550 default_initial_value_ptr = &default_initial_value;
572 DynArray(
size_t _pow_dir,
size_t _pow_seg,
size_t _pow_block)
573 throw (std::exception, std::bad_alloc,
574 std::length_error, std::overflow_error)
575 : pow_dir ( _pow_dir ),
576 pow_seg ( _pow_seg ),
577 pow_block ( _pow_block ),
578 seg_plus_block_pow ( _pow_seg + _pow_block ),
579 mask_seg_plus_block ( two_raised(seg_plus_block_pow) - 1 ),
580 dir_size ( two_raised(pow_dir) ),
581 seg_size ( two_raised(pow_seg) ),
582 block_size ( two_raised(pow_block) ),
583 max_dim ( two_raised(seg_plus_block_pow + pow_dir) ),
584 mask_seg ( seg_size - 1 ),
585 mask_block ( block_size - 1 ),
590 I(Max_Dim_Allowed > 0);
592 if (max_dim > Max_Dim_Allowed)
593 throw std::length_error (
"Dimension too large");
618 throw (std::exception, std::bad_alloc,
619 std::length_error, std::overflow_error)
622 I(Max_Dim_Allowed > 0);
624 if (max_dim > Max_Dim_Allowed)
625 throw std::length_error (
"Dimension too large");
633 list.for_each([&i,
this] (
const T & item) { touch(i++) = item; });
655 for (
int i = 0; i < src_array.current_dim; ++i)
656 if (src_array.
exist(i))
657 (*
this)[i] = src_array.
access(i);
670 throw (std::exception, std::bad_alloc)
671 : pow_dir (array.pow_dir),
672 pow_seg (array.pow_seg),
673 pow_block (array.pow_block),
674 seg_plus_block_pow (array.seg_plus_block_pow),
675 mask_seg_plus_block (array.mask_seg_plus_block),
676 dir_size (array.dir_size),
677 seg_size (array.seg_size),
678 block_size (array.block_size),
679 max_dim (array.max_dim),
680 mask_seg (array.mask_seg),
681 mask_block (array.mask_block),
686 default_initial_value_ptr (array.default_initial_value_ptr)
688 allocate_dir(array.dir);
700 throw (std::exception, std::bad_alloc)
707 if (array.current_dim < current_dim)
708 cut(array.current_dim);
710 current_dim = array.current_dim;
727 std::swap(dir, array.dir);
728 std::swap(pow_dir, array.pow_dir);
729 std::swap(pow_seg, array.pow_seg);
730 std::swap(pow_block, array.pow_block);
731 std::swap(seg_plus_block_pow, array.seg_plus_block_pow);
732 std::swap(mask_seg_plus_block, array.mask_seg_plus_block);
733 std::swap(dir_size, array.dir_size);
734 std::swap(seg_size, array.seg_size);
735 std::swap(block_size, array.block_size);
736 std::swap(mask_seg, array.mask_seg);
737 std::swap(mask_block, array.mask_block);
738 std::swap(max_dim, array.max_dim);
739 std::swap(current_dim, array.current_dim);
740 std::swap(num_segs, array.num_segs);
741 std::swap(num_blocks, array.num_blocks);
745 : pow_dir ( Default_Pow_Dir ),
746 pow_seg ( Default_Pow_Seg ),
747 pow_block (std::min(Default_Pow_Block, Max_Pow_Block)),
748 seg_plus_block_pow ( pow_seg + pow_block ),
749 mask_seg_plus_block ( two_raised(seg_plus_block_pow) - 1 ),
750 dir_size ( two_raised(pow_dir) ),
751 seg_size ( two_raised(pow_seg) ),
752 block_size ( two_raised(pow_block) ),
753 max_dim ( two_raised(seg_plus_block_pow + pow_dir) ),
754 mask_seg ( seg_size - 1 ),
755 mask_block ( block_size - 1 ),
795 I(dir[index_in_dir(i)] != NULL);
796 I(dir[index_in_dir(i)][index_in_seg(i)] != NULL);
798 if (i >= current_dim)
801 return dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
804 T & operator () (
const size_t i)
830 I(dir[index_in_dir(i)] != NULL);
831 I(dir[index_in_dir(i)][index_in_seg(i)] != NULL);
833 return dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
836 const T & operator () (
const size_t i)
const
854 bool exist(
const size_t i)
const throw (std::exception, std::out_of_range)
857 throw std::out_of_range (
"index out of maximun range");
859 const size_t pos_in_dir = index_in_dir(i);
861 I(pos_in_dir < dir_size);
863 if (dir[pos_in_dir] == NULL)
866 const size_t pos_in_seg = index_in_seg(i);
868 I(pos_in_seg < seg_size);
870 if (dir[pos_in_dir][pos_in_seg] == NULL)
893 const size_t pos_in_dir = index_in_dir(i);
894 if (dir[pos_in_dir] == NULL)
897 const size_t pos_in_seg = index_in_seg(i);
898 if (dir[pos_in_dir][pos_in_seg] == NULL)
901 return &dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
916 throw (std::exception, std::bad_alloc, std::out_of_range)
921 const size_t pos_in_dir = index_in_dir(i);
922 if (dir[pos_in_dir] == NULL)
923 allocate_segment(dir[pos_in_dir]);
925 const size_t pos_in_seg = index_in_seg(i);
926 if (dir[pos_in_dir][pos_in_seg] == NULL)
930 allocate_block(dir[pos_in_dir][pos_in_seg]);
934 release_segment(dir[pos_in_dir]);
939 if (i >= current_dim)
942 return dir[pos_in_dir][pos_in_seg][index_in_block(i)];
961 throw (std::exception, std::bad_alloc, std::domain_error, std::length_error)
964 throw std::domain_error(
"invalid range");
969 const size_t first_seg = index_in_dir(l);
970 const size_t last_seg = index_in_dir(r);
971 const size_t first_block = index_in_seg(l);
972 const size_t last_block = index_in_seg(r);
976 for (
size_t seg_idx = first_seg; seg_idx <= last_seg; ++seg_idx)
978 if (dir[seg_idx] == NULL)
979 allocate_segment(dir[seg_idx]);
981 size_t block_idx = (seg_idx == first_seg) ? first_block : 0;
982 const size_t final_block =
983 (seg_idx == last_seg) ? last_block : seg_size - 1;
985 while (block_idx <= final_block)
987 if (dir[seg_idx][block_idx] == NULL)
988 allocate_block(dir[seg_idx][block_idx]);
994 if (r + 1 > current_dim)
999 if (r + 1 > current_dim)
1000 current_dim = r + 1;
1024 reserve(0, dim - 1);
1040 void cut(
const size_t new_dim = 0)
1041 throw (std::exception, std::domain_error)
1043 if (new_dim > current_dim)
1044 throw std::domain_error(
"new dimension greater that current dimension");
1048 release_all_segments_and_blocks();
1054 const size_t old_dim = current_dim;
1057 const int idx_first_seg = index_in_dir(old_dim - 1);
1058 const int idx_first_block = index_in_seg(old_dim - 1);
1061 const int idx_last_seg = index_in_dir(new_dim - 1);
1062 const int idx_last_block = index_in_seg(new_dim - 1);
1063 for (
int idx_seg = index_in_dir(old_dim - 1); idx_seg >= idx_last_seg;
1066 if (dir[idx_seg] == NULL)
1070 idx_seg == idx_first_seg ? idx_first_block : seg_size - 1;
1073 while ( (idx_seg > idx_last_seg and idx_block >= 0) or
1074 (idx_seg == idx_last_seg and idx_block > idx_last_block) )
1076 if (dir[idx_seg][idx_block] != NULL)
1077 release_block(dir[idx_seg][idx_block]);
1083 release_segment(dir[idx_seg]);
1086 current_dim = new_dim;
1093 Proxy operator [] (
const size_t i)
const
1094 throw (std::exception, std::bad_alloc, std::length_error,
1095 std::invalid_argument)
1098 throw std::out_of_range (
"index out of maximun range");
1100 return Proxy (
const_cast<DynArray<T>&
>(*
this), i);
1103 Proxy operator [] (
const size_t i)
1104 throw (std::exception, std::length_error,
1105 std::invalid_argument, std::bad_alloc)
1110 return Proxy (
const_cast<DynArray<T>&
>(*
this), i);
1117 return touch(this->size());
1124 T & ref = this->append();
1129 T & append(T && data)
1131 T & ref = this->append();
1132 std::swap(ref, data);
1137 void push(
const T & data) { this->append(data); }
1140 T &
push() {
return this->append(); }
1142 bool is_empty() {
return this->size() == 0; }
1147 T ret_val = this->access(this->size() - 1);
1154 T &
top() {
return (*
this)[size() - 1]; }
1169 Iterator() : array_ptr(NULL), curr_idx(0) { }
1172 : array_ptr(const_cast<DynArray*>(&array)), curr_idx(0)
1177 bool has_curr()
const
1179 return curr_idx >= 0 and curr_idx < array_ptr->size();
1182 bool has_current()
const {
return has_curr(); }
1184 T & get_curr() {
return array_ptr->access(curr_idx); }
1188 if (curr_idx == array_ptr->size())
1189 throw std::overflow_error(
"not current item in iterator");
1197 throw std::underflow_error(
"not current item in iterator");
1202 void reset_last() { curr_idx = array_ptr->size() - 1; }
1204 void reset_first() { curr_idx = 0; }
1206 void reset() { reset_first(); }
1212 template <
class Operation>
1213 bool __traverse(Operation & operation)
1215 size_t dir_idx = 0, seg_idx = 0, block_idx = 0;
1216 for (
size_t i = 0; i < current_dim; ++i)
1218 if (not operation(dir[dir_idx][seg_idx][block_idx]))
1221 if (++block_idx == block_size)
1224 if (++seg_idx == seg_size)
1250 template <
class Operation>
1253 return const_cast<DynArray&
>(*this).__traverse(operation);
1256 template <
class Operation>
1257 bool traverse(Operation & operation)
1259 return __traverse(operation);
1262 template <
class Operation>
1263 bool traverse(Operation && operation = Operation())
const
1265 return traverse<Operation>(operation);
1268 template <
class Operation>
1269 bool traverse(Operation && operation = Operation())
1271 return traverse<Operation>(operation);
1274 Functional_Methods(T);
1277 template <
typename T>
1280 template <
typename T>
1283 template <
typename T>
1286 template <
typename T>
1289 template <
typename T>
1291 256*1024*1024*1024ull;
1293 template <
typename T>
1295 (Max_Bits_Allowed - Default_Pow_Dir - Default_Pow_Seg - 1);
T pop()
Elimina el último elemento del arreglo como si fuese una pila.
Definition: tpl_dynArray.H:1145
void reserve(const size_t l, const size_t r)
Definition: tpl_dynArray.H:960
DynArray(const DynArray< T > &array)
Definition: tpl_dynArray.H:669
void empty()
Definition: tpl_dynArray.H:1091
void cut(const size_t new_dim=0)
Definition: tpl_dynArray.H:1040
size_t size() const
Retorna dimensión actual (más lejano índice escrito)
Definition: tpl_dynArray.H:523
size_t get_dir_size() const
Retorna tamaño del directorio.
Definition: tpl_dynArray.H:514
T & append(const T &data)
Definition: tpl_dynArray.H:1122
T & touch(const size_t i)
Definition: tpl_dynArray.H:915
void copy_array(const DynArray< T > &src_array)
Definition: tpl_dynArray.H:653
T & top()
Retorna el último elemento del arreglo como si fuese una pila.
Definition: tpl_dynArray.H:1154
void set_default_initial_value(const T &value)
Definition: tpl_dynArray.H:541
T & push()
Aparta un elemento al final del arrreglo.
Definition: tpl_dynArray.H:1140
T & get_first()
Retorna el último elemento del arreglo como si fuese una cola.
Definition: tpl_dynArray.H:1157
size_t get_seg_size() const
Retorna tamaño del segmento.
Definition: tpl_dynArray.H:517
bool exist(const size_t i) const
Definition: tpl_dynArray.H:854
void reserve(const size_t dim)
Definition: tpl_dynArray.H:1021
~DynArray()
Destructor que libera toda la memoria ocupada.
Definition: tpl_dynArray.H:637
const T & access(const size_t i) const
Definition: tpl_dynArray.H:828
T * test(const size_t i) const
Definition: tpl_dynArray.H:891
static void compute_sizes(const size_t n, size_t &d, size_t &s, size_t &b)
Definition: tpl_dynArray.H:123
T & get_last()
Retorna el primer elemento del arreglo como si fuese una cola.
Definition: tpl_dynArray.H:1160
T & append()
Definition: tpl_dynArray.H:1115
bool traverse(Operation &operation) const
Definition: tpl_dynArray.H:1251
size_t max_size() const
Retorna máxima dimensión permitida.
Definition: tpl_dynArray.H:526
Definition: tpl_dynArray.H:70
DynArray(size_t _pow_dir, size_t _pow_seg, size_t _pow_block)
Definition: tpl_dynArray.H:572
T & access(const size_t i)
Definition: tpl_dynArray.H:793
Definition: tpl_dynArray.H:1162
size_t get_block_size() const
Retorna tamaño del bloque.
Definition: tpl_dynArray.H:520
DynArray(const size_t dim=0)
Definition: tpl_dynArray.H:617
void push(const T &data)
Inserta como en una pila un elemento al final del arreglo.
Definition: tpl_dynArray.H:1137
size_t get_num_blocks() const
Retorna la cantidad de bloques actualmente apartados.
Definition: tpl_dynArray.H:529
void swap(DynArray< T > &array)
Definition: tpl_dynArray.H:725