• Main Page
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

chomp/struct/multitab.h

Go to the documentation of this file.
00001 /// @addtogroup struct
00002 /// @{
00003 
00004 /////////////////////////////////////////////////////////////////////////////
00005 ///
00006 /// @file multitab.h
00007 ///
00008 /// This file contains the definition of the container "multitable"
00009 /// which is essentially an automatically extendable array whose memory
00010 /// is allocated in small chunks which hold the elements.
00011 ///
00012 /// @author Pawel Pilarczyk
00013 ///
00014 /////////////////////////////////////////////////////////////////////////////
00015 
00016 // Copyright (C) 1997-2013 by Pawel Pilarczyk.
00017 //
00018 // This file is part of the Homology Library.  This library is free software;
00019 // you can redistribute it and/or modify it under the terms of the GNU
00020 // General Public License as published by the Free Software Foundation;
00021 // either version 2 of the License, or (at your option) any later version.
00022 //
00023 // This library is distributed in the hope that it will be useful,
00024 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00026 // GNU General Public License for more details.
00027 //
00028 // You should have received a copy of the GNU General Public License along
00029 // with this software; see the file "license.txt".  If not, write to the
00030 // Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00031 // MA 02111-1307, USA.
00032 
00033 // Started in January 2002. Last revision: February 21, 2007.
00034 
00035 
00036 #ifndef _CHOMP_STRUCT_MULTITAB_H_
00037 #define _CHOMP_STRUCT_MULTITAB_H_
00038 
00039 #include "chomp/system/config.h"
00040 //#include "chomp/system/textfile.h"
00041 //#include "chomp/struct/integer.h"
00042 
00043 #include <algorithm>
00044 //#include <cstdlib>
00045 //#include <ctime>
00046 //#include <iostream>
00047 
00048 namespace chomp {
00049 namespace homology {
00050 
00051 
00052 // --------------------------------------------------
00053 // ------------------ multi table -------------------
00054 // --------------------------------------------------
00055 
00056 /// The default size of a piece used in the multi-table.
00057 #define DEFAULTPIECESIZE 32
00058 
00059 /// A container for elements placed in a table (like a vector)
00060 /// that is actually built of many smaller tables. This may be important
00061 /// for good memory allocation.
00062 /// The table extends automatically upon use of elements that are outside
00063 /// the range of its indices.
00064 template <class element>
00065 class multitable
00066 {
00067 public:
00068         /// The default constructor for a table with the given size
00069         /// of each piece (should be a power of 2 or is rounded up).
00070         multitable (int piecesize = 0);
00071 
00072         /// The copy constructor.
00073         multitable (const multitable<element> &m);
00074 
00075         /// The assignment operator.
00076         multitable<element> &operator = (const multitable<element> &m);
00077 
00078         /// The destructor.
00079         ~multitable ();
00080 
00081         /// Returns a reference of an element for reading/writing.
00082         /// If the index is out of range, the table is automatically
00083         /// extended.
00084         element &operator [] (int_t n);
00085 
00086         /// Returns a reference of an element for reading only.
00087         /// Throws an error message if the index is out of range.
00088         const element &operator () (int_t n) const;
00089 
00090         /// Returns a reference of an element for reading only.
00091         /// Throws an error message if the index is out of range.
00092         const element &operator [] (int_t n) const;
00093 
00094         /// Allocates the table for holding 'n' elements.
00095         /// The table is still able to grow further if necessary.
00096         void allocate (int_t n);
00097 
00098         /// Fills the table from 0 to the given index
00099         /// with the given element.
00100         void fill (const element &e, int_t n);
00101 
00102         /// Swaps data with another multitable object.
00103         void swap (multitable<element> &other);
00104 
00105 private:
00106         /// The number of pieces ready to allocate.
00107         int_t npieces;
00108 
00109         /// The number of bits to shift the index of an element
00110         /// in the table.
00111         int shiftbits;
00112 
00113         /// The mask to get the offset of an element in a table piece.
00114         int offsetmask;
00115 
00116         /// The actual tables.
00117         element **tab;
00118 
00119         /// Increases the number of pieces to the desired one.
00120         void increase (int_t n);
00121 
00122 }; /* class multitable */
00123 
00124 // --------------------------------------------------
00125 
00126 template <class element>
00127 inline multitable<element>::multitable (int piecesize)
00128 {
00129         tab = 0;
00130         npieces = 0;
00131         if (piecesize <= 0)
00132                 piecesize = DEFAULTPIECESIZE;
00133         shiftbits = 1;
00134         while ((1 << shiftbits) < piecesize)
00135                 ++ shiftbits;
00136         offsetmask = (1 << shiftbits) - 1;
00137         return;
00138 } /* multitable<element>::multitable */
00139 
00140 template <class element>
00141 multitable<element>::multitable (const multitable<element> &m):
00142         npieces (m. npieces), shiftbits (m. shiftbits),
00143         offsetmask (m. offsetmask)
00144 {
00145         int piecesize = 1 << shiftbits;
00146         tab = new element * [npieces];
00147         if (!tab)
00148                 throw "Cannot alloc mem in copying constructor of a table.";
00149         for (int_t i = 0; i < npieces; ++ i)
00150         {
00151                 if (m. tab [i])
00152                 {
00153                         tab [i] = new element [piecesize];
00154                         if (!tab [i])
00155                                 throw "No memory in copying constr.";
00156                         for (int j = 0; j < piecesize; ++ j)
00157                                 tab [i] [j] = m. tab [i] [j];
00158                 }
00159                 else
00160                 {
00161                         tab [i] = 0;
00162                 }
00163         }
00164         return;
00165 } /* multitable<element>::multitable */
00166 
00167 template <class element>
00168 multitable<element> &multitable<element>::operator =
00169         (const multitable<element> &m)
00170 {
00171         // if this is the same object then do nothing
00172         if (this == &m)
00173                 return *this;
00174 
00175         // have all the tables been deallocated?
00176         int deallocated = 0;
00177 
00178         // if the size of pieces does not match, they must be deallocated
00179         if (shiftbits != m. shiftbits)
00180         {
00181                 // deallocate all the pieces
00182                 for (int_t i = 0; i < npieces; ++ i)
00183                 {
00184                         if (tab [i])
00185                         {
00186                                 delete [] tab [i];
00187                                 tab [i] = 0;
00188                         }
00189                 }
00190                 deallocated = 1;
00191                 shiftbits = m. shiftbits;
00192                 offsetmask = m. offsetmask;
00193         }
00194 
00195         // if the number of pieces is not the same, change the table
00196         // and for the moment gather in the new table all the pieces
00197         // that are already allocated
00198         if (npieces != m. npieces)
00199         {
00200                 // allocate a new table of pieces
00201                 element **newtab = (m. npieces) ?
00202                         (new element * [m. npieces]) : 0;
00203                 if (!newtab && m. npieces)
00204                         throw "No memory for a table in operator =.";
00205 
00206                 // if there may be some not deallocated elements,
00207                 // gather them at the beginning of the table
00208                 // and set the rest of the pointers to 0s
00209                 if (!deallocated)
00210                 {
00211                         // 'i' points to the current entry in the new table,
00212                         // 'j' points to the current entry in the old table
00213                         int_t i = 0;
00214                         int_t j = 0;
00215                         while (i < m. npieces)
00216                         {
00217                                 // find an allocated piece in the old table
00218                                 while ((j < npieces) && !tab [j])
00219                                         ++ j;
00220                                 // if found, take it to the new table
00221                                 if (j < npieces)
00222                                         newtab [i ++] = tab [j ++];
00223                                 // otherwise zero the rest of the new table
00224                                 else
00225                                 {
00226                                         while (i < m. npieces)
00227                                                 newtab [i ++] = 0;
00228                                 }
00229                         }
00230                         // if there are some pieces remaining, delete them
00231                         while (j < npieces)
00232                         {
00233                                 if (tab [j])
00234                                         delete [] tab [j];
00235                                 ++ j;
00236                         }
00237                 }
00238                 else
00239                 {
00240                         for (int_t i = 0; i < m. npieces; ++ i)
00241                                 newtab [i] = 0;
00242                 }
00243 
00244                 if (tab)
00245                         delete [] tab;
00246                 tab = newtab;
00247                 npieces = m. npieces;
00248         }
00249 
00250         // if the table is empty, then finish now
00251         if (!npieces)
00252                 return *this;
00253 
00254         // copy the data from 'm' to the current table;
00255         // try to use pieces which are already allocated
00256         int_t first_nonempty = 0;
00257         int_t first_empty = 0;
00258         int_t pos = 0;
00259         int piecesize = 1 << shiftbits;
00260 
00261         // find the first nonempty piece and the first empty one
00262         while ((first_nonempty < npieces) && !tab [first_nonempty])
00263                 ++ first_nonempty;
00264         while ((first_empty < npieces) && tab [first_empty])
00265                 ++ first_empty;
00266 
00267         // copy all the pieces
00268         while (pos < npieces)
00269         {
00270                 if (m. tab [pos])
00271                 {
00272                         if (!tab [pos])
00273                         {
00274                                 if (first_nonempty < npieces)
00275                                 {
00276                                         tab [pos] = tab [first_nonempty];
00277                                         tab [first_nonempty ++] = 0;
00278                                 }
00279                                 else
00280                                 {
00281                                         tab [pos] = new element [piecesize];
00282                                         if (!tab [pos])
00283                                                 throw "Error in operator =.";
00284                                 }
00285                                 ++ first_empty;
00286                         }
00287                         else
00288                         {
00289                                 ++ first_nonempty;
00290                         }
00291 
00292                         // copy the source piece to this piece
00293                         for (int i = 0; i < piecesize; ++ i)
00294                                 tab [pos] [i] = m. tab [pos] [i];
00295                 }
00296                 else if (tab [pos])
00297                 {
00298                         if (first_empty < npieces)
00299                         {
00300                                 tab [first_empty] = tab [pos];
00301                                 ++ first_empty;
00302                         }
00303                         else
00304                                 delete [] tab [pos];
00305                         ++ first_nonempty;
00306                         tab [pos] = 0;
00307                 }
00308                 else
00309                 {
00310                         ++ first_empty;
00311                 }
00312 
00313                 // move to the next position
00314                 ++ pos;
00315 
00316                 // update pointers to the first available [non]empty piece
00317                 while ((first_nonempty < npieces) && !tab [first_nonempty])
00318                         ++ first_nonempty;
00319                 while ((first_empty < npieces) && tab [first_empty])
00320                         ++ first_empty;
00321         }
00322 
00323         return *this;
00324 } /* multitable<element>::operator = */
00325 
00326 template <class element>
00327 inline multitable<element>::~multitable ()
00328 {
00329         if (!tab)
00330                 return;
00331         for (int_t i = 0; i < npieces; ++ i)
00332         {
00333                 if (tab [i])
00334                         delete [] tab [i];
00335         }
00336         delete [] tab;
00337         return;
00338 } /* multitable<element>::~multitable */
00339 
00340 template <class element>
00341 inline element &multitable<element>::operator [] (int_t n)
00342 {
00343         if (n < 0)
00344                 throw "Negative index of an element in a table used.";
00345 
00346         // calculate the number of piece of interest
00347         int_t piece = n >> shiftbits;
00348 
00349         // increase the number of pieces if necessary
00350         if (piece >= npieces)
00351         {
00352                 int_t newnpieces = (npieces << 1) + 1;
00353                 if (newnpieces <= piece)
00354                         newnpieces = piece + 1;
00355                 increase (newnpieces);
00356         }
00357 
00358         // allocate the piece if necessary
00359         if (!tab [piece])
00360         {
00361                 tab [piece] = new element [1 << shiftbits];
00362                 if (!tab [piece])
00363                         throw "Cannot allocate a piece of a table";
00364         }
00365 
00366         return tab [piece] [n & offsetmask];
00367 } /* multitable<element>::operator [] */
00368 
00369 template <class element>
00370 inline const element &multitable<element>::operator () (int_t n) const
00371 {
00372         if (n < 0)
00373                 throw "Negative index of an element in a table used.";
00374 
00375         // calculate the number of piece of interest
00376         int_t piece = n >> shiftbits;
00377 
00378         if ((piece >= npieces) || (!tab [piece]))
00379                 throw "Non-existent table entry requested.";
00380 
00381         return tab [piece] [n & offsetmask];
00382 } /* multitable<element>::operator () */
00383 
00384 template <class element>
00385 inline const element &multitable<element>::operator [] (int_t n) const
00386 {
00387         return (*this) (n);
00388 } /* multitable<element>::operator [] const */
00389 
00390 template <class element>
00391 void multitable<element>::allocate (int_t n)
00392 {
00393         if (n <= 0)
00394                 return;
00395         int piecesize = 1 << shiftbits;
00396         int_t necessarypieces = (n + piecesize - 1) / piecesize;
00397 
00398         // allocate more pieces if needed
00399         if (necessarypieces > npieces)
00400                 increase (necessarypieces);
00401 
00402         // deallocate unnecessary pieces
00403         for (int_t i = necessarypieces; i < npieces; ++ i)
00404         {
00405                 if (tab [i])
00406                 {
00407                         delete [] tab [i];
00408                         tab [i] = 0;
00409                 }
00410         }
00411         return;
00412 } /* multitable<element>::allocate */
00413 
00414 template <class element>
00415 void multitable<element>::fill (const element &e, int_t n)
00416 {
00417         if (n <= 0)
00418                 return;
00419         int piecesize = 1 << shiftbits;
00420         int_t maxpiece = (n + piecesize - 1) / piecesize;
00421         if (maxpiece > npieces)
00422                 increase (maxpiece);
00423         for (int_t piece = 0; piece < maxpiece; ++ piece)
00424         {
00425                 if (!tab [piece])
00426                 {
00427                         tab [piece] = new element [piecesize];
00428                         if (!tab [piece])
00429                                 throw "Too little mem for a piece.";
00430 
00431                 }
00432                 if ((piece == maxpiece - 1) && (n & offsetmask))
00433                         piecesize = n & offsetmask;
00434                 for (int i = 0; i < piecesize; ++ i)
00435                         tab [piece] [i] = e;
00436         }
00437         return;
00438 } /* multitable<element>::fill */
00439 
00440 template <class element>
00441 inline void multitable<element>::swap (multitable<element> &other)
00442 {
00443         std::swap (npieces, other. npieces);
00444         std::swap (shiftbits, other. shiftbits);
00445         std::swap (offsetmask, other. offsetmask);
00446         std::swap (tab, other. tab);
00447         return;
00448 } /* multitable<element>::swap */
00449 
00450 template <class element>
00451 void multitable<element>::increase (int_t n)
00452 {
00453         // DEBUG
00454 //      if (n != 1)
00455 //              sbug << "Inc " << n << ".\n";
00456         if (n <= npieces)
00457                 throw "Trying to increase a multitable incorrectly.";
00458         element **newtab = new element * [n];
00459         if (!newtab)
00460                 throw "Cannot increase a table.";
00461         for (int_t i = 0; i < npieces; ++ i)
00462                 newtab [i] = tab [i];
00463         for (int_t i = npieces; i < n; ++ i)
00464                 newtab [i] = 0;
00465         delete [] tab;
00466         tab = newtab;
00467         npieces = n;
00468         return;
00469 } /* multitable<element>::increase */
00470 
00471 
00472 } // namespace homology
00473 } // namespace chomp
00474 
00475 #endif // _CHOMP_STRUCT_MULTITAB_H_
00476 
00477 /// @}
00478 

Generated on Sun Feb 3 2013 12:40:31 for The Uniform Expansion Software by  doxygen 1.7.2