Open64 (mfef90, whirl2f, and IR tools)  TAG: version-openad; SVN changeset: 916
segmented_array.h
Go to the documentation of this file.
00001 /*
00002 
00003   Copyright (C) 2000, 2001 Silicon Graphics, Inc.  All Rights Reserved.
00004 
00005   This program is free software; you can redistribute it and/or modify it
00006   under the terms of version 2 of the GNU General Public License as
00007   published by the Free Software Foundation.
00008 
00009   This program is distributed in the hope that it would be useful, but
00010   WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00012 
00013   Further, this software is distributed without any warranty that it is
00014   free of the rightful claim of any third person regarding infringement 
00015   or the like.  Any license provided herein, whether implied or 
00016   otherwise, applies only to this software file.  Patent licenses, if 
00017   any, provided herein do not apply to combinations of this program with 
00018   other software, or any other product whatsoever.  
00019 
00020   You should have received a copy of the GNU General Public License along
00021   with this program; if not, write the Free Software Foundation, Inc., 59
00022   Temple Place - Suite 330, Boston MA 02111-1307, USA.
00023 
00024   Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pky,
00025   Mountain View, CA 94043, or:
00026 
00027   http://www.sgi.com
00028 
00029   For further information regarding this notice, see:
00030 
00031   http://oss.sgi.com/projects/GenInfo/NoticeExplan
00032 
00033 */
00034 
00035 
00036 /* -*-Mode: c++;-*- (Tell emacs to use c++ mode) */
00037 
00038 #ifndef segmented_array_INCLUDED
00039 #define segmented_array_INCLUDED
00040 
00041 #ifndef __SGI_STL_VECTOR_H
00042 
00043 # if defined(defs_INCLUDED) && !defined(USE_STANDARD_TYPES)
00044 #  undef short                          // get around bogus type defs.
00045 #  undef int
00046 #  undef long
00047 # endif // defined(defs_INCLUDED) && !defined(USE_STANDARD_TYPES)
00048 
00049 using namespace std;
00050 #include <vector>
00051 
00052 #endif // __SGI_STL_VECTOR_H
00053 
00054 #include "errors.h"
00055 #include "mempool.h"
00056 #include "mempool_allocator.h"
00057 
00058 
00059 // SA_Ptr is pointer to SEG_ARRAY,
00060 // SA_vt_Ptr is pointer to SEG_ARRAY::value_type,
00061 // SA_vt_Ref is reference to SEG_ARRAY::value_type.
00062 //
00063 // These are template parameters because we need both constant and
00064 // mutable iterators.  For a constant iterator they will be,
00065 // respectively, const SEG_ARRAY*, const SEG_ARRAY::value_type*, and
00066 // const SEG_ARRAY::value_type&.  For a mutable iterator they will be
00067 // SEG_ARRAY*, SEG_ARRAY::value_type*, and SEG_ARRAY::value_type&.
00068 
00069 // TO DO: add a conversion from the mutable version to the constant
00070 // version.
00071 
00072 template <class SA_Ptr, class T, class SA_vt_Ptr, class SA_vt_Ref>
00073 class SEGMENTED_ARRAY_ITERATOR
00074 {
00075 public:
00076   typedef T                         value_type;
00077   typedef UINT                      difference_type;
00078   typedef std::forward_iterator_tag iterator_category;
00079   typedef SA_vt_Ptr                 pointer;
00080   typedef SA_vt_Ref                 reference;
00081 
00082 private:
00083     
00084     SA_Ptr segmented_array;
00085     SA_vt_Ptr ptr;                      // pointer to the current element
00086     SA_vt_Ptr segment_last;             // ptr after the current segment
00087     UINT map_idx;                       // index to the map array
00088 
00089 private:
00090 
00091     typedef SEGMENTED_ARRAY_ITERATOR self;
00092 
00093 public:
00094 
00095     SEGMENTED_ARRAY_ITERATOR (SA_Ptr sa, T* p, T* last, UINT idx) 
00096         : segmented_array (sa), ptr (p), segment_last (last) {
00097             map_idx = sa->Block_index(idx);
00098     }
00099 
00100     SEGMENTED_ARRAY_ITERATOR (SA_Ptr sa, UINT idx)
00101         : segmented_array (sa) {
00102             map_idx = sa->Block_index(idx);
00103             ptr = &(sa->Entry(idx));
00104             segment_last = sa->Block_end(map_idx);
00105     }
00106 
00107     SEGMENTED_ARRAY_ITERATOR () {}
00108 
00109     SA_vt_Ref operator* () const                { return *ptr; }
00110     SA_vt_Ptr Ptr () const                      { return ptr; }
00111     SA_vt_Ptr operator->() const              { return ptr; }
00112     UINT Index () const {
00113       return map_idx * segmented_array->Block_size() +
00114              (ptr - segmented_array->Block_begin(map_idx));
00115     }
00116 
00117     self& operator ++ () {
00118         ++ptr;
00119         if (ptr == segment_last) {
00120             UINT map_entries =
00121                 (segment_last - segmented_array->Block_begin(map_idx)) / 
00122                 segmented_array->Block_size ();
00123             if (map_idx + map_entries < segmented_array->Block_index_end()) {
00124                 map_idx += map_entries;
00125                 ptr = segmented_array->Block_begin(map_idx);
00126                 segment_last = segmented_array->Block_end(map_idx);
00127             }
00128         }
00129         return *this;
00130     }
00131 
00132     self operator ++ (int) {
00133         self tmp = *this;
00134         ++(*this);
00135         return tmp;
00136     }
00137 
00138     BOOL operator == (const self& x) const      { return ptr == x.ptr; }
00139     BOOL operator != (const self& x) const      { return !(*this == x); }
00140 
00141 }; // SEGMENTED_ARRAY_ITERATOR
00142 
00143 
00144 template <class T, UINT block_size = 128>
00145 class SEGMENTED_ARRAY
00146 {
00147 private:
00148 
00149     std::vector<std::pair<T *, BOOL>, mempool_allocator<std::pair<T *,BOOL> > > map;
00150 
00151     MEM_POOL *pool;
00152     UINT size_;                         // total number of elements inserted
00153     UINT max_size_;                     // total # of elements allocated
00154     INT block_base;                     // idx of the beginning of
00155                                         // block (signed so we can set
00156                                         // to -1, meaning no block allocated)
00157     UINT next_block_size;               // size of block to be allocated
00158     T *block;                           // points to the last block
00159 
00160     typedef SEGMENTED_ARRAY<T, block_size> self;
00161 
00162 public:
00163     typedef T base_type;
00164 
00165     typedef T                 value_type;
00166     typedef value_type*       pointer;
00167     typedef const value_type* const_pointer;
00168     typedef value_type&       reference;
00169     typedef const value_type& const_reference;
00170     typedef UINT              size_type;
00171     typedef INT               difference_type;
00172 
00173     typedef SEGMENTED_ARRAY_ITERATOR<self*, T, pointer, reference>
00174             iterator;
00175     typedef SEGMENTED_ARRAY_ITERATOR<const self*, T, 
00176                                      const_pointer, const_reference> 
00177             const_iterator;
00178 
00179 private:
00180 
00181     // private operations
00182     
00183     UINT Round_up (UINT s) {
00184         UINT mask = block_size - 1;
00185         return (s + mask) & ~mask;
00186     }
00187 
00188     void Update_Map (T *marker, UINT new_size, BOOL own_memory);
00189 
00190     void Pop_Map ();
00191 
00192     // allocate a block, assume the array is completely filled
00193     void Allocate ();
00194 
00195     T& New_entry () {
00196         if (size_ == max_size_) Allocate ();
00197         return block[size_++ - block_base];
00198     }
00199     
00200     // copy n elements to current buffer, assume no overflow
00201     void Copy (const T* x, UINT n) {
00202         std::copy(x, x + n, block + (size_ - block_base));
00203         size_ += n;
00204     }
00205 
00206     // block_idx is an index into the map.  This function returns
00207     // the first map index that points to a different block. 
00208     UINT next_block_idx(UINT block_idx) const {
00209       for ( ; block_idx + 1 < map.size() &&
00210               map[block_idx].first + block_size == map[block_idx + 1].first ;
00211             ++block_idx)
00212         {}
00213       return block_idx + 1;
00214     }
00215 
00216 public:
00217 
00218   SEGMENTED_ARRAY(MEM_POOL *m = Malloc_Mem_Pool) : map (m), pool (m) {
00219     size_ = max_size_ = next_block_size = 0;
00220     block_base = -1;
00221     block = 0;
00222   }
00223 
00224   ~SEGMENTED_ARRAY() {
00225     typedef typename vector<pair<T *, BOOL>, mempool_allocator<pair<T *, BOOL> > >::iterator TempIteratorType;
00226     // Free memory from blocks. Map memory gets freed when the map
00227     // vector is destructed.
00228     for ( TempIteratorType entry = map.begin(); entry != map.end(); ++entry ) {
00229       // entry->second <==> this map entry owns the block's memory.
00230       if (entry->second) {
00231         MEM_POOL_FREE(pool, entry->first);
00232       }
00233     }
00234   }
00235 
00236   UINT Block_size () const      { return block_size; }
00237 
00238   UINT Size () const            { return size_; }
00239   UINT size () const            { return size_; }
00240 
00241     T& Entry (UINT idx) {
00242         Is_True (idx < size_, ("Array subscript out of bound"));
00243         return map[idx / block_size].first[idx % block_size];
00244     }
00245 
00246     const T& Entry (UINT idx) const {
00247         Is_True (idx < size_, ("Array subscript out of bound"));
00248         return map[idx / block_size].first[idx % block_size];
00249     }
00250     T& operator[] (UINT idx)             { return Entry(idx); }
00251     const T& operator[] (UINT idx) const { return Entry(idx); }
00252 
00253     iterator begin () {
00254         return iterator (this, map[0].first, Block_end (0), 0);
00255     }
00256 
00257     iterator end () {
00258         return iterator (this, block + (size_ - block_base),
00259                          block + (max_size_ - block_base), size_);
00260     }
00261 
00262     const_iterator begin () const {
00263         return const_iterator (this, map[0].first, Block_end (0), 0);
00264     }
00265 
00266     const_iterator end () const {
00267         return const_iterator (this, block + (size_ - block_base),
00268                                block + (max_size_ - block_base), size_);
00269     }
00270 
00271         
00272     T& New_entry (UINT& idx)    { idx = size_; return New_entry (); }
00273 
00274     UINT Insert (const T& x);
00275 
00276     void Delete_last () {
00277         --size_;
00278         if (size_ == block_base)
00279             Pop_Map ();
00280     }
00281             
00282 
00283     void Delete_last (UINT n);
00284 
00285     void Delete_down_to (UINT idx) {
00286         if (size_ > idx)
00287             Delete_last (size_ - idx);
00288     }
00289 
00290     // insert multiple elements, always copy to new buffer.
00291     UINT Insert (const T* x, UINT n_elemt);
00292     
00293     // similar to insert, except reuse the given buffer if possible
00294     UINT Transfer (T* x, UINT n_elemt);
00295     
00296     // Reserve extra storage.  Actual allocation will be done when the
00297     // already allocated storage is filled.
00298     void Reserve (UINT n_elemt) {
00299         if (max_size_ - size_ + next_block_size < n_elemt)
00300             next_block_size = n_elemt - (max_size_ - size_);
00301     }
00302 
00303     // return the number of element till the end of the block
00304     UINT Get_block_size (UINT idx) const {
00305       UINT block_idx = idx / block_size;
00306       return std::min(next_block_idx(block_idx) * block_size, size_) - idx;
00307     }
00308 
00309     UINT Block_index (UINT idx) const { return idx / block_size; }
00310 
00311     // A valid block index n is in the range 0 <= n < Block_index_end().
00312     UINT Block_index_end () const { return map.size(); }
00313 
00314     T* Block_begin (UINT block_idx)             { return map[block_idx].first; }
00315     const T* Block_begin (UINT block_idx) const { return map[block_idx].first; }
00316 
00317     T* Block_end(UINT block_idx) {
00318       return Block_begin(block_idx) +
00319              (next_block_idx(block_idx) - block_idx) * block_size;
00320     }
00321 
00322     const T* Block_end(UINT block_idx) const {
00323       return Block_begin(block_idx) +
00324              (next_block_idx(block_idx) - block_idx) * block_size;
00325     }
00326 
00327 }; // SEGMENTED_ARRAY
00328 
00329 
00330 template <class T, UINT block_size>
00331 inline void
00332 SEGMENTED_ARRAY<T,block_size>::Update_Map(T    *marker,
00333                                           UINT  new_size,
00334                                           BOOL  own_memory)
00335 {
00336   do {
00337     map.push_back(std::pair<T*, BOOL>(marker, own_memory));
00338     // own_memory = FALSE;
00339     new_size -= block_size;
00340     marker += block_size;
00341   } while (new_size);
00342 } // SEGMENTED_ARRAY<T,block_size>::Update_Map
00343 
00344 
00345 // deallocate a block and re-adjust the map and other variables
00346 template <class T, UINT block_size>
00347 void
00348 SEGMENTED_ARRAY<T,block_size>::Pop_Map ()
00349 {
00350     next_block_size += max_size_ - block_base;
00351     MEM_POOL_FREE (pool, block);
00352 
00353     T *last_map_entry;
00354     do {
00355       last_map_entry = (map.end() - 1)->first;
00356       map.pop_back ();
00357     } while (last_map_entry != block);
00358 
00359     max_size_ = size_;
00360     if (size_ > 0) {
00361       Is_True(size_ >= block_size,
00362               ("SEGMENTED_ARRAY: size in limbo"));
00363       block_base = size_ - block_size;
00364       UINT idx = block_base / block_size;
00365       block = map[idx].first;
00366       while (idx > 0 && map[idx - 1].first + block_size == block) {
00367         block = map[--idx].first;
00368         block_base -= block_size;
00369       }
00370     }
00371     else {
00372       Is_True(map.begin() == map.end(),
00373               ("SEGMENTED_ARRAY::Pop_Map: Map should be empty"));
00374       block_base = -1;
00375       block = NULL;
00376     }
00377 } // SEGMENTED_ARRAY<T,block_size>::Pop_Map
00378 
00379 
00380 template <class T, UINT block_size>
00381 void
00382 SEGMENTED_ARRAY<T,block_size>::Allocate ()
00383 {
00384     Is_True (size_ == max_size_, ("Invalid internal state in segmented array"));
00385 
00386     UINT new_size;
00387 
00388     if (next_block_size == 0)
00389         new_size = block_size;
00390     else {
00391         new_size = Round_up (next_block_size);
00392         next_block_size = 0;
00393     }
00394 
00395     block = (T *) MEM_POOL_Alloc (pool, new_size * sizeof(T));
00396     max_size_ += new_size;
00397     block_base = size_;
00398 
00399     Update_Map (block, new_size, TRUE);
00400     
00401 } // SEGMENTED_ARRAY::Allocate
00402 
00403 
00404 template <class T, UINT block_size>
00405 void
00406 SEGMENTED_ARRAY<T,block_size>::Delete_last (UINT n)
00407 {
00408     while (n >= size_ - block_base) {
00409         n -= size_ - block_base;
00410         size_ = block_base;
00411         Pop_Map ();
00412     }
00413     
00414     size_ -= n;
00415 } // Delete_last
00416 
00417 
00418 template <class T, UINT block_size>
00419 inline UINT
00420 SEGMENTED_ARRAY<T,block_size>::Insert (const T& x)
00421 {
00422     UINT idx = size_;
00423     T &entry = New_entry ();
00424 
00425     entry = x;
00426     return idx;
00427 } // SEGMENTED_ARRAY::Insert
00428 
00429 
00430 template <class T, UINT block_size>
00431 UINT
00432 SEGMENTED_ARRAY<T,block_size>::Insert (const T* x, UINT n_elemt)
00433 {
00434     UINT result = size_;
00435     if (size_ + n_elemt <= max_size_) {
00436         Copy (x, n_elemt);
00437         return result;
00438     }
00439 
00440     UINT space_left = max_size_ - size_;
00441     Copy (x, space_left);
00442     n_elemt -= space_left;
00443 
00444     Reserve (n_elemt);
00445     Allocate ();
00446     Copy (x + space_left, n_elemt);
00447 
00448     return result;
00449 } // SEGMENTED_ARRAY::Insert
00450 
00451 
00452 template <class T, UINT block_size>
00453 UINT
00454 SEGMENTED_ARRAY<T,block_size>::Transfer (T* x, UINT n_elemt)
00455 {
00456     UINT result = size_;
00457 
00458     if (size_ + n_elemt <= max_size_) {
00459         Copy (x, n_elemt);
00460         return result;
00461     }
00462 
00463     UINT space_left = max_size_ - size_;
00464     if (space_left > 0) {
00465         Copy (x, space_left);
00466         n_elemt -= space_left;
00467         x += space_left;
00468     }
00469 
00470     if (n_elemt >= block_size) {
00471         UINT reused_size = n_elemt & ~(block_size - 1);
00472         block = x;
00473         Update_Map (block, reused_size, FALSE);
00474         block_base = size_;
00475         size_ += reused_size;
00476         max_size_ += reused_size;
00477         n_elemt -= reused_size;
00478         x += reused_size;
00479         if (next_block_size > reused_size)
00480             next_block_size -= reused_size;
00481         else
00482             next_block_size = 0;
00483     }
00484 
00485     if (n_elemt > 0) {
00486         Allocate ();
00487         Copy (x, n_elemt);
00488     }
00489 
00490     return result;
00491     
00492 } // SEGMENTED_ARRAY::Transfer
00493 
00494 
00495 template <class T, UINT block_size, class OP>
00496 inline void
00497 For_all_entries (SEGMENTED_ARRAY<T, block_size>& array, const OP &op,
00498                  UINT32 first = 0)
00499 {
00500     UINT last = array.size ();
00501 
00502     while (first < last) {
00503         T *block = &array[first];
00504         UINT size = array.Get_block_size (first);
00505         for (UINT j = 0; j < size; ++j, ++block)
00506             op (first + j, block);
00507         first += size;
00508     }
00509 }
00510 
00511 // The following function is ifdefed out because, until we have
00512 // partial ordering of function templates, the compiler will flag it
00513 // as ambiguous.
00514 #if 0
00515 
00516 template <class T, UINT block_size, class OP>
00517 inline void
00518 For_all_entries (const SEGMENTED_ARRAY<T, block_size>& array, const OP &op,
00519                  UINT32 first = 0)
00520 {
00521     UINT last = array.size ();
00522 
00523     while (first < last) {
00524         const T *block = &array[first];
00525         UINT size = array.Get_block_size (first);
00526         for (UINT j = 0; j < size; ++j, ++block)
00527             op (first + j, block);
00528         first += size;
00529     }
00530 }
00531 
00532 #endif
00533 
00534 template <class T, UINT block_size, class OP>
00535 inline void
00536 For_all_blocks (SEGMENTED_ARRAY<T, block_size>& array, const OP &op)
00537 {
00538     UINT max_size = array.size ();
00539     UINT i = 0;
00540 
00541     while (i < max_size) {
00542         T *block = &array[i];
00543         UINT size = array.Get_block_size (i);
00544         op (i, block, size);
00545         i += size;
00546     }
00547 }
00548 
00549 
00550 #define NOT_FOUND ((UINT) -1)
00551 
00552 template <class T, UINT block_size, class PREDICATE>
00553 inline UINT
00554 Find_entry_if (const SEGMENTED_ARRAY<T, block_size>& array,
00555                const PREDICATE& pred, UINT i = 0)
00556 {
00557     UINT max_size = array.size ();
00558 
00559     while (i < max_size) {
00560         const T *block = &array[i];
00561         UINT size = array.Get_block_size (i);
00562         for (UINT j = 0; j < size; ++j, ++block)
00563             if (pred (i+j, block))
00564                 return i + j;
00565         i += size;
00566     }
00567 
00568     return (UINT) NOT_FOUND;
00569 }
00570 
00571 
00572 // copy the content of one segmented array to another, optionally specified
00573 // the range [first_idx, last_idx) to be copied.
00574 // returns the number of entries copied.
00575 template <class T, UINT block_size>
00576 UINT32
00577 Copy_array_range (const SEGMENTED_ARRAY<T, block_size>& from_array,
00578                   SEGMENTED_ARRAY<T, block_size>& to_array,
00579                   UINT32 first_idx = 0, UINT32 last_idx = (UINT32) -1)
00580 {
00581     if (last_idx > from_array.size ())
00582         last_idx = from_array.size ();
00583 
00584     Is_True (last_idx >= first_idx, ("Invalid copy range"));
00585 
00586     UINT32 entries = last_idx - first_idx;
00587 
00588     to_array.Reserve (entries);
00589 
00590     while (first_idx < last_idx) {
00591         const T* block = &from_array[first_idx];
00592         UINT32 size = from_array.Get_block_size (first_idx);
00593         if (size > last_idx - first_idx)
00594             size = last_idx - first_idx;
00595 
00596         to_array.Insert (block, size);
00597         first_idx += size;
00598     }
00599 
00600     return entries;
00601 } // Copy_array_range
00602 
00603 #endif /* segmented_array_INCLUDED */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines