00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 # ifndef TPL_DYNARRAY_H
00045 # define TPL_DYNARRAY_H
00046
00047 # include <string>
00048 # include <cmath>
00049 # include <aleph.H>
00050
00051 using namespace std;
00052
00053 # ifdef DEBUG
00054 # include <math.h>
00055 # endif
00056
00057 using namespace Aleph;
00058
00059 namespace Aleph {
00060
00112 template <typename T>
00113 class DynArray
00114 {
00115
00116 private:
00117
00118 static const size_t Default_Pow_Dir;
00119 static const size_t Default_Pow_Seg;
00120 static const size_t Default_Pow_Block;
00121 static const size_t Max_Bits_Allowed;
00122 static const size_t Max_Dim_Allowed;
00123 static const size_t Max_Pow_Block;
00124 mutable size_t pow_dir;
00125 mutable size_t pow_seg;
00126 mutable size_t pow_block;
00127 mutable size_t seg_plus_block_pow;
00128 mutable size_t mask_seg_plus_block;
00129 mutable size_t dir_size;
00130 mutable size_t seg_size;
00131 mutable size_t block_size;
00132 mutable size_t max_dim;
00133 static size_t two_raised(const size_t & n)
00134 {
00135 if (n >= Max_Bits_Allowed)
00136 throw std::overflow_error ("number of bits exceeds de maximun allowed");
00137
00138 I((1 << n) == (int) pow((float) 2.0, (float) n));
00139
00140 return 1 << n;
00141 }
00142 size_t mask_seg;
00143 size_t mask_block;
00144 size_t index_in_dir(const size_t & i) const
00145 {
00146
00147 I( (pow_block + pow_seg) == seg_plus_block_pow );
00148 I( seg_size * block_size == two_raised(seg_plus_block_pow) );
00149 I( i >> seg_plus_block_pow == i/(seg_size*block_size) );
00150
00151 return i >> seg_plus_block_pow;
00152 }
00153
00154 size_t modulus_from_index_in_dir(const size_t & i) const
00155 {
00156
00157 I( mask_seg_plus_block == seg_size*block_size - 1 );
00158 I( (i & mask_seg_plus_block) == i%(seg_size*block_size) );
00159
00160 return (i & mask_seg_plus_block);
00161 }
00162
00163 size_t index_in_seg(const size_t & i) const
00164 {
00165
00166 I( two_raised(pow_block) == block_size );
00167 I( (modulus_from_index_in_dir(i) >> pow_block) ==
00168 (i%(seg_size*block_size))/block_size );
00169
00170 return modulus_from_index_in_dir(i) >> pow_block;
00171 }
00172
00173 size_t index_in_block(const size_t & i) const
00174 {
00175
00176 I( mask_block == block_size - 1 );
00177 I( (modulus_from_index_in_dir(i) & mask_block) ==
00178 ((i%(seg_size*block_size))%block_size) );
00179
00180 return modulus_from_index_in_dir(i) & mask_block;
00181 }
00182 size_t current_dim;
00183 size_t num_segs;
00184 size_t num_blocks;
00185 T *** dir;
00186 void fill_dir_to_null()
00187 {
00188
00189 I(dir != NULL);
00190
00191 for (size_t i = 0; i < dir_size; ++i)
00192 dir[i] = NULL;
00193 }
00194
00195 void fill_seg_to_null(T ** seg)
00196 {
00197
00198 I(seg != NULL);
00199
00200 for (size_t i = 0; i < seg_size; ++i)
00201 seg[i] = NULL;
00202 }
00203 void allocate_dir()
00204 {
00205
00206 try
00207 {
00208
00209 dir = new T ** [dir_size];
00210 fill_dir_to_null();
00211
00212 }
00213 catch (...)
00214 {
00215 dir = NULL;
00216 throw;
00217 }
00218
00219 }
00220
00221 void allocate_segment(T **& seg)
00222 {
00223
00224 I(seg == NULL);
00225
00226 seg = new T* [seg_size];
00227 fill_seg_to_null(seg);
00228 ++num_segs;
00229 }
00230 T default_initial_value;
00231
00232 T * default_initial_value_ptr;
00233 void allocate_block(T *& block)
00234 {
00235
00236 I(block == NULL);
00237
00238 block = new T [block_size];
00239 ++num_blocks;
00240
00241 if (default_initial_value_ptr == NULL)
00242 return;
00243
00244 for (size_t i = 0; i < block_size; ++i)
00245 block[i] = default_initial_value;
00246 }
00247 void release_segment(T **& seg)
00248 {
00249
00250 I(seg != NULL);
00251
00252 delete [] seg;
00253 seg = NULL;
00254 --num_segs;
00255 }
00256
00257 void release_block(T *& block)
00258 {
00259
00260 I(block != NULL);
00261
00262 delete [] block;
00263 block = NULL;
00264 --num_blocks;
00265 }
00266 void release_blocks_and_segment(T ** & seg)
00267 {
00268
00269 I(seg != NULL);
00270
00271 for(size_t i = 0; i < seg_size ; ++i)
00272 if (seg[i] != NULL)
00273 release_block(seg[i]);
00274
00275 release_segment(seg);
00276 }
00277
00278 void release_all_segments_and_blocks()
00279 {
00280 for(size_t i = 0; i < dir_size ; ++i)
00281 if (dir[i] != NULL)
00282 release_blocks_and_segment(dir[i]);
00283
00284 current_dim = 0;
00285 }
00286
00287 void release_dir()
00288 {
00289 release_all_segments_and_blocks();
00290
00291 delete [] dir;
00292 dir = NULL;
00293 current_dim = 0;
00294 }
00295 static size_t next2Pow(const size_t & number)
00296 {
00297 return static_cast<size_t>(ceil(log(static_cast<float>(number))/log(2.0)));
00298 }
00299 size_t divide_by_block_size(const size_t & number) const
00300 {
00301
00302 I(number/block_size == number >> pow_block);
00303
00304 return number >> pow_block;
00305 }
00306
00307 size_t modulus_by_block_size(const size_t & number) const
00308 {
00309
00310 I((number%block_size) == (number & mask_block));
00311
00312 return number & mask_block;
00313 }
00314
00315 void advance_block_index(size_t & block_index,
00316 size_t & seg_index,
00317 const size_t & len) const
00318 {
00319 if (block_index + len < block_size)
00320 {
00321 block_index += len;
00322 return;
00323 }
00324
00325 seg_index += divide_by_block_size(len);
00326 block_index = modulus_by_block_size(len);
00327 }
00328 class Proxy
00329 {
00330 size_t index;
00331 size_t pos_in_dir;
00332 size_t pos_in_seg;
00333 size_t pos_in_block;
00334 T**& ref_seg;
00335 T* block;
00336 DynArray& array;
00337
00338 public:
00339
00340 Proxy(DynArray<T>& _array, const size_t & i)
00341 : index ( i ),
00342 pos_in_dir ( _array.index_in_dir(index) ),
00343 pos_in_seg ( _array.index_in_seg(index) ),
00344 pos_in_block( _array.index_in_block(index) ),
00345 ref_seg ( _array.dir[pos_in_dir] ),
00346 block ( NULL ),
00347 array ( _array )
00348 {
00349 if (ref_seg != NULL)
00350 block = ref_seg[pos_in_seg];
00351 }
00352 operator T & ()
00353 {
00354
00355 if (block == NULL)
00356 throw std::invalid_argument("accessed entry has not been still written");
00357
00358 return block[pos_in_block];
00359 }
00360 T * operator -> ()
00361 {
00362 bool seg_was_allocated_in_current_call = false;
00363
00364 if (ref_seg == NULL)
00365 {
00366 array.allocate_segment(ref_seg);
00367 seg_was_allocated_in_current_call = true;
00368 }
00369 if (block == NULL)
00370 {
00371
00372 try
00373 {
00374
00375 array.allocate_block(block);
00376 ref_seg[pos_in_seg] = block;
00377
00378 I(array.dir[pos_in_dir] == ref_seg);
00379 }
00380 catch (...)
00381 {
00382 if (seg_was_allocated_in_current_call)
00383 array.release_segment(ref_seg);
00384
00385 throw;
00386 }
00387
00388 }
00389
00390 if (index >= array.current_dim)
00391 array.current_dim = index + 1;
00392
00393 return &block[pos_in_block];
00394 }
00395 Proxy & operator = (const T & data)
00396 {
00397 bool seg_was_allocated_in_current_call = false;
00398
00399 if (ref_seg == NULL)
00400 {
00401 array.allocate_segment(ref_seg);
00402 seg_was_allocated_in_current_call = true;
00403 }
00404 if (block == NULL)
00405 {
00406
00407 try
00408 {
00409
00410 array.allocate_block(block);
00411 ref_seg[pos_in_seg] = block;
00412
00413 I(array.dir[pos_in_dir] == ref_seg);
00414 }
00415 catch (...)
00416 {
00417 if (seg_was_allocated_in_current_call)
00418 array.release_segment(ref_seg);
00419
00420 throw;
00421 }
00422
00423 }
00424 if (index >= array.current_dim)
00425 array.current_dim = index + 1;
00426
00427 block[pos_in_block] = data;
00428
00429 return *this;
00430 }
00431
00432 Proxy & operator = (const Proxy & proxy)
00433 {
00434 if (proxy.block == NULL)
00435 throw std::invalid_argument("right entry has not been still written");
00436
00437 if (&proxy == this)
00438 return *this;
00439
00440
00441 bool seg_was_allocated_in_current_call = false;
00442
00443 if (ref_seg == NULL)
00444 {
00445 array.allocate_segment(ref_seg);
00446 seg_was_allocated_in_current_call = true;
00447 }
00448 if (block == NULL)
00449 {
00450
00451 try
00452 {
00453
00454 array.allocate_block(block);
00455 ref_seg[pos_in_seg] = block;
00456
00457 I(array.dir[pos_in_dir] == ref_seg);
00458 }
00459 catch (...)
00460 {
00461 if (seg_was_allocated_in_current_call)
00462 array.release_segment(ref_seg);
00463
00464 throw;
00465 }
00466
00467 }
00468 if (index >= array.current_dim)
00469 array.current_dim = index + 1;
00470
00471 block[pos_in_block] = proxy.block[proxy.pos_in_block];
00472
00473 return *this;
00474 }
00475 };
00476
00477 public:
00478
00480 const size_t & get_dir_size() const { return dir_size; }
00482 const size_t & get_seg_size() const { return seg_size; }
00484 const size_t & get_block_size() const { return block_size; }
00486 const size_t & size() const { return current_dim; }
00488 const size_t & max_size() const { return max_dim; }
00490 const size_t & get_num_blocks() const { return num_blocks; }
00501 void set_default_initial_value(const T & value)
00502 {
00503 default_initial_value = value;
00504 default_initial_value_ptr = &default_initial_value;
00505 }
00525 DynArray(const size_t & _pow_dir,
00526 const size_t & _pow_seg,
00527 const size_t & _pow_block)
00528 throw (std::exception, std::bad_alloc,
00529 std::length_error, std::overflow_error)
00530 : pow_dir ( _pow_dir ),
00531 pow_seg ( _pow_seg ),
00532 pow_block ( _pow_block ),
00533 seg_plus_block_pow ( _pow_seg + _pow_block ),
00534 mask_seg_plus_block ( two_raised(seg_plus_block_pow) - 1 ),
00535 dir_size ( two_raised(pow_dir) ),
00536 seg_size ( two_raised(pow_seg) ),
00537 block_size ( two_raised(pow_block) ),
00538 max_dim ( two_raised(seg_plus_block_pow + pow_dir) ),
00539 mask_seg ( seg_size - 1 ),
00540 mask_block ( block_size - 1 ),
00541 current_dim ( 0 ),
00542 num_segs ( 0 ),
00543 num_blocks ( 0 ),
00544 default_initial_value_ptr (NULL)
00545 {
00546 I(Max_Dim_Allowed > 0);
00547
00548 if (max_dim > Max_Dim_Allowed)
00549 throw std::length_error ("Dimension too large");
00550
00551 allocate_dir();
00552 }
00572 DynArray(const size_t & dim = 10000)
00573
00574 throw (std::exception, std::bad_alloc,
00575 std::length_error, std::overflow_error)
00576
00577 : pow_dir ( Default_Pow_Dir ),
00578 pow_seg ( Default_Pow_Seg ),
00579 pow_block (std::min(std::max(next2Pow(dim/8), Default_Pow_Block),
00580 Max_Pow_Block)
00581 ),
00582 seg_plus_block_pow ( pow_seg + pow_block ),
00583 mask_seg_plus_block ( two_raised(seg_plus_block_pow) - 1 ),
00584 dir_size ( two_raised(pow_dir) ),
00585 seg_size ( two_raised(pow_seg) ),
00586 block_size ( two_raised(pow_block) ),
00587 max_dim ( two_raised(seg_plus_block_pow + pow_dir) ),
00588 mask_seg ( seg_size - 1 ),
00589 mask_block ( block_size - 1 ),
00590 current_dim ( 0 ),
00591 num_segs ( 0 ),
00592 num_blocks ( 0 ),
00593 default_initial_value_ptr (NULL)
00594 {
00595
00596 I(Max_Dim_Allowed > 0);
00597
00598 if (max_dim > Max_Dim_Allowed)
00599 throw std::length_error ("Dimension too large");
00600
00601 allocate_dir();
00602 }
00604 ~DynArray()
00605 {
00606 I(dir != NULL);
00607
00608 release_dir();
00609 }
00621 void copy_array(const DynArray<T> & src_array)
00622 {
00623 for (int i = 0; i < src_array.current_dim; ++i)
00624 if (src_array.exist(i))
00625 (*this)[i] = src_array.access(i);
00626 }
00636 DynArray(const DynArray<T> & array)
00637 throw (std::exception, std::bad_alloc)
00638 : pow_dir (array.pow_dir),
00639 pow_seg (array.pow_seg),
00640 pow_block (array.pow_block),
00641 seg_plus_block_pow (array.seg_plus_block_pow),
00642 mask_seg_plus_block (array.mask_seg_plus_block),
00643 dir_size (array.dir_size),
00644 seg_size (array.seg_size),
00645 block_size (array.block_size),
00646 max_dim (array.max_dim),
00647 mask_seg (array.mask_seg),
00648 mask_block (array.mask_block),
00649 current_dim (0),
00650 num_segs (0),
00651 num_blocks (0),
00652 default_initial_value_ptr (NULL)
00653 {
00654 allocate_dir();
00655 copy_array(array);
00656 }
00657
00665 DynArray<T> & operator = (const DynArray<T> & array)
00666 throw (std::exception, std::bad_alloc)
00667 {
00668 if (this == &array)
00669 return *this;
00670
00671 copy_array(array);
00672
00673 if (array.current_dim < current_dim)
00674 cut(array.current_dim);
00675
00676 current_dim = array.current_dim;
00677
00678 return *this;
00679 }
00690 void swap(DynArray<T> & array)
00691 {
00692 Aleph::swap(dir, array.dir);
00693 Aleph::swap(pow_dir, array.pow_dir);
00694 Aleph::swap(pow_seg, array.pow_seg);
00695 Aleph::swap(pow_block, array.pow_block);
00696 Aleph::swap(seg_plus_block_pow, array.seg_plus_block_pow);
00697 Aleph::swap(mask_seg_plus_block, array.mask_seg_plus_block);
00698 Aleph::swap(dir_size, array.dir_size);
00699 Aleph::swap(seg_size, array.seg_size);
00700 Aleph::swap(block_size, array.block_size);
00701 Aleph::swap(mask_seg, array.mask_seg);
00702 Aleph::swap(mask_block, array.mask_block);
00703 Aleph::swap(max_dim, array.max_dim);
00704 Aleph::swap(current_dim, array.current_dim);
00705 Aleph::swap(num_segs, array.num_segs);
00706 Aleph::swap(num_blocks, array.num_blocks);
00707 }
00727 T & access(const size_t & i)
00728 {
00729
00730 I(dir[index_in_dir(i)] != NULL);
00731 I(dir[index_in_dir(i)][index_in_seg(i)] != NULL);
00732
00733 return dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
00734 }
00735
00755 const T & access(const size_t & i) const
00756 {
00757 I(dir[index_in_dir(i)] != NULL);
00758 I(dir[index_in_dir(i)][index_in_seg(i)] != NULL);
00759
00760 return dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
00761 }
00762
00777 bool exist(const size_t & i) const
00778
00779 throw (std::exception, std::out_of_range)
00780
00781 {
00782
00783 if (i >= max_dim)
00784 throw std::out_of_range ("index out of maximun range");
00785
00786 const size_t pos_in_dir = index_in_dir(i);
00787
00788
00789 I(pos_in_dir < dir_size);
00790
00791 if (dir[pos_in_dir] == NULL)
00792 return false;
00793
00794 const size_t pos_in_seg = index_in_seg(i);
00795
00796
00797 I(pos_in_seg < seg_size);
00798
00799 if (dir[pos_in_dir][pos_in_seg] == NULL)
00800 return false;
00801
00802 return true;
00803 }
00804 T * test(const size_t & i)
00805 {
00806 const size_t pos_in_dir = index_in_dir(i);
00807
00808 if (dir[pos_in_dir] == NULL)
00809 return NULL;
00810
00811 const size_t pos_in_seg = index_in_seg(i);
00812
00813 if (dir[pos_in_dir][pos_in_seg] == NULL)
00814 return NULL;
00815
00816 return &dir[index_in_dir(i)][index_in_seg(i)][index_in_block(i)];
00817 }
00829 T & touch(const size_t & i)
00830
00831 throw (std::exception, std::bad_alloc, std::out_of_range)
00832
00833 {
00834
00835 if (i >= max_dim)
00836 throw std::out_of_range ("index out of maximun range");
00837
00838 const size_t pos_in_dir = index_in_dir(i);
00839
00840 if (dir[pos_in_dir] == NULL)
00841 allocate_segment(dir[pos_in_dir]);
00842
00843 const size_t pos_in_seg = index_in_seg(i);
00844
00845 if (dir[pos_in_dir][pos_in_seg] == NULL)
00846
00847 {
00848 try
00849 {
00850
00851 allocate_block(dir[pos_in_dir][pos_in_seg]);
00852
00853 }
00854 catch (...)
00855 {
00856 release_segment(dir[pos_in_dir]);
00857 throw;
00858 }
00859 }
00860
00861 if (i >= current_dim)
00862 current_dim = i + 1;
00863
00864 return dir[pos_in_dir][pos_in_seg][index_in_block(i)];
00865 }
00881 void reserve(const size_t & l, const size_t & r)
00882
00883 throw (std::exception, std::bad_alloc, std::domain_error, std::length_error)
00884
00885 {
00886
00887 if (l > r)
00888 throw std::domain_error("invalid range");
00889
00890 if (r >= max_dim)
00891 throw std::length_error ("dimension too large");
00892
00893 const size_t first_seg = index_in_dir(l);
00894 const size_t last_seg = index_in_dir(r);
00895
00896 const size_t first_block = index_in_seg(l);
00897 const size_t last_block = index_in_seg(r);
00898
00899
00900 try
00901 {
00902
00903 for (size_t seg_idx = first_seg; seg_idx <= last_seg; ++seg_idx)
00904 {
00905 if (dir[seg_idx] == NULL)
00906 allocate_segment(dir[seg_idx]);
00907
00908 size_t block_idx = (seg_idx == first_seg) ? first_block : 0;
00909
00910 const size_t final_block =
00911 (seg_idx == last_seg) ? last_block : seg_size - 1;
00912
00913 while (block_idx <= final_block)
00914 {
00915 if (dir[seg_idx][block_idx] == NULL)
00916 allocate_block(dir[seg_idx][block_idx]);
00917
00918 ++block_idx;
00919 }
00920 }
00921
00922 if (r + 1 > current_dim)
00923 current_dim = r + 1;
00924
00925 }
00926 catch (...)
00927 {
00928 if (r + 1 > current_dim)
00929 current_dim = r + 1;
00930 throw;
00931 }
00932
00933 }
00947 void cut(const size_t & new_dim = 0)
00948
00949 throw (std::exception, std::domain_error)
00950
00951 {
00952
00953 if (new_dim > current_dim)
00954 throw std::domain_error("new dimension is greater that current dimension");
00955
00956 if (new_dim == 0)
00957 {
00958 release_all_segments_and_blocks();
00959 current_dim = 0;
00960 return;
00961 }
00962
00963 const size_t old_dim = current_dim;
00964
00965
00966 const int idx_first_seg = index_in_dir(old_dim - 1);
00967 const int idx_first_block = index_in_seg(old_dim - 1);
00968
00969
00970 const int idx_last_seg = index_in_dir(new_dim - 1);
00971 const int idx_last_block = index_in_seg(new_dim - 1);
00972
00973
00974 for (int idx_seg = index_in_dir(old_dim - 1); idx_seg >= idx_last_seg;
00975 --idx_seg)
00976 {
00977 if (dir[idx_seg] == NULL)
00978 continue;
00979
00980
00981 int idx_block = idx_seg == idx_first_seg ? idx_first_block : seg_size - 1;
00982
00983 while ( (idx_seg > idx_last_seg and idx_block >= 0) or
00984 (idx_seg == idx_last_seg and idx_block > idx_last_block) )
00985 {
00986 if (dir[idx_seg][idx_block] != NULL)
00987 release_block(dir[idx_seg][idx_block]);
00988 --idx_block;
00989 }
00990 if (idx_block < 0)
00991 release_segment(dir[idx_seg]);
00992 }
00993
00994 I(dir[idx_last_seg] != NULL and dir[idx_last_seg][idx_last_block] != NULL);
00995
00996
00997 current_dim = new_dim;
00998 }
00999
01000 Proxy operator [] (const size_t & i) const
01001 throw (std::exception, std::bad_alloc, std::length_error,
01002 std::invalid_argument)
01003 {
01004 if (i >= max_dim)
01005 throw std::out_of_range ("index out of maximun range");
01006
01007 return Proxy (const_cast<DynArray<T>&>(*this), i);
01008 }
01009
01010 Proxy operator [] (const size_t & i)
01011
01012 throw (std::exception, std::length_error,
01013 std::invalid_argument, std::bad_alloc)
01014
01015 {
01016
01017 if (i >= max_dim)
01018 throw std::out_of_range ("index out of maximun range");
01019
01020 return Proxy (const_cast<DynArray<T>&>(*this), i);
01021 }
01022 };
01023
01024 template <typename T> const size_t DynArray<T>::Default_Pow_Dir = 4;
01025 template <typename T> const size_t DynArray<T>::Default_Pow_Seg = 6;
01026 template <typename T> const size_t DynArray<T>::Default_Pow_Block = 12;
01027 template <typename T> const size_t DynArray<T>::Max_Bits_Allowed = 8 * sizeof(size_t);
01028 template <typename T> const size_t DynArray<T>::Max_Dim_Allowed = 2*1024*1024*1024ul;
01029
01030 template <typename T> const size_t DynArray<T>::Max_Pow_Block =
01031 (Max_Bits_Allowed - Default_Pow_Dir - Default_Pow_Seg - 1);
01032
01033 }
01034
01035 # endif
01036