multitab.h

Go to the documentation of this file.
00001 
00002 
00003 
00015 
00016 // Copyright (C) 1997-2010 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 <cstdlib>
00044 //#include <ctime>
00045 //#include <iostream>
00046 
00047 namespace chomp {
00048 namespace homology {
00049 
00050 
00051 // --------------------------------------------------
00052 // ------------------- swap data --------------------
00053 // --------------------------------------------------
00054 
00055 template <typename T>
00056 inline void my_swap (T &x, T &y)
00057 {
00058         T tmp = x;
00059         x = y;
00060         y = tmp;
00061         return;
00062 } /* my_swap */
00063 
00064 
00065 // --------------------------------------------------
00066 // ------------------ multi table -------------------
00067 // --------------------------------------------------
00068 
00070 #define DEFAULTPIECESIZE 32
00071 
00077 template <class element>
00078 class multitable
00079 {
00080 public:
00083         multitable (int piecesize = 0);
00084 
00086         multitable (const multitable<element> &m);
00087 
00089         multitable<element> &operator = (const multitable<element> &m);
00090 
00092         ~multitable ();
00093 
00097         element &operator [] (int_t n);
00098 
00101         const element &operator () (int_t n) const;
00102 
00105         const element &operator [] (int_t n) const;
00106 
00109         void allocate (int_t n);
00110 
00113         void fill (const element &e, int_t n);
00114 
00116         void swap (multitable<element> &other);
00117 
00118 private:
00120         int_t npieces;
00121 
00124         int shiftbits;
00125 
00127         int offsetmask;
00128 
00130         element **tab;
00131 
00133         void increase (int_t n);
00134 
00135 }; /* class multitable */
00136 
00137 // --------------------------------------------------
00138 
00139 template <class element>
00140 inline multitable<element>::multitable (int piecesize)
00141 {
00142         tab = 0;
00143         npieces = 0;
00144         if (piecesize <= 0)
00145                 piecesize = DEFAULTPIECESIZE;
00146         shiftbits = 1;
00147         while ((1 << shiftbits) < piecesize)
00148                 ++ shiftbits;
00149         offsetmask = (1 << shiftbits) - 1;
00150         return;
00151 } /* multitable<element>::multitable */
00152 
00153 template <class element>
00154 multitable<element>::multitable (const multitable<element> &m):
00155         npieces (m. npieces), shiftbits (m. shiftbits),
00156         offsetmask (m. offsetmask)
00157 {
00158         int piecesize = 1 << shiftbits;
00159         tab = new element * [npieces];
00160         if (!tab)
00161                 throw "Cannot alloc mem in copying constructor of a table.";
00162         for (int_t i = 0; i < npieces; ++ i)
00163         {
00164                 if (m. tab [i])
00165                 {
00166                         tab [i] = new element [piecesize];
00167                         if (!tab [i])
00168                                 throw "No memory in copying constr.";
00169                         for (int j = 0; j < piecesize; ++ j)
00170                                 tab [i] [j] = m. tab [i] [j];
00171                 }
00172                 else
00173                 {
00174                         tab [i] = 0;
00175                 }
00176         }
00177         return;
00178 } /* multitable<element>::multitable */
00179 
00180 template <class element>
00181 multitable<element> &multitable<element>::operator =
00182         (const multitable<element> &m)
00183 {
00184         // if this is the same object then do nothing
00185         if (this == &m)
00186                 return *this;
00187 
00188         // have all the tables been deallocated?
00189         int deallocated = 0;
00190 
00191         // if the size of pieces does not match, they must be deallocated
00192         if (shiftbits != m. shiftbits)
00193         {
00194                 // deallocate all the pieces
00195                 for (int_t i = 0; i < npieces; ++ i)
00196                 {
00197                         if (tab [i])
00198                         {
00199                                 delete [] tab [i];
00200                                 tab [i] = 0;
00201                         }
00202                 }
00203                 deallocated = 1;
00204                 shiftbits = m. shiftbits;
00205                 offsetmask = m. offsetmask;
00206         }
00207 
00208         // if the number of pieces is not the same, change the table
00209         // and for the moment gather in the new table all the pieces
00210         // that are already allocated
00211         if (npieces != m. npieces)
00212         {
00213                 // allocate a new table of pieces
00214                 element **newtab = (m. npieces) ?
00215                         (new element * [m. npieces]) : 0;
00216                 if (!newtab && m. npieces)
00217                         throw "No memory for a table in operator =.";
00218 
00219                 // if there may be some not deallocated elements,
00220                 // gather them at the beginning of the table
00221                 // and set the rest of the pointers to 0s
00222                 if (!deallocated)
00223                 {
00224                         // 'i' points to the current entry in the new table,
00225                         // 'j' points to the current entry in the old table
00226                         int_t i = 0;
00227                         int_t j = 0;
00228                         while (i < m. npieces)
00229                         {
00230                                 // find an allocated piece in the old table
00231                                 while ((j < npieces) && !tab [j])
00232                                         ++ j;
00233                                 // if found, take it to the new table
00234                                 if (j < npieces)
00235                                         newtab [i ++] = tab [j ++];
00236                                 // otherwise zero the rest of the new table
00237                                 else
00238                                 {
00239                                         while (i < m. npieces)
00240                                                 newtab [i ++] = 0;
00241                                 }
00242                         }
00243                         // if there are some pieces remaining, delete them
00244                         while (j < npieces)
00245                         {
00246                                 if (tab [j])
00247                                         delete [] tab [j];
00248                                 ++ j;
00249                         }
00250                 }
00251                 else
00252                 {
00253                         for (int_t i = 0; i < m. npieces; ++ i)
00254                                 newtab [i] = 0;
00255                 }
00256 
00257                 if (tab)
00258                         delete [] tab;
00259                 tab = newtab;
00260                 npieces = m. npieces;
00261         }
00262 
00263         // if the table is empty, then finish now
00264         if (!npieces)
00265                 return *this;
00266 
00267         // copy the data from 'm' to the current table;
00268         // try to use pieces which are already allocated
00269         int_t first_nonempty = 0;
00270         int_t first_empty = 0;
00271         int_t pos = 0;
00272         int piecesize = 1 << shiftbits;
00273 
00274         // find the first nonempty piece and the first empty one
00275         while ((first_nonempty < npieces) && !tab [first_nonempty])
00276                 ++ first_nonempty;
00277         while ((first_empty < npieces) && tab [first_empty])
00278                 ++ first_empty;
00279 
00280         // copy all the pieces
00281         while (pos < npieces)
00282         {
00283                 if (m. tab [pos])
00284                 {
00285                         if (!tab [pos])
00286                         {
00287                                 if (first_nonempty < npieces)
00288                                 {
00289                                         tab [pos] = tab [first_nonempty];
00290                                         tab [first_nonempty ++] = 0;
00291                                 }
00292                                 else
00293                                 {
00294                                         tab [pos] = new element [piecesize];
00295                                         if (!tab [pos])
00296                                                 throw "Error in operator =.";
00297                                 }
00298                                 ++ first_empty;
00299                         }
00300                         else
00301                         {
00302                                 ++ first_nonempty;
00303                         }
00304 
00305                         // copy the source piece to this piece
00306                         for (int i = 0; i < piecesize; ++ i)
00307                                 tab [pos] [i] = m. tab [pos] [i];
00308                 }
00309                 else if (tab [pos])
00310                 {
00311                         if (first_empty < npieces)
00312                         {
00313                                 tab [first_empty] = tab [pos];
00314                                 ++ first_empty;
00315                         }
00316                         else
00317                                 delete [] tab [pos];
00318                         ++ first_nonempty;
00319                         tab [pos] = 0;
00320                 }
00321                 else
00322                 {
00323                         ++ first_empty;
00324                 }
00325 
00326                 // move to the next position
00327                 ++ pos;
00328 
00329                 // update pointers to the first available [non]empty piece
00330                 while ((first_nonempty < npieces) && !tab [first_nonempty])
00331                         ++ first_nonempty;
00332                 while ((first_empty < npieces) && tab [first_empty])
00333                         ++ first_empty;
00334         }
00335 
00336         return *this;
00337 } /* multitable<element>::operator = */
00338 
00339 template <class element>
00340 inline multitable<element>::~multitable ()
00341 {
00342         if (!tab)
00343                 return;
00344         for (int_t i = 0; i < npieces; ++ i)
00345         {
00346                 if (tab [i])
00347                         delete [] tab [i];
00348         }
00349         delete [] tab;
00350         return;
00351 } /* multitable<element>::~multitable */
00352 
00353 template <class element>
00354 inline element &multitable<element>::operator [] (int_t n)
00355 {
00356         if (n < 0)
00357                 throw "Negative index of an element in a table used.";
00358 
00359         // calculate the number of piece of interest
00360         int_t piece = n >> shiftbits;
00361 
00362         // increase the number of pieces if necessary
00363         if (piece >= npieces)
00364         {
00365                 int_t newnpieces = (npieces << 1) + 1;
00366                 if (newnpieces <= piece)
00367                         newnpieces = piece + 1;
00368                 increase (newnpieces);
00369         }
00370 
00371         // allocate the piece if necessary
00372         if (!tab [piece])
00373         {
00374                 tab [piece] = new element [1 << shiftbits];
00375                 if (!tab [piece])
00376                         throw "Cannot allocate a piece of a table";
00377         }
00378 
00379         return tab [piece] [n & offsetmask];
00380 } /* multitable<element>::operator [] */
00381 
00382 template <class element>
00383 inline const element &multitable<element>::operator () (int_t n) const
00384 {
00385         if (n < 0)
00386                 throw "Negative index of an element in a table used.";
00387 
00388         // calculate the number of piece of interest
00389         int_t piece = n >> shiftbits;
00390 
00391         if ((piece >= npieces) || (!tab [piece]))
00392                 throw "Non-existent table entry requested.";
00393 
00394         return tab [piece] [n & offsetmask];
00395 } /* multitable<element>::operator () */
00396 
00397 template <class element>
00398 inline const element &multitable<element>::operator [] (int_t n) const
00399 {
00400         return (*this) (n);
00401 } /* multitable<element>::operator [] const */
00402 
00403 template <class element>
00404 void multitable<element>::allocate (int_t n)
00405 {
00406         if (n <= 0)
00407                 return;
00408         int piecesize = 1 << shiftbits;
00409         int_t necessarypieces = (n + piecesize - 1) / piecesize;
00410 
00411         // allocate more pieces if needed
00412         if (necessarypieces > npieces)
00413                 increase (necessarypieces);
00414 
00415         // deallocate unnecessary pieces
00416         for (int_t i = necessarypieces; i < npieces; ++ i)
00417         {
00418                 if (tab [i])
00419                 {
00420                         delete [] tab [i];
00421                         tab [i] = 0;
00422                 }
00423         }
00424         return;
00425 } /* multitable<element>::allocate */
00426 
00427 template <class element>
00428 void multitable<element>::fill (const element &e, int_t n)
00429 {
00430         if (n <= 0)
00431                 return;
00432         int piecesize = 1 << shiftbits;
00433         int_t maxpiece = (n + piecesize - 1) / piecesize;
00434         if (maxpiece > npieces)
00435                 increase (maxpiece);
00436         for (int_t piece = 0; piece < maxpiece; ++ piece)
00437         {
00438                 if (!tab [piece])
00439                 {
00440                         tab [piece] = new element [piecesize];
00441                         if (!tab [piece])
00442                                 throw "Too little mem for a piece.";
00443 
00444                 }
00445                 if ((piece == maxpiece - 1) && (n & offsetmask))
00446                         piecesize = n & offsetmask;
00447                 for (int i = 0; i < piecesize; ++ i)
00448                         tab [piece] [i] = e;
00449         }
00450         return;
00451 } /* multitable<element>::fill */
00452 
00453 template <class element>
00454 inline void multitable<element>::swap (multitable<element> &other)
00455 {
00456         my_swap (npieces, other. npieces);
00457         my_swap (shiftbits, other. shiftbits);
00458         my_swap (offsetmask, other. offsetmask);
00459         my_swap (tab, other. tab);
00460         return;
00461 } /* multitable<element>::swap */
00462 
00463 template <class element>
00464 void multitable<element>::increase (int_t n)
00465 {
00466         // DEBUG
00467 //      if (n != 1)
00468 //              sbug << "Inc " << n << ".\n";
00469         if (n <= npieces)
00470                 throw "Trying to increase a multitable incorrectly.";
00471         element **newtab = new element * [n];
00472         if (!newtab)
00473                 throw "Cannot increase a table.";
00474         for (int_t i = 0; i < npieces; ++ i)
00475                 newtab [i] = tab [i];
00476         for (int_t i = npieces; i < n; ++ i)
00477                 newtab [i] = 0;
00478         delete [] tab;
00479         tab = newtab;
00480         npieces = n;
00481         return;
00482 } /* multitable<element>::increase */
00483 
00484 
00485 } // namespace homology
00486 } // namespace chomp
00487 
00488 #endif // _CHOMP_STRUCT_MULTITAB_H_
00489 
00491