array3d/Array3D.cxx

00001 // Copyright (C) 2001-2009 Vivien Mallet
00002 // Copyright (C) 2003-2009 Marc Duruflé
00003 //
00004 // This file is part of the linear-algebra library Seldon,
00005 // http://seldon.sourceforge.net/.
00006 //
00007 // Seldon is free software; you can redistribute it and/or modify it under the
00008 // terms of the GNU Lesser General Public License as published by the Free
00009 // Software Foundation; either version 2.1 of the License, or (at your option)
00010 // any later version.
00011 //
00012 // Seldon is distributed in the hope that it will be useful, but WITHOUT ANY
00013 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00014 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
00015 // more details.
00016 //
00017 // You should have received a copy of the GNU Lesser General Public License
00018 // along with Seldon. If not, see http://www.gnu.org/licenses/.
00019 
00020 
00021 #ifndef SELDON_FILE_ARRAY3D_CXX
00022 
00023 #include "Array3D.hxx"
00024 
00025 namespace Seldon
00026 {
00027 
00028 
00029   /****************
00030    * CONSTRUCTORS *
00031    ****************/
00032 
00033 
00035 
00038   template <class T, class Allocator>
00039   inline Array3D<T, Allocator>::Array3D()
00040   {
00041     length1_ = 0;
00042     length2_ = 0;
00043     length3_ = 0;
00044 
00045     length23_ = 0;
00046 
00047     data_ = NULL;
00048   }
00049 
00050 
00052 
00057   template <class T, class Allocator>
00058   inline Array3D<T, Allocator>::Array3D(int i, int j, int k)
00059   {
00060     length1_ = i;
00061     length2_ = j;
00062     length3_ = k;
00063 
00064     length23_ = length2_ * length3_;
00065 
00066 #ifdef SELDON_CHECK_MEMORY
00067     try
00068       {
00069 #endif
00070 
00071         data_ = array3D_allocator_.allocate(i*j*k, this);
00072 
00073 #ifdef SELDON_CHECK_MEMORY
00074       }
00075     catch (...)
00076       {
00077         length1_ = 0;
00078         length2_ = 0;
00079         length3_ = 0;
00080         length23_ = 0;
00081         data_ = NULL;
00082       }
00083     if (data_ == NULL && i != 0 && j != 0 && k != 0)
00084       throw NoMemory("Array3D::Array3D(int, int, int)",
00085                      string("Unable to allocate memory for an array of size ")
00086                      + to_str(static_cast<long int>(i)
00087                               * static_cast<long int>(j)
00088                               * static_cast<long int>(k)
00089                               * static_cast<long int>(sizeof(T)))
00090                      + " bytes (" + to_str(i) + " x " + to_str(j)
00091                      + " x " + to_str(k) + " elements).");
00092 #endif
00093 
00094   }
00095 
00096 
00098   template <class T, class Allocator>
00099   Array3D<T, Allocator>::Array3D(const Array3D<T, Allocator>& A)
00100   {
00101     length1_ = 0;
00102     length2_ = 0;
00103     length3_ = 0;
00104 
00105     length23_ = 0;
00106 
00107     data_ = NULL;
00108 
00109     Copy(A);
00110   }
00111 
00112 
00113   /**************
00114    * DESTRUCTOR *
00115    **************/
00116 
00117 
00119   template <class T, class Allocator>
00120   inline Array3D<T, Allocator>::~Array3D()
00121   {
00122     length1_ = 0;
00123     length2_ = 0;
00124     length3_ = 0;
00125     length23_ = 0;
00126 
00127 #ifdef SELDON_CHECK_MEMORY
00128     try
00129       {
00130 #endif
00131 
00132         if (data_ != NULL)
00133           {
00134             array3D_allocator_.deallocate(data_, length1_ * length23_);
00135             data_ = NULL;
00136           }
00137 
00138 #ifdef SELDON_CHECK_MEMORY
00139       }
00140     catch (...)
00141       {
00142         data_ = NULL;
00143       }
00144 #endif
00145 
00146   }
00147 
00148 
00149   /*********************
00150    * MEMORY MANAGEMENT *
00151    *********************/
00152 
00153 
00155 
00162   template <class T, class Allocator>
00163   inline void Array3D<T, Allocator>::Reallocate(int i, int j, int k)
00164   {
00165     if (i != length1_ || j != length2_ || k != length3_)
00166       {
00167         length1_ = i;
00168         length2_ = j;
00169         length3_ = k;
00170 
00171         length23_ = j * k;
00172 
00173 #ifdef SELDON_CHECK_MEMORY
00174         try
00175           {
00176 #endif
00177 
00178             data_ =
00179               reinterpret_cast<pointer>(array3D_allocator_.reallocate(data_,
00180                                                                       i*j*k,
00181                                                                       this));
00182 
00183 #ifdef SELDON_CHECK_MEMORY
00184           }
00185         catch (...)
00186           {
00187             length1_ = 0;
00188             length2_ = 0;
00189             length3_ = 0;
00190             length23_ = 0;
00191             data_ = NULL;
00192           }
00193         if (data_ == NULL && i != 0 && j != 0 && k != 0)
00194           throw NoMemory("Array3D::Reallocate(int, int, int)",
00195                          string("Unable to reallocate memory")
00196                          + " for an array of size "
00197                          + to_str(static_cast<long int>(i)
00198                                   * static_cast<long int>(j)
00199                                   * static_cast<long int>(k)
00200                                   * static_cast<long int>(sizeof(T)))
00201                          + " bytes (" + to_str(i) + " x " + to_str(j)
00202                          + " x " + to_str(k) + " elements).");
00203 #endif
00204 
00205       }
00206   }
00207 
00208 
00210 
00214   template <class T, class Allocator>
00215   inline void Array3D<T, Allocator>::Clear()
00216   {
00217     this->~Array3D();
00218     this->length1_ = 0;
00219     this->length2_ = 0;
00220     this->length3_ = 0;
00221   }
00222 
00223 
00224   /*****************
00225    * BASIC METHODS *
00226    *****************/
00227 
00228 
00230 
00233   template <class T, class Allocator>
00234   int Array3D<T, Allocator>::GetLength1() const
00235   {
00236     return length1_;
00237   }
00238 
00239 
00241 
00244   template <class T, class Allocator>
00245   int Array3D<T, Allocator>::GetLength2() const
00246   {
00247     return length2_;
00248   }
00249 
00250 
00252 
00255   template <class T, class Allocator>
00256   int Array3D<T, Allocator>::GetLength3() const
00257   {
00258     return length3_;
00259   }
00260 
00261 
00263 
00268   template <class T, class Allocator>
00269   int Array3D<T, Allocator>::GetSize() const
00270   {
00271     return length1_ * length23_;
00272   }
00273 
00274 
00276 
00282   template <class T, class Allocator>
00283   int Array3D<T, Allocator>::GetDataSize() const
00284   {
00285     return length1_ * length23_;
00286   }
00287 
00288 
00290 
00295   template <class T, class Allocator>
00296   typename Array3D<T, Allocator>::pointer Array3D<T, Allocator>
00297   ::GetData() const
00298   {
00299     return data_;
00300   }
00301 
00302 
00303   /**********************************
00304    * ELEMENT ACCESS AND AFFECTATION *
00305    **********************************/
00306 
00307 
00309 
00316   template <class T, class Allocator>
00317   inline typename Array3D<T, Allocator>::reference
00318   Array3D<T, Allocator>::operator() (int i, int j, int k)
00319   {
00320 
00321 #ifdef SELDON_CHECK_BOUNDS
00322     if (i < 0 || i >= length1_)
00323       throw WrongIndex("Array3D::operator()",
00324                        string("Index along dimension #1 should be in [0, ")
00325                        + to_str(length1_-1) + "], but is equal to "
00326                        + to_str(i) + ".");
00327     if (j < 0 || j >= length2_)
00328       throw WrongIndex("Array3D::operator()",
00329                        string("Index along dimension #2 should be in [0, ")
00330                        + to_str(length2_-1) + "], but is equal to "
00331                        + to_str(j) + ".");
00332     if (k < 0 || k >= length3_)
00333       throw WrongIndex("Array3D::operator()",
00334                        string("Index along dimension #3 should be in [0, ")
00335                        + to_str(length3_-1) + "], but is equal to "
00336                        + to_str(k) + ".");
00337 #endif
00338 
00339     return data_[i * length23_ + j * length3_ + k];
00340   }
00341 
00342 
00344 
00351   template <class T, class Allocator>
00352   inline typename Array3D<T, Allocator>::const_reference
00353   Array3D<T, Allocator>::operator() (int i, int j, int k) const
00354   {
00355 
00356 #ifdef SELDON_CHECK_BOUNDS
00357     if (i < 0 || i >= length1_)
00358       throw WrongIndex("Array3D::operator()",
00359                        string("Index along dimension #1 should be in [0, ")
00360                        + to_str(length1_-1) + "], but is equal to "
00361                        + to_str(i) + ".");
00362     if (j < 0 || j >= length2_)
00363       throw WrongIndex("Array3D::operator()",
00364                        string("Index along dimension #2 should be in [0, ")
00365                        + to_str(length2_-1) + "], but is equal to "
00366                        + to_str(j) + ".");
00367     if (k < 0 || k >= length3_)
00368       throw WrongIndex("Array3D::operator()",
00369                        string("Index along dimension #3 should be in [0, ")
00370                        + to_str(length3_-1) + "], but is equal to "
00371                        + to_str(k) + ".");
00372 #endif
00373 
00374     return data_[i*length23_ + j*length3_ + k];
00375   }
00376 
00378 
00383   template <class T, class Allocator>
00384   inline Array3D<T, Allocator>& Array3D<T, Allocator>::operator=
00385   (const Array3D<T, Allocator>& A)
00386   {
00387     Copy(A);
00388 
00389     return *this;
00390   }
00391 
00393 
00398   template <class T, class Allocator>
00399   inline void Array3D<T, Allocator>::Copy(const Array3D<T, Allocator>& A)
00400   {
00401     Reallocate(A.GetLength1(), A.GetLength2(), A.GetLength3());
00402 
00403     array3D_allocator_.memorycpy(data_, A.GetData(), GetDataSize());
00404   }
00405 
00406 
00407   /************************
00408    * CONVENIENT FUNCTIONS *
00409    ************************/
00410 
00411 
00413 
00417   template <class T, class Allocator>
00418   void Array3D<T, Allocator>::Zero()
00419   {
00420     array3D_allocator_.memoryset(data_, char(0),
00421                                  GetDataSize()*sizeof(value_type));
00422   }
00423 
00424 
00426 
00430   template <class T, class Allocator>
00431   void Array3D<T, Allocator>::Fill()
00432   {
00433     for (int i = 0; i < GetDataSize(); i++)
00434       data_[i] = i;
00435   }
00436 
00437 
00439 
00443   template <class T, class Allocator>
00444   template <class T0>
00445   void Array3D<T, Allocator>::Fill(const T0& x)
00446   {
00447     for (int i = 0; i < GetDataSize(); i++)
00448       data_[i] = x;
00449   }
00450 
00451 
00453 
00456   template <class T, class Allocator>
00457   void Array3D<T, Allocator>::FillRand()
00458   {
00459     srand(time(NULL));
00460     for (int i = 0; i < GetDataSize(); i++)
00461       data_[i] = rand();
00462   }
00463 
00464 
00466 
00469   template <class T, class Allocator>
00470   void Array3D<T, Allocator>::Print() const
00471   {
00472     int i, j, k;
00473 
00474     for (i = 0; i < GetLength1(); i++)
00475       {
00476         for (j = 0; j < GetLength2(); j++)
00477           {
00478             for (k = 0; k < GetLength3(); k++)
00479               cout << (*this)(i, j, k) << '\t';
00480             cout << endl;
00481           }
00482         cout << endl;
00483       }
00484   }
00485 
00486 
00487   /**************************
00488    * INPUT/OUTPUT FUNCTIONS *
00489    **************************/
00490 
00491 
00493 
00500   template <class T, class Allocator> void Array3D<T, Allocator>
00501   ::Write(string FileName) const
00502   {
00503     ofstream FileStream;
00504     FileStream.open(FileName.c_str(), ofstream::binary);
00505 
00506 #ifdef SELDON_CHECK_IO
00507     // Checks if the file was opened.
00508     if (!FileStream.is_open())
00509       throw IOError("Array3D::Write(string FileName)",
00510                     string("Unable to open file \"") + FileName + "\".");
00511 #endif
00512 
00513     Write(FileStream);
00514 
00515     FileStream.close();
00516   }
00517 
00518 
00520 
00527   template <class T, class Allocator> void Array3D<T, Allocator>
00528   ::Write(ofstream& FileStream) const
00529   {
00530 
00531 #ifdef SELDON_CHECK_IO
00532     // Checks if the stream is ready.
00533     if (!FileStream.good())
00534       throw IOError("Array3D::Write(ofstream& FileStream)",
00535                     "Stream is not ready.");
00536 #endif
00537 
00538     FileStream.write(reinterpret_cast<char*>(const_cast<int*>(&length1_)),
00539                      sizeof(int));
00540     FileStream.write(reinterpret_cast<char*>(const_cast<int*>(&length2_)),
00541                      sizeof(int));
00542     FileStream.write(reinterpret_cast<char*>(const_cast<int*>(&length3_)),
00543                      sizeof(int));
00544 
00545     FileStream.write(reinterpret_cast<char*>(data_),
00546                      length23_ * length1_ * sizeof(value_type));
00547 
00548 #ifdef SELDON_CHECK_IO
00549     // Checks if data was written.
00550     if (!FileStream.good())
00551       throw IOError("Array3D::Write(ofstream& FileStream)",
00552                     string("Output operation failed.")
00553                     + string("  The output file may have been removed")
00554                     + " or there is no space left on device.");
00555 #endif
00556 
00557   }
00558 
00559 
00561 
00568   template <class T, class Allocator>
00569   void Array3D<T, Allocator>::Read(string FileName)
00570   {
00571     ifstream FileStream;
00572     FileStream.open(FileName.c_str(), ifstream::binary);
00573 
00574 #ifdef SELDON_CHECK_IO
00575     // Checks if the file was opened.
00576     if (!FileStream.is_open())
00577       throw IOError("Array3D::Read(string FileName)",
00578                     string("Unable to open file \"") + FileName + "\".");
00579 #endif
00580 
00581     Read(FileStream);
00582 
00583     FileStream.close();
00584   }
00585 
00586 
00588 
00595   template <class T, class Allocator>
00596   void Array3D<T, Allocator>
00597   ::Read(ifstream& FileStream)
00598   {
00599 
00600 #ifdef SELDON_CHECK_IO
00601     // Checks if the stream is ready.
00602     if (!FileStream.good())
00603       throw IOError("Matrix_Pointers::Read(ifstream& FileStream)",
00604                     "Stream is not ready.");
00605 #endif
00606 
00607     int new_l1, new_l2, new_l3;
00608     FileStream.read(reinterpret_cast<char*>(&new_l1), sizeof(int));
00609     FileStream.read(reinterpret_cast<char*>(&new_l2), sizeof(int));
00610     FileStream.read(reinterpret_cast<char*>(&new_l3), sizeof(int));
00611     Reallocate(new_l1, new_l2, new_l3);
00612 
00613     FileStream.read(reinterpret_cast<char*>(data_),
00614                     length23_ * length1_ * sizeof(value_type));
00615 
00616 #ifdef SELDON_CHECK_IO
00617     // Checks if data was read.
00618     if (!FileStream.good())
00619       throw IOError("Array3D::Read(ifstream& FileStream)",
00620                     string("Input operation failed.")
00621                     + string(" The input file may have been removed")
00622                     + " or may not contain enough data.");
00623 #endif
00624 
00625   }
00626 
00627 
00629 
00634   template <class T, class Allocator>
00635   ostream& operator << (ostream& out,
00636                         const Array3D<T, Allocator>& A)
00637   {
00638     int i, j, k;
00639 
00640     for (i = 0; i < A.GetLength1(); i++)
00641       {
00642         for (j = 0; j < A.GetLength2(); j++)
00643           {
00644             for (k = 0; k < A.GetLength3(); k++)
00645               out << A(i, j, k) << '\t';
00646             out << endl;
00647           }
00648         out << endl;
00649       }
00650 
00651     return out;
00652   }
00653 
00654 
00656 
00660   template <class T0, class T, class Allocator>
00661   void Mlt(const T0& alpha, Array3D<T, Allocator>& A)
00662   {
00663     T* data = A.GetData();
00664     for (int i = 0; i < A.GetDataSize(); i++)
00665       data[i] *= alpha;
00666   }
00667 
00668 
00669 } // namespace Seldon.
00670 
00671 #define SELDON_FILE_ARRAY3D_CXX
00672 #endif