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

Generated on Tue Jun 24 16:48:37 2008 for dlrUtilities Utility Library by  doxygen 1.5.5