array3D.h

Go to the documentation of this file.
00001 
00015 #ifndef _DLR_ARRAY3D_H_
00016 #define _DLR_ARRAY3D_H_
00017 
00018 #include <iostream>
00019 #include <dlrNumeric/array1D.h>
00020 #include <dlrNumeric/array2D.h>
00021 #include <dlrCommon/exception.h>
00022 
00023 namespace dlr {
00024 
00025   namespace numeric {
00026     
00049     template <class Type>
00050     class Array3D {
00051     public:
00052       /* ******** Public typedefs ******** */
00053 
00057       typedef Type value_type;
00058 
00062       typedef Type* iterator;
00063     
00068       typedef const Type* const_iterator;
00069 
00070       /* ******** Public member functions ******** */
00071 
00075       Array3D();
00076 
00094       Array3D(size_t shape0, size_t shape1, size_t shape2);
00095 
00111       explicit
00112       Array3D(const std::string& inputString);
00113 
00120       Array3D(const Array3D<Type> &source);
00121 
00138       Array3D(size_t shape0, size_t shape1, size_t shape2, Type* const dataPtr);
00139 
00144       virtual
00145       ~Array3D();
00146 
00152       iterator
00153       begin() {return m_dataPtr;}
00154 
00161       const_iterator
00162       begin() const {return m_dataPtr;}
00163 
00168       void
00169       clear() {this->reinit(0, 0, 0);}
00170 
00171 
00183       inline void 
00184       checkDimension(size_t shape0, size_t shape1, size_t shape2) const;
00185 
00186 
00192       Array3D<Type>
00193       copy() const;
00194 
00203       template <class Type2>
00204       void
00205       copy(const Array3D<Type2>& source);
00206 
00213       template <class Type2>
00214       void
00215       copy(const Type2* dataPtr);
00216 
00226       Type*
00227       data() {return m_dataPtr;}
00228 
00235       const Type*
00236       data() const {return m_dataPtr;}
00237 
00247       Type*
00248       data(size_t index) {
00249         checkBounds(index);
00250         return m_dataPtr + index;
00251       }
00252 
00261       const Type*
00262       data(size_t index) const {
00263         checkBounds(index);
00264         return m_dataPtr+index;
00265       }
00266 
00276       Type*
00277       data(size_t index0, size_t index1, size_t index2) {
00278         checkBounds(index0, index1, index2);
00279         return (m_dataPtr + index2 + (index1 * m_shape2)
00280                 + (index0 * m_shape1Times2));
00281       }
00282 
00292       const Type*
00293       data(size_t index0, size_t index1, size_t index2) const {
00294         checkBounds(index0, index1, index2);
00295         return (m_dataPtr + index2 + (index1 * m_shape2)
00296                 + (index0 * m_shape1Times2));
00297       }
00298 
00299 
00307       bool
00308       empty() const {return this->size() == 0;}
00309 
00310     
00317       iterator
00318       end() {return m_dataPtr + m_size;}
00319 
00326       const_iterator
00327       end() const {return m_dataPtr + m_size;}
00328 
00340       std::istream&
00341       readFromStream(std::istream& inputStream);
00342     
00352       void
00353       reinit(size_t shape0, size_t shape1, size_t shape2);
00354 
00366       void
00367       reshape(int shape0, int shape1, int shape2);
00368 
00377       Array1D<size_t>
00378       shape() const;
00379 
00388       size_t
00389       shape(size_t axis) const;
00390 
00397       size_t
00398       shape0() const {return m_shape0;}
00399 
00406       size_t
00407       shape1() const {return m_shape1;}
00408 
00415       size_t
00416       shape2() const {return m_shape2;}
00417 
00424       size_t
00425       size() const {return m_size;}
00426   
00435       Array2D<Type>
00436       slice(size_t index);
00437 
00446       const Array2D<Type>
00447       slice(size_t index) const;
00448 
00456       Array3D<Type>&
00457       operator=(const Array3D<Type>& source);
00458 
00465       Array3D<Type>&
00466       operator=(Type value);
00467 
00475       Type&
00476       operator()(size_t index) {
00477         checkBounds(index);
00478         return m_dataPtr[index];
00479       }
00480 
00488       Type
00489       operator()(size_t index) const {
00490         checkBounds(index);
00491         return m_dataPtr[index];
00492       }
00493     
00507       Type&
00508       operator()(size_t index0, size_t index1, size_t index2) {
00509         checkBounds(index0, index1, index2);
00510         return m_dataPtr[index2 + (index1 * m_shape2)
00511                          + (index0 * m_shape1Times2)];
00512       }
00513 
00527       Type
00528       operator()(size_t index0, size_t index1, size_t index2) const {
00529         checkBounds(index0, index1, index2);
00530         return m_dataPtr[index2 + (index1 * m_shape2)
00531                          + (index0 * m_shape1Times2)];
00532       }
00533 
00541       Type&
00542       operator[](size_t index) {return this->operator()(index);}
00543 
00551       Type
00552       operator[](size_t index) const {return this->operator()(index);}
00553 
00562       template <class Type2>
00563       Array3D<Type>&
00564       operator*=(const Array3D<Type2>& arg);
00565 
00574       template <class Type2>
00575       Array3D<Type>&
00576       operator/=(const Array3D<Type2>& arg);
00577 
00586       template <class Type2>
00587       Array3D<Type>&
00588       operator+=(const Array3D<Type2>& arg);
00589 
00598       template <class Type2>
00599       Array3D<Type>&
00600       operator-=(const Array3D<Type2>& arg);
00601 
00608       Array3D<Type>&
00609       operator+=(const Type arg);
00610 
00617       Array3D<Type>&
00618       operator-=(const Type arg);
00619 
00626       Array3D<Type>&
00627       operator*=(const Type arg);
00628 
00635       Array3D<Type>&
00636       operator/=(const Type arg);
00637 
00638     private:
00639       // Private member functions
00640       void allocate();
00641 
00642       // Optionally throw an exception if index is beyond the range of
00643       // this array.
00644       inline void
00645       checkBounds(size_t index) const;
00646 
00647       // Optionally throw an exception if any index is beyond the range of
00648       // this array.
00649       inline void
00650       checkBounds(size_t index0, size_t index1, size_t index2) const;
00651 
00652       void deAllocate();
00653 
00654       // Constants to help with formatting.  We use the initialization
00655       // on first use paradigm for the string constants to avoid
00656       // headaches.
00657 
00662       static const std::string& ioIntro(); 
00663 
00668       static const std::string& ioOutro();
00669 
00674       static const char ioOpening = '[';
00675 
00680       static const char ioClosing = ']';
00681 
00686       static const char ioSeparator = ',';
00687     
00688       // Private member variables
00689       size_t m_shape0;
00690       size_t m_shape1;
00691       size_t m_shape2;
00692       size_t m_shape1Times2;
00693       size_t m_size;
00694       Type* m_dataPtr;
00695       size_t* m_refCountPtr;
00696       bool m_isAllocated;
00697     
00698     };
00699 
00700 
00701     /* =========== Non-member functions related to Array3D =========== */
00702 
00703 //   /** 
00704 //    * This function returns the maximum element of the an Array3D
00705 //    * instance.
00706 //    * 
00707 //    * @param array This argument is the Array3D instance in which to
00708 //    * search for the largest element.
00709 //    * 
00710 //    * @return The return value is the value of the largest element.
00711 //    */
00712 //   template <class Type> 
00713 //   Type maximum(const Array3D<Type>& array);
00714 
00715 
00716 //   /** 
00717 //    * This function returns the minimum element of the an Array3D
00718 //    * instance.
00719 //    * 
00720 //    * @param array This argument is the Array3D instance in which to
00721 //    * search for the smallest element.
00722 //    * 
00723 //    * @return The return value is the value of the smallest element.
00724 //    */
00725 //   template <class Type> 
00726 //   Type minimum(const Array3D<Type>& array);
00727 
00728 
00729 //   /** 
00730 //    * This function computes the sum of the elements of its argument.
00731 //    * The summation is accumulated into a variable of type
00732 //    * NumericTraits<Type>::SumType, which for now defaults to Type, but
00733 //    * ultimately should be a type which (for fixed point and integral
00734 //    * types) has enough bits to hold the sum of at least 65535
00735 //    * elements.
00736 //    * 
00737 //    * @param array0 This argument is the array to be summed.
00738 //    *
00739 //    * @return The summation of all the elements of array0.
00740 //    */
00741 //   template <class Type> 
00742 //   Type sum(const Array3D<Type>& array);
00743 
00744 
00745   
00759     template <class Type>
00760     Array3D<Type>
00761     operator+(const Array3D<Type>& array0, const Array3D<Type>& array1);
00762 
00763 
00777     template <class Type>
00778     Array3D<Type>
00779     operator-(const Array3D<Type>& array0, const Array3D<Type>& array1);
00780 
00781 
00795     template <class Type>
00796     Array3D<Type>
00797     operator*(const Array3D<Type>& array0, const Array3D<Type>& array1);
00798 
00799   
00813     template <class Type>
00814     Array3D<Type>
00815     operator/(const Array3D<Type>& array0, const Array3D<Type>& array1);
00816 
00817 
00829     template <class Type>
00830     Array3D<Type>
00831     operator+(const Array3D<Type>& array0, Type scalar);
00832 
00833   
00845     template <class Type>
00846     Array3D<Type>
00847     operator-(const Array3D<Type>& array0, Type scalar);
00848 
00849   
00861     template <class Type>
00862     Array3D<Type>
00863     operator*(const Array3D<Type>& array0, Type scalar);
00864 
00865   
00877     template <class Type>
00878     Array3D<Type>
00879     operator/(const Array3D<Type>& array0, Type scalar);
00880 
00881   
00893     template <class Type>
00894     inline Array3D<Type>
00895     operator+(Type scalar, const Array3D<Type>& array0);
00896 
00897   
00909     template <class Type>
00910     inline Array3D<Type>
00911     operator*(Type scalar, const Array3D<Type>& array0);
00912 
00913 
00925     template <class Type>
00926     Array3D<bool>
00927     operator==(const Array3D<Type>& array0, const Type arg);
00928 
00929     
00942     template <class Type>
00943     Array3D<bool>
00944     operator==(const Array3D<Type>& array0, const Array3D<Type>& array1);
00945     
00946 
00957     template <class Type>
00958     Array3D<bool>
00959     operator<(const Array3D<Type>& array0, Type arg);
00960 
00961   
00972     template <class Type>
00973     Array3D<bool>
00974     operator<=(const Array3D<Type>& array0, Type arg);
00975 
00976 
00987     template <class Type>
00988     Array3D<bool>
00989     operator>(const Array3D<Type>& array0, Type arg);
00990 
00991   
01002     template <class Type>
01003     Array3D<bool>
01004     operator>=(const Array3D<Type>& array0, Type arg);
01005 
01006 
01027     template <class Type>
01028     std::ostream& operator<<(std::ostream& stream, const Array3D<Type>& array0);
01029 
01030   
01042     template <class Type>
01043     std::istream&
01044     operator>>(std::istream& stream, Array3D<Type>& array0);
01045   
01046   } // namespace numeric
01047 
01048 } // namespace dlr
01049 
01050 
01051 /* ======= Declarations to maintain compatibility with legacy code. ======= */
01052 
01053 namespace dlr {
01054 
01055   using numeric::Array3D;
01056 
01057 } // namespace dlr
01058 
01059 
01060 /*******************************************************************
01061  * Member function definitions follow.  This would be a .C file
01062  * if it weren't templated.
01063  *******************************************************************/
01064 
01065 #include <algorithm>
01066 #include <sstream>
01067 #include <numeric>
01068 #include <functional>
01069 #include <dlrNumeric/numericTraits.h>
01070 
01071 namespace dlr {
01072 
01073   namespace numeric {
01074     
01075     // Static constant describing how the string representation of an
01076     // Array3D should start.
01077     template <class Type>
01078     const std::string&
01079     Array3D<Type>::
01080     ioIntro()
01081     {
01082       static const std::string intro = "Array3D(";
01083       return intro;
01084     }
01085 
01086   
01087     // Static constant describing how the string representation of an
01088     // Array3D should end.
01089     template <class Type>
01090     const std::string&
01091     Array3D<Type>::
01092     ioOutro()
01093     {
01094       static const std::string outro = ")";
01095       return outro;
01096     }
01097 
01098     // Non-static member functions below.
01099 
01100     template <class Type>
01101     Array3D<Type>::
01102     Array3D()
01103       : m_shape0(0),
01104         m_shape1(0),
01105         m_shape2(0),
01106         m_shape1Times2(0),
01107         m_size(0),
01108         m_dataPtr(0),
01109         m_refCountPtr(0),
01110         m_isAllocated(false)
01111     {
01112       // Empty.
01113     }
01114 
01115   
01116     template <class Type>
01117     Array3D<Type>::
01118     Array3D(size_t shape0, size_t shape1, size_t shape2)
01119       : m_shape0(shape0),
01120         m_shape1(shape1),
01121         m_shape2(shape2),
01122         m_shape1Times2(0), // This will be set in the call to allocate().
01123         m_size(0),         // This will be set in the call to allocate().
01124         m_dataPtr(0),      // This will be set in the call to allocate().
01125         m_refCountPtr(0),  // This will be set in the call to allocate().
01126         m_isAllocated(false)
01127     {
01128       this->allocate();
01129     }
01130 
01131   
01132     // Construct from an initialization string.
01133     template <class Type>
01134     Array3D<Type>::
01135     Array3D(const std::string& inputString)
01136       : m_shape0(0),
01137         m_shape1(0),
01138         m_shape2(0),
01139         m_shape1Times2(0),
01140         m_size(0),
01141         m_dataPtr(0),
01142         m_refCountPtr(0),
01143         m_isAllocated(false)
01144     {
01145       // We'll use the stream input operator to parse the string.
01146       std::istringstream inputStream(inputString);
01147 
01148       // Now read the string into an array.
01149       Array3D<Type> inputArray;
01150       inputStream >> inputArray;
01151       if(!inputStream) {
01152         std::ostringstream message;
01153         message << "Couldn't parse input string: \"" << inputString << "\".";
01154         DLR_THROW3(ValueException, "Array3D::Array3D(const std::string&)",
01155                    message.str().c_str());                 
01156       }
01157 
01158       // If all went well, copy into *this.
01159       *this = inputArray;
01160     }
01161 
01162 
01163   
01164     /* When copying from a Array3D do a shallow copy */
01165     /* Update reference count if the array we're copying has */
01166     /* valid data. */
01167     template <class Type>
01168     Array3D<Type>::
01169     Array3D(const Array3D<Type>& source)
01170       : m_shape0(source.m_shape0),
01171         m_shape1(source.m_shape1),
01172         m_shape2(source.m_shape2),
01173         m_shape1Times2(source.m_shape1 * source.m_shape2),
01174         m_size(source.m_size),
01175         m_dataPtr(source.m_dataPtr),
01176         m_refCountPtr(source.m_refCountPtr),
01177         m_isAllocated(source.m_isAllocated)
01178     {
01179       if(m_isAllocated) {
01180         ++(*m_refCountPtr);
01181       }
01182     }
01183 
01184 
01185     /* Here's a constructor for getting image data into the array */
01186     /* cheaply. */
01187     template <class Type>
01188     Array3D<Type>::
01189     Array3D(size_t shape0, size_t shape1, size_t shape2, Type* const dataPtr)
01190       : m_shape0(shape0),
01191         m_shape1(shape1),
01192         m_shape2(shape2),
01193         m_shape1Times2(shape1 * shape2),
01194         m_size(shape0 * shape1 * shape2),
01195         m_dataPtr(dataPtr),
01196         m_refCountPtr(0),
01197         m_isAllocated(false)
01198     {
01199       // empty
01200     }
01201 
01202   
01203     template <class Type>
01204     Array3D<Type>::
01205     ~Array3D()
01206     {
01207       deAllocate();
01208     }
01209 
01210 
01211     template <class Type>
01212     inline void Array3D<Type>::
01213     checkDimension(size_t shape0, size_t shape1, size_t shape2) const
01214     {
01215 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01216       if(shape0 != this->shape0()
01217          || shape1 != this->shape1()
01218          || shape2 != this->shape2()){
01219         std::ostringstream message;
01220         message << "Size mismatch: required dimension is ("
01221                 << shape0 << ", " << shape1 << ", " << shape2 << ") "
01222                 << " while *this has dimension "
01223                 << this->shape0() << ", " << this->shape1() << ", "
01224                 << this->shape2() << ") ";
01225         DLR_THROW(IndexException, "Array3D::checkDimension()",
01226                   message.str().c_str());
01227       }
01228 #endif
01229     }
01230 
01231 
01232     template <class Type>
01233     Array3D<Type> Array3D<Type>::
01234     copy() const
01235     {
01236       Array3D<Type> newArray(m_shape0, m_shape1, m_shape2);
01237       newArray.copy(*this);
01238       return newArray;
01239     }
01240 
01241   
01242     template <class Type> template <class Type2>
01243     void Array3D<Type>::
01244     copy(const Array3D<Type2>& source)
01245     {
01246       if(source.size() != m_size) {
01247         std::ostringstream message;
01248         message << "Mismatched array sizes. Source array has "
01249                 << source.size() << " elements, while destination array has "
01250                 << m_size << " elements.";
01251         DLR_THROW3(ValueException, "Array3D::copy(const Array3D&)",
01252                    message.str().c_str());
01253       }
01254       if(m_size != 0) {
01255         this->copy(source.data());
01256       }
01257     }
01258 
01259   
01260     template <class Type> template <class Type2>
01261     void Array3D<Type>::
01262     copy(const Type2* dataPtr)
01263     {
01264       if (dataPtr == 0) {
01265         DLR_THROW(ValueException, "Array3D::copy(const Type2*)",
01266                   "Argument is a NULL pointer.");
01267       }
01268       std::copy(dataPtr, dataPtr + m_size, m_dataPtr);
01269     }
01270 
01271   
01272     // This member function sets the value of the array from an input
01273     // stream.
01274     template <class Type>
01275     std::istream&
01276     Array3D<Type>::
01277     readFromStream(std::istream& inputStream)
01278     {
01279       // Most of the time, InputType will be the same as Type.
01280       typedef typename NumericTraits<Type>::TextOutputType InputType;
01281 
01282       // If stream is in a bad state, we can't read from it.
01283       if (!inputStream){
01284         return inputStream;
01285       }
01286     
01287       // It's a lot easier to use a try block than to be constantly
01288       // testing whether the IO has succeeded, so we tell inputStream to
01289       // complain if anything goes wrong.
01290       std::ios_base::iostate oldExceptionState = inputStream.exceptions();
01291       inputStream.exceptions(
01292         std::ios_base::badbit | std::ios_base::failbit | std::ios_base::eofbit);
01293 
01294       // Now on with the show.
01295       try{
01296         // Construct an InputStream instance so we can use our
01297         // convenience functions.
01298         InputStream stream(inputStream);
01299 
01300         // We won't require the input format to start with "Array3D(", but
01301         // if it does we read it here.
01302         bool foundIntro = false;
01303         if(stream.peek() == ioIntro()[0]) {
01304           foundIntro = true;
01305           stream.expect(ioIntro());
01306         }
01307 
01308         // OK.  We've dispensed with the intro.  What's left should be of
01309         // the format "[row, row, row, ...]".  We require the square
01310         // brackets to be there.
01311         stream.expect(ioOpening);
01312 
01313         // Read the data.  We'll use the Array1D<Type> stream operator to
01314         // read each row.
01315         Array2D<Type> inputValue;
01316         std::vector< Array2D<Type> > inputBuffer;
01317         while(1) {
01318           // Read the next row.
01319           stream >> inputValue;
01320           inputBuffer.push_back(inputValue);
01321 
01322           // Read the separator, or else the closing character.
01323           char inChar = 0;
01324           stream >> inChar;
01325           if(inChar == ioClosing) {
01326             // Found a closing.  Stop here.
01327             break;
01328           }
01329           if(inChar != ioSeparator) {
01330             // Missing separator?  Fail here.
01331             stream.clear(std::ios_base::failbit);
01332           }
01333         }
01334     
01335         // If we found an intro, we expect the corresponding outro.
01336         if(foundIntro) {
01337           stream.expect(ioOutro());
01338         }
01339 
01340         // Now we're done with all of the parsing, verify that all slices
01341         // have the same number of rows and columns.
01342         size_t shape0 = inputBuffer.size();
01343         size_t shape1 = ((shape0 != 0) ? inputBuffer[0].rows() : 0);
01344         size_t shape2 = ((shape0 != 0) ? inputBuffer[0].columns() : 0);
01345         for(size_t index = 1; index < shape0; ++index) {
01346           if((inputBuffer[index].rows() != shape1)
01347              || (inputBuffer[index].columns() != shape2)) {
01348             // Inconsistent slice sizes!  Fail here.
01349             stream.clear(std::ios_base::failbit);
01350           }
01351         }
01352 
01353         // And finally, copy the data.
01354         size_t sliceSize = shape1 * shape2;
01355         this->reinit(shape0, shape1, shape2);
01356         for(size_t index = 0; index < shape0; ++index) {
01357           std::copy(inputBuffer[index].begin(), inputBuffer[index].end(),
01358                     this->begin() + (index * sliceSize));
01359         }
01360       } catch(std::ios_base::failure) {
01361         // Empty
01362       }
01363       inputStream.exceptions(oldExceptionState);
01364       return inputStream;
01365     }
01366 
01367   
01368     template <class Type>
01369     void Array3D<Type>::
01370     reinit(size_t shape0, size_t shape1, size_t shape2)
01371     {
01372       this->deAllocate();
01373       this->m_shape0 = shape0;
01374       this->m_shape1 = shape1;
01375       this->m_shape2 = shape2;
01376       this->allocate();
01377     }
01378 
01379 
01380     template <class Type>
01381     void Array3D<Type>::
01382     reshape(int shape0, int shape1, int shape2)
01383     {
01384       if ((shape0 * shape1 * shape2 != 0)){
01385         // If one axis is specified as -1, it will be automatically 
01386         // chosen to match the number of elements in the array.
01387         if((shape0 == -1) && (shape1 != -1) && (shape2 != -1)) {
01388           shape0 = static_cast<int>(this->size()) / (shape1 * shape2);
01389         } else if((shape1 == -1) && (shape0 != -1) && (shape2 != -1)) {
01390           shape1 = static_cast<int>(this->size()) / (shape0 * shape2);
01391         } else if((shape2 == -1) && (shape1 != -1) && (shape0 != -1)) {
01392           shape2 = static_cast<int>(this->size()) / (shape1 * shape0);
01393         }
01394       }
01395       if((shape0 * shape1 * shape2) != static_cast<int>(this->size())) {
01396         std::ostringstream message;
01397         message << "Can't reshape a(n) " << this->size()
01398                 << " element array to be " << shape0 << " x " << shape1
01399                 << " x " << shape2 << ".";
01400         DLR_THROW(ValueException, "Array3D::reshape()", message.str().c_str());
01401       }
01402 
01403       m_shape0 = static_cast<size_t>(shape0);
01404       m_shape1 = static_cast<size_t>(shape1);
01405       m_shape2 = static_cast<size_t>(shape2);
01406       m_shape1Times2 = shape1 * shape2;
01407     }
01408 
01409   
01410     template <class Type>
01411     Array1D<size_t> Array3D<Type>::
01412     shape() const
01413     {
01414       Array1D<size_t> rc(3);
01415       rc(0) = this->shape0();
01416       rc(1) = this->shape1();
01417       rc(2) = this->shape2();
01418       return rc;
01419     }
01420 
01421 
01422     template <class Type>
01423     size_t Array3D<Type>::
01424     shape(size_t axis) const
01425     {
01426       switch(axis) {
01427       case 0:
01428         return this->shape0();
01429         break;
01430       case 1:
01431         return this->shape1();
01432         break;
01433       case 2:
01434         return this->shape2();
01435         break;
01436       default:
01437         std::ostringstream message;
01438         message << "Invalid Axis: "<< axis << ".";
01439         DLR_THROW(ValueException, "Array3D::shape(size_t)",
01440                   message.str().c_str());
01441         break;
01442       }
01443       return 0;                     // To keep the darn compiler happy.
01444     }
01445 
01446 
01447     template <class Type>
01448     Array2D<Type>
01449     Array3D<Type>::
01450     slice(size_t index0)
01451     {
01452       this->checkBounds(index0, 0, 0);
01453       return Array2D<Type>(
01454         m_shape1, m_shape2, m_dataPtr + (index0 * m_shape1Times2));
01455     }
01456 
01457   
01458     template <class Type>
01459     const Array2D<Type>
01460     Array3D<Type>::
01461     slice(size_t index0) const
01462     {
01463       this->checkBounds(index0, 0, 0);
01464       return Array2D<Type>(
01465         m_shape1, m_shape2, m_dataPtr + (index0 * m_shape1Times2));
01466     }
01467 
01468   
01469     template <class Type>
01470     Array3D<Type>& Array3D<Type>::
01471     operator=(const Array3D<Type>& source)
01472     {
01473       // Check for self-assignment
01474       if(&source != this) {
01475         this->deAllocate();
01476         m_shape0 = source.m_shape0;
01477         m_shape1 = source.m_shape1;
01478         m_shape2 = source.m_shape2;
01479         m_shape1Times2 = source.m_shape1Times2;
01480         m_size = source.m_size;
01481         m_dataPtr = source.m_dataPtr;
01482         m_refCountPtr = source.m_refCountPtr;
01483         m_isAllocated = source.m_isAllocated;
01484         if(m_isAllocated) {
01485           ++(*m_refCountPtr);
01486         }
01487       }
01488       return *this;
01489     }
01490 
01491 
01492     template <class Type>
01493     Array3D<Type>& Array3D<Type>::
01494     operator=(Type value)
01495     {
01496       std::fill(m_dataPtr, m_dataPtr + m_size, value);
01497       return *this;
01498     }
01499 
01500 
01501     template <class Type> template <class Type2>
01502     Array3D<Type>& Array3D<Type>::
01503     operator*=(const Array3D<Type2>& arg)
01504     {
01505       if(m_size != arg.size()) {
01506         std::ostringstream message;
01507         message << "Mismatched array sizes. Argument array has "
01508                 << arg.size() << " elements, while destination array has "
01509                 << m_size << " elements.";
01510         DLR_THROW(ValueException, "Array3D::operator*=()",
01511                   message.str().c_str());
01512       }
01513       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01514                      std::multiplies<Type>());
01515       return *this;
01516     }
01517 
01518 
01519     template <class Type> template <class Type2>
01520     Array3D<Type>& Array3D<Type>::
01521     operator/=(const Array3D<Type2>& arg)
01522     {
01523       if(m_size != arg.size()) {
01524         std::ostringstream message;
01525         message << "Mismatched array sizes. Argument array has "
01526                 << arg.size() << " elements, while destination array has "
01527                 << m_size << " elements.";
01528         DLR_THROW(ValueException, "Array3D::operator/=()",
01529                   message.str().c_str());
01530       }
01531       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01532                      std::divides<Type>());
01533       return *this;
01534     }
01535 
01536 
01537     template <class Type> template <class Type2>
01538     Array3D<Type>& Array3D<Type>::
01539     operator+=(const Array3D<Type2>& arg)
01540     {
01541       if(m_size != arg.size()) {
01542         std::ostringstream message;
01543         message << "Mismatched array sizes. Argument array has "
01544                 << arg.size() << " elements, while destination array has "
01545                 << m_size << " elements.";
01546         DLR_THROW(ValueException, "Array3D::operator+=()",
01547                   message.str().c_str());
01548       }
01549       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01550                      std::plus<Type>());
01551       return *this;
01552     }
01553 
01554 
01555     template <class Type> template <class Type2>
01556     Array3D<Type>& Array3D<Type>::
01557     operator-=(const Array3D<Type2>& arg)
01558     {
01559       if(m_size != arg.size()) {
01560         std::ostringstream message;
01561         message << "Mismatched array sizes. Argument array has "
01562                 << arg.size() << " elements, while destination array has "
01563                 << m_size << " elements.";
01564         DLR_THROW(ValueException, "Array3D::operator-=()",
01565                   message.str().c_str());
01566       }
01567       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01568                      std::minus<Type>());
01569       return *this;
01570     }
01571 
01572 
01573     template <class Type>
01574     Array3D<Type>& Array3D<Type>::
01575     operator+=(const Type arg)
01576     {
01577       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01578                      std::bind2nd(std::plus<Type>(), arg));
01579       return *this;
01580     }
01581 
01582 
01583     template <class Type>
01584     Array3D<Type>& Array3D<Type>::
01585     operator-=(const Type arg)
01586     {
01587       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01588                      std::bind2nd(std::minus<Type>(), arg));
01589       return *this;
01590     }
01591 
01592 
01593     template <class Type>
01594     Array3D<Type>& Array3D<Type>::
01595     operator*=(const Type arg)
01596     {
01597       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01598                      std::bind2nd(std::multiplies<Type>(), arg));
01599       return *this;
01600     }
01601 
01602 
01603     template <class Type>
01604     Array3D<Type>& Array3D<Type>::
01605     operator/=(const Type arg)
01606     {
01607       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01608                      std::bind2nd(std::divides<Type>(), arg));
01609       return *this;
01610     }
01611 
01612 
01613     template <class Type>
01614     void Array3D<Type>::
01615     allocate()
01616     {
01617       m_shape1Times2  = m_shape1 * m_shape2;
01618       m_size = m_shape0 * m_shape1 * m_shape2;
01619       if(m_shape0 > 0 && m_shape1 > 0 && m_shape2 > 0) {
01620         m_dataPtr = new(Type[m_size]); // should throw an exeption
01621         m_refCountPtr = new size_t;      // if we're out of memory.
01622         *m_refCountPtr = 1;
01623         m_isAllocated = true;
01624         return;
01625       }
01626       m_dataPtr = 0;
01627       m_refCountPtr = 0;
01628       m_isAllocated = false;
01629       return;
01630     }
01631 
01632 
01633     template <class Type>
01634     inline void Array3D<Type>::
01635     checkBounds(size_t index) const
01636     {
01637 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01638       if(index >= m_size) {
01639         std::ostringstream message;
01640         message << "Index " << index << " is invalid for a(n) " << m_size
01641                 << " element array.";
01642         DLR_THROW(IndexException, "Array3D::checkBounds(size_t)",
01643                   message.str().c_str());
01644       }
01645 #endif
01646     }
01647 
01648   
01649     template <class Type>
01650     inline void Array3D<Type>::
01651     checkBounds(size_t index0, size_t index1, size_t index2) const
01652     {
01653 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01654       if(index0 >= m_shape0) {
01655         std::ostringstream message;
01656         message << "index0 should be less than " << m_shape0
01657                 << ", but is actually " << index0 << ".";
01658         DLR_THROW3(IndexException, "Array3D::checkBounds()",
01659                    message.str().c_str());
01660       }
01661       if(index1 >= m_shape1) {
01662         std::ostringstream message;
01663         message << "index1 should be less than " << m_shape1
01664                 << ", but is actually " << index1 << ".";
01665         DLR_THROW3(IndexException, "Array3D::checkBounds()",
01666                    message.str().c_str());
01667       }
01668       if(index2 >= m_shape2) {
01669         std::ostringstream message;
01670         message << "index2 should be less than " << m_shape2
01671                 << ", but is actually " << index2 << ".";
01672         DLR_THROW3(IndexException, "Array3D::checkBounds()",
01673                    message.str().c_str());
01674       }
01675 #endif
01676     }
01677 
01678   
01679     template <class Type>
01680     void Array3D<Type>::
01681     deAllocate()
01682     {
01683       if(m_isAllocated == true) {
01684         if(--(*m_refCountPtr) == 0) {
01685           delete[] m_dataPtr;
01686           delete m_refCountPtr;
01687           m_isAllocated = false;
01688           m_dataPtr = 0;
01689           m_refCountPtr = 0;
01690         }
01691       } else {
01692         m_dataPtr = 0;
01693         m_refCountPtr = 0;
01694       }
01695     }
01696 
01697   
01698     /* Non-member functions which will ultimately wind up in a different file */
01699 //   template <class Type> 
01700 //   Type maximum(const Array3D<Type>& array)
01701 //   {
01702 //     return *std::max_element(array.data(), array.data() + array.size());
01703 //   }
01704 
01705 //   template <class Type> 
01706 //   Type minimum(const Array3D<Type>& array)
01707 //   {
01708 //     return *std::min_element(array.data(), array.data() + array.size());
01709 //   }
01710 
01711 //   template <class Type> 
01712 //   Type sum(const Array3D<Type>& array)
01713 //   {
01714 //     return std::accumulate(array.data(), array.data() + array.size(),
01715 //                            static_cast<Type>(0));
01716 //   }
01717   
01718     template <class Type>
01719     Array3D<Type> operator+(const Array3D<Type>& array0,
01720                             const Array3D<Type>& array1)
01721     {
01722       if((array0.shape0() != array1.shape0())
01723          || (array0.shape1() != array1.shape1())        
01724          || (array0.shape2() != array1.shape2())) {
01725         std::ostringstream message;
01726         message << "Array sizes do not match.  Array0 is "
01727                 << array0.shape0() << " x " << array0.shape1()
01728                 << " x " << array0.shape2()
01729                 << ", while array1 is "
01730                 << array1.shape0() << " x " << array1.shape1()
01731                 << " x " << array1.shape2() << ".";
01732         DLR_THROW(ValueException, "Array3D::operator+()", message.str().c_str());
01733       }
01734       Array3D<Type> result(array0.shape0(), array0.shape1(), array0.shape2());
01735       std::transform(array0.begin(), array0.end(), array1.begin(),
01736                      result.begin(), std::plus<Type>());
01737       return result;
01738     }
01739 
01740 
01741     template <class Type>
01742     Array3D<Type> operator-(const Array3D<Type>& array0,
01743                             const Array3D<Type>& array1)
01744     {
01745       if((array0.shape0() != array1.shape0())
01746          || (array0.shape1() != array1.shape1())        
01747          || (array0.shape2() != array1.shape2())) {
01748         std::ostringstream message;
01749         message << "Array sizes do not match.  Array0 is "
01750                 << array0.shape0() << " x " << array0.shape1()
01751                 << " x " << array0.shape2()
01752                 << ", while array1 is "
01753                 << array1.shape0() << " x " << array1.shape1()
01754                 << " x " << array1.shape2() << ".";
01755         DLR_THROW(ValueException, "Array3D::operator-()", message.str().c_str());
01756       }
01757       Array3D<Type> result(array0.shape0(), array0.shape1(), array0.shape2());
01758       std::transform(array0.begin(), array0.end(), array1.begin(),
01759                      result.begin(), std::minus<Type>());
01760       return result;
01761     }
01762 
01763   
01764     template <class Type>
01765     Array3D<Type> operator*(const Array3D<Type>& array0,
01766                             const Array3D<Type>& array1)
01767     {
01768       if((array0.shape0() != array1.shape0())
01769          || (array0.shape1() != array1.shape1())        
01770          || (array0.shape2() != array1.shape2())) {
01771         std::ostringstream message;
01772         message << "Array sizes do not match.  Array0 is "
01773                 << array0.shape0() << " x " << array0.shape1()
01774                 << " x " << array0.shape2()
01775                 << ", while array1 is "
01776                 << array1.shape0() << " x " << array1.shape1()
01777                 << " x " << array1.shape2() << ".";
01778         DLR_THROW(ValueException, "Array3D::operator*()", message.str().c_str());
01779       }
01780       Array3D<Type> result(array0.shape0(), array0.shape1(), array0.shape2());
01781       std::transform(array0.begin(), array0.end(), array1.begin(),
01782                      result.begin(), std::multiplies<Type>());
01783       return result;
01784     }
01785   
01786 
01787     template <class Type>
01788     Array3D<Type> operator/(const Array3D<Type>& array0,
01789                             const Array3D<Type>& array1)
01790     {
01791       if((array0.shape0() != array1.shape0())
01792          || (array0.shape1() != array1.shape1())        
01793          || (array0.shape2() != array1.shape2())) {
01794         std::ostringstream message;
01795         message << "Array sizes do not match.  Array0 is "
01796                 << array0.shape0() << " x " << array0.shape1()
01797                 << " x " << array0.shape2()
01798                 << ", while array1 is "
01799                 << array1.shape0() << " x " << array1.shape1()
01800                 << " x " << array1.shape2() << ".";
01801         DLR_THROW(ValueException, "Array3D::operator/()", message.str().c_str());
01802       }
01803       Array3D<Type> result(array0.shape0(), array0.shape1(), array0.shape2());
01804       std::transform(array0.begin(), array0.end(), array1.begin(), result.begin(),
01805                      std::divides<Type>());
01806       return result;
01807     }
01808 
01809 
01810     template <class Type>
01811     Array3D<Type> operator+(const Array3D<Type>& array0, Type scalar)
01812     {
01813       Array3D<Type> result(array0.shape0(), array0.shape1(), array0.shape2());
01814       std::transform(array0.begin(), array0.end(), result.begin(),
01815                      std::bind2nd(std::plus<Type>(), scalar));
01816       return result;
01817     }
01818 
01819 
01820     template <class Type>
01821     Array3D<Type> operator-(const Array3D<Type>& array0, Type scalar)
01822     {
01823       Array3D<Type> result(array0.shape0(), array0.shape1(), array0.shape2()); 
01824       std::transform(array0.begin(), array0.end(), result.begin(),
01825                      std::bind2nd(std::minus<Type>(), scalar));
01826       return result;
01827     }
01828 
01829 
01830     template <class Type>
01831     Array3D<Type> operator*(const Array3D<Type>& array0, Type scalar)
01832     {
01833       Array3D<Type> result(array0.shape0(), array0.shape1(), array0.shape2()); 
01834       std::transform(array0.begin(), array0.end(), result.begin(),
01835                      std::bind2nd(std::multiplies<Type>(), scalar));
01836       return result;
01837     }
01838 
01839 
01840     template <class Type>
01841     Array3D<Type> operator/(const Array3D<Type>& array0, Type scalar)
01842     {
01843       Array3D<Type> result(array0.shape0(), array0.shape1(), array0.shape2()); 
01844       std::transform(array0.begin(), array0.end(), result.begin(),
01845                      std::bind2nd(std::divides<Type>(), scalar));
01846       return result;
01847     }
01848 
01849 
01850     template <class Type>
01851     inline Array3D<Type> operator+(Type scalar, const Array3D<Type>& array0)
01852     {
01853       return array0 + scalar;
01854     }
01855 
01856 
01857     template <class Type>
01858     inline Array3D<Type> operator*(Type scalar, const Array3D<Type>& array0)
01859     {
01860       return array0 * scalar;
01861     }
01862 
01863 
01864     // Elementwise comparison of an Array3D with a constant.
01865     template <class Type>
01866     Array3D<bool>
01867     operator==(const Array3D<Type>& array0, const Type arg)
01868     {
01869       Array3D<bool> result(array0.shape0(), array0.shape1(), array0.shape2());
01870       std::transform(array0.begin(), array0.end(), result.data(),
01871                      std::bind2nd(std::equal_to<Type>(), arg));
01872       return result;
01873     }
01874 
01875     
01876     // Elementwise comparison of an Array3D with another array.
01877     template <class Type>
01878     Array3D<bool>
01879     operator==(const Array3D<Type>& array0, const Array3D<Type>& array1)
01880     {
01881       array0.checkDimension(array1.shape0(), array1.shape1(), array1.shape2());
01882       Array3D<bool> result(array0.shape0(), array0.shape1(), array0.shape2());
01883       std::transform(array0.begin(), array0.end(), array1.begin(),
01884                      result.begin(), std::equal_to<Type>());
01885       return result;
01886     }
01887 
01888     
01889     template <class Type>
01890     Array3D<bool> operator>(const Array3D<Type>& array0, Type arg)
01891     {
01892       Array3D<bool> result(array0.shape0(), array0.shape1(), array0.shape2()); 
01893       std::transform(array0.begin(), array0.end(), result.begin(),
01894                      std::bind2nd(std::greater<Type>(), arg));
01895       return result;
01896     }
01897 
01898 
01899     template <class Type>
01900     Array3D<bool> operator<(const Array3D<Type>& array0, Type arg)
01901     {
01902       Array3D<bool> result(array0.shape0(), array0.shape1(), array0.shape2()); 
01903       std::transform(array0.begin(), array0.end(), result.begin(),
01904                      std::bind2nd(std::less<Type>(), arg));
01905       return result;
01906     }
01907 
01908   
01909     template <class Type>
01910     Array3D<bool> operator>=(const Array3D<Type>& array0, Type arg)
01911     {
01912       Array3D<bool> result(array0.shape0(), array0.shape1(), array0.shape2()); 
01913       std::transform(array0.begin(), array0.end(), result.begin(),
01914                      std::bind2nd(std::greater_equal<Type>(), arg));
01915       return result;
01916     }
01917 
01918   
01919     template <class Type>
01920     Array3D<bool> operator<=(const Array3D<Type>& array0, Type arg)
01921     {
01922       Array3D<bool> result(array0.shape0(), array0.shape1(), array0.shape2()); 
01923       std::transform(array0.begin(), array0.end(), result.begin(),
01924                      std::bind2nd(std::less_equal<Type>(), arg));
01925       return result;
01926     }
01927 
01928 
01929     // This operator outputs a text representation of an Array3D
01930     // instance to a std::ostream.
01931     template <class Type>  
01932     std::ostream& operator<<(std::ostream& stream, const Array3D<Type>& array0)
01933     {
01934       // Most of the time, OutputType will be the same as Type.
01935       typedef typename NumericTraits<Type>::TextOutputType OutputType;
01936 
01937       size_t index0, index1, index2;
01938       stream << "Array3D([";
01939       for(index0 = 0; index0 < array0.shape0(); ++index0) {
01940         if(index0 != 0) {
01941           stream << "         ";
01942         }
01943         stream << "[";
01944         for(index1 = 0; index1 < array0.shape1(); ++index1) {
01945           if(index1 != 0) {
01946             stream << "          ";     
01947           }
01948           stream << "[";
01949           for(index2 = 0; index2 < array0.shape2(); ++index2) {
01950             stream << static_cast<OutputType>(array0(index0, index1, index2));
01951             if(index2 != array0.shape2() - 1) {
01952               stream << ", ";
01953             }
01954           }
01955           stream << "]";
01956           if(index1 != array0.shape1() - 1) {
01957             stream << ",\n";
01958           }     
01959         }
01960         stream << "]";
01961         if(index0 != array0.shape0() - 1) {
01962           stream << ",\n";
01963         }
01964       }
01965       stream << "])\n";
01966       stream.flush();
01967       return stream;
01968     }
01969 
01970 
01971     template <class Type>
01972     std::istream&
01973     operator>>(std::istream& inputStream, Array3D<Type>& array0)
01974     {
01975       return array0.readFromStream(inputStream);
01976     }
01977   
01978   } // namespace numeric
01979 
01980 } // namespace dlr
01981 
01982 #endif // #ifdef _DLR_ARRAY3D_H_

Generated on Mon Jul 9 20:34:02 2007 for dlrLibs Utility Libraries by  doxygen 1.5.2