Basic3DArray.h

00001 /*  _________________________________________________________________________
00002  *
00003  *  UTILIB: A utility library for developing portable C++ codes.
00004  *  Copyright (c) 2001, Sandia National Laboratories.
00005  *  This software is distributed under the GNU Lesser General Public License.
00006  *  For more information, see the README file in the top UTILIB directory.
00007  *  _________________________________________________________________________
00008  */
00009 
00010 //
00011 // Basic3DArray.h
00012 //
00013 // Definitions for a basic 3D array data type that manages the allocation and
00014 // deallocation of memory.  Note that 3DArrays are different from Arrays
00015 // of 2D Arrays, though they are quite similar.
00016 //
00017 // NOTE: this code is still under development!
00018 //
00019 // William Hart
00020 //
00021 
00022 
00023 #ifndef __Basic3DArray_h
00024 #define __Basic3DArray_h
00025 
00026 #ifdef __GNUC__
00027 #pragma interface
00028 #endif
00029 
00030 #ifdef NON_ANSI
00031 #include <iostream.h>
00032 #else
00033 #include <iostream>
00034 using namespace std;
00035 #endif
00036 #ifndef ANSI_HDRS
00037 #include <stdlib.h>
00038 #include <assert.h>
00039 #else
00040 #include <cassert>
00041 #include <cstdlib>
00042 #endif
00043 #include "_generic.h"
00044 #include "BasicArray.h"
00045 
00046 
00047 
00048 //
00049 // If the macro ThreeDArraySanityChecking=1 then some routine sanity checks will 
00050 // be performed when accessing vectors.  Sanity checking generally degrades 
00051 // performance.  The default is is to perform sanity checking.
00052 //
00053 // Note: Because inlines are typically put "in place" when the optimization flag
00054 // -O is used, you can define some files with ThreeDArraySanityChecking=0 to 
00055 // acheive better performance, while using the default debugging mode in the
00056 // rest of the code.
00057 // 
00058 #if !defined(ThreeDArraySanityChecking)
00059 #define ThreeDArraySanityChecking    1
00060 #endif
00061 
00062 template <class T>
00063 class UTILIB_API Basic3DArray;
00064 
00065 template <class T>
00066 class UTILIB_API Simple3DArray;
00067 
00068 template <class T>
00069 class UTILIB_API Num3DArray;
00070 
00071 //
00072 // The internal class that is used to manage the data for
00073 // Basic3DArray's and their derived classes.
00074 //
00075 // Ownership Categories
00076 //
00077 // DataNotOwned     - Data owned by some other Simple3DArray
00078 // AcquireOwnership - Data originally copied from another Simple3DArray
00079 // AssumeOwnership  - Data pointer points to another Simple3DArray's data
00080 //
00081 template <class T>
00082 class UTILIB_API   Basic3DArrayRep {
00083  
00084   friend class Basic3DArray<T>;
00085   friend class Simple3DArray<T>;
00086   friend class Num3DArray<T>;
00087 
00088 protected:
00089  
00090   Basic3DArrayRep() {ref=1; Nrows=0; Ncols=0; Data=0;}
00091   T** Data; 
00092   int ref;
00093   size_type Nrows;
00094   size_type Ncols;
00095   EnumDataOwned own_data;
00096   EnumDataOwned own_ptrs;
00097 
00098 };
00099 
00100 
00101 
00102 //
00103 // The main body of the Basic3DArray class.
00104 //
00105 template <class T>
00106 class UTILIB_API Basic3DArray
00107 {
00108 public:
00109 
00110   Basic3DArray()
00111                 {construct(0,0,0,(T*)0);}
00112   Basic3DArray(const BasicArray<T>& array, const size_type nrows=1, 
00113                 const EnumDataOwned own=DataNotOwned)
00114                 {construct(nrows,array.size()/nrows,array,own);}
00115   Basic3DArray(const size_type nrows, const size_type ncols, const size_type ndeep, T *d=((T*)0), 
00116                 const EnumDataOwned own=DataNotOwned)
00117                 {construct(nrows,ncols,ndeep,d,own);}
00118   Basic3DArray(const size_type nrows, const size_type ncols, const BasicArray<T>& array, 
00119                 const EnumDataOwned own=DataNotOwned)
00120                 {construct(nrows,ncols,array.size(),array.data(),own);}
00121   Basic3DArray(const Basic3DArray& array)
00122                 {construct(array.nrows(),array.ncols(),array.array.data(),
00123                                 AcquireOwnership);}
00124 
00125   virtual ~Basic3DArray()
00126         {free();}
00127 
00128   int resize(const size_type nrows, const size_type ncols);
00129   size_type nrows() const
00130         {return a->Nrows;}
00131   size_type ncols() const
00132         {return a->Ncols;}
00133   operator T** () const
00134         {return a->Data;}
00135   T** data() const
00136         {return a->Data;}
00137   int nrefs() const
00138         {return a->ref;}
00139   T* operator[](const size_type );
00140   const T* operator[](const size_type ) const;
00141   T& operator()(const size_type row, const size_type col);
00142   const T& operator()(const size_type row, const size_type col) const;
00143 
00144   Basic3DArray<T>& operator=(const Basic3DArray<T>& array); // construct & copy
00145   Basic3DArray<T>& operator&=(const Basic3DArray<T>& array);// copy ptr
00146   Basic3DArray<T>& operator<<(const Basic3DArray<T>& array);// copy 3Darray
00147   Basic3DArray<T>& operator=(const T& val);             // 3Darray set to val
00148   Basic3DArray<T>& operator=(const BasicArray<T>& val); // rows set to val
00149 
00150   Basic3DArray<T>& set_data(const size_type len, T* data,
00151                                 const EnumDataOwned o=DataNotOwned);
00152   Basic3DArray<T>& set_data(const BasicArray<T>& array,
00153                                 const EnumDataOwned o=DataNotOwned)
00154                 {return set_data(array.size(),array,o);}
00155 
00156 /* BUG? Where are these defined?
00157   friend Basic3DArray<T> T(const BasicArray<T>& array);
00158   friend Basic3DArray<T> T(const Basic3DArray<T>& array);
00159 */
00160 
00161 protected:
00162 
00163   Basic3DArrayRep<T>* a;
00164 
00165   void construct(const size_type nrows, const size_type ncols, const size_type ndeep, T *d, 
00166                 const EnumDataOwned o=DataNotOwned);
00167   void construct(const size_type nrows, const size_type ncols, const size_type ndeep, T** d, 
00168                 const EnumDataOwned o=DataNotOwned);
00169   void free();
00170 
00171 };
00172 
00173 
00174 template <class T>
00175 inline T* Basic3DArray<T>::operator[](const size_type idx)
00176 {
00177 #if (ThreeDArraySanityChecking==1)
00178 if ((idx < 0) || (idx >= a->Nrows))
00179    ErrAbort(errmsg("Basic3DArray<T>::operator[] : iterator out of range. idx=%d len=%d",idx,a->Nrows));
00180 #endif
00181  
00182 return a->Data[idx];
00183 }
00184  
00185  
00186 template <class T>
00187 inline const T* Basic3DArray<T>::operator[](const size_type idx) const
00188 {
00189 #if (ThreeDArraySanityChecking==1)
00190 if ((idx < 0) || (idx >= a->Nrows))
00191    ErrAbort(errmsg("Basic3DArray<T>::operator[] : iterator out of range. idx=%d len=%d",idx,a->Nrows));
00192 #endif
00193  
00194 return a->Data[idx];
00195 }
00196 
00197 
00198 template <class T>
00199 inline T& Basic3DArray<T>::operator()(const size_type row, const size_type col)
00200 {
00201 #if (ThreeDArraySanityChecking==1)
00202 if ((row < 0) || (row >= a->Nrows) || (col < 0) || (col >= a->Ncols))
00203    ErrAbort(errmsg("Basic3DArray<T>::operator() : iterator out of range. %dx%d not in %dx%d",row,col,a->Nrows,a->Ncols));
00204 #endif
00205  
00206 return a->Data[row][col];
00207 }
00208  
00209  
00210 template <class T>
00211 inline const T& Basic3DArray<T>::operator()(const size_type row, const size_type col) const
00212 {
00213 #if (ThreeDArraySanityChecking==1)
00214 if ((row < 0) || (row >= a->Nrows) || (col < 0) || (col >= a->Ncols))
00215    ErrAbort(errmsg("Basic3DArray<T>::operator() : iterator out of range. %dx%d not in %dx%d",row,col,a->Nrows,a->Ncols));
00216 #endif
00217  
00218 return a->Data[row][col];
00219 }
00220 
00221 
00222 
00223 
00224 //
00225 // Basic3DArray
00226 //
00227 
00228 
00229 template <class T>
00230 void Basic3DArray<T>::construct(const size_type nrows, const size_type ncols, 
00231                         const size_type ndeep, T * d, const EnumDataOwned o)
00232 {
00233 a = new Basic3DArrayRep<T>;
00234 assert(a != 0);
00235 
00236 a->Nrows = nrows;
00237 a->Ncols = ncols;
00238 a->Ndeep = ndeep;
00239 if (d == NULL) {
00240    if (nrows > 0) {
00241       a->Data = new T** [nrows] ;
00242       assert(a != 0);
00243       for (size_type i=0; i<nrows; i++) {
00244          a->Data[i] = new T* [ncols] ;
00245          for (size_type j=0; j<ncols; j++) {
00246            a->Data[i][j] = new T [ndeep] ;
00247            assert(a->Data[i][j] != 0);
00248            }
00249          assert(a->Data[i] != 0);
00250          }
00251       }
00252    else
00253       a->Data = NULL;
00254    a->own_ptrs = AcquireOwnership;
00255    a->own_data = AcquireOwnership;
00256    }
00257 
00258 else {
00259    if (o == AcquireOwnership) {
00260       if (nrows > 0)  {
00261          a->Data = new T** [nrows] ;
00262          assert(a != 0);
00263          for (size_type i=0; i<nrows; i++) {
00264             a->Data[i] = new T* [ncols] ;
00265             for (size_type j=0; j<ncols; j++) {
00266               a->Data[i][j] = new T [ndeep] ;
00267               assert(a->Data[i][j] != 0);
00268               }
00269             assert(a->Data[i] != 0);
00270             }
00271 
00272          size_type ndx=0;
00273          for (size_type ii=0; ii<nrows; ii++)
00274            for (size_type jj=0; jj<ncols; jj++)
00275              for (size_type kk=0; kk<ndeep; kk++)
00276                a->Data[ii][jj][kk] = d[ndx++];
00277          }
00278       else
00279          a->Data = NULL;
00280       a->own_ptrs = AcquireOwnership;
00281       a->own_data = AcquireOwnership;
00282       }
00283    else {
00284       if (nrows > 0)  {
00285          a->Data = new T** [nrows] ;
00286          assert(a->Data != 0);
00287          for (size_type i=0; i<nrows; i++) {
00288             a->Data[i] = new T* [ncols] ;
00289             assert(a->Data[i] != 0);
00290             }
00291          T* tmp = d;
00292          for (size_type i=0; i<ncols; i++) {
00293             a->Data[i] = tmp;
00294             tmp+= ncols;
00295             }
00296          }
00297       else
00298          a->Data = NULL;
00299       a->own_ptrs = AcquireOwnership;
00300       a->own_data = DataNotOwned;
00301       }
00302    }
00303 }
00304 
00305 
00306 template <class T>
00307 void Basic3DArray<T>::construct(const size_type nrows, const size_type ncols, const size_type ndeep, T **d, 
00308                                         const EnumDataOwned o)
00309 {
00310 a = new Basic3DArrayRep<T>;
00311 assert(a != 0);
00312 
00313 a->Nrows = nrows;
00314 a->Ncols = ncols;
00315 if (d == NULL) {
00316    if (nrows > 0) {
00317       a->Data = new T** [nrows] ;
00318       assert(a != 0);
00319       for (size_type i=0; i<nrows; i++) {
00320          a->Data[i] = new T* [ncols] ;
00321          for (size_type j=0; j<ncols; j++) {
00322            a->Data[i][j] = new T [ndeep] ;
00323            assert(a->Data[i][j] != 0);
00324            }
00325          assert(a->Data[i] != 0);
00326          }
00327       }
00328    else
00329       a->Data = NULL;
00330    a->own_ptrs = AcquireOwnership;
00331    a->own_data = AcquireOwnership;
00332    }
00333 
00334 else {
00335    if (o == AcquireOwnership) {
00336       if (nrows > 0)  {
00337          a->Data = new T** [nrows] ;
00338          assert(a->Data != 0);
00339          for (size_type i=0; i<nrows; i++) {
00340             a->Data[i] = new T* [ncols] ;
00341             for (size_type j=0; j<ncols; j++) {
00342               a->Data[i][j] = new T [ndeep] ;
00343               assert(a->Data[i][j] != 0);
00344               }
00345             assert(a->Data[i] != 0);
00346             }
00347 
00348          for (size_type ii=0; ii<nrows; ii++)
00349            for (size_type jj=0; jj<ncols; jj++)
00350              a->Data[ii][jj] = d[ii][jj];
00351          }
00352       else
00353          a->Data = NULL;
00354       a->own_ptrs = AcquireOwnership;
00355       a->own_data = AcquireOwnership;
00356       }
00357    else {
00358       a->Data=d;
00359       a->own_ptrs = DataNotOwned;
00360       a->own_data = DataNotOwned;
00361       }
00362    }
00363 }
00364 
00365 
00366 template <class T>
00367 void Basic3DArray<T>::free()
00368 {
00369 if (--a->ref == 0) {
00370    if ((a->Data) && (a->Nrows>0)) {
00371       if (a->own_data && (a->Ncols > 0)) {
00372          for (size_type i=0; i<a->Nrows; i++) {
00373            for (size_type j=0; j<a->Ncols; j++)
00374              if (a->Ndeep > 0) delete [] a->Data[i][j];
00375            delete [] a->Data[i];
00376            }
00377          }
00378       if (a->own_ptrs)
00379          delete [] a->Data;
00380       }
00381    delete a;
00382    }
00383 }
00384 
00385 
00386 template <class T>
00387 int Basic3DArray<T>::resize(const size_type nrows, const size_type ncols)
00388 {
00389 //
00390 // Maybe we get lucky.
00391 //
00392 if ((ncols == a->Ncols) && (nrows == a->Nrows) && (ndeep == a->Ndeep))
00393    return OK;
00394 
00395 //
00396 // Need to completely replace old data.
00397 //
00398 if ((ncols != a->Ncols) && (nrows != a->Nrows) && (ndeep != a->Ndeep)) {
00399    //
00400    // Delete old data (if owned)
00401    //
00402    if ((a->Data) && (a->Nrows>0)) {
00403       if (a->own_data && (a->Ncols > 0)) {
00404          for (size_type i=0; i<a->Nrows; i++) {
00405            for (size_type j=0; j<a->Ncols; j++)
00406              if (a->Ndeep > 0) delete [] a->Data[i][j];
00407            delete [] a->Data[i];
00408            }
00409          }
00410       if (a->own_ptrs)
00411          delete [] a->Data;
00412       }
00413    //
00414    // Make new data
00415    //
00416    if (nrows > 0) {
00417       a->Data = new T** [nrows] ;
00418       assert(a != 0);
00419       for (size_type i=0; i<nrows; i++) {
00420          a->Data[i] = new T* [ncols] ;
00421          for (size_type j=0; j<ncols; j++) {
00422            a->Data[i][j] = new T [ndeep] ;
00423            assert(a->Data[i][j] != 0);
00424            }
00425          assert(a->Data[i] != 0);
00426          }
00427       }
00428    else
00429       a->Data = NULL;
00430    a->own_ptrs = AcquireOwnership;
00431    a->own_data = AcquireOwnership;
00432    a->Nrows = nrows;
00433    a->Ncols = ncols;
00434    a->Ndeep = ndeep;
00435    return OK;
00436    }
00437 
00438 //
00439 // We need to simply resize the number of rows.
00440 //
00441 if (nrows != a->Nrows) {
00442    T **d=NULL;
00443    if (nrows > 0) {
00444       d = new T* [nrows];
00445       assert(d != 0);
00446       // 
00447       // Note:  the new memory is not initialized beyond what the constructors
00448       // do.
00449       //
00450       if (a->Nrows > 0) {
00451          for (size_type i=0; i<MIN(nrows,a->Nrows); i++)
00452            d[i] = a->Data[i];
00453          }
00454       }
00455  
00456    if (a->Data && a->own_ptrs && (a->Nrows > 0))
00457       delete [] a->Data;
00458  
00459    a->Data = d;
00460    a->Nrows = nrows;
00461    }
00462 
00463 //
00464 // We need to simply resize the number of columns
00465 //
00466 if (ncols != a->Ncols) {
00467    if (ncols > 0) {
00468       for (size_type j=0; j<a->Nrows; j++) {
00469         T* d=NULL;
00470         d = new T [ncols];
00471         assert(d != 0);
00472         // 
00473         // Note:  the new memory is not initialized beyond what the constructors
00474         // do.
00475         //
00476         if (a->Ncols > 0) {
00477            for (size_type i=0; i<MIN(ncols,a->Ncols); i++)
00478              d[i] = a->Data[j][i];
00479            }
00480         if (a->Data && a->own_data && (a->Ncols > 0))
00481            delete [] a->Data[j];
00482         a->Data[j] = d;
00483         }
00484       }
00485    else 
00486       if (a->Data && a->own_data && (a->Ncols > 0))
00487          for (size_type i=0; i<a->Nrows; i++) {
00488            delete [] a->Data[i];
00489            a->Data[i] = NULL;
00490            }
00491  
00492    a->Ncols = ncols;
00493    }
00494 
00495 return OK;
00496 }
00497 
00498 
00499 template <class T>
00500 Basic3DArray<T>& Basic3DArray<T>::operator=(const Basic3DArray<T>& array)
00501 {
00502 //ErrAbort("Basic3DArray<T>::operator= : has been temporarily disabled during the transition to the new vector classes.");
00503 
00504 if (this != &array) {
00505    free();
00506    construct(array.nrows(),array.ncols(),array.data(),AcquireOwnership);
00507    }
00508 return *this;
00509 }
00510 
00511 
00512 template <class T>
00513 Basic3DArray<T>& Basic3DArray<T>::operator<<(const Basic3DArray<T>& array)
00514 {
00515 if (array.a == a)
00516    return *this;
00517 if ((array.a->Nrows != a->Nrows) || (array.a->Ncols != a->Ncols))
00518    ErrAbort(errmsg("Basic3DArray<T>::operator<< : Unequal vector matrices %dx%d and %dx%d.",a->Nrows,a->Ncols,array.a->Nrows,array.a->Ncols));
00519  
00520 for (size_type i=0; i<a->Nrows; i++)
00521   for (size_type j=0; j<a->Ncols; j++)
00522     a->Data[i][j] = array.a->Data[i][j];
00523  
00524 return *this;
00525 }
00526 
00527 
00528 
00529 template <class T>
00530 Basic3DArray<T>& Basic3DArray<T>::operator&=(const Basic3DArray<T>& array)
00531 {
00532 if (array.a == a) return *this;
00533 
00534 free();
00535 a = array.a;
00536 a->ref++;
00537 return *this;
00538 }
00539 
00540 
00541 
00542 template <class T>
00543 Basic3DArray<T>& Basic3DArray<T>::operator=(const T& val)
00544 {
00545 for (size_type i=0; i<a->Nrows; i++)
00546   for (size_type j=0; j<a->Ncols; j++)
00547     a->Data[i][j] = ( T ) val;
00548 return *this;
00549 }
00550 
00551 
00552 
00553 template <class T>
00554 Basic3DArray<T>& Basic3DArray<T>::operator=(const BasicArray<T>& val)
00555 {
00556 if (a->Ncols != val.size())
00557    ErrAbort(errmsg("Basic3DArray<T>::operator= : Array length does not equal the 3DArray columns %d and %d",val.size(),a->Ncols));
00558 
00559 for (size_type i=0; i<a->Nrows; i++)
00560   for (size_type j=0; j<a->Ncols; j++)
00561     a->Data[i][j] = val[j];
00562 return *this;
00563 }
00564 
00565 template <class T>
00566 Basic3DArray<T>& Basic3DArray<T>::set_data(const size_type len, T * data, const EnumDataOwned o)
00567 {
00568 #if TwoDArraySanityChecking==1
00569 if ( (nrows()*ncols()) != len)
00570    ErrAbort(errmsg("Basic3DArray<T>::set_data : bad vector size %d != %d.",
00571                         (nrows()*ncols()),len));
00572 #endif
00573 
00574 if (a->own_data && (a->Ncols > 0)) {
00575    for (size_type i=0; i<a->Nrows; i++)
00576      delete [] a->Data[i];
00577    }
00578 size_type ndx=0;
00579 for (size_type i=0; i<a->Nrows; i++) {
00580   a->Data[i] = &(data[ndx]);
00581   ndx += a->Ncols;
00582   }
00583 
00584 //
00585 // BUG: I need to fix the model of ownership here.
00586 //
00587 a->own_data = DataNotOwned;
00588 return *this;
00589 }
00590 
00591 #endif