Aleph-w  1.9
General library for algorithms and data structures
tpl_dynArray.H
1 
2 # ifndef TPL_DYNARRAY_H
3 # define TPL_DYNARRAY_H
4 
5 # include <math.h>
6 
7 # include <string>
8 # include <aleph.H>
9 # include <ahIterator.H>
10 # include <array_utils.H>
11 # include <ahDry.H>
12 # include <tpl_dynDlist.H>
13 # include <ah-args-ctor.H>
14 # include <htlist.H>
15 # include <ah-dry.H>
16 
17 using namespace std;
18 
19 using namespace Aleph;
20 
21 namespace Aleph {
22 
23  class BitArray; // forward needed
24 
158  template <typename T>
159 class DynArray : public LocateFunctions<DynArray<T>, T>,
160  public FunctionalMethods<DynArray<T>, T>,
161  public GenericKeys<DynArray<T>, T>,
162  public EqualToMethod<DynArray<T>>,
163  public StlAlephIterator<DynArray<T>>
164 {
165  friend class BitArray; // for access to __traversal() method
166 
167  // look at the end of this file for seeing the values
168 public:
169 
170  using Item_Type = T;
171  using Key_Type = T;
172 
173  static const size_t Default_Pow_Dir;
174  static const size_t Default_Pow_Seg;
175  static const size_t Default_Pow_Block;
176 
177  private:
178 
179  static const size_t Max_Bits_Allowed;
180 
181  public:
182 
184  static const unsigned long long Max_Dim_Allowed;
185 
186 private:
187 
188  static const size_t Max_Pow_Block;
189 
190  mutable size_t pow_dir = Default_Pow_Dir;
191  mutable size_t pow_seg = Default_Pow_Seg;
192  mutable size_t pow_block =
193  std::min(Default_Pow_Block, Max_Pow_Block);
194  mutable size_t seg_plus_block_pow = pow_seg + pow_block;
195  mutable size_t mask_seg_plus_block = two_raised(seg_plus_block_pow) - 1;
196  mutable size_t dir_size = two_raised(pow_dir); // = 2^pow_dir
197  mutable size_t seg_size = two_raised(pow_seg); // = 2^pow_seg
198  mutable size_t block_size = two_raised(pow_block); // = 2^pow_block
199 
200  // 2^(pow_dir + pow_seg + pow_block) - 1
201  unsigned long long max_dim = two_raised(seg_plus_block_pow + pow_dir);
202 
203  static size_t two_raised(const size_t n) noexcept
204  {
205  assert(n < Max_Bits_Allowed);
206  return 1 << n;
207  }
208 
209  static size_t compute_dim(size_t d, size_t s, size_t b) noexcept
210  {
211  return two_raised(d)*two_raised(s)*two_raised(b);
212  }
213 
214 public:
215 
224  static void compute_sizes(const size_t n, size_t & d, size_t & s, size_t & b)
225  noexcept
226  {
227  d = Default_Pow_Dir;
228  s = Default_Pow_Seg;
229  b = Default_Pow_Block;
230  if (compute_dim(d, s, b) >= n)
231  return;
232 
233  while (true)
234  {
235  if (compute_dim(++d, s, b) >= n)
236  break;
237 
238  if (compute_dim(d, ++s, b) >= n)
239  break;
240 
241  if (compute_dim(d, s, ++b) >= n)
242  break;
243  }
244  }
245 
252  static std::tuple<size_t, size_t, size_t> compute_sizes(const size_t n)
253  noexcept
254  {
255  size_t d, s, b;
256  compute_sizes(n, d, s, b);
257  return make_tuple(d, s, b);
258  }
259 
260 private:
261 
262  size_t mask_seg = seg_size - 1;
263  size_t mask_block = block_size - 1;
264 
265  size_t index_in_dir(const size_t i) const noexcept
266  {
267  assert( (pow_block + pow_seg) == seg_plus_block_pow );
268  assert( seg_size * block_size == two_raised(seg_plus_block_pow) );
269  assert( i >> seg_plus_block_pow == i/(seg_size*block_size) );
270 
271  return i >> seg_plus_block_pow;
272  }
273 
274  size_t modulus_from_index_in_dir(const size_t i) const noexcept
275  {
276  assert( mask_seg_plus_block == seg_size*block_size - 1 );
277  assert( (i & mask_seg_plus_block) == i%(seg_size*block_size) );
278 
279  return (i & mask_seg_plus_block);
280  }
281 
282  size_t index_in_seg(const size_t & i) const noexcept
283  {
284  assert( two_raised(pow_block) == block_size );
285  assert( (modulus_from_index_in_dir(i) >> pow_block) ==
286  (i%(seg_size*block_size))/block_size );
287 
288  return modulus_from_index_in_dir(i) >> pow_block;
289  }
290 
291  size_t index_in_block(const size_t i) const noexcept
292  {
293  assert( mask_block == block_size - 1 );
294  assert( (modulus_from_index_in_dir(i) & mask_block) ==
295  ((i%(seg_size*block_size))%block_size) );
296 
297  return modulus_from_index_in_dir(i) & mask_block;
298  }
299 
300  size_t current_dim;
301  size_t num_segs = 0;
302  size_t num_blocks = 0;
303  T *** dir = nullptr;
304 
305  void fill_dir_to_null() noexcept
306  {
307  assert(dir != nullptr);
308 
309  for (size_t i = 0; i < dir_size; ++i)
310  dir[i] = nullptr;
311  }
312 
313  void fill_seg_to_null(T ** seg) noexcept
314  {
315  assert(seg != nullptr);
316 
317  for (size_t i = 0; i < seg_size; ++i)
318  seg[i] = nullptr;
319  }
320 
321  void allocate_dir()
322  {
323  dir = (T***) malloc(dir_size*sizeof(T**));
324  if (dir == nullptr)
325  throw std::bad_alloc();
326 
327  fill_dir_to_null();
328  }
329 
330  void resize_dir(const size_t i) // resize dir to fit index i
331  {
332  assert(i >= max_dim);
333 
334  size_t new_pow_dir = pow_dir + 1;
335  while (compute_dim(new_pow_dir, pow_seg, pow_block) <= i)
336  ++new_pow_dir;
337 
338  const size_t new_dir_sz = two_raised(new_pow_dir);
339  T *** new_dir = (T***) realloc(dir, new_dir_sz*sizeof(T**));
340  if (new_dir == nullptr)
341  throw std::bad_alloc();
342 
343  dir = new_dir;
344  for (size_t k = dir_size; k < new_dir_sz; ++k)
345  dir[k] = nullptr;
346 
347  pow_dir = new_pow_dir;
348  dir_size = new_dir_sz;
349 
350  max_dim = compute_dim(pow_dir, pow_seg, pow_block);
351  }
352 
353  void allocate_segment(T **& seg)
354  {
355  assert(seg == nullptr);
356 
357  seg = new T* [seg_size];
358  fill_seg_to_null(seg);
359  ++num_segs;
360  }
361 
362  T default_initial_value = T();
363  T * default_initial_value_ptr = &default_initial_value;
364 
365  void allocate_block(T *& block)
366  {
367  assert(block == nullptr);
368 
369  block = new T [block_size];
370  ++num_blocks;
371 
372  if (default_initial_value_ptr == nullptr)
373  return;
374 
375  for (size_t i = 0; i < block_size; ++i)
376  block[i] = *default_initial_value_ptr;
377  }
378 
379  void release_segment(T **& seg) noexcept
380  {
381  assert(seg != nullptr);
382 
383  delete [] seg;
384  seg = nullptr;
385  --num_segs;
386  }
387 
388  void release_block(T *& block) noexcept
389  {
390  assert(block != nullptr);
391 
392  delete [] block;
393  block = nullptr;
394  --num_blocks;
395  }
396 
397  void release_blocks_and_segment(T ** & seg) noexcept
398  {
399  assert(seg != nullptr);
400 
401  for(size_t i = 0; i < seg_size ; ++i)
402  if (seg[i] != nullptr)
403  release_block(seg[i]);
404 
405  release_segment(seg);
406  }
407 
408  void release_all_segments_and_blocks() noexcept
409  {
410  assert(dir != nullptr);
411 
412  for(size_t i = 0; i < dir_size ; ++i)
413  if (dir[i] != nullptr)
414  release_blocks_and_segment(dir[i]);
415 
416  current_dim = 0;
417  }
418 
419  void release_dir() noexcept
420  {
421  if (dir == nullptr)
422  return;
423 
424  release_all_segments_and_blocks();
425  if (dir != nullptr)
426  free(dir);
427 
428  dir = nullptr;
429  current_dim = 0;
430  }
431 
432  static size_t next2Pow(const size_t number) noexcept
433  {
434  return (size_t) ceil( log((float) number)/ log(2.0) );
435  }
436 
437  size_t divide_by_block_size(const size_t number) const noexcept
438  {
439  assert(number/block_size == number >> pow_block);
440 
441  return number >> pow_block;
442  }
443 
444  size_t modulus_by_block_size(const size_t number) const noexcept
445  {
446  assert((number%block_size) == (number & mask_block));
447 
448  return number & mask_block;
449  }
450 
451  void advance_block_index(size_t block_index, size_t seg_index,
452  const size_t len) const noexcept
453  {
454  if (block_index + len < block_size)
455  {
456  block_index += len;
457  return;
458  }
459 
460  seg_index += divide_by_block_size(len);
461  block_index = modulus_by_block_size(len);
462  }
463 
464  void allocate_block(T *& block, T * src_block)
465  {
466  allocate_block(block);
467  for (size_t i = 0; i < block_size; i++)
468  block[i] = src_block[i];
469  }
470 
471  void allocate_segment(T **& seg, T ** src_seg)
472  {
473  allocate_segment(seg);
474  for (size_t i = 0; i < seg_size; i++)
475  if (src_seg[i] != nullptr)
476  allocate_block(seg[i], src_seg[i]);
477  }
478 
479  void allocate_dir(T *** src_dir)
480  {
481  allocate_dir();
482  for (size_t i = 0; i < dir_size; i++)
483  if (src_dir[i] != nullptr)
484  allocate_segment(dir[i], src_dir[i]);
485  }
486 
487  class Proxy
488  {
489  size_t index;
490  size_t pos_in_dir;
491  size_t pos_in_seg;
492  size_t pos_in_block;
493  T **& ref_seg;
494  T * block;
495  DynArray & array;
496 
497  public:
498 
499  Proxy(DynArray<T> & _array, const size_t i) noexcept
500  : index(i), pos_in_dir(_array.index_in_dir(index)),
501  pos_in_seg(_array.index_in_seg(index)),
502  pos_in_block(_array.index_in_block(index)),
503  ref_seg(_array.dir[pos_in_dir]), block (nullptr), array(_array)
504  {
505  if (ref_seg != nullptr)
506  block = ref_seg[pos_in_seg]; // ya existe bloque para entrada i
507  }
508 
509  operator T & ()
510  {
511  if (block == nullptr)
512  throw std::invalid_argument("accessed entry not been still written");
513  return block[pos_in_block];
514  }
515 
516  T * operator -> ()
517  {
518  bool seg_was_allocated_in_current_call = false;
519 
520  if (ref_seg == nullptr) // hay segmento?
521  { // No ==> apartarlo!
522  array.allocate_segment(ref_seg);
523  seg_was_allocated_in_current_call = true;
524  }
525 
526  if (block == nullptr) // test if block is allocated
527  {
528  try // tratar apartar bloque
529  {
530  array.allocate_block(block);
531  ref_seg[pos_in_seg] = block;
532 
533  assert(array.dir[pos_in_dir] == ref_seg);
534  }
535  catch (...) // Ocurre una falla en el apartado del bloque
536  {
537  if (seg_was_allocated_in_current_call)
538  array.release_segment(ref_seg);
539 
540  throw;
541  }
542  }
543 
544  if (index >= array.current_dim)
545  array.current_dim = index + 1;
546 
547  return &block[pos_in_block];
548  }
549 
550  Proxy & operator = (const T & data)
551  {
552  bool seg_was_allocated_in_current_call = false;
553  if (ref_seg == nullptr) // hay segmento?
554  { // No ==> apartarlo!
555  array.allocate_segment(ref_seg);
556  seg_was_allocated_in_current_call = true;
557  }
558 
559  if (block == nullptr) // test if block is allocated
560  {
561  try // tratar apartar bloque
562  {
563  array.allocate_block(block);
564  ref_seg[pos_in_seg] = block;
565 
566  assert(array.dir[pos_in_dir] == ref_seg);
567  }
568  catch (...) // Ocurre una falla en el apartado del bloque
569  {
570  if (seg_was_allocated_in_current_call)
571  array.release_segment(ref_seg);
572 
573  throw;
574  }
575  }
576 
577  if (index >= array.current_dim)
578  array.current_dim = index + 1;
579 
580  block[pos_in_block] = data;
581 
582  return *this;
583  }
584 
585  Proxy & operator = (const Proxy & proxy)
586  {
587  if (proxy.block == nullptr) // ¿operando derecho puede leerse?
588  throw std::domain_error("right entry has not been still written");
589 
590  if (&proxy == this)
591  return *this;
592 
593  bool seg_was_allocated_in_current_call = false;
594  if (ref_seg == nullptr) // hay segmento?
595  { // No ==> apartarlo!
596  array.allocate_segment(ref_seg);
597  seg_was_allocated_in_current_call = true;
598  }
599 
600  if (block == nullptr) // test if block is allocated
601  {
602  try // tratar apartar bloque
603  {
604  array.allocate_block(block);
605  ref_seg[pos_in_seg] = block;
606 
607  assert(array.dir[pos_in_dir] == ref_seg);
608  }
609  catch (...) // Ocurre una falla en el apartado del bloque
610  {
611  if (seg_was_allocated_in_current_call)
612  array.release_segment(ref_seg);
613 
614  throw;
615  }
616  }
617 
618  if (index >= array.current_dim)
619  array.current_dim = index + 1;
620 
621  block[pos_in_block] = proxy.block[proxy.pos_in_block];
622 
623  return *this;
624  }
625  };
626 
627 public:
628 
630  size_t get_dir_size() const noexcept { return dir_size; }
631 
633  size_t get_seg_size() const noexcept { return seg_size; }
634 
636  size_t get_block_size() const noexcept { return block_size; }
637 
641  size_t size() const noexcept { return current_dim; }
642 
647  size_t max_size() const noexcept { return max_dim; }
648 
650  size_t get_num_blocks() const noexcept { return num_blocks; }
651 
659  void set_default_initial_value(const T & value) noexcept
660  {
661  default_initial_value = value;
662  default_initial_value_ptr = &default_initial_value;
663  }
664 
666  void set_default_initial_value(T && value = T())
667  noexcept(noexcept(std::swap(default_initial_value, value)))
668  {
669  std::swap(default_initial_value, value);
670  default_initial_value_ptr = &default_initial_value;
671  }
672 
688  DynArray(size_t _pow_dir, size_t _pow_seg, size_t _pow_block)
689  : pow_dir ( _pow_dir ),
690  pow_seg ( _pow_seg ),
691  pow_block ( _pow_block ),
692  seg_plus_block_pow ( _pow_seg + _pow_block ),
693  mask_seg_plus_block ( two_raised(seg_plus_block_pow) - 1 ),
694  dir_size ( two_raised(pow_dir) ),
695  seg_size ( two_raised(pow_seg) ),
696  block_size ( two_raised(pow_block) ),
697  max_dim ( two_raised(seg_plus_block_pow + pow_dir) ),
698  mask_seg ( seg_size - 1 ),
699  mask_block ( block_size - 1 ),
700  current_dim ( 0 ),
701  num_segs ( 0 ),
702  num_blocks ( 0 )
703  {
704  static_assert(std::is_copy_constructible<T>::value,
705  "No copy constructor for T");
706  static_assert(std::is_move_constructible<T>::value,
707  "No move constructor for T");
708  static_assert(std::is_copy_assignable<T>::value,
709  "No copy assign for T");
710  static_assert(std::is_move_assignable<T>::value,
711  "No move assign for T");
712  assert(Max_Dim_Allowed > 0);
713 
714  if (max_dim > Max_Dim_Allowed)
715  throw std::length_error ("Dimension too large");
716 
717  allocate_dir();
718  }
719 
728  DynArray(const size_t dim = 0)
729  : current_dim(dim)
730  {
731  static_assert(std::is_default_constructible<T>::value,
732  "No default constructor for T");
733  static_assert(std::is_copy_constructible<T>::value,
734  "No copy constructor for T");
735  static_assert(std::is_move_constructible<T>::value,
736  "No move constructor for T");
737  static_assert(std::is_copy_assignable<T>::value,
738  "No copy assign for T");
739  static_assert(std::is_move_assignable<T>::value,
740  "No move assign for T");
741  assert(Max_Dim_Allowed > 0);
742 
743  if (max_dim > Max_Dim_Allowed)
744  throw std::length_error ("Dimension too large");
745 
746  allocate_dir();
747  }
748 
749  Special_Ctors(DynArray, T);
750 
751  ~DynArray()
752  {
753  release_dir();
754  }
755 
760  void copy_array(const DynArray<T> & src_array)
761  {
762  for (size_t i = 0; i < src_array.current_dim; ++i)
763  if (src_array.exist(i))
764  (*this)[i] = src_array.access(i);
765  }
766 
772  DynArray(const DynArray<T> & array)
773  : pow_dir (array.pow_dir),
774  pow_seg (array.pow_seg),
775  pow_block (array.pow_block),
776  seg_plus_block_pow (array.seg_plus_block_pow),
777  mask_seg_plus_block (array.mask_seg_plus_block),
778  dir_size (array.dir_size),
779  seg_size (array.seg_size),
780  block_size (array.block_size),
781  max_dim (array.max_dim),
782  mask_seg (array.mask_seg),
783  mask_block (array.mask_block),
784  current_dim (0),
785  num_segs (0),
786  num_blocks (0),
787  dir (nullptr),
788  default_initial_value_ptr (array.default_initial_value_ptr)
789  {
790  allocate_dir(array.dir);
791  copy_array(array);
792  }
793 
799  DynArray<T> & operator = (const DynArray<T> & array)
800  {
801  if (this == &array)
802  return *this;
803 
804  copy_array(array);
805 
806  if (array.current_dim < current_dim)
807  cut(array.current_dim);
808 
809  current_dim = array.current_dim;
810 
811  return *this;
812  }
813 
819  void swap(DynArray<T> & array) noexcept
820  {
821  std::swap(dir, array.dir);
822  std::swap(pow_dir, array.pow_dir);
823  std::swap(pow_seg, array.pow_seg);
824  std::swap(pow_block, array.pow_block);
825  std::swap(seg_plus_block_pow, array.seg_plus_block_pow);
826  std::swap(mask_seg_plus_block, array.mask_seg_plus_block);
827  std::swap(dir_size, array.dir_size);
828  std::swap(seg_size, array.seg_size);
829  std::swap(block_size, array.block_size);
830  std::swap(mask_seg, array.mask_seg);
831  std::swap(mask_block, array.mask_block);
832  std::swap(max_dim, array.max_dim);
833  std::swap(current_dim, array.current_dim);
834  std::swap(num_segs, array.num_segs);
835  std::swap(num_blocks, array.num_blocks);
836  }
837 
839  DynArray(DynArray && other) noexcept
840  : pow_dir ( Default_Pow_Dir ),
841  pow_seg ( Default_Pow_Seg ),
842  pow_block (std::min(Default_Pow_Block, Max_Pow_Block)),
843  seg_plus_block_pow ( pow_seg + pow_block ),
844  mask_seg_plus_block ( two_raised(seg_plus_block_pow) - 1 ),
845  dir_size ( two_raised(pow_dir) ),
846  seg_size ( two_raised(pow_seg) ),
847  block_size ( two_raised(pow_block) ),
848  max_dim ( two_raised(seg_plus_block_pow + pow_dir) ),
849  mask_seg ( seg_size - 1 ),
850  mask_block ( block_size - 1 ),
851  current_dim ( 0 ),
852  num_segs ( 0 ),
853  num_blocks ( 0 ),
854  dir (nullptr )
855  {
856  swap(other);
857  }
858 
860  DynArray & operator = (DynArray && other) noexcept
861  {
862  swap(other);
863  return *this;
864  }
865 
874  T & access(const size_t i) const noexcept
875  {
876  assert(dir[index_in_dir(i)] != nullptr);
877  assert(dir[index_in_dir(i)][index_in_seg(i)] != nullptr);
878 
879  return dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
880  }
881 
883  T & operator () (const size_t i) const noexcept
884  {
885  return access(i);
886  }
887 
895  bool exist(const size_t i) const
896  {
897  if (i >= max_dim)
898  return false;
899 
900  const size_t pos_in_dir = index_in_dir(i);
901 
902  assert(pos_in_dir < dir_size);
903 
904  if (dir[pos_in_dir] == nullptr)
905  return false;
906 
907  const size_t pos_in_seg = index_in_seg(i);
908 
909  assert(pos_in_seg < seg_size);
910 
911  if (dir[pos_in_dir][pos_in_seg] == nullptr)
912  return false;
913 
914  return true;
915  }
916 
927  T * test(const size_t i) const noexcept
928  {
929  if (i >= max_dim)
930  return nullptr;
931 
932  const size_t pos_in_dir = index_in_dir(i);
933  if (dir[pos_in_dir] == nullptr)
934  return nullptr;
935 
936  const size_t pos_in_seg = index_in_seg(i);
937  if (dir[pos_in_dir][pos_in_seg] == nullptr)
938  return nullptr;
939 
940  return &dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
941  }
942 
958  T & touch(const size_t i)
959  {
960  if (i >= max_dim)
961  resize_dir(i);
962 
963  const size_t pos_in_dir = index_in_dir(i);
964  if (dir[pos_in_dir] == nullptr)
965  allocate_segment(dir[pos_in_dir]);
966 
967  const size_t pos_in_seg = index_in_seg(i);
968  if (dir[pos_in_dir][pos_in_seg] == nullptr)
969  {
970  try
971  {
972  allocate_block(dir[pos_in_dir][pos_in_seg]);
973  }
974  catch (...)
975  {
976  release_segment(dir[pos_in_dir]);
977  throw;
978  }
979  }
980 
981  if (i >= current_dim)
982  current_dim = i + 1;
983 
984  return dir[pos_in_dir][pos_in_seg][index_in_block(i)];
985  }
986 
998  void reserve(const size_t l, const size_t r)
999  {
1000  if (l > r)
1001  throw std::domain_error("invalid range");
1002 
1003  if (r >= max_dim)
1004  resize_dir(r);
1005 
1006  const size_t first_seg = index_in_dir(l);
1007  const size_t last_seg = index_in_dir(r);
1008  const size_t first_block = index_in_seg(l);
1009  const size_t last_block = index_in_seg(r);
1010 
1011  try
1012  {
1013  for (size_t seg_idx = first_seg; seg_idx <= last_seg; ++seg_idx)
1014  {
1015  if (dir[seg_idx] == nullptr)
1016  allocate_segment(dir[seg_idx]);
1017 
1018  size_t block_idx = (seg_idx == first_seg) ? first_block : 0;
1019  const size_t final_block =
1020  (seg_idx == last_seg) ? last_block : seg_size - 1;
1021 
1022  while (block_idx <= final_block)
1023  {
1024  if (dir[seg_idx][block_idx] == nullptr)
1025  allocate_block(dir[seg_idx][block_idx]);
1026 
1027  ++block_idx;
1028  }
1029  } // end for (...)
1030 
1031  if (r + 1 > current_dim)
1032  current_dim = r + 1;
1033  }
1034  catch (...)
1035  {
1036  if (r + 1 > current_dim)
1037  current_dim = r + 1;
1038 
1039  throw;
1040  }
1041  }
1042 
1048  void reserve(const size_t dim)
1049  {
1050  if (dim > 0)
1051  reserve(0, dim - 1);
1052  }
1053 
1054  void cut_ne(const size_t new_dim = 0)
1055  {
1056  if (new_dim == 0)
1057  {
1058  release_all_segments_and_blocks();
1059  current_dim = 0;
1060  return;
1061  }
1062 
1063  const size_t old_dim = current_dim; // old dimension
1064 
1065  // segment and block first indexes
1066  const long idx_first_seg = index_in_dir(old_dim - 1);
1067  const long idx_first_block = index_in_seg(old_dim - 1);
1068 
1069  // segment and block last indexes
1070  const long idx_last_seg = index_in_dir(new_dim - 1);
1071  const long idx_last_block = index_in_seg(new_dim - 1);
1072  for (long idx_seg = index_in_dir(old_dim - 1); idx_seg >= idx_last_seg;
1073  --idx_seg) // recorre descendentemente los segmentos
1074  {
1075  if (dir[idx_seg] == nullptr) // ¿hay un segmento?
1076  continue; // no ==> avance al siguiente
1077 
1078  long idx_block = // primer bloque a liberar
1079  idx_seg == idx_first_seg ? idx_first_block : seg_size - 1;
1080 
1081  // Libera descendentemente los bloques reservados del segmento
1082  while ( (idx_seg > idx_last_seg and idx_block >= 0) or
1083  (idx_seg == idx_last_seg and idx_block > idx_last_block) )
1084  {
1085  if (dir[idx_seg][idx_block] != nullptr) // ¿Hay un bloque aquí?
1086  release_block(dir[idx_seg][idx_block]);
1087 
1088  --idx_block;
1089  }
1090 
1091  if (idx_block < 0)
1092  release_segment(dir[idx_seg]);
1093  }
1094 
1095  current_dim = new_dim; // actualiza nueva dimensión
1096  }
1097 
1104  void cut(const size_t new_dim = 0)
1105  {
1106  if (new_dim > current_dim)
1107  throw std::length_error("new dimension greater that current dimension");
1108  cut_ne(new_dim);
1109  }
1110 
1119  void adjust(const size_t dim)
1120  {
1121  if (dim > current_dim)
1122  reserve(dim);
1123  else
1124  cut(dim);
1125  }
1126 
1129  void empty() noexcept { cut(0); }
1130 
1131  Proxy operator [] (const size_t i) const
1132  {
1133  if (i >= max_dim)
1134  throw std::out_of_range ("index out of maximun range");
1135 
1136  return Proxy (const_cast<DynArray<T>&>(*this), i);
1137  }
1138 
1139  Proxy operator [] (const size_t i)
1140  {
1141  if (i >= max_dim)
1142  resize_dir(i);
1143 
1144  return Proxy (const_cast<DynArray<T>&>(*this), i);
1145  }
1146 
1149  T & append()
1150  {
1151  return touch(this->size());
1152  }
1153 
1156  T & append(const T & data)
1157  {
1158  T & ref = this->append();
1159  ref = data;
1160  return ref;
1161  }
1162 
1165  T & append(T && data)
1166  {
1167  T & ref = this->append();
1168  ref = std::move(data);
1169  return ref;
1170  }
1171 
1172  T & insert(const T & item)
1173  {
1174  this->append();
1175  Aleph::open_gap(*this, current_dim);
1176  T & ret = access(0);
1177  ret = item;
1178  return ret;
1179  }
1180 
1181  T & insert(T && item)
1182  {
1183  this->append();
1184  Aleph::open_gap(*this, current_dim);
1185  T & ret = access(0);
1186  ret = std::forward<T>(item);
1187  return ret;
1188  }
1189 
1191  void push(const T & data) { this->append(data); }
1192 
1194  T & push(T && data) { return this->append(std::forward<T>(data)); }
1195 
1197  void put(const T & data) { this->append(data); }
1198 
1200  T & put(T && data) { return this->append(std::forward<T>(data)); }
1201 
1207  void remove(T & item) noexcept
1208  {
1209  std::swap(item, this->access(this->size() - 1));
1210  this->cut_ne(this->size() - 1);
1211  }
1212 
1214  void erase(T & item) noexcept { remove(item); }
1215 
1217  bool is_empty() const noexcept { return this->size() == 0; }
1218 
1221  {
1222  for (size_t i = 0, j = current_dim - 1; i < j; ++i, --j)
1223  swap(touch(i), touch(j));
1224 
1225  return *this;
1226  }
1227 
1229  T pop()
1230  {
1231  T ret_val = std::move(this->access(this->size() - 1));
1232  cut(size() - 1);
1233 
1234  return ret_val;
1235  }
1236 
1238  T & top() const { return (*this)[size() - 1]; }
1239 
1242  T & get_first() const { return (*this)[0]; }
1243 
1246  T & get_last() const { return (*this)[size() - 1]; }
1247 
1258  class Iterator
1259  {
1260  protected:
1261 
1262  DynArray * array_ptr = nullptr;
1263  long curr_idx = 0;
1264 
1265  public:
1266 
1267  using Set_Type = DynArray;
1268 
1270  Iterator(const DynArray & array) noexcept
1271  : array_ptr(const_cast<DynArray*>(&array)), curr_idx(0)
1272  {
1273  // empty
1274  }
1275 
1277  bool has_curr() const noexcept
1278  {
1279  return curr_idx >= 0 and curr_idx < array_ptr->size();
1280  }
1281 
1282  bool is_last() const noexcept { return curr_idx == array_ptr->size() - 1; }
1283 
1285  T & get_curr_ne() const noexcept { return array_ptr->access(curr_idx); }
1286 
1291  T & get_curr() const
1292  {
1293  if (curr_idx == array_ptr->size())
1294  throw std::overflow_error("not current item in iterator");
1295  return get_curr_ne();
1296  }
1297 
1299  long get_pos() const noexcept { return curr_idx; }
1300 
1303  void next_ne() noexcept { ++curr_idx; }
1304 
1307  void next()
1308  {
1309  if (curr_idx == array_ptr->size())
1310  throw std::overflow_error("not current item in iterator");
1311  next_ne();
1312  }
1313 
1314  // Move the iterator one position backward guaranteeing no
1316  void prev_ne() noexcept { --curr_idx; }
1317 
1320  void prev()
1321  {
1322  if (curr_idx == -1)
1323  throw std::underflow_error("not current item in iterator");
1324  prev_ne();
1325  }
1326 
1328  void reset_last() noexcept { curr_idx = array_ptr->size() - 1; }
1329 
1331  void end() noexcept { curr_idx = array_ptr->size(); }
1332 
1334  void reset_first() noexcept { curr_idx = 0; }
1335  };
1336 
1337 private:
1338 
1339  // super fast array traversal
1340  template <class Operation>
1341  bool __traverse(Operation & operation) noexcept(noexcept(operation))
1342  {
1343  size_t dir_idx = 0, seg_idx = 0, block_idx = 0;
1344  for (size_t i = 0; i < current_dim; ++i)
1345  {
1346  if (not operation(dir[dir_idx][seg_idx][block_idx]))
1347  return false;
1348 
1349  if (++block_idx == block_size)
1350  {
1351  block_idx = 0;
1352  if (++seg_idx == seg_size)
1353  {
1354  seg_idx = 0;
1355  ++dir_idx;
1356  }
1357  }
1358  }
1359  return true;
1360  }
1361 
1362 public:
1363 
1378  template <class Operation>
1379  bool traverse(Operation & operation) const noexcept(noexcept(operation))
1380  {
1381  return const_cast<DynArray&>(*this).__traverse(operation);
1382  }
1383 
1385  template <class Operation>
1386  bool traverse(Operation & operation) noexcept(noexcept(operation))
1387  {
1388  return __traverse(operation);
1389  }
1390 
1392  template <class Operation>
1393  bool traverse(Operation && operation) const noexcept(noexcept(operation))
1394  {
1395  return traverse<Operation>(operation);
1396  }
1397 
1399  template <class Operation> bool traverse(Operation && operation)
1400  noexcept(noexcept(operation))
1401  {
1402  return traverse<Operation>(operation);
1403  }
1404 };
1405 
1406  template <typename T>
1407 const size_t DynArray<T>::Default_Pow_Dir = 6; /* 64 */
1408 
1409  template <typename T>
1410 const size_t DynArray<T>::Default_Pow_Seg = 8; /* 256 */
1411 
1412  template <typename T>
1413 const size_t DynArray<T>::Default_Pow_Block = 12; /* 4096 */
1414 
1415  template <typename T>
1416 const size_t DynArray<T>::Max_Bits_Allowed = 8 * sizeof(size_t);
1417 
1418  template <typename T>
1419 const unsigned long long DynArray<T>::Max_Dim_Allowed =
1420  256*1024*1024*1024ull; // 256 Gb
1421 
1422  template <typename T>
1423 const size_t DynArray<T>::Max_Pow_Block =
1424  (Max_Bits_Allowed - Default_Pow_Dir - Default_Pow_Seg - 1);
1425 
1426 } // end namespace Aleph
1427 
1428 # endif /* TPL_DYNARRAY_H */
1429 
T pop()
Remove the last item of array (as if this was a stack)
Definition: tpl_dynArray.H:1229
Definition: htlist.H:450
Definition: htlist.H:1290
void reserve(const size_t l, const size_t r)
Definition: tpl_dynArray.H:998
Definition: htlist.H:133
DynArray(const DynArray< T > &array)
Definition: tpl_dynArray.H:772
void cut(const size_t new_dim=0)
Definition: tpl_dynArray.H:1104
T & push(T &&data)
Definition: tpl_dynArray.H:1194
DynArray & reverse()
Reverse the order of items in array.
Definition: tpl_dynArray.H:1220
bool is_empty() const noexcept
Return true if the array is empty.
Definition: tpl_dynArray.H:1217
void empty() noexcept
Definition: tpl_dynArray.H:1129
Definition: bitArray.H:135
void next_ne() noexcept
Definition: tpl_dynArray.H:1303
T & append(const T &data)
Definition: tpl_dynArray.H:1156
T & access(const size_t i) const noexcept
Definition: tpl_dynArray.H:874
void end() noexcept
Put the iterator in the end state.
Definition: tpl_dynArray.H:1331
T & touch(const size_t i)
Definition: tpl_dynArray.H:958
bool traverse(Operation &operation) noexcept(noexcept(operation))
Definition: tpl_dynArray.H:1386
void copy_array(const DynArray< T > &src_array)
Definition: tpl_dynArray.H:760
static const unsigned long long Max_Dim_Allowed
Maximum dimension allowed.
Definition: tpl_dynArray.H:184
long get_pos() const noexcept
Return the ordinal position of current item.
Definition: tpl_dynArray.H:1299
size_t max_size() const noexcept
Definition: tpl_dynArray.H:647
T & get_last() const
Definition: tpl_dynArray.H:1246
Iterator(const DynArray &array) noexcept
Initializes an iterator on array
Definition: tpl_dynArray.H:1270
size_t get_num_blocks() const noexcept
Return the number of blocks consumed by the array.
Definition: tpl_dynArray.H:650
size_t get_block_size() const noexcept
Return the block size.
Definition: tpl_dynArray.H:636
T & top() const
Return a modifiable reference to the last item of stack.
Definition: tpl_dynArray.H:1238
static void compute_sizes(const size_t n, size_t &d, size_t &s, size_t &b) noexcept
Definition: tpl_dynArray.H:224
void swap(DynArray< T > &array) noexcept
Definition: tpl_dynArray.H:819
T & get_first() const
Definition: tpl_dynArray.H:1242
void next()
Definition: tpl_dynArray.H:1307
void set_default_initial_value(T &&value=T()) noexcept(noexcept(std::swap(default_initial_value, value)))
Definition: tpl_dynArray.H:666
void reserve(const size_t dim)
Definition: tpl_dynArray.H:1048
T & get_curr_ne() const noexcept
Return the current link guaranteeing no exception. Be careful.
Definition: tpl_dynArray.H:1285
bool exist(const size_t i) const
Definition: tpl_dynArray.H:895
void prev()
Definition: tpl_dynArray.H:1320
void put(const T &data)
Definition: tpl_dynArray.H:1197
void prev_ne() noexcept
exception. Be careful.
Definition: tpl_dynArray.H:1316
bool traverse(Operation &&operation) const noexcept(noexcept(operation))
Definition: tpl_dynArray.H:1393
static const size_t Default_Pow_Dir
The type of element stored in the array.
Definition: tpl_dynArray.H:173
Definition: ah-comb.H:35
bool traverse(Operation &operation) const noexcept(noexcept(operation))
Definition: tpl_dynArray.H:1379
T * test(const size_t i) const noexcept
Definition: tpl_dynArray.H:927
DynArray(DynArray &&other) noexcept
Move constructor.
Definition: tpl_dynArray.H:839
void adjust(const size_t dim)
Definition: tpl_dynArray.H:1119
Node_Type Key_Type
The type of element stored in the array.
Definition: tpl_dynArray.H:171
T & append()
Definition: tpl_dynArray.H:1149
T & get_curr() const
Definition: tpl_dynArray.H:1291
size_t size() const noexcept
Definition: tpl_dynArray.H:641
size_t get_seg_size() const noexcept
Return the segment size.
Definition: tpl_dynArray.H:633
void reset_last() noexcept
Reset the iterator to the last item.
Definition: tpl_dynArray.H:1328
Definition: tpl_dynArray.H:159
DynArray(size_t _pow_dir, size_t _pow_seg, size_t _pow_block)
Definition: tpl_dynArray.H:688
void set_default_initial_value(const T &value) noexcept
Definition: tpl_dynArray.H:659
bool traverse(Operation &&operation) noexcept(noexcept(operation))
Definition: tpl_dynArray.H:1399
void reset_first() noexcept
Reset the iterator to the first item.
Definition: tpl_dynArray.H:1334
static const size_t Default_Pow_Block
Default two power for segment size.
Definition: tpl_dynArray.H:175
Definition: tpl_dynArray.H:1258
DynArray(const size_t dim=0)
Definition: tpl_dynArray.H:728
void push(const T &data)
Definition: tpl_dynArray.H:1191
bool has_curr() const noexcept
Return true if there is current item.
Definition: tpl_dynArray.H:1277
static std::tuple< size_t, size_t, size_t > compute_sizes(const size_t n) noexcept
Definition: tpl_dynArray.H:252
size_t get_dir_size() const noexcept
Return the directory size.
Definition: tpl_dynArray.H:630
T & put(T &&data)
Definition: tpl_dynArray.H:1200
static const size_t Default_Pow_Seg
Default two power for directory size.
Definition: tpl_dynArray.H:174
void erase(T &item) noexcept
Definition: tpl_dynArray.H:1214
Definition: htlist.H:1323
T & append(T &&data)
Definition: tpl_dynArray.H:1165

Leandro Rabindranath León