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 arrayShape0, size_t arrayShape1, size_t arrayShape2);
00095 
00111       explicit
00112       Array3D(const std::string& inputString);
00113 
00120       Array3D(const Array3D<Type> &source);
00121 
00138       Array3D(size_t arrayShape0, size_t arrayShape1, size_t arrayShape2, 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 arrayShape0, size_t arrayShape1, size_t arrayShape2) 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 
00329 
00339       inline Type
00340       getElement(size_t index0) const {return this->operator()(index0);}
00341 
00342 
00358       Type
00359       getElement(size_t index0, size_t index1, size_t index2) const {
00360         return this->operator()(index0, index1, index2);
00361       }        
00362 
00363 
00375       std::istream&
00376       readFromStream(std::istream& inputStream);
00377     
00388       void
00389       reinit(size_t arrayShape0, size_t arrayShape1, size_t arrayShape2);
00390 
00391 
00403       inline void
00404       reinitIfNecessary(size_t arrayShape0, size_t arrayShape1,
00405                         size_t arrayShape2);
00406 
00407       
00419       void
00420       reshape(int arrayShape0, int arrayShape1, int arrayShape2);
00421 
00422 
00436       Type&
00437       setElement(size_t index0, const Type& value) {
00438         return this->operator()(index0) = value;
00439       }
00440 
00441 
00461       Type&
00462       setElement(size_t index0, size_t index1, size_t index2,
00463                  const Type& value) {
00464         return this->operator()(index0, index1, index2) = value;
00465       }
00466 
00467 
00476       Array1D<size_t>
00477       shape() const;
00478 
00487       size_t
00488       shape(size_t axis) const;
00489 
00496       size_t
00497       shape0() const {return m_shape0;}
00498 
00505       size_t
00506       shape1() const {return m_shape1;}
00507 
00514       size_t
00515       shape2() const {return m_shape2;}
00516 
00523       size_t
00524       size() const {return m_size;}
00525   
00534       Array2D<Type>
00535       slice(size_t index);
00536 
00545       const Array2D<Type>
00546       slice(size_t index) const;
00547 
00555       Array3D<Type>&
00556       operator=(const Array3D<Type>& source);
00557 
00564       Array3D<Type>&
00565       operator=(Type value);
00566 
00574       inline Type&
00575       operator()(size_t index) {
00576         checkBounds(index);
00577         return m_dataPtr[index];
00578       }
00579 
00587       inline Type
00588       operator()(size_t index) const {
00589         checkBounds(index);
00590         return m_dataPtr[index];
00591       }
00592     
00606       inline Type&
00607       operator()(size_t index0, size_t index1, size_t index2) {
00608         checkBounds(index0, index1, index2);
00609         return m_dataPtr[index2 + (index1 * m_shape2)
00610                          + (index0 * m_shape1Times2)];
00611       }
00612 
00626       inline Type
00627       operator()(size_t index0, size_t index1, size_t index2) const {
00628         checkBounds(index0, index1, index2);
00629         return m_dataPtr[index2 + (index1 * m_shape2)
00630                          + (index0 * m_shape1Times2)];
00631       }
00632 
00640       inline Type&
00641       operator[](size_t index) {return this->operator()(index);}
00642 
00650       inline Type
00651       operator[](size_t index) const {return this->operator()(index);}
00652 
00661       template <class Type2>
00662       Array3D<Type>&
00663       operator*=(const Array3D<Type2>& arg);
00664 
00673       template <class Type2>
00674       Array3D<Type>&
00675       operator/=(const Array3D<Type2>& arg);
00676 
00685       template <class Type2>
00686       Array3D<Type>&
00687       operator+=(const Array3D<Type2>& arg);
00688 
00697       template <class Type2>
00698       Array3D<Type>&
00699       operator-=(const Array3D<Type2>& arg);
00700 
00707       Array3D<Type>&
00708       operator+=(const Type arg);
00709 
00716       Array3D<Type>&
00717       operator-=(const Type arg);
00718 
00725       Array3D<Type>&
00726       operator*=(const Type arg);
00727 
00734       Array3D<Type>&
00735       operator/=(const Type arg);
00736 
00737     private:
00738       // Private member functions
00739       void allocate();
00740 
00741       // Optionally throw an exception if index is beyond the range of
00742       // this array.
00743       inline void
00744       checkBounds(size_t index) const;
00745 
00746       // Optionally throw an exception if any index is beyond the range of
00747       // this array.
00748       inline void
00749       checkBounds(size_t index0, size_t index1, size_t index2) const;
00750 
00751       void deAllocate();
00752 
00753       // Constants to help with formatting.  We use the initialization
00754       // on first use paradigm for the string constants to avoid
00755       // headaches.
00756 
00761       static const std::string& ioIntro(); 
00762 
00767       static const std::string& ioOutro();
00768 
00773       static const char ioOpening = '[';
00774 
00779       static const char ioClosing = ']';
00780 
00785       static const char ioSeparator = ',';
00786     
00787       // Private member variables
00788       size_t m_shape0;
00789       size_t m_shape1;
00790       size_t m_shape2;
00791       size_t m_shape1Times2;
00792       size_t m_size;
00793       Type* m_dataPtr;
00794       size_t* m_refCountPtr;
00795       bool m_isAllocated;
00796     
00797     };
00798 
00799 
00800     /* =========== Non-member functions related to Array3D =========== */
00801 
00802 //   /** 
00803 //    * This function returns the maximum element of the an Array3D
00804 //    * instance.
00805 //    * 
00806 //    * @param array This argument is the Array3D instance in which to
00807 //    * search for the largest element.
00808 //    * 
00809 //    * @return The return value is the value of the largest element.
00810 //    */
00811 //   template <class Type> 
00812 //   Type maximum(const Array3D<Type>& array);
00813 
00814 
00815 //   /** 
00816 //    * This function returns the minimum element of the an Array3D
00817 //    * instance.
00818 //    * 
00819 //    * @param array This argument is the Array3D instance in which to
00820 //    * search for the smallest element.
00821 //    * 
00822 //    * @return The return value is the value of the smallest element.
00823 //    */
00824 //   template <class Type> 
00825 //   Type minimum(const Array3D<Type>& array);
00826 
00827 
00828 //   /** 
00829 //    * This function computes the sum of the elements of its argument.
00830 //    * The summation is accumulated into a variable of type
00831 //    * NumericTraits<Type>::SumType, which for now defaults to Type, but
00832 //    * ultimately should be a type which (for fixed point and integral
00833 //    * types) has enough bits to hold the sum of at least 65535
00834 //    * elements.
00835 //    * 
00836 //    * @param array0 This argument is the array to be summed.
00837 //    *
00838 //    * @return The summation of all the elements of array0.
00839 //    */
00840 //   template <class Type> 
00841 //   Type sum(const Array3D<Type>& array);
00842 
00843 
00844   
00858     template <class Type>
00859     Array3D<Type>
00860     operator+(const Array3D<Type>& array0, const Array3D<Type>& array1);
00861 
00862 
00876     template <class Type>
00877     Array3D<Type>
00878     operator-(const Array3D<Type>& array0, const Array3D<Type>& array1);
00879 
00880 
00894     template <class Type>
00895     Array3D<Type>
00896     operator*(const Array3D<Type>& array0, const Array3D<Type>& array1);
00897 
00898   
00912     template <class Type>
00913     Array3D<Type>
00914     operator/(const Array3D<Type>& array0, const Array3D<Type>& array1);
00915 
00916 
00928     template <class Type>
00929     Array3D<Type>
00930     operator+(const Array3D<Type>& array0, Type scalar);
00931 
00932   
00944     template <class Type>
00945     Array3D<Type>
00946     operator-(const Array3D<Type>& array0, Type scalar);
00947 
00948   
00960     template <class Type>
00961     Array3D<Type>
00962     operator*(const Array3D<Type>& array0, Type scalar);
00963 
00964   
00976     template <class Type>
00977     Array3D<Type>
00978     operator/(const Array3D<Type>& array0, Type scalar);
00979 
00980   
00992     template <class Type>
00993     inline Array3D<Type>
00994     operator+(Type scalar, const Array3D<Type>& array0);
00995 
00996   
01008     template <class Type>
01009     inline Array3D<Type>
01010     operator*(Type scalar, const Array3D<Type>& array0);
01011 
01012 
01024     template <class Type>
01025     Array3D<bool>
01026     operator==(const Array3D<Type>& array0, const Type arg);
01027 
01028     
01041     template <class Type>
01042     Array3D<bool>
01043     operator==(const Array3D<Type>& array0, const Array3D<Type>& array1);
01044     
01045 
01056     template <class Type>
01057     Array3D<bool>
01058     operator<(const Array3D<Type>& array0, Type arg);
01059 
01060   
01071     template <class Type>
01072     Array3D<bool>
01073     operator<=(const Array3D<Type>& array0, Type arg);
01074 
01075 
01086     template <class Type>
01087     Array3D<bool>
01088     operator>(const Array3D<Type>& array0, Type arg);
01089 
01090   
01101     template <class Type>
01102     Array3D<bool>
01103     operator>=(const Array3D<Type>& array0, Type arg);
01104 
01105 
01126     template <class Type>
01127     std::ostream& operator<<(std::ostream& stream, const Array3D<Type>& array0);
01128 
01129   
01141     template <class Type>
01142     std::istream&
01143     operator>>(std::istream& stream, Array3D<Type>& array0);
01144   
01145   } // namespace numeric
01146 
01147 } // namespace dlr
01148 
01149 
01150 /* ======= Declarations to maintain compatibility with legacy code. ======= */
01151 
01152 namespace dlr {
01153 
01154   using numeric::Array3D;
01155 
01156 } // namespace dlr
01157 
01158 
01159 /*******************************************************************
01160  * Member function definitions follow.  This would be a .C file
01161  * if it weren't templated.
01162  *******************************************************************/
01163 
01164 #include <algorithm>
01165 #include <sstream>
01166 #include <numeric>
01167 #include <functional>
01168 #include <dlrNumeric/numericTraits.h>
01169 
01170 namespace dlr {
01171 
01172   namespace numeric {
01173     
01174     // Static constant describing how the string representation of an
01175     // Array3D should start.
01176     template <class Type>
01177     const std::string&
01178     Array3D<Type>::
01179     ioIntro()
01180     {
01181       static const std::string intro = "Array3D(";
01182       return intro;
01183     }
01184 
01185   
01186     // Static constant describing how the string representation of an
01187     // Array3D should end.
01188     template <class Type>
01189     const std::string&
01190     Array3D<Type>::
01191     ioOutro()
01192     {
01193       static const std::string outro = ")";
01194       return outro;
01195     }
01196 
01197     // Non-static member functions below.
01198 
01199     template <class Type>
01200     Array3D<Type>::
01201     Array3D()
01202       : m_shape0(0),
01203         m_shape1(0),
01204         m_shape2(0),
01205         m_shape1Times2(0),
01206         m_size(0),
01207         m_dataPtr(0),
01208         m_refCountPtr(0),
01209         m_isAllocated(false)
01210     {
01211       // Empty.
01212     }
01213 
01214   
01215     template <class Type>
01216     Array3D<Type>::
01217     Array3D(size_t arrayShape0, size_t arrayShape1, size_t arrayShape2)
01218       : m_shape0(arrayShape0),
01219         m_shape1(arrayShape1),
01220         m_shape2(arrayShape2),
01221         m_shape1Times2(0), // This will be set in the call to allocate().
01222         m_size(0),         // This will be set in the call to allocate().
01223         m_dataPtr(0),      // This will be set in the call to allocate().
01224         m_refCountPtr(0),  // This will be set in the call to allocate().
01225         m_isAllocated(false)
01226     {
01227       this->allocate();
01228     }
01229 
01230   
01231     // Construct from an initialization string.
01232     template <class Type>
01233     Array3D<Type>::
01234     Array3D(const std::string& inputString)
01235       : m_shape0(0),
01236         m_shape1(0),
01237         m_shape2(0),
01238         m_shape1Times2(0),
01239         m_size(0),
01240         m_dataPtr(0),
01241         m_refCountPtr(0),
01242         m_isAllocated(false)
01243     {
01244       // We'll use the stream input operator to parse the string.
01245       std::istringstream inputStream(inputString);
01246 
01247       // Now read the string into an array.
01248       Array3D<Type> inputArray;
01249       inputStream >> inputArray;
01250       if(!inputStream) {
01251         std::ostringstream message;
01252         message << "Couldn't parse input string: \"" << inputString << "\".";
01253         DLR_THROW3(ValueException, "Array3D::Array3D(const std::string&)",
01254                    message.str().c_str());                 
01255       }
01256 
01257       // If all went well, copy into *this.
01258       *this = inputArray;
01259     }
01260 
01261 
01262   
01263     /* When copying from a Array3D do a shallow copy */
01264     /* Update reference count if the array we're copying has */
01265     /* valid data. */
01266     template <class Type>
01267     Array3D<Type>::
01268     Array3D(const Array3D<Type>& source)
01269       : m_shape0(source.m_shape0),
01270         m_shape1(source.m_shape1),
01271         m_shape2(source.m_shape2),
01272         m_shape1Times2(source.m_shape1 * source.m_shape2),
01273         m_size(source.m_size),
01274         m_dataPtr(source.m_dataPtr),
01275         m_refCountPtr(source.m_refCountPtr),
01276         m_isAllocated(source.m_isAllocated)
01277     {
01278       if(m_isAllocated) {
01279         ++(*m_refCountPtr);
01280       }
01281     }
01282 
01283 
01284     /* Here's a constructor for getting image data into the array */
01285     /* cheaply. */
01286     template <class Type>
01287     Array3D<Type>::
01288     Array3D(size_t arrayShape0, size_t arrayShape1, size_t arrayShape2, Type* const dataPtr)
01289       : m_shape0(arrayShape0),
01290         m_shape1(arrayShape1),
01291         m_shape2(arrayShape2),
01292         m_shape1Times2(arrayShape1 * arrayShape2),
01293         m_size(arrayShape0 * arrayShape1 * arrayShape2),
01294         m_dataPtr(dataPtr),
01295         m_refCountPtr(0),
01296         m_isAllocated(false)
01297     {
01298       // empty
01299     }
01300 
01301   
01302     template <class Type>
01303     Array3D<Type>::
01304     ~Array3D()
01305     {
01306       deAllocate();
01307     }
01308 
01309 
01310     template <class Type>
01311     inline void Array3D<Type>::
01312     checkDimension(size_t arrayShape0, size_t arrayShape1, size_t arrayShape2) const
01313     {
01314 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01315       if(arrayShape0 != this->shape0()
01316          || arrayShape1 != this->shape1()
01317          || arrayShape2 != this->shape2()){
01318         std::ostringstream message;
01319         message << "Size mismatch: required dimension is ("
01320                 << arrayShape0 << ", " << arrayShape1 << ", " << arrayShape2 << ") "
01321                 << " while *this has dimension "
01322                 << this->shape0() << ", " << this->shape1() << ", "
01323                 << this->shape2() << ") ";
01324         DLR_THROW(IndexException, "Array3D::checkDimension()",
01325                   message.str().c_str());
01326       }
01327 #endif
01328     }
01329 
01330 
01331     template <class Type>
01332     Array3D<Type> Array3D<Type>::
01333     copy() const
01334     {
01335       Array3D<Type> newArray(m_shape0, m_shape1, m_shape2);
01336       newArray.copy(*this);
01337       return newArray;
01338     }
01339 
01340   
01341     template <class Type> template <class Type2>
01342     void Array3D<Type>::
01343     copy(const Array3D<Type2>& source)
01344     {
01345       if(source.size() != m_size) {
01346         std::ostringstream message;
01347         message << "Mismatched array sizes. Source array has "
01348                 << source.size() << " elements, while destination array has "
01349                 << m_size << " elements.";
01350         DLR_THROW3(ValueException, "Array3D::copy(const Array3D&)",
01351                    message.str().c_str());
01352       }
01353       if(m_size != 0) {
01354         this->copy(source.data());
01355       }
01356     }
01357 
01358   
01359     template <class Type> template <class Type2>
01360     void Array3D<Type>::
01361     copy(const Type2* dataPtr)
01362     {
01363       if (dataPtr == 0) {
01364         DLR_THROW(ValueException, "Array3D::copy(const Type2*)",
01365                   "Argument is a NULL pointer.");
01366       }
01367       std::copy(dataPtr, dataPtr + m_size, m_dataPtr);
01368     }
01369 
01370   
01371     // This member function sets the value of the array from an input
01372     // stream.
01373     template <class Type>
01374     std::istream&
01375     Array3D<Type>::
01376     readFromStream(std::istream& inputStream)
01377     {
01378       // Most of the time, InputType will be the same as Type.
01379       typedef typename NumericTraits<Type>::TextOutputType InputType;
01380 
01381       // If stream is in a bad state, we can't read from it.
01382       if (!inputStream){
01383         return inputStream;
01384       }
01385     
01386       // It's a lot easier to use a try block than to be constantly
01387       // testing whether the IO has succeeded, so we tell inputStream to
01388       // complain if anything goes wrong.
01389       std::ios_base::iostate oldExceptionState = inputStream.exceptions();
01390       inputStream.exceptions(
01391         std::ios_base::badbit | std::ios_base::failbit | std::ios_base::eofbit);
01392 
01393       // Now on with the show.
01394       try{
01395         // Construct an InputStream instance so we can use our
01396         // convenience functions.
01397         InputStream stream(inputStream);
01398 
01399         // We won't require the input format to start with "Array3D(", but
01400         // if it does we read it here.
01401         bool foundIntro = false;
01402         if(stream.peek() == ioIntro()[0]) {
01403           foundIntro = true;
01404           stream.expect(ioIntro());
01405         }
01406 
01407         // OK.  We've dispensed with the intro.  What's left should be of
01408         // the format "[row, row, row, ...]".  We require the square
01409         // brackets to be there.
01410         stream.expect(ioOpening);
01411 
01412         // Read the data.  We'll use the Array1D<Type> stream operator to
01413         // read each row.
01414         Array2D<Type> inputValue;
01415         std::vector< Array2D<Type> > inputBuffer;
01416         while(1) {
01417           // Read the next row.
01418           stream >> inputValue;
01419           inputBuffer.push_back(inputValue);
01420 
01421           // Read the separator, or else the closing character.
01422           char inChar = 0;
01423           stream >> inChar;
01424           if(inChar == ioClosing) {
01425             // Found a closing.  Stop here.
01426             break;
01427           }
01428           if(inChar != ioSeparator) {
01429             // Missing separator?  Fail here.
01430             stream.clear(std::ios_base::failbit);
01431           }
01432         }
01433     
01434         // If we found an intro, we expect the corresponding outro.
01435         if(foundIntro) {
01436           stream.expect(ioOutro());
01437         }
01438 
01439         // Now we're done with all of the parsing, verify that all slices
01440         // have the same number of rows and columns.
01441         size_t arrayShape0 = inputBuffer.size();
01442         size_t arrayShape1 = ((arrayShape0 != 0) ? inputBuffer[0].rows() : 0);
01443         size_t arrayShape2 = ((arrayShape0 != 0) ? inputBuffer[0].columns() : 0);
01444         for(size_t index = 1; index < arrayShape0; ++index) {
01445           if((inputBuffer[index].rows() != arrayShape1)
01446              || (inputBuffer[index].columns() != arrayShape2)) {
01447             // Inconsistent slice sizes!  Fail here.
01448             stream.clear(std::ios_base::failbit);
01449           }
01450         }
01451 
01452         // And finally, copy the data.
01453         size_t sliceSize = arrayShape1 * arrayShape2;
01454         this->reinit(arrayShape0, arrayShape1, arrayShape2);
01455         for(size_t index = 0; index < arrayShape0; ++index) {
01456           std::copy(inputBuffer[index].begin(), inputBuffer[index].end(),
01457                     this->begin() + (index * sliceSize));
01458         }
01459       } catch(std::ios_base::failure) {
01460         // Empty
01461       }
01462       inputStream.exceptions(oldExceptionState);
01463       return inputStream;
01464     }
01465 
01466   
01467     template <class Type>
01468     void Array3D<Type>::
01469     reinit(size_t arrayShape0, size_t arrayShape1, size_t arrayShape2)
01470     {
01471       this->deAllocate();
01472       this->m_shape0 = arrayShape0;
01473       this->m_shape1 = arrayShape1;
01474       this->m_shape2 = arrayShape2;
01475       this->allocate();
01476     }
01477 
01478 
01479     template <class Type>
01480     void Array3D<Type>::
01481     reinitIfNecessary(size_t arrayShape0, size_t arrayShape1,
01482                       size_t arrayShape2)
01483     {
01484       if(this->size() != arrayShape0 * arrayShape1 * arrayShape2) {
01485         this->reinit(arrayShape0, arrayShape1, arrayShape2);
01486       } else {
01487         if(this->shape0() != arrayShape0
01488            || this->shape1() != arrayShape1) {
01489           this->reshape(arrayShape0, arrayShape1, arrayShape2);
01490         }
01491       }
01492     }
01493 
01494 
01495     template <class Type>
01496     void Array3D<Type>::
01497     reshape(int arrayShape0, int arrayShape1, int arrayShape2)
01498     {
01499       if ((arrayShape0 * arrayShape1 * arrayShape2 != 0)){
01500         // If one axis is specified as -1, it will be automatically 
01501         // chosen to match the number of elements in the array.
01502         if((arrayShape0 == -1) && (arrayShape1 != -1) && (arrayShape2 != -1)) {
01503           arrayShape0 = static_cast<int>(this->size()) / (arrayShape1 * arrayShape2);
01504         } else if((arrayShape1 == -1) && (arrayShape0 != -1) && (arrayShape2 != -1)) {
01505           arrayShape1 = static_cast<int>(this->size()) / (arrayShape0 * arrayShape2);
01506         } else if((arrayShape2 == -1) && (arrayShape1 != -1) && (arrayShape0 != -1)) {
01507           arrayShape2 = static_cast<int>(this->size()) / (arrayShape1 * arrayShape0);
01508         }
01509       }
01510       if((arrayShape0 * arrayShape1 * arrayShape2) != static_cast<int>(this->size())) {
01511         std::ostringstream message;
01512         message << "Can't reshape a(n) " << this->size()
01513                 << " element array to be " << arrayShape0 << " x " << arrayShape1
01514                 << " x " << arrayShape2 << ".";
01515         DLR_THROW(ValueException, "Array3D::reshape()", message.str().c_str());
01516       }
01517 
01518       m_shape0 = static_cast<size_t>(arrayShape0);
01519       m_shape1 = static_cast<size_t>(arrayShape1);
01520       m_shape2 = static_cast<size_t>(arrayShape2);
01521       m_shape1Times2 = arrayShape1 * arrayShape2;
01522     }
01523 
01524   
01525     template <class Type>
01526     Array1D<size_t> Array3D<Type>::
01527     shape() const
01528     {
01529       Array1D<size_t> rc(3);
01530       rc(0) = this->shape0();
01531       rc(1) = this->shape1();
01532       rc(2) = this->shape2();
01533       return rc;
01534     }
01535 
01536 
01537     template <class Type>
01538     size_t Array3D<Type>::
01539     shape(size_t axis) const
01540     {
01541       switch(axis) {
01542       case 0:
01543         return this->shape0();
01544         break;
01545       case 1:
01546         return this->shape1();
01547         break;
01548       case 2:
01549         return this->shape2();
01550         break;
01551       default:
01552         std::ostringstream message;
01553         message << "Invalid Axis: "<< axis << ".";
01554         DLR_THROW(ValueException, "Array3D::shape(size_t)",
01555                   message.str().c_str());
01556         break;
01557       }
01558       return 0;                     // To keep the darn compiler happy.
01559     }
01560 
01561 
01562     template <class Type>
01563     Array2D<Type>
01564     Array3D<Type>::
01565     slice(size_t index0)
01566     {
01567       this->checkBounds(index0, 0, 0);
01568       return Array2D<Type>(
01569         m_shape1, m_shape2, m_dataPtr + (index0 * m_shape1Times2));
01570     }
01571 
01572   
01573     template <class Type>
01574     const Array2D<Type>
01575     Array3D<Type>::
01576     slice(size_t index0) const
01577     {
01578       this->checkBounds(index0, 0, 0);
01579       return Array2D<Type>(
01580         m_shape1, m_shape2, m_dataPtr + (index0 * m_shape1Times2));
01581     }
01582 
01583   
01584     template <class Type>
01585     Array3D<Type>& Array3D<Type>::
01586     operator=(const Array3D<Type>& source)
01587     {
01588       // Check for self-assignment
01589       if(&source != this) {
01590         this->deAllocate();
01591         m_shape0 = source.m_shape0;
01592         m_shape1 = source.m_shape1;
01593         m_shape2 = source.m_shape2;
01594         m_shape1Times2 = source.m_shape1Times2;
01595         m_size = source.m_size;
01596         m_dataPtr = source.m_dataPtr;
01597         m_refCountPtr = source.m_refCountPtr;
01598         m_isAllocated = source.m_isAllocated;
01599         if(m_isAllocated) {
01600           ++(*m_refCountPtr);
01601         }
01602       }
01603       return *this;
01604     }
01605 
01606 
01607     template <class Type>
01608     Array3D<Type>& Array3D<Type>::
01609     operator=(Type value)
01610     {
01611       std::fill(m_dataPtr, m_dataPtr + m_size, value);
01612       return *this;
01613     }
01614 
01615 
01616     template <class Type> template <class Type2>
01617     Array3D<Type>& Array3D<Type>::
01618     operator*=(const Array3D<Type2>& arg)
01619     {
01620       if(m_size != arg.size()) {
01621         std::ostringstream message;
01622         message << "Mismatched array sizes. Argument array has "
01623                 << arg.size() << " elements, while destination array has "
01624                 << m_size << " elements.";
01625         DLR_THROW(ValueException, "Array3D::operator*=()",
01626                   message.str().c_str());
01627       }
01628       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01629                      std::multiplies<Type>());
01630       return *this;
01631     }
01632 
01633 
01634     template <class Type> template <class Type2>
01635     Array3D<Type>& Array3D<Type>::
01636     operator/=(const Array3D<Type2>& arg)
01637     {
01638       if(m_size != arg.size()) {
01639         std::ostringstream message;
01640         message << "Mismatched array sizes. Argument array has "
01641                 << arg.size() << " elements, while destination array has "
01642                 << m_size << " elements.";
01643         DLR_THROW(ValueException, "Array3D::operator/=()",
01644                   message.str().c_str());
01645       }
01646       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01647                      std::divides<Type>());
01648       return *this;
01649     }
01650 
01651 
01652     template <class Type> template <class Type2>
01653     Array3D<Type>& Array3D<Type>::
01654     operator+=(const Array3D<Type2>& arg)
01655     {
01656       if(m_size != arg.size()) {
01657         std::ostringstream message;
01658         message << "Mismatched array sizes. Argument array has "
01659                 << arg.size() << " elements, while destination array has "
01660                 << m_size << " elements.";
01661         DLR_THROW(ValueException, "Array3D::operator+=()",
01662                   message.str().c_str());
01663       }
01664       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01665                      std::plus<Type>());
01666       return *this;
01667     }
01668 
01669 
01670     template <class Type> template <class Type2>
01671     Array3D<Type>& Array3D<Type>::
01672     operator-=(const Array3D<Type2>& arg)
01673     {
01674       if(m_size != arg.size()) {
01675         std::ostringstream message;
01676         message << "Mismatched array sizes. Argument array has "
01677                 << arg.size() << " elements, while destination array has "
01678                 << m_size << " elements.";
01679         DLR_THROW(ValueException, "Array3D::operator-=()",
01680                   message.str().c_str());
01681       }
01682       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01683                      std::minus<Type>());
01684       return *this;
01685     }
01686 
01687 
01688     template <class Type>
01689     Array3D<Type>& Array3D<Type>::
01690     operator+=(const Type arg)
01691     {
01692       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01693                      std::bind2nd(std::plus<Type>(), arg));
01694       return *this;
01695     }
01696 
01697 
01698     template <class Type>
01699     Array3D<Type>& Array3D<Type>::
01700     operator-=(const Type arg)
01701     {
01702       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01703                      std::bind2nd(std::minus<Type>(), arg));
01704       return *this;
01705     }
01706 
01707 
01708     template <class Type>
01709     Array3D<Type>& Array3D<Type>::
01710     operator*=(const Type arg)
01711     {
01712       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01713                      std::bind2nd(std::multiplies<Type>(), arg));
01714       return *this;
01715     }
01716 
01717 
01718     template <class Type>
01719     Array3D<Type>& Array3D<Type>::
01720     operator/=(const Type arg)
01721     {
01722       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01723                      std::bind2nd(std::divides<Type>(), arg));
01724       return *this;
01725     }
01726 
01727 
01728     template <class Type>
01729     void Array3D<Type>::
01730     allocate()
01731     {
01732       m_shape1Times2  = m_shape1 * m_shape2;
01733       m_size = m_shape0 * m_shape1 * m_shape2;
01734       if(m_shape0 > 0 && m_shape1 > 0 && m_shape2 > 0) {
01735         m_dataPtr = new(Type[m_size]); // should throw an exeption
01736         m_refCountPtr = new size_t;      // if we're out of memory.
01737         *m_refCountPtr = 1;
01738         m_isAllocated = true;
01739         return;
01740       }
01741       m_dataPtr = 0;
01742       m_refCountPtr = 0;
01743       m_isAllocated = false;
01744       return;
01745     }
01746 
01747 
01748     template <class Type>
01749     inline void Array3D<Type>::
01750     checkBounds(size_t index) const
01751     {
01752 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01753       if(index >= m_size) {
01754         std::ostringstream message;
01755         message << "Index " << index << " is invalid for a(n) " << m_size
01756                 << " element array.";
01757         DLR_THROW(IndexException, "Array3D::checkBounds(size_t)",
01758                   message.str().c_str());
01759       }
01760 #endif
01761     }
01762 
01763   
01764     template <class Type>
01765     inline void Array3D<Type>::
01766     checkBounds(size_t index0, size_t index1, size_t index2) const
01767     {
01768 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01769       if(index0 >= m_shape0) {
01770         std::ostringstream message;
01771         message << "index0 should be less than " << m_shape0
01772                 << ", but is actually " << index0 << ".";
01773         DLR_THROW3(IndexException, "Array3D::checkBounds()",
01774                    message.str().c_str());
01775       }
01776       if(index1 >= m_shape1) {
01777         std::ostringstream message;
01778         message << "index1 should be less than " << m_shape1
01779                 << ", but is actually " << index1 << ".";
01780         DLR_THROW3(IndexException, "Array3D::checkBounds()",
01781                    message.str().c_str());
01782       }
01783       if(index2 >= m_shape2) {
01784         std::ostringstream message;
01785         message << "index2 should be less than " << m_shape2
01786                 << ", but is actually " << index2 << ".";
01787         DLR_THROW3(IndexException, "Array3D::checkBounds()",
01788                    message.str().c_str());
01789       }
01790 #endif
01791     }
01792 
01793   
01794     template <class Type>
01795     void Array3D<Type>::
01796     deAllocate()
01797     {
01798       if(m_isAllocated == true) {
01799         if(--(*m_refCountPtr) == 0) {
01800           delete[] m_dataPtr;
01801           delete m_refCountPtr;
01802           m_isAllocated = false;
01803           m_dataPtr = 0;
01804           m_refCountPtr = 0;
01805         }
01806       } else {
01807         m_dataPtr = 0;
01808         m_refCountPtr = 0;
01809       }
01810     }
01811 
01812   
01813     /* Non-member functions which will ultimately wind up in a different file */
01814 //   template <class Type> 
01815 //   Type maximum(const Array3D<Type>& array)
01816 //   {
01817 //     return *std::max_element(array.data(), array.data() + array.size());
01818 //   }
01819 
01820 //   template <class Type> 
01821 //   Type minimum(const Array3D<Type>& array)
01822 //   {
01823 //     return *std::min_element(array.data(), array.data() + array.size());
01824 //   }
01825 
01826 //   template <class Type> 
01827 //   Type sum(const Array3D<Type>& array)
01828 //   {
01829 //     return std::accumulate(array.data(), array.data() + array.size(),
01830 //                            static_cast<Type>(0));
01831 //   }
01832   
01833     template <class Type>
01834     Array3D<Type> operator+(const Array3D<Type>& array0,
01835                             const Array3D<Type>& array1)
01836     {
01837       if((array0.shape0() != array1.shape0())
01838          || (array0.shape1() != array1.shape1())        
01839          || (array0.shape2() != array1.shape2())) {
01840         std::ostringstream message;
01841         message << "Array sizes do not match.  Array0 is "
01842                 << array0.shape0() << " x " << array0.shape1()
01843                 << " x " << array0.shape2()
01844                 << ", while array1 is "
01845                 << array1.shape0() << " x " << array1.shape1()
01846                 << " x " << array1.shape2() << ".";
01847         DLR_THROW(ValueException, "Array3D::operator+()", message.str().c_str());
01848       }
01849       Array3D<Type> result(array0.shape0(), array0.shape1(), array0.shape2());
01850       std::transform(array0.begin(), array0.end(), array1.begin(),
01851                      result.begin(), std::plus<Type>());
01852       return result;
01853     }
01854 
01855 
01856     template <class Type>
01857     Array3D<Type> operator-(const Array3D<Type>& array0,
01858                             const Array3D<Type>& array1)
01859     {
01860       if((array0.shape0() != array1.shape0())
01861          || (array0.shape1() != array1.shape1())        
01862          || (array0.shape2() != array1.shape2())) {
01863         std::ostringstream message;
01864         message << "Array sizes do not match.  Array0 is "
01865                 << array0.shape0() << " x " << array0.shape1()
01866                 << " x " << array0.shape2()
01867                 << ", while array1 is "
01868                 << array1.shape0() << " x " << array1.shape1()
01869                 << " x " << array1.shape2() << ".";
01870         DLR_THROW(ValueException, "Array3D::operator-()", message.str().c_str());
01871       }
01872       Array3D<Type> result(array0.shape0(), array0.shape1(), array0.shape2());
01873       std::transform(array0.begin(), array0.end(), array1.begin(),
01874                      result.begin(), std::minus<Type>());
01875       return result;
01876     }
01877 
01878   
01879     template <class Type>
01880     Array3D<Type> operator*(const Array3D<Type>& array0,
01881                             const Array3D<Type>& array1)
01882     {
01883       if((array0.shape0() != array1.shape0())
01884          || (array0.shape1() != array1.shape1())        
01885          || (array0.shape2() != array1.shape2())) {
01886         std::ostringstream message;
01887         message << "Array sizes do not match.  Array0 is "
01888                 << array0.shape0() << " x " << array0.shape1()
01889                 << " x " << array0.shape2()
01890                 << ", while array1 is "
01891                 << array1.shape0() << " x " << array1.shape1()
01892                 << " x " << array1.shape2() << ".";
01893         DLR_THROW(ValueException, "Array3D::operator*()", message.str().c_str());
01894       }
01895       Array3D<Type> result(array0.shape0(), array0.shape1(), array0.shape2());
01896       std::transform(array0.begin(), array0.end(), array1.begin(),
01897                      result.begin(), std::multiplies<Type>());
01898       return result;
01899     }
01900   
01901 
01902     template <class Type>
01903     Array3D<Type> operator/(const Array3D<Type>& array0,
01904                             const Array3D<Type>& array1)
01905     {
01906       if((array0.shape0() != array1.shape0())
01907          || (array0.shape1() != array1.shape1())        
01908          || (array0.shape2() != array1.shape2())) {
01909         std::ostringstream message;
01910         message << "Array sizes do not match.  Array0 is "
01911                 << array0.shape0() << " x " << array0.shape1()
01912                 << " x " << array0.shape2()
01913                 << ", while array1 is "
01914                 << array1.shape0() << " x " << array1.shape1()
01915                 << " x " << array1.shape2() << ".";
01916         DLR_THROW(ValueException, "Array3D::operator/()", message.str().c_str());
01917       }
01918       Array3D<Type> result(array0.shape0(), array0.shape1(), array0.shape2());
01919       std::transform(array0.begin(), array0.end(), array1.begin(), result.begin(),
01920                      std::divides<Type>());
01921       return result;
01922     }
01923 
01924 
01925     template <class Type>
01926     Array3D<Type> operator+(const Array3D<Type>& array0, Type scalar)
01927     {
01928       Array3D<Type> result(array0.shape0(), array0.shape1(), array0.shape2());
01929       std::transform(array0.begin(), array0.end(), result.begin(),
01930                      std::bind2nd(std::plus<Type>(), scalar));
01931       return result;
01932     }
01933 
01934 
01935     template <class Type>
01936     Array3D<Type> operator-(const Array3D<Type>& array0, Type scalar)
01937     {
01938       Array3D<Type> result(array0.shape0(), array0.shape1(), array0.shape2()); 
01939       std::transform(array0.begin(), array0.end(), result.begin(),
01940                      std::bind2nd(std::minus<Type>(), scalar));
01941       return result;
01942     }
01943 
01944 
01945     template <class Type>
01946     Array3D<Type> operator*(const Array3D<Type>& array0, Type scalar)
01947     {
01948       Array3D<Type> result(array0.shape0(), array0.shape1(), array0.shape2()); 
01949       std::transform(array0.begin(), array0.end(), result.begin(),
01950                      std::bind2nd(std::multiplies<Type>(), scalar));
01951       return result;
01952     }
01953 
01954 
01955     template <class Type>
01956     Array3D<Type> operator/(const Array3D<Type>& array0, Type scalar)
01957     {
01958       Array3D<Type> result(array0.shape0(), array0.shape1(), array0.shape2()); 
01959       std::transform(array0.begin(), array0.end(), result.begin(),
01960                      std::bind2nd(std::divides<Type>(), scalar));
01961       return result;
01962     }
01963 
01964 
01965     template <class Type>
01966     inline Array3D<Type> operator+(Type scalar, const Array3D<Type>& array0)
01967     {
01968       return array0 + scalar;
01969     }
01970 
01971 
01972     template <class Type>
01973     inline Array3D<Type> operator*(Type scalar, const Array3D<Type>& array0)
01974     {
01975       return array0 * scalar;
01976     }
01977 
01978 
01979     // Elementwise comparison of an Array3D with a constant.
01980     template <class Type>
01981     Array3D<bool>
01982     operator==(const Array3D<Type>& array0, const Type arg)
01983     {
01984       Array3D<bool> result(array0.shape0(), array0.shape1(), array0.shape2());
01985       std::transform(array0.begin(), array0.end(), result.data(),
01986                      std::bind2nd(std::equal_to<Type>(), arg));
01987       return result;
01988     }
01989 
01990     
01991     // Elementwise comparison of an Array3D with another array.
01992     template <class Type>
01993     Array3D<bool>
01994     operator==(const Array3D<Type>& array0, const Array3D<Type>& array1)
01995     {
01996       array0.checkDimension(array1.shape0(), array1.shape1(), array1.shape2());
01997       Array3D<bool> result(array0.shape0(), array0.shape1(), array0.shape2());
01998       std::transform(array0.begin(), array0.end(), array1.begin(),
01999                      result.begin(), std::equal_to<Type>());
02000       return result;
02001     }
02002 
02003     
02004     template <class Type>
02005     Array3D<bool> operator>(const Array3D<Type>& array0, Type arg)
02006     {
02007       Array3D<bool> result(array0.shape0(), array0.shape1(), array0.shape2()); 
02008       std::transform(array0.begin(), array0.end(), result.begin(),
02009                      std::bind2nd(std::greater<Type>(), arg));
02010       return result;
02011     }
02012 
02013 
02014     template <class Type>
02015     Array3D<bool> operator<(const Array3D<Type>& array0, Type arg)
02016     {
02017       Array3D<bool> result(array0.shape0(), array0.shape1(), array0.shape2()); 
02018       std::transform(array0.begin(), array0.end(), result.begin(),
02019                      std::bind2nd(std::less<Type>(), arg));
02020       return result;
02021     }
02022 
02023   
02024     template <class Type>
02025     Array3D<bool> operator>=(const Array3D<Type>& array0, Type arg)
02026     {
02027       Array3D<bool> result(array0.shape0(), array0.shape1(), array0.shape2()); 
02028       std::transform(array0.begin(), array0.end(), result.begin(),
02029                      std::bind2nd(std::greater_equal<Type>(), arg));
02030       return result;
02031     }
02032 
02033   
02034     template <class Type>
02035     Array3D<bool> operator<=(const Array3D<Type>& array0, Type arg)
02036     {
02037       Array3D<bool> result(array0.shape0(), array0.shape1(), array0.shape2()); 
02038       std::transform(array0.begin(), array0.end(), result.begin(),
02039                      std::bind2nd(std::less_equal<Type>(), arg));
02040       return result;
02041     }
02042 
02043 
02044     // This operator outputs a text representation of an Array3D
02045     // instance to a std::ostream.
02046     template <class Type>  
02047     std::ostream& operator<<(std::ostream& stream, const Array3D<Type>& array0)
02048     {
02049       // Most of the time, OutputType will be the same as Type.
02050       typedef typename NumericTraits<Type>::TextOutputType OutputType;
02051 
02052       size_t index0, index1, index2;
02053       stream << "Array3D([";
02054       for(index0 = 0; index0 < array0.shape0(); ++index0) {
02055         if(index0 != 0) {
02056           stream << "         ";
02057         }
02058         stream << "[";
02059         for(index1 = 0; index1 < array0.shape1(); ++index1) {
02060           if(index1 != 0) {
02061             stream << "          ";     
02062           }
02063           stream << "[";
02064           for(index2 = 0; index2 < array0.shape2(); ++index2) {
02065             stream << static_cast<OutputType>(array0(index0, index1, index2));
02066             if(index2 != array0.shape2() - 1) {
02067               stream << ", ";
02068             }
02069           }
02070           stream << "]";
02071           if(index1 != array0.shape1() - 1) {
02072             stream << ",\n";
02073           }     
02074         }
02075         stream << "]";
02076         if(index0 != array0.shape0() - 1) {
02077           stream << ",\n";
02078         }
02079       }
02080       stream << "])\n";
02081       stream.flush();
02082       return stream;
02083     }
02084 
02085 
02086     template <class Type>
02087     std::istream&
02088     operator>>(std::istream& inputStream, Array3D<Type>& array0)
02089     {
02090       return array0.readFromStream(inputStream);
02091     }
02092   
02093   } // namespace numeric
02094 
02095 } // namespace dlr
02096 
02097 #endif /* #ifdef _DLR_ARRAY3D_H_ */

Generated on Wed Nov 25 00:42:41 2009 for dlrUtilities Utility Library by  doxygen 1.5.8