Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members

Table.h

Go to the documentation of this file.
00001 // Copyright (C) 2002 Johan Hoffman and Anders Logg.
00002 // Licensed under the GNU GPL Version 2.
00003 
00004 #ifndef __TABLE_H
00005 #define __TABLE_H
00006 
00007 #include <dolfin/dolfin_log.h>
00008 
00009 namespace dolfin {
00010 
00016   
00017   template <class T> class Table {
00018 
00019     // Forward declaration of nested classes
00020     class Block;
00021 
00022   public:
00023 
00024     // Forward declaration of nested classes
00025     class Iterator;
00026          
00028     Table();
00029     
00031     ~Table();
00032 
00034     void clear();
00035 
00037     T& create();
00038 
00040     T& create(int& id);
00041          
00043     T& add(T x);
00044          
00046     T& operator() (int id);
00047                 
00049     void remove(T& x);
00050  
00052     int size() const;
00053          
00055     bool empty() const;
00056 
00058     template <class X>
00059     friend LogStream & operator<< (LogStream & stream, const Table<X> & table);
00060 
00062     Iterator begin() const;
00063 
00065     Iterator end() const;
00066 
00068     Iterator iterator(int id);
00069 
00071     friend class Block;
00072     friend class Iterator;
00073  
00079 
00080     class Iterator {
00081     public:
00082                 
00084       Iterator();
00085       
00087       Iterator(const Iterator& it);
00088 
00090       Iterator(const Table<T>& table);
00091                 
00093       Iterator(const Table<T>& table, int id);
00094 
00096       int index() const;
00097                 
00099       Iterator& operator++();
00100                 
00102       bool end() const;
00103                 
00105       bool last() const;
00106                 
00108       T& operator*() const;
00109 
00111       T* operator->() const;
00112                 
00114       operator T*() const;
00115       
00117       T* pointer() const;
00118                 
00120       void operator=(const Iterator& it);
00121 
00123       bool operator==(const Iterator& it) const;
00124                 
00126       bool operator!=(const Iterator& it) const;
00127 
00129       friend class Table<T>;
00130         
00131     private:
00132 
00133       // The table
00134       const Table<T>* table;
00135 
00136       // Current block
00137       Block* block;
00138 
00139       // Position in current block
00140       int pos;
00141 
00142       // Iterator index, 0,1,2,...
00143       int _index;
00144 
00145       // True if we have reached the end of the table
00146       bool at_end;
00147 
00148     };
00149                  
00150   private:
00151     
00152     class Block {
00153     public:
00154       
00155       friend class Table<T>;
00156       friend class Iterator;
00157                 
00158       Block(Block* prev);
00159       ~Block();
00160                 
00161       T* pointer(int id);
00162       int position(int id);
00163       bool full();
00164       int first_pos();
00165       int next_pos(int start);
00166       T& create(int& id);
00167       bool remove(T& x);
00168       
00169     private:
00170                 
00171       // Pointer to previous and next blocks
00172       Block* prev;
00173       Block* next;
00174                 
00175       // Data
00176       T* data;
00177       bool* empty;
00178       
00179       // Next available position
00180       int pos;
00181 
00182       // Number of used elements
00183       int used;
00184                 
00185       // Number of this block
00186       int number;
00187       
00188     };
00189          
00190     // Place iterator at the beginning of the table
00191     void iterator_start(Iterator* it) const;
00192 
00193     // Place iterator at the element with given id
00194     void iterator_id(Iterator* it, int id) const;
00195          
00196     // Step iterator to the next position in the table
00197     void iterator_step(Iterator* it) const;
00198 
00199     //--- Table data ---
00200 
00201     // Pointers to first and current blocks
00202     Block* _first_block;
00203     Block* _current_block;
00204          
00205     // Number of blocks and size of table
00206     int _blocks;
00207     int _size;
00208 
00209     // Number of empty positions before current position
00210     int _empty;
00211          
00212   };
00213 
00214   //---------------------------------------------------------------------------
00215   // Implementation of Table
00216   //---------------------------------------------------------------------------
00217   template <class T> Table<T>::Table()
00218   {
00219     _first_block = 0;
00220     _current_block = 0;
00221     
00222     _blocks = 0;
00223     _size = 0;
00224     _empty = 0;  
00225   }
00226   //---------------------------------------------------------------------------
00227   template <class T> Table<T>::~Table()
00228   {
00229     clear();
00230   }
00231   //---------------------------------------------------------------------------
00232   template <class T> void Table<T>::clear()
00233   {
00234     // Delete all blocks
00235     if ( _first_block ) {
00236       
00237       Block *b = _first_block;
00238       while ( true ) {
00239         
00240         if ( b->prev )
00241           delete b->prev;
00242         
00243         if ( !b->next )
00244           break;
00245         
00246         b = b->next;
00247         
00248       }
00249       
00250       delete b;
00251     }
00252 
00253     _first_block = 0;
00254     _current_block = 0;
00255     
00256     _blocks = 0;
00257     _size = 0;
00258     _empty = 0;  
00259   }
00260   //---------------------------------------------------------------------------
00261   template <class T> T& Table<T>::create()
00262   {
00263     int dummy;
00264     T& t = create(&dummy);
00265     return t;
00266   }
00267   //---------------------------------------------------------------------------
00268   template <class T> T& Table<T>::create(int& id)
00269   {
00270     // Create a new block if there are no blocks
00271     if ( !_first_block ){
00272       _first_block = new Block(0);
00273       _current_block = _first_block;
00274       _blocks = 1;
00275     }
00276     
00277     // Check for empty position
00278     if ( _empty > 0 ) {
00279       for (Block *b = _first_block; b; b = b->next) {
00280         if ( !(b->full()) ) {
00281           _size += 1;
00282           _empty -= 1;
00283           return b->create(id);
00284         }
00285       }
00286       dolfin_error("Unable to find empty position in table.");
00287     }
00288     
00289     // Use next available position
00290     if ( !_current_block->full() ) {
00291       _size += 1;
00292       return _current_block->create(id);
00293     }
00294     
00295     // Create new block
00296     _current_block = new Block(_current_block);
00297     _size += 1;
00298     _blocks += 1;
00299     
00300     return _current_block->create(id);
00301   }
00302   //---------------------------------------------------------------------------
00303   template <class T> T& Table<T>::add(T x)
00304   {
00305     T& new_x = create();
00306     new_x = x;
00307     return *new_x;
00308   }
00309   //---------------------------------------------------------------------------
00310   template <class T> T& Table<T>::operator() (int id)
00311   {
00312     // Check current block
00313     if ( id >= _current_block->number*DOLFIN_BLOCK_SIZE && 
00314          id < (_current_block->number+1)*DOLFIN_BLOCK_SIZE )
00315       return *_current_block->pointer(id);
00316     
00317     // Check all blocks
00318     for (Block *b = _first_block;; b = b->next){
00319       
00320       if ( id >= b->number*DOLFIN_BLOCK_SIZE && 
00321            id < (b->number+1)*DOLFIN_BLOCK_SIZE )
00322         return *b->pointer(id);
00323       
00324       if ( !b->next )
00325         break;
00326       
00327     }
00328     
00329     // No element with given id
00330     dolfin_error("No element in table with given id.");
00331     return *_current_block->data;
00332   }
00333   //---------------------------------------------------------------------------  
00334   template <class T> void Table<T>::remove(T& x)
00335   {
00336     // Check current block
00337     if ( _current_block->remove(x) ) {
00338       _size--;
00339       _empty++;
00340       return;
00341     }
00342 
00343     // Check all blocks
00344     for (Block *b = _first_block;; b = b->next)
00345       if ( b->remove(x) ) {
00346         _size--;
00347         _empty++;
00348         return;
00349       }
00350 
00351     // Couldn't find the element
00352     dolfin_error("Unable to remove element from table.");
00353   }
00354   //---------------------------------------------------------------------------  
00355   template <class T> int Table<T>::size() const
00356   {
00357     return _size;
00358   }
00359   //---------------------------------------------------------------------------  
00360   template <class T> bool Table<T>::empty() const
00361   {
00362     return _size == 0;
00363   }
00364   //---------------------------------------------------------------------------
00365   template <class T> LogStream& operator<<(LogStream& stream, const Table<T> &table)
00366   {
00367     stream << "[ Block-linked list of size " << table._size << ". ";
00368     stream << table._blocks*DOLFIN_BLOCK_SIZE << " elements allocated in " 
00369            << table._blocks << " blocks.]";
00370     
00371     return stream;
00372   }
00373   //---------------------------------------------------------------------------
00374   template <class T> typename Table<T>::Iterator Table<T>::begin() const
00375     {
00376     return Iterator(*this);
00377   }
00378   //---------------------------------------------------------------------------  
00379   template <class T> typename Table<T>::Iterator Table<T>::end() const
00380   {
00381     return Iterator();
00382   }
00383   //---------------------------------------------------------------------------
00384   template <class T> typename Table<T>::Iterator Table<T>::iterator(int id)
00385   {
00386     return Iterator(*this, id);
00387   }
00388   //---------------------------------------------------------------------------
00389   template <class T> void Table<T>::iterator_start(Iterator* it) const
00390   {
00391     // Check if the table is empty
00392     if ( _size == 0 ) {
00393       it->at_end = true;
00394       return;
00395     }
00396     
00397     // Table is not empty
00398     it->at_end = false;
00399     
00400     // Place iterator at the beginning of the table
00401     for (Block *b = _first_block; b; b = b->next) {
00402       
00403       int pos = 0;
00404       if ( (pos = b->first_pos()) != -1 ) {
00405         it->block = b;
00406         it->pos = pos;
00407         return;
00408       }
00409       
00410     }
00411     
00412     // Something strange happened
00413     dolfin_error("Unable to find first element in the table.");
00414   }
00415   //---------------------------------------------------------------------------
00416   template <class T> void Table<T>::iterator_id(Iterator* it, int id) const
00417   {
00418     it->at_end = false;
00419 
00420     // Check current block
00421     if ( id >= _current_block->number*DOLFIN_BLOCK_SIZE && 
00422          id < (_current_block->number+1)*DOLFIN_BLOCK_SIZE ) {
00423       it->block = _current_block;
00424       it->pos = _current_block->position(id);
00425       return;
00426     }
00427          
00428     // Check all blocks
00429     for (Block *b = _first_block; b; b = b->next) {
00430       
00431       if ( id >= b->number*DOLFIN_BLOCK_SIZE && 
00432            id < (b->number+1)*DOLFIN_BLOCK_SIZE ) {
00433         it->block = _current_block;
00434         it->pos = _current_block->position(id);
00435         return;
00436       }
00437       
00438     }
00439     
00440     // No element with given id
00441     dolfin_error("Unable to create iterator for given id.");
00442   }
00443   //---------------------------------------------------------------------------
00444   template <class T> void Table<T>::iterator_step(Iterator* it) const
00445   {
00446     // Check if the table is empty
00447     if ( _size == 0 ) {
00448       it->at_end = true;
00449       return;
00450     }
00451     
00452     // Step to next position
00453     int start = it->pos + 1;
00454     for (Block* b = it->block; b; b = b->next) {
00455 
00456       int pos = 0;
00457       if ( (pos = b->next_pos(start)) != -1 ) {
00458         it->block = b;
00459         it->pos = pos;
00460         return;
00461       }
00462       
00463       start = 0;
00464     }
00465                 
00466     // We have reached the end of the table
00467     it->at_end = true;
00468   }
00469   //---------------------------------------------------------------------------
00470   // Implementation of Table<T>::Iterator
00471   //---------------------------------------------------------------------------
00472   template <class T> Table<T>::Iterator::Iterator()
00473   {
00474     table = 0;
00475     
00476     block = 0;
00477     _index = -1;
00478     pos = 0;
00479     
00480     at_end = true;
00481   }
00482   //---------------------------------------------------------------------------
00483   template <class T> Table<T>::Iterator::Iterator(const Iterator& it)
00484   {
00485     table  = it.table;
00486     block  = it.block;
00487     pos    = it.pos;
00488     _index = it._index;
00489     at_end = it.at_end;    
00490   }
00491   //---------------------------------------------------------------------------
00492   template <class T> Table<T>::Iterator::Iterator(const Table<T>& table)
00493   {
00494     this->table = &table;
00495     table.iterator_start(this);
00496     _index = 0;
00497   }
00498   //---------------------------------------------------------------------------
00499   template <class T> Table<T>::Iterator::Iterator(const Table<T>& table, int id)
00500   {
00501     this->table = &table;
00502     table.iterator_id(this, id);
00503     _index = id;
00504   }
00505   //---------------------------------------------------------------------------
00506   template <class T> int Table<T>::Iterator::index() const
00507   {
00508     return _index;
00509   }
00510   //---------------------------------------------------------------------------         
00511   template <class T> typename Table<T>::Iterator& Table<T>::Iterator::operator++()
00512   {
00513     if ( table ) {
00514       table->iterator_step(this);
00515       _index++;
00516     }
00517     return *this;
00518   }
00519   //---------------------------------------------------------------------------         
00520   template <class T> bool Table<T>::Iterator::end() const
00521   {
00522     return at_end;
00523   }
00524   //---------------------------------------------------------------------------         
00525   template <class T> bool Table<T>::Iterator::last() const
00526   {
00527     return _index == (table->size() - 1);
00528   }
00529   //---------------------------------------------------------------------------         
00530   template <class T> T& Table<T>::Iterator::operator*() const
00531   {
00532     return block->data[pos];
00533   }
00534   //---------------------------------------------------------------------------         
00535   template <class T> T* Table<T>::Iterator::operator->() const
00536   {
00537     return block->data+pos;
00538   }
00539   //---------------------------------------------------------------------------         
00540   template <class T> Table<T>::Iterator::operator T*() const
00541   {
00542     return block->data+pos;
00543   }
00544   //---------------------------------------------------------------------------         
00545   template <class T> T* Table<T>::Iterator::pointer() const
00546   {
00547     return block->data+pos;
00548   }
00549   //---------------------------------------------------------------------------         
00550   template <class T> void Table<T>::Iterator::operator=(const Iterator& it)
00551   {
00552     table  = it.table;
00553     block  = it.block;
00554     pos    = it.pos;
00555     _index = it._index;
00556     at_end = it.at_end;
00557   }
00558   //---------------------------------------------------------------------------         
00559   template <class T> bool Table<T>::Iterator::operator==
00560   (const Iterator& it) const
00561   {
00562     if ( at_end && it.at_end )
00563       return true;
00564     
00565     return table == it.table && block == it.block && pos == it.pos;
00566   }
00567   //---------------------------------------------------------------------------         
00568   template <class T> bool Table<T>::Iterator::operator!=
00569   (const Iterator& it) const
00570   {
00571     return !( *this == it );
00572   }
00573   //---------------------------------------------------------------------------
00574   // Implementation of Table<T>::Block
00575   //---------------------------------------------------------------------------
00576   template <class T> Table<T>::Block::Block(Block* prev)
00577   {
00578     // Set block number
00579     if ( prev )
00580       number = prev->number + 1;
00581     else
00582       number = 0;
00583     
00584     // Link blocks
00585     if ( prev )
00586       prev->next = this;
00587     this->prev = prev;
00588     next = 0;
00589     
00590     // Allocate memory for this block
00591     if ( !(data = new T[DOLFIN_BLOCK_SIZE]) )
00592       dolfin_error("Out of memory.");
00593     if ( !(empty = new bool[DOLFIN_BLOCK_SIZE]) )
00594       dolfin_error("Out of memory.");
00595     for (int i=0;i<DOLFIN_BLOCK_SIZE;i++)
00596       empty[i] = true;
00597     pos = 0;
00598     used = 0;
00599   }
00600   //---------------------------------------------------------------------------         
00601   template <class T> Table<T>::Block::~Block()
00602   {
00603     delete [] data;
00604     delete [] empty;
00605   }
00606   //--------------------------------------------------------------------------- 
00607   template <class T> T* Table<T>::Block::pointer(int id)
00608   {
00609     id -= number*DOLFIN_BLOCK_SIZE;
00610     
00611     if ( id < 0 || id >= DOLFIN_BLOCK_SIZE )
00612       return 0;
00613     
00614     return data + id;
00615   }
00616   //--------------------------------------------------------------------------- 
00617   template <class T> int Table<T>::Block::position(int id)
00618   {
00619     return id - number*DOLFIN_BLOCK_SIZE;
00620   }
00621   //---------------------------------------------------------------------------  
00622   template <class T> bool Table<T>::Block::full()
00623   {
00624     return used == DOLFIN_BLOCK_SIZE;
00625   }
00626   //---------------------------------------------------------------------------
00627   template <class T> int Table<T>::Block::first_pos()
00628   {
00629     for (int i =0 ; i < DOLFIN_BLOCK_SIZE; i++)
00630       if ( !empty[i] )
00631         return i;
00632     
00633     return -1;
00634   }
00635   //---------------------------------------------------------------------------  
00636   template <class T> int Table<T>::Block::next_pos(int start)
00637   {
00638     for (int i = start; i < DOLFIN_BLOCK_SIZE; i++)
00639       if ( !empty[i] )
00640         return i;
00641     
00642     return -1;
00643   }
00644   //---------------------------------------------------------------------------
00645   template <class T> T& Table<T>::Block::create(int& id)
00646   {
00647     // Check if the table is full
00648     if ( used == DOLFIN_BLOCK_SIZE )
00649       dolfin_error("Block is full.");
00650     
00651     // Check if there is an empty position
00652     if ( used != pos ){
00653       for (int i = 0; i < DOLFIN_BLOCK_SIZE; i++)
00654         if ( empty[i] ){
00655           empty[i] = false;
00656           used += 1;
00657           id = number*DOLFIN_BLOCK_SIZE + i;
00658           return data[i];
00659         }
00660       dolfin_error("Unable to find an empty position.");
00661     }
00662     
00663     // Use next available position
00664     empty[pos] = false;
00665     id = number*DOLFIN_BLOCK_SIZE + pos;
00666     pos += 1;
00667     used += 1;
00668     
00669     return data[pos-1];
00670   }
00671   //---------------------------------------------------------------------------
00672   template <class T> bool Table<T>::Block::remove(T& x)
00673   {
00674     int pos = &x - data;
00675     
00676     if ( pos < 0 )
00677       return false;
00678 
00679     if ( pos >= DOLFIN_BLOCK_SIZE )
00680       return false;
00681 
00682     // Mark the position as empty
00683     empty[pos] = true;
00684     used--;
00685 
00686     return true;
00687   }
00688   //---------------------------------------------------------------------------
00689   
00690 }
00691   
00692 #endif


Documentation automatically generated with Doxygen on 10 Sep 2004.