Aleph-w  1.5a.2
Biblioteca general de algoritmos y estructuras de datos
 Todo Clases Archivos Funciones Variables 'typedefs' Enumeraciones Amigas Grupos Páginas
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 <ahDry.H>
10 # include <htlist.H>
11 
12 using namespace std;
13 
14 using namespace Aleph;
15 
16 namespace Aleph {
17 
69  template <typename T>
70 class DynArray
71 {
72 private:
73 
74  // look at the end of this file for seeing the values
75 public:
76 
77  typedef T Item_Type;
78  typedef T Key_Type;
79 
80  static const size_t Default_Pow_Dir;
81  static const size_t Default_Pow_Seg;
82  static const size_t Default_Pow_Block;
83 
84  static const size_t Max_Bits_Allowed;
85 
86  static const unsigned long long Max_Dim_Allowed;
87 
88 private:
89 
90  static const size_t Max_Pow_Block;
91 
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); // = 2^pow_dir
99  mutable size_t seg_size = two_raised(pow_seg); // = 2^pow_seg
100  mutable size_t block_size = two_raised(pow_block); // = 2^pow_block
101 
102  // 2^(pow_dir + pow_seg + pow_block) - 1
103  unsigned long long max_dim = two_raised(seg_plus_block_pow + pow_dir);
104 
105  static size_t two_raised(const size_t n)
106  {
107  if (n >= Max_Bits_Allowed)
108  throw std::overflow_error ("number of bits exceeds maximum allowed");
109 
110  return 1 << n;
111  }
112 
113  static size_t compute_dim(size_t d, size_t s, size_t b)
114  {
115  return two_raised(d)*two_raised(s)*two_raised(b);
116  }
117 
118 public:
119 
123  static void compute_sizes(const size_t n, size_t & d, size_t & s, size_t & b)
124  {
125  d = Default_Pow_Dir;
126  s = Default_Pow_Seg;
127  b = Default_Pow_Block;
128  if (compute_dim(d, s, b) >= n)
129  return;
130 
131  while (true)
132  {
133  if (compute_dim(++d, s, b) >= n)
134  break;
135 
136  if (compute_dim(d, ++s, b) >= n)
137  break;
138 
139  if (compute_dim(d, s, ++b) >= n)
140  break;
141  }
142  }
143 
144 private:
145 
146  size_t mask_seg = seg_size - 1;
147  size_t mask_block = block_size - 1;
148 
149  size_t index_in_dir(const size_t i) const
150  {
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) );
154 
155  return i >> seg_plus_block_pow;
156  }
157 
158  size_t modulus_from_index_in_dir(const size_t i) const
159  {
160  I( mask_seg_plus_block == seg_size*block_size - 1 );
161  I( (i & mask_seg_plus_block) == i%(seg_size*block_size) );
162 
163  return (i & mask_seg_plus_block);
164  }
165 
166  size_t index_in_seg(const size_t & i) const
167  {
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 );
171 
172  return modulus_from_index_in_dir(i) >> pow_block;
173  }
174 
175  size_t index_in_block(const size_t i) const
176  {
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) );
180 
181  return modulus_from_index_in_dir(i) & mask_block;
182  }
183 
184  size_t current_dim;
185  size_t num_segs = 0;
186  size_t num_blocks = 0;
187  T *** dir = NULL;
188 
189  void fill_dir_to_null()
190  {
191  I(dir != NULL);
192 
193  for (size_t i = 0; i < dir_size; ++i)
194  dir[i] = NULL;
195  }
196 
197  void fill_seg_to_null(T ** seg)
198  {
199  I(seg != NULL);
200 
201  for (size_t i = 0; i < seg_size; ++i)
202  seg[i] = NULL;
203  }
204 
205  void allocate_dir()
206  {
207  dir = (T***) malloc(dir_size*sizeof(T**));
208  if (dir == NULL)
209  throw std::bad_alloc();
210 
211  fill_dir_to_null();
212  }
213 
214  void resize_dir(const size_t i) // resize dir to fit index i
215  {
216  I(i >= max_dim);
217 
218  size_t new_pow_dir = pow_dir + 1;
219  while (compute_dim(new_pow_dir, pow_seg, pow_block) <= i)
220  ++new_pow_dir;
221 
222  const size_t new_dir_sz = two_raised(new_pow_dir);
223  T *** new_dir = (T***) realloc(dir, new_dir_sz*sizeof(T**));
224  if (new_dir == NULL)
225  throw std::bad_alloc();
226 
227  dir = new_dir;
228  for (size_t k = dir_size; k < new_dir_sz; ++k)
229  dir[k] = NULL;
230 
231  pow_dir = new_pow_dir;
232  dir_size = new_dir_sz;
233 
234  max_dim = compute_dim(pow_dir, pow_seg, pow_block);
235  }
236 
237  void allocate_segment(T **& seg)
238  {
239  I(seg == NULL);
240 
241  seg = new T* [seg_size];
242  fill_seg_to_null(seg);
243  ++num_segs;
244  }
245 
246  T default_initial_value = T();
247  T * default_initial_value_ptr = &default_initial_value;
248 
249  void allocate_block(T *& block)
250  {
251  I(block == NULL);
252 
253  block = new T [block_size];
254  ++num_blocks;
255 
256  if (default_initial_value_ptr == NULL)
257  return;
258 
259  for (size_t i = 0; i < block_size; ++i)
260  block[i] = *default_initial_value_ptr;
261  }
262 
263  void release_segment(T **& seg)
264  {
265  I(seg != NULL);
266 
267  delete [] seg;
268  seg = NULL;
269  --num_segs;
270  }
271 
272  void release_block(T *& block)
273  {
274  I(block != NULL);
275 
276  delete [] block;
277  block = NULL;
278  --num_blocks;
279  }
280 
281  void release_blocks_and_segment(T ** & seg)
282  {
283  I(seg != NULL);
284 
285  for(size_t i = 0; i < seg_size ; ++i)
286  if (seg[i] != NULL)
287  release_block(seg[i]);
288 
289  release_segment(seg);
290  }
291 
292  void release_all_segments_and_blocks()
293  {
294  I(dir != NULL);
295 
296  for(size_t i = 0; i < dir_size ; ++i)
297  if (dir[i] != NULL)
298  release_blocks_and_segment(dir[i]);
299 
300  current_dim = 0;
301  }
302 
303  void release_dir()
304  {
305  if (dir == NULL)
306  return;
307 
308  release_all_segments_and_blocks();
309  if (dir != NULL)
310  free(dir);
311 
312  dir = NULL;
313  current_dim = 0;
314  }
315 
316  static size_t next2Pow(const size_t number)
317  {
318  return (size_t) ceil( log((float) number)/ log(2.0) );
319  }
320 
321  size_t divide_by_block_size(const size_t number) const
322  {
323  I(number/block_size == number >> pow_block);
324 
325  return number >> pow_block;
326  }
327 
328  size_t modulus_by_block_size(const size_t number) const
329  {
330  I((number%block_size) == (number & mask_block));
331 
332  return number & mask_block;
333  }
334 
335  void advance_block_index(size_t block_index, size_t seg_index,
336  const size_t len) const
337  {
338  if (block_index + len < block_size)
339  {
340  block_index += len;
341  return;
342  }
343 
344  seg_index += divide_by_block_size(len);
345  block_index = modulus_by_block_size(len);
346  }
347 
348  void allocate_block(T *& block, T * src_block)
349  {
350  allocate_block(block);
351  for (int i = 0; i < block_size; i++)
352  block[i] = src_block[i];
353  }
354 
355  void allocate_segment(T **& seg, T ** src_seg)
356  {
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]);
361  }
362 
363  void allocate_dir(T *** src_dir)
364  {
365  allocate_dir();
366  for (int i = 0; i < dir_size; i++)
367  if (src_dir[i] != NULL)
368  allocate_segment(dir[i], src_dir[i]);
369  }
370 
371  class Proxy
372  {
373  size_t index;
374  size_t pos_in_dir;
375  size_t pos_in_seg;
376  size_t pos_in_block;
377  T **& ref_seg;
378  T * block;
379  DynArray & array;
380 
381  public:
382 
383  Proxy(DynArray<T> & _array, const size_t 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)
388  {
389  if (ref_seg != NULL)
390  block = ref_seg[pos_in_seg]; // ya existe bloque para entrada i
391  }
392 
393  operator T & ()
394  {
395  if (block == NULL)
396  throw std::invalid_argument("accessed entry not been still written");
397  return block[pos_in_block];
398  }
399 
400  T * operator -> ()
401  {
402  bool seg_was_allocated_in_current_call = false;
403 
404  if (ref_seg == NULL) // hay segmento?
405  { // No ==> apartarlo!
406  array.allocate_segment(ref_seg);
407  seg_was_allocated_in_current_call = true;
408  }
409 
410  if (block == NULL) // test if block is allocated
411  {
412  try // tratar apartar bloque
413  {
414  array.allocate_block(block);
415  ref_seg[pos_in_seg] = block;
416 
417  I(array.dir[pos_in_dir] == ref_seg);
418  }
419  catch (...) // Ocurre una falla en el apartado del bloque
420  {
421  if (seg_was_allocated_in_current_call)
422  array.release_segment(ref_seg);
423 
424  throw;
425  }
426  }
427 
428  if (index >= array.current_dim)
429  array.current_dim = index + 1;
430 
431  return &block[pos_in_block];
432  }
433 
434  Proxy & operator = (const T & data)
435  {
436  bool seg_was_allocated_in_current_call = false;
437  if (ref_seg == NULL) // hay segmento?
438  { // No ==> apartarlo!
439  array.allocate_segment(ref_seg);
440  seg_was_allocated_in_current_call = true;
441  }
442 
443  if (block == NULL) // test if block is allocated
444  {
445  try // tratar apartar bloque
446  {
447  array.allocate_block(block);
448  ref_seg[pos_in_seg] = block;
449 
450  I(array.dir[pos_in_dir] == ref_seg);
451  }
452  catch (...) // Ocurre una falla en el apartado del bloque
453  {
454  if (seg_was_allocated_in_current_call)
455  array.release_segment(ref_seg);
456 
457  throw;
458  }
459  }
460 
461  if (index >= array.current_dim)
462  array.current_dim = index + 1;
463 
464  block[pos_in_block] = data;
465 
466  return *this;
467  }
468 
469  Proxy & operator = (const Proxy & proxy)
470  {
471  if (proxy.block == NULL) // ¿operando derecho puede leerse?
472  throw std::domain_error("right entry has not been still written");
473 
474  if (&proxy == this)
475  return *this;
476 
477  bool seg_was_allocated_in_current_call = false;
478  if (ref_seg == NULL) // hay segmento?
479  { // No ==> apartarlo!
480  array.allocate_segment(ref_seg);
481  seg_was_allocated_in_current_call = true;
482  }
483 
484  if (block == NULL) // test if block is allocated
485  {
486  try // tratar apartar bloque
487  {
488  array.allocate_block(block);
489  ref_seg[pos_in_seg] = block;
490 
491  I(array.dir[pos_in_dir] == ref_seg);
492  }
493  catch (...) // Ocurre una falla en el apartado del bloque
494  {
495  if (seg_was_allocated_in_current_call)
496  array.release_segment(ref_seg);
497 
498  throw;
499  }
500  }
501 
502  if (index >= array.current_dim)
503  array.current_dim = index + 1;
504 
505  block[pos_in_block] = proxy.block[proxy.pos_in_block];
506 
507  return *this;
508  }
509  };
510 
511 public:
512 
514  size_t get_dir_size() const { return dir_size; }
515 
517  size_t get_seg_size() const { return seg_size; }
518 
520  size_t get_block_size() const { return block_size; }
521 
523  size_t size() const { return current_dim; }
524 
526  size_t max_size() const { return max_dim; }
527 
529  size_t get_num_blocks() const { return num_blocks; }
530 
541  void set_default_initial_value(const T & value)
542  {
543  default_initial_value = value;
544  default_initial_value_ptr = &default_initial_value;
545  }
546 
547  void set_default_initial_value(T && value = T())
548  {
549  std::swap(default_initial_value, value);
550  default_initial_value_ptr = &default_initial_value;
551  }
552 
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 ),
586  current_dim ( 0 ),
587  num_segs ( 0 ),
588  num_blocks ( 0 )
589  {
590  I(Max_Dim_Allowed > 0);
591 
592  if (max_dim > Max_Dim_Allowed)
593  throw std::length_error ("Dimension too large");
594 
595  allocate_dir();
596  }
597 
617  DynArray(const size_t dim = 0)
618  throw (std::exception, std::bad_alloc,
619  std::length_error, std::overflow_error)
620  : current_dim(dim)
621  {
622  I(Max_Dim_Allowed > 0);
623 
624  if (max_dim > Max_Dim_Allowed)
625  throw std::length_error ("Dimension too large");
626 
627  allocate_dir();
628  }
629 
630  DynArray(const DynList<T> & list) : DynArray()
631  {
632  int i = 0;
633  list.for_each([&i, this] (const T & item) { touch(i++) = item; });
634  }
635 
638  {
639  release_dir();
640  }
641 
653  void copy_array(const DynArray<T> & src_array)
654  {
655  for (int i = 0; i < src_array.current_dim; ++i)
656  if (src_array.exist(i))
657  (*this)[i] = src_array.access(i);
658  }
659 
669  DynArray(const DynArray<T> & array)
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),
682  current_dim (0),
683  num_segs (0),
684  num_blocks (0),
685  dir (NULL),
686  default_initial_value_ptr (array.default_initial_value_ptr)
687  {
688  allocate_dir(array.dir);
689  copy_array(array);
690  }
691 
699  DynArray<T> & operator = (const DynArray<T> & array)
700  throw (std::exception, std::bad_alloc)
701  {
702  if (this == &array)
703  return *this;
704 
705  copy_array(array);
706 
707  if (array.current_dim < current_dim)
708  cut(array.current_dim);
709 
710  current_dim = array.current_dim;
711 
712  return *this;
713  }
714 
725  void swap(DynArray<T> & array)
726  {
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);
742  }
743 
744  DynArray(DynArray && other)
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 ),
756  current_dim ( 0 ),
757  num_segs ( 0 ),
758  num_blocks ( 0 ),
759  dir (NULL )
760  {
761  swap(other);
762  }
763 
764  DynArray & operator = (DynArray && other)
765  {
766  swap(other);
767  return *this;
768  }
769 
793  T & access(const size_t i)
794  {
795  I(dir[index_in_dir(i)] != NULL);
796  I(dir[index_in_dir(i)][index_in_seg(i)] != NULL);
797 
798  if (i >= current_dim)
799  current_dim = i;
800 
801  return dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
802  }
803 
804  T & operator () (const size_t i)
805  {
806  return access(i);
807  }
808 
828  const T & access(const size_t i) const
829  {
830  I(dir[index_in_dir(i)] != NULL);
831  I(dir[index_in_dir(i)][index_in_seg(i)] != NULL);
832 
833  return dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
834  }
835 
836  const T & operator () (const size_t i) const
837  {
838  return access(i);
839  }
854  bool exist(const size_t i) const throw (std::exception, std::out_of_range)
855  {
856  if (i >= max_dim)
857  throw std::out_of_range ("index out of maximun range");
858 
859  const size_t pos_in_dir = index_in_dir(i);
860 
861  I(pos_in_dir < dir_size);
862 
863  if (dir[pos_in_dir] == NULL)
864  return false;
865 
866  const size_t pos_in_seg = index_in_seg(i);
867 
868  I(pos_in_seg < seg_size);
869 
870  if (dir[pos_in_dir][pos_in_seg] == NULL)
871  return false;
872 
873  return true;
874  }
875 
891  T * test(const size_t i) const
892  {
893  const size_t pos_in_dir = index_in_dir(i);
894  if (dir[pos_in_dir] == NULL)
895  return NULL;
896 
897  const size_t pos_in_seg = index_in_seg(i);
898  if (dir[pos_in_dir][pos_in_seg] == NULL)
899  return NULL;
900 
901  return &dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
902  }
903 
915  T & touch(const size_t i)
916  throw (std::exception, std::bad_alloc, std::out_of_range)
917  {
918  if (i >= max_dim)
919  resize_dir(i);
920 
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]);
924 
925  const size_t pos_in_seg = index_in_seg(i);
926  if (dir[pos_in_dir][pos_in_seg] == NULL)
927  {
928  try
929  {
930  allocate_block(dir[pos_in_dir][pos_in_seg]);
931  }
932  catch (...)
933  {
934  release_segment(dir[pos_in_dir]);
935  throw;
936  }
937  }
938 
939  if (i >= current_dim)
940  current_dim = i + 1;
941 
942  return dir[pos_in_dir][pos_in_seg][index_in_block(i)];
943  }
944 
960  void reserve(const size_t l, const size_t r)
961  throw (std::exception, std::bad_alloc, std::domain_error, std::length_error)
962  {
963  if (l > r)
964  throw std::domain_error("invalid range");
965 
966  if (r >= max_dim)
967  resize_dir(r);
968 
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);
973 
974  try
975  {
976  for (size_t seg_idx = first_seg; seg_idx <= last_seg; ++seg_idx)
977  {
978  if (dir[seg_idx] == NULL)
979  allocate_segment(dir[seg_idx]);
980 
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;
984 
985  while (block_idx <= final_block)
986  {
987  if (dir[seg_idx][block_idx] == NULL)
988  allocate_block(dir[seg_idx][block_idx]);
989 
990  ++block_idx;
991  }
992  } // end for (...)
993 
994  if (r + 1 > current_dim)
995  current_dim = r + 1;
996  }
997  catch (...)
998  {
999  if (r + 1 > current_dim)
1000  current_dim = r + 1;
1001 
1002  throw;
1003  }
1004  }
1005 
1021  void reserve(const size_t dim)
1022  {
1023  if (dim > 0)
1024  reserve(0, dim - 1);
1025  }
1026 
1040  void cut(const size_t new_dim = 0)
1041  throw (std::exception, std::domain_error)
1042  {
1043  if (new_dim > current_dim)
1044  throw std::domain_error("new dimension greater that current dimension");
1045 
1046  if (new_dim == 0)
1047  {
1048  release_all_segments_and_blocks();
1049  current_dim = 0;
1050 
1051  return;
1052  }
1053 
1054  const size_t old_dim = current_dim; // antigua dimensión
1055 
1056  // índices cotas bloques
1057  const int idx_first_seg = index_in_dir(old_dim - 1);
1058  const int idx_first_block = index_in_seg(old_dim - 1);
1059 
1060  // índices cotas segmentos
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;
1064  --idx_seg) // recorre descendentemente los segmentos
1065  {
1066  if (dir[idx_seg] == NULL) // ¿hay un segmento?
1067  continue; // no ==> avance al siguiente
1068 
1069  int idx_block = // primer bloque a liberar
1070  idx_seg == idx_first_seg ? idx_first_block : seg_size - 1;
1071 
1072  // Libera descendentemente los bloques reservados del segmento
1073  while ( (idx_seg > idx_last_seg and idx_block >= 0) or
1074  (idx_seg == idx_last_seg and idx_block > idx_last_block) )
1075  {
1076  if (dir[idx_seg][idx_block] != NULL) // ¿Hay un bloque aquí?
1077  release_block(dir[idx_seg][idx_block]);
1078 
1079  --idx_block;
1080  }
1081 
1082  if (idx_block < 0)
1083  release_segment(dir[idx_seg]);
1084  }
1085 
1086  current_dim = new_dim; // actualiza nueva dimensión
1087  }
1088 
1091  void empty() { cut(0); }
1092 
1093  Proxy operator [] (const size_t i) const
1094  throw (std::exception, std::bad_alloc, std::length_error,
1095  std::invalid_argument)
1096  {
1097  if (i >= max_dim)
1098  throw std::out_of_range ("index out of maximun range");
1099 
1100  return Proxy (const_cast<DynArray<T>&>(*this), i);
1101  }
1102 
1103  Proxy operator [] (const size_t i)
1104  throw (std::exception, std::length_error,
1105  std::invalid_argument, std::bad_alloc)
1106  {
1107  if (i >= max_dim)
1108  resize_dir(i);
1109 
1110  return Proxy (const_cast<DynArray<T>&>(*this), i);
1111  }
1112 
1115  T & append()
1116  {
1117  return touch(this->size());
1118  }
1119 
1122  T & append(const T & data)
1123  {
1124  T & ref = this->append();
1125  ref = data;
1126  return ref;
1127  }
1128 
1129  T & append(T && data)
1130  {
1131  T & ref = this->append();
1132  std::swap(ref, data);
1133  return ref;
1134  }
1135 
1137  void push(const T & data) { this->append(data); }
1138 
1140  T & push() { return this->append(); }
1141 
1142  bool is_empty() { return this->size() == 0; }
1143 
1145  T pop()
1146  {
1147  T ret_val = this->access(this->size() - 1);
1148  cut(size() - 1);
1149 
1150  return ret_val;
1151  }
1152 
1154  T & top() { return (*this)[size() - 1]; }
1155 
1157  T & get_first() { return top(); }
1158 
1160  T & get_last() { return (*this)[0]; }
1161 
1162  class Iterator
1163  {
1164  DynArray * array_ptr;
1165  long curr_idx;
1166 
1167  public:
1168 
1169  Iterator() : array_ptr(NULL), curr_idx(0) { /* empty */ }
1170 
1171  Iterator(const DynArray & array)
1172  : array_ptr(const_cast<DynArray*>(&array)), curr_idx(0)
1173  {
1174  // empty
1175  }
1176 
1177  bool has_curr() const
1178  {
1179  return curr_idx >= 0 and curr_idx < array_ptr->size();
1180  }
1181 
1182  bool has_current() const { return has_curr(); }
1183 
1184  T & get_curr() { return array_ptr->access(curr_idx); }
1185 
1186  void next()
1187  {
1188  if (curr_idx == array_ptr->size())
1189  throw std::overflow_error("not current item in iterator");
1190 
1191  ++curr_idx;
1192  }
1193 
1194  void prev()
1195  {
1196  if (curr_idx == -1)
1197  throw std::underflow_error("not current item in iterator");
1198 
1199  --curr_idx;
1200  }
1201 
1202  void reset_last() { curr_idx = array_ptr->size() - 1; }
1203 
1204  void reset_first() { curr_idx = 0; }
1205 
1206  void reset() { reset_first(); }
1207  };
1208 
1209 private:
1210 
1211  // super fast array traversal
1212  template <class Operation>
1213  bool __traverse(Operation & operation)
1214  {
1215  size_t dir_idx = 0, seg_idx = 0, block_idx = 0;
1216  for (size_t i = 0; i < current_dim; ++i)
1217  {
1218  if (not operation(dir[dir_idx][seg_idx][block_idx]))
1219  return false;
1220 
1221  if (++block_idx == block_size)
1222  {
1223  block_idx = 0;
1224  if (++seg_idx == seg_size)
1225  {
1226  seg_idx = 0;
1227  ++dir_idx;
1228  }
1229  }
1230  }
1231  return true;
1232  }
1233 
1234 public:
1235 
1250  template <class Operation>
1251  bool traverse(Operation & operation) const
1252  {
1253  return const_cast<DynArray&>(*this).__traverse(operation);
1254  }
1255 
1256  template <class Operation>
1257  bool traverse(Operation & operation)
1258  {
1259  return __traverse(operation);
1260  }
1261 
1262  template <class Operation>
1263  bool traverse(Operation && operation = Operation()) const
1264  {
1265  return traverse<Operation>(operation);
1266  }
1267 
1268  template <class Operation>
1269  bool traverse(Operation && operation = Operation())
1270  {
1271  return traverse<Operation>(operation);
1272  }
1273 
1274  Functional_Methods(T);
1275 };
1276 
1277  template <typename T>
1278 const size_t DynArray<T>::Default_Pow_Dir = 6; /* 64 */
1279 
1280  template <typename T>
1281 const size_t DynArray<T>::Default_Pow_Seg = 8; /* 256 */
1282 
1283  template <typename T>
1284 const size_t DynArray<T>::Default_Pow_Block = 12; /* 4096 */
1285 
1286  template <typename T>
1287 const size_t DynArray<T>::Max_Bits_Allowed = 8 * sizeof(size_t);
1288 
1289  template <typename T>
1290 const unsigned long long DynArray<T>::Max_Dim_Allowed =
1291  256*1024*1024*1024ull; // 256 Gb
1292 
1293  template <typename T>
1294 const size_t DynArray<T>::Max_Pow_Block =
1295  (Max_Bits_Allowed - Default_Pow_Dir - Default_Pow_Seg - 1);
1296 
1297 } // end namespace Aleph
1298 
1299 # endif /* TPL_DYNARRAY_H */
1300 
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
Definition: ahDry.H:13
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
Definition: List.H:23
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

Leandro Rabindranath León