[ VIGRA Homepage | Class Index | Function Index | File Index | Main Page ]

details vigra/multi_array.hxx VIGRA

00001 /************************************************************************/
00002 /*                                                                      */
00003 /*               Copyright 2003 by Gunnar Kedenburg                     */
00004 /*       Cognitive Systems Group, University of Hamburg, Germany        */
00005 /*                                                                      */
00006 /*    This file is part of the VIGRA computer vision library.           */
00007 /*    ( Version 1.2.0, Aug 07 2003 )                                    */
00008 /*    You may use, modify, and distribute this software according       */
00009 /*    to the terms stated in the LICENSE file included in               */
00010 /*    the VIGRA distribution.                                           */
00011 /*                                                                      */
00012 /*    The VIGRA Website is                                              */
00013 /*        http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/      */
00014 /*    Please direct questions, bug reports, and contributions to        */
00015 /*        koethe@informatik.uni-hamburg.de                              */
00016 /*                                                                      */
00017 /*  THIS SOFTWARE IS PROVIDED AS IS AND WITHOUT ANY EXPRESS OR          */
00018 /*  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED      */
00019 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
00020 /*                                                                      */
00021 /************************************************************************/
00022 
00023 
00024 #ifndef VIGRA_MULTI_ARRAY_HXX
00025 #define VIGRA_MULTI_ARRAY_HXX
00026 
00027 #include <memory>
00028 #include <algorithm>
00029 #include "vigra/accessor.hxx"
00030 #include "vigra/tinyvector.hxx"
00031 #include "vigra/rgbvalue.hxx"
00032 #include "vigra/basicimageview.hxx"
00033 #include "vigra/imageiterator.hxx"
00034 #include "vigra/numerictraits.hxx"
00035 #include "vigra/multi_iterator.hxx"
00036 #include "vigra/metaprogramming.hxx"
00037 
00038 namespace vigra
00039 {
00040 
00041 namespace detail
00042 {
00043 /********************************************************/
00044 /*                                                      */
00045 /*                    defaultStride                     */
00046 /*                                                      */
00047 /********************************************************/
00048 
00049 /* generates the stride for a gapless shape.
00050 
00051     Namespace: vigra::detail
00052 */
00053 template <unsigned int N>
00054 TinyVector <int, N> defaultStride (const TinyVector <int, N> &shape)
00055 {
00056     TinyVector <int, N> ret;
00057     ret [0] = 1;
00058     for (unsigned int i = 1; i < N; ++i)
00059         ret [i] = ret [i-1] * shape [i-1];
00060     return ret;
00061 }
00062 
00063 /********************************************************/
00064 /*                                                      */
00065 /*                     MaybeStrided                     */
00066 /*                                                      */
00067 /********************************************************/
00068 
00069 /* metatag implementing a test for marking MultiArrays that were
00070     indexed at the zero'th dimension as strided, and all others as
00071     unstrided.
00072 
00073 <b>\#include</b>
00074 "<a href="multi_array_8hxx-source.html">vigra/multi_array.hxx</a>"
00075 
00076 Namespace: vigra::detail
00077 */
00078 template <unsigned int N>
00079 struct MaybeStrided
00080 {
00081     typedef UnstridedArrayTag type;
00082 };
00083 
00084 template <>
00085 struct MaybeStrided <0>
00086 {
00087     typedef StridedArrayTag type;
00088 };
00089 
00090 /********************************************************/
00091 /*                                                      */
00092 /*                MultiIteratorChooser                  */
00093 /*                                                      */
00094 /********************************************************/
00095 
00096 /* metatag implementing a test (by pattern matching) for marking
00097     MultiArrays that were indexed at the zero'th dimension as strided.
00098 
00099 <b>\#include</b>
00100 "<a href="multi_array_8hxx-source.html">vigra/multi_array.hxx</a>"
00101 
00102 Namespace: vigra::detail
00103 */
00104 template <class O>
00105 struct MultiIteratorChooser
00106 {
00107     struct Nil {};
00108 
00109     template <unsigned int N, class T, class REFERENCE, class POINTER>
00110     struct Traverser
00111     {
00112         typedef Nil type;
00113     };
00114 };
00115 
00116 /********************************************************/
00117 /*                                                      */
00118 /*       MultiIteratorChooser <StridedArrayTag>         */
00119 /*                                                      */
00120 /********************************************************/
00121 
00122 /* specialization of the MultiIteratorChooser for strided arrays.
00123 
00124 <b>\#include</b>
00125 "<a href="multi_array_8hxx-source.html">vigra/multi_array.hxx</a>"
00126 
00127 Namespace: vigra::detail
00128 */
00129 template <>
00130 struct MultiIteratorChooser <StridedArrayTag>
00131 {
00132     template <unsigned int N, class T, class REFERENCE, class POINTER>
00133     struct Traverser
00134     {
00135         typedef StridedMultiIterator <N, T, REFERENCE, POINTER> type;
00136     };
00137 };
00138 
00139 /********************************************************/
00140 /*                                                      */
00141 /*      MultiIteratorChooser <UnstridedArrayTag>        */
00142 /*                                                      */
00143 /********************************************************/
00144 
00145 /* specialization of the MultiIteratorChooser for unstrided arrays.
00146 
00147 <b>\#include</b>
00148 "<a href="multi_array_8hxx-source.html">vigra/multi_array.hxx</a>"
00149 
00150 Namespace: vigra::detail
00151 */
00152 template <>
00153 struct MultiIteratorChooser <UnstridedArrayTag>
00154 {
00155     template <unsigned int N, class T, class REFERENCE, class POINTER>
00156     struct Traverser
00157     {
00158         typedef MultiIterator <N, T, REFERENCE, POINTER> type;
00159     };
00160 };
00161 
00162 } // namespace detail
00163 
00164 /********************************************************/
00165 /*                                                      */
00166 /*                     MultiArrayView                   */
00167 /*                                                      */
00168 /********************************************************/
00169 
00170 // forward declaration
00171 template <unsigned int N, class T, class C = UnstridedArrayTag>
00172 class MultiArrayView;
00173 template <unsigned int N, class T, class A = std::allocator<T> >
00174 class MultiArray;
00175 
00176 /** \brief Base class for, and view to, \ref vigra::MultiArray.
00177 
00178 This class implements the interface of both MultiArray and MultiArrayView.
00179 By default, MultiArrayViews are tagged as unstrided. I necessary, strided arrays are
00180 constructed automatically by calls to a variant of the bind...() function.
00181 
00182 <b>\#include</b>
00183 "<a href="multi_array_8hxx-source.html">vigra/multi_array.hxx</a>"
00184 
00185 Namespace: vigra
00186 */
00187 
00188 template <unsigned int N, class T, class C>
00189 class MultiArrayView
00190 {
00191 public:
00192 
00193         /** the array's actual dimensionality.
00194             This ensures that MultiArrayView can also be used for 
00195             scalars (that is, when <tt>N == 0</tt>). Calculated as:<br>
00196             \code
00197             actual_dimension = (N==0) ? 1 : N
00198             \endcode
00199          */
00200     enum ActualDimension { actual_dimension = (N==0) ? 1 : N };
00201 
00202         /** the array's value type
00203          */
00204     typedef T value_type;
00205 
00206         /** reference type (result of operator[])
00207          */
00208     typedef value_type &reference;
00209 
00210         /** const reference type (result of operator[] const)
00211          */
00212     typedef const value_type &const_reference;
00213 
00214         /** pointer type
00215          */
00216     typedef value_type *pointer;
00217 
00218         /** const pointer type
00219          */
00220     typedef const value_type *const_pointer;
00221 
00222         /** size type
00223          */
00224     typedef TinyVector <int, actual_dimension> size_type;
00225 
00226         /** difference type (used for offsetting)
00227          */
00228     typedef TinyVector <int, actual_dimension> difference_type;
00229 
00230         /** traverser (MultiIterator) type
00231          */
00232     typedef typename detail::MultiIteratorChooser <
00233         C>::template Traverser <actual_dimension, T, T &, T *>::type traverser;
00234 
00235         /** const traverser (MultiIterator) type
00236          */
00237     typedef typename detail::MultiIteratorChooser <
00238         C>::template Traverser <actual_dimension, T, T const &, T const *>::type const_traverser;
00239 
00240         /** the view type associated with this array.
00241          */
00242     typedef MultiArrayView <N, T, C> view_type;
00243 
00244         /** the matrix type associated with this array.
00245          */
00246     typedef MultiArray <N, T> matrix_type;
00247 
00248 protected:
00249 
00250         /** the strides (offset of a sample to the next) for every dimension
00251             are stored here.
00252         */
00253     difference_type m_stride;
00254 
00255         /** the shape of the image pointed to is stored here.
00256          */
00257     difference_type m_shape;
00258 
00259         /** pointer to the image.
00260          */
00261     pointer m_ptr;
00262 
00263 private:
00264 
00265         /** traverse an array element-by-element by using a difference_type
00266          *  object as access coordinates.
00267          */
00268     bool inc_navigator (difference_type &nav)
00269     {
00270         // essentially, this is nothing more than incrementing a number
00271         // in radix representation up to a certain limit, the shape.
00272         int carry = 1;
00273         for (unsigned int d = 0; d < actual_dimension; ++d) {
00274             if (nav [d] + carry < m_shape [d]) {
00275                 nav [d] += carry;
00276                 return true;
00277             } else {
00278                 nav [d] = 0;
00279             }
00280         }
00281         return false;
00282     }
00283 
00284 public:
00285 
00286         /** default constructor: create an empty image of size 0.
00287          */
00288     MultiArrayView ()
00289         : m_shape (0), m_stride (0), m_ptr (0)
00290     {}
00291 
00292 
00293         /** construct from shape and pointer
00294          */
00295     MultiArrayView (const difference_type &shape, pointer ptr);
00296 
00297         /** construct from shape, strides (offset of a sample to the next)
00298             for every dimension) and pointer
00299          */
00300     MultiArrayView (const difference_type &shape,
00301                     const difference_type &stride,
00302                     pointer ptr);
00303 
00304         /** array access.
00305          */
00306     reference operator[] (const difference_type &d)
00307     {
00308         return m_ptr [dot (d, m_stride)];
00309     }
00310 
00311         /** array access.
00312          */
00313     const_reference operator[] (const difference_type &d) const
00314     {
00315         return m_ptr [dot (d, m_stride)];
00316     }
00317 
00318         /** 1D array access. Use only if N == 1.
00319          */
00320     reference operator() (int x)
00321     {
00322         return m_ptr [m_stride[0]*x];
00323     }
00324 
00325         /** 2D array access. Use only if N == 2.
00326          */
00327     reference operator() (int x, int y)
00328     {
00329         return m_ptr [m_stride[0]*x + m_stride[1]*y];
00330     }
00331 
00332         /** 3D array access. Use only if N == 3.
00333          */
00334     reference operator() (int x, int y, int z)
00335     {
00336         return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z];
00337     }
00338 
00339         /** 4D array access. Use only if N == 4.
00340          */
00341     reference operator() (int x, int y, int z, int u)
00342     {
00343         return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u];
00344     }
00345 
00346         /** 5D array access. Use only if N == 5.
00347          */
00348     reference operator() (int x, int y, int z, int u, int v)
00349     {
00350         return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u + m_stride[4]*v];
00351     }
00352 
00353         /** 1D const array access. Use only if N == 1.
00354          */
00355     const_reference operator() (int x) const
00356     {
00357         return m_ptr [m_stride[0]*x];
00358     }
00359 
00360         /** 2D const array access. Use only if N == 2.
00361          */
00362     const_reference operator() (int x, int y) const
00363     {
00364         return m_ptr [m_stride[0]*x + m_stride[1]*y];
00365     }
00366 
00367         /** 3D const array access. Use only if N == 3.
00368          */
00369     const_reference operator() (int x, int y, int z) const
00370     {
00371         return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z];
00372     }
00373 
00374         /** 4D const array access. Use only if N == 4.
00375          */
00376     const_reference operator() (int x, int y, int z, int u) const
00377     {
00378         return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u];
00379     }
00380 
00381         /** 5D const array access. Use only if N == 5.
00382          */
00383     const_reference operator() (int x, int y, int z, int u, int v) const
00384     {
00385         return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u + m_stride[4]*v];
00386     }
00387 
00388 
00389 #if 0
00390         /** shape assignment.
00391          */
00392     template <class CN>
00393     reference operator= (const MultiArrayView <N, T, CN>& rhs)
00394     {
00395         assert (shape () == rhs.shape ());
00396         difference_type nav;
00397         if (shape () != nav)
00398             (*this) [nav] = rhs [nav];
00399         while (inc_navigator (nav))
00400             (*this) [nav] = rhs [nav];
00401     }
00402 #endif /* #if 0 */
00403 
00404     
00405 #ifndef NO_OUT_OF_LINE_MEMBER_TEMPLATES
00406         /** bind the M outmost dimensions to certain indices.
00407             this reduces the dimensionality of the image to
00408             min { 1, N-M }
00409         */
00410     template <unsigned int M>
00411     MultiArrayView <N-M, T, C> bindOuter (const TinyVector <int, M> &d) const;
00412 
00413         /** bind the M innermost dimensions to certain indices.
00414             this reduces the dimensionality of the image to
00415             min { 1, N-M }
00416         */
00417     template <unsigned int M>
00418     MultiArrayView <N-M, T, StridedArrayTag>
00419     bindInner (const TinyVector <int, M> &d) const;
00420     
00421         /** bind dimension M to index d.
00422             this reduces the dimensionality of the image to
00423             min { 1, N-1 }
00424          */
00425     template <unsigned int M>
00426     MultiArrayView <N-1, T, typename detail::MaybeStrided <M>::type >
00427     bind (int d) const;
00428 #else
00429     template <unsigned int M>
00430     MultiArrayView <N-M, T, C> bindOuter (const TinyVector <int, M> &d) const
00431     {
00432         return bindOuterImpl(*this, d);
00433     }
00434  
00435     template <unsigned int M>
00436     MultiArrayView <N-M, T, StridedArrayTag>
00437     bindInner (const TinyVector <int, M> &d) const
00438     {
00439         return bindInnerImpl(*this, d);
00440     }
00441 
00442     template <unsigned int M>
00443     MultiArrayView <N-1, T, typename detail::MaybeStrided <M>::type >
00444     bind (int d) const
00445     {
00446         return bindImpl<M>(*this, d);
00447     }
00448 #endif
00449 
00450         /** bind the outmost dimension to a certain index.
00451             this reduces the dimensionality of the image to
00452             min { 1, N-1 }
00453         */
00454     MultiArrayView <N-1, T, C> bindOuter (int d) const;
00455     
00456         /** bind the innermost dimension to a certain index.
00457             this reduces the dimensionality of the image to
00458             min { 1, N-1 }
00459         */
00460     MultiArrayView <N-1, T, StridedArrayTag> bindInner (int d) const;
00461 
00462         /** bind dimension m to index d.
00463             this reduces the dimensionality of the image to
00464             min { 1, N-1 }
00465          */
00466     MultiArrayView <N-1, T, StridedArrayTag>
00467     bindAt (int m, int d) const;
00468 
00469         /** bind dimension m to index d.
00470             this reduces the dimensionality of the image to
00471             min { 1, N-1 }
00472          */
00473     MultiArrayView <N-1, T, StridedArrayTag>
00474     bindRow (int d) const;
00475 
00476         /** bind dimension m to index d.
00477             this reduces the dimensionality of the image to
00478             min { 1, N-1 }
00479          */
00480     MultiArrayView <N-1, T, C>
00481     bindColumn (int d) const;
00482 
00483         /** create a rectangular subarray that spans between the
00484             points p and q, where p is in the subarray, q not.
00485         */
00486     MultiArrayView subarray (const difference_type &p,
00487                              const difference_type &q) const
00488     {
00489         const int offset = dot (m_stride, p);
00490         return MultiArrayView (q - p, m_stride, m_ptr + offset);
00491     }
00492 
00493         /** apply an additional striding to the image, thereby reducing
00494             the shape of the array.
00495             for example, multiplying the stride of dimension one by three
00496             turns an appropriately layed out (interleaved) rgb image into
00497             a single band image.
00498         */
00499     MultiArrayView <N, T, StridedArrayTag>
00500     stridearray (const difference_type &s) const
00501     {
00502         difference_type shape = m_shape;
00503         for (unsigned int i = 0; i < actual_dimension; ++i)
00504             shape [i] /= s [i];
00505         return MultiArrayView <N, T, StridedArrayTag>
00506             (shape, m_stride * s, m_ptr);
00507     }
00508 
00509         /** number of the elements in the array.
00510          */
00511     std::size_t elementCount () const
00512     {
00513         return m_shape [actual_dimension-1] * m_stride [actual_dimension-1];
00514     }
00515 
00516         /** return the array's size (same as the shape).
00517          */
00518     const size_type & size () const
00519     {
00520         return m_shape;
00521     }
00522 
00523         /** return the array's shape.
00524          */
00525     const difference_type & shape () const
00526     {
00527         return m_shape;
00528     }
00529 
00530         /** return the array's shape at a certain dimension.
00531          */
00532     int shape (int n) const
00533     {
00534         return m_shape [n];
00535     }
00536 
00537         /** return the array's stride for every dimension.
00538          */
00539     const difference_type & stride () const
00540     {
00541         return m_stride;
00542     }
00543 
00544         /** return the array's stride at a certain dimension.
00545          */
00546     int stride (int n) const
00547     {
00548         return m_stride [n];
00549     }
00550 
00551         /** return the pointer to the image data
00552          */
00553     pointer data () const
00554     {
00555         return m_ptr;
00556     }
00557 
00558         /** returns the N-dimensional MultiIterator pointing
00559             to the first element in every dimension.
00560         */
00561     traverser traverser_begin ()
00562     {
00563         traverser ret (m_ptr, m_stride.begin (), m_shape.begin ());
00564         return ret;
00565     }
00566 
00567         /** returns the N-dimensional MultiIterator pointing
00568             to the const first element in every dimension.
00569         */
00570     const_traverser traverser_begin () const
00571     {
00572         const_traverser ret (m_ptr, m_stride.begin (), m_shape.begin ());
00573         return ret;
00574     }
00575 
00576         /** returns the N-dimensional MultiIterator pointing
00577             beyond the last element in dimension N, and to the
00578             first element in every other dimension.
00579         */
00580     traverser traverser_end ()
00581     {
00582         traverser ret (m_ptr, m_stride.begin (), m_shape.begin ());
00583         ret += m_shape [actual_dimension-1];
00584         return ret;
00585     }
00586 
00587         /** returns the N-dimensional const MultiIterator pointing
00588             beyond the last element in dimension N, and to the
00589             first element in every other dimension.
00590         */
00591     const_traverser traverser_end () const
00592     {
00593         const_traverser ret (m_ptr, m_stride.begin (), m_shape.begin ());
00594         ret += m_shape [actual_dimension-1];
00595         return ret;
00596     }
00597 
00598     view_type view ()
00599     {
00600         return *this;
00601     }
00602 };
00603 
00604 template <unsigned int N, class T, class C>
00605 MultiArrayView <N, T, C>::MultiArrayView (const difference_type &shape,
00606                                           pointer ptr)
00607     : m_shape (shape), m_stride (defaultStride (shape)), m_ptr (ptr)
00608 {}
00609 
00610 template <unsigned int N, class T, class C>
00611 MultiArrayView <N, T, C>::MultiArrayView
00612 (const difference_type &shape, const difference_type &stride, pointer ptr)
00613     : m_shape (shape), m_stride (stride), m_ptr (ptr)
00614 {}
00615 
00616 #ifndef NO_OUT_OF_LINE_MEMBER_TEMPLATES
00617 template <unsigned int N, class T, class C>
00618 template <unsigned int M>
00619 MultiArrayView <N-M, T, C>
00620 MultiArrayView <N, T, C>::bindOuter (const TinyVector <int, M> &d) const
00621 {
00622     TinyVector <int, M> stride;
00623     stride.init (m_stride.begin () + N-M, m_stride.end ());
00624     pointer ptr = m_ptr + dot (d, stride);
00625     static const int NNew = (N-M == 0) ? 1 : N-M;
00626     TinyVector <int, NNew> inner_shape, inner_stride;
00627     if (N-M == 0)
00628     {
00629         inner_shape [0] = 1;
00630         inner_stride [0] = 0;
00631     }
00632     else
00633     {
00634         inner_shape.init (m_shape.begin (), m_shape.end () - M);
00635         inner_stride.init (m_stride.begin (), m_stride.end () - M);
00636     }
00637     return MultiArrayView <N-M, T, C> (inner_shape, inner_stride, ptr);
00638 }
00639 
00640 template <unsigned int N, class T, class C>
00641 template <unsigned int M>
00642 MultiArrayView <N - M, T, StridedArrayTag>
00643 MultiArrayView <N, T, C>::bindInner (const TinyVector <int, M> &d) const
00644 {
00645     TinyVector <int, M> stride;
00646     stride.init (m_stride.begin (), m_stride.end () - N + M);
00647     pointer ptr = m_ptr + dot (d, stride);
00648     static const int NNew = (N-M == 0) ? 1 : N-M;
00649     TinyVector <int, NNew> outer_shape, outer_stride;
00650     if (N-M == 0)
00651     {
00652         outer_shape [0] = 1;
00653         outer_stride [0] = 0;
00654     }
00655     else
00656     {
00657         outer_shape.init (m_shape.begin () + M, m_shape.end ());
00658         outer_stride.init (m_stride.begin () + M, m_stride.end ());
00659     }
00660     return MultiArrayView <N-M, T, StridedArrayTag>
00661         (outer_shape, outer_stride, ptr);
00662 }
00663 
00664 template <unsigned int N, class T, class C>
00665 template <unsigned int M>
00666 MultiArrayView <N-1, T, typename detail::MaybeStrided <M>::type >
00667 MultiArrayView <N, T, C>::bind (int d) const
00668 {
00669     static const int NNew = (N-1 == 0) ? 1 : N-1;
00670     TinyVector <int, NNew> shape, stride;
00671     // the remaining dimensions are 0..n-1,n+1..N-1
00672     if (N-1 == 0)
00673     {
00674         shape[0] = 1;
00675         stride[0] = 0;
00676     }
00677     else
00678     {
00679         std::copy (m_shape.begin (), m_shape.begin () + M, shape.begin ());
00680         std::copy (m_shape.begin () + M+1, m_shape.end (),
00681                    shape.begin () + M);
00682         std::copy (m_stride.begin (), m_stride.begin () + M, stride.begin ());
00683         std::copy (m_stride.begin () + M+1, m_stride.end (),
00684                    stride.begin () + M);
00685     }
00686     return MultiArrayView <N-1, T, typename detail::MaybeStrided <M>::type>
00687         (shape, stride, m_ptr + d * m_stride[M]);
00688 }
00689 
00690 #else // NO_OUT_OF_LINE_MEMBER_TEMPLATES
00691 template <unsigned int N, class T, class C, unsigned int M>
00692 MultiArrayView <N-M, T, C>
00693 bindOuterImpl(MultiArrayView <N, T, C> const & self, const TinyVector <int, M> &d)
00694 {
00695     TinyVector <int, M> stride;
00696     stride.init (self.stride().begin () + N-M, self.stride().end ());
00697     typename MultiArrayView <N, T, C>::pointer ptr = self.data() + dot (d, stride);
00698     static const int NNew = (N-M == 0) ? 1 : N-M;
00699     TinyVector <int, NNew> inner_shape, inner_stride;
00700     if (N-M == 0)
00701     {
00702         inner_shape [0] = 1;
00703         inner_stride [0] = 0;
00704     }
00705     else
00706     {
00707         inner_shape.init (self.shape().begin (), self.shape().end () - M);
00708         inner_stride.init (self.stride().begin (), self.stride().end () - M);
00709     }
00710     return MultiArrayView <N-M, T, C> (inner_shape, inner_stride, ptr);
00711 }
00712 
00713 template <unsigned int N, class T, class C, unsigned int M>
00714 MultiArrayView <N - M, T, StridedArrayTag>
00715 bindInnerImpl(MultiArrayView <N, T, C> const & self, const TinyVector <int, M> &d)
00716 {
00717     TinyVector <int, M> stride;
00718     stride.init (self.stride().begin (), self.stride().end () - N + M);
00719     typename MultiArrayView <N, T, C>::pointer ptr = self.data() + dot (d, stride);
00720     static const int NNew = (N-M == 0) ? 1 : N-M;
00721     TinyVector <int, NNew> outer_shape, outer_stride;
00722     if (N-M == 0)
00723     {
00724         outer_shape [0] = 1;
00725         outer_stride [0] = 0;
00726     }
00727     else
00728     {
00729         outer_shape.init (self.shape().begin () + M, self.shape().end ());
00730         outer_stride.init (self.stride().begin () + M, self.stride().end ());
00731     }
00732     return MultiArrayView <N-M, T, StridedArrayTag>
00733         (outer_shape, outer_stride, ptr);
00734 }
00735 
00736 template <unsigned int M, unsigned int N, class T, class C>
00737 MultiArrayView <N-1, T, typename detail::MaybeStrided <M>::type >
00738 bindImpl(MultiArrayView <N, T, C> const & self, int d)
00739 {
00740     static const int NNew = (N-1 == 0) ? 1 : N-1;
00741     TinyVector <int, NNew> shape, stride;
00742     // the remaining dimensions are 0..n-1,n+1..N-1
00743     if (N-1 == 0)
00744     {
00745         shape[0] = 1;
00746         stride[0] = 0;
00747     }
00748     else
00749     {
00750         std::copy (self.shape().begin (), self.shape().begin () + M, shape.begin ());
00751         std::copy (self.shape().begin () + M+1, self.shape().end (),
00752                    shape.begin () + M);
00753         std::copy (self.stride().begin (), self.stride().begin () + M, stride.begin ());
00754         std::copy (self.stride().begin () + M+1, self.stride().end (),
00755                    stride.begin () + M);
00756     }
00757     return MultiArrayView <N-1, T, typename detail::MaybeStrided <M>::type>
00758         (shape, stride, self.data() + d * self.stride(M));
00759 }
00760 
00761 #endif // NO_OUT_OF_LINE_MEMBER_TEMPLATES
00762 
00763 template <unsigned int N, class T, class C>
00764 MultiArrayView <N - 1, T, C>
00765 MultiArrayView <N, T, C>::bindOuter (int d) const
00766 {
00767     static const int NNew = (N-1 == 0) ? 1 : N-1;
00768     TinyVector <int, NNew> inner_shape, inner_stride;
00769     if (N-1 == 0)
00770     {
00771         inner_shape [0] = 1;
00772         inner_stride [0] = 0;
00773     }
00774     else
00775     {
00776         inner_shape.init (m_shape.begin (), m_shape.end () - 1);
00777         inner_stride.init (m_stride.begin (), m_stride.end () - 1);
00778     }
00779     return MultiArrayView <N-1, T, C> (inner_shape, inner_stride,
00780                                        m_ptr + d * m_stride [N-1]);
00781 }
00782 
00783 template <unsigned int N, class T, class C>
00784 MultiArrayView <N - 1, T, StridedArrayTag>
00785 MultiArrayView <N, T, C>::bindInner (int d) const
00786 {
00787     static const int NNew = (N-1 == 0) ? 1 : N-1;
00788     TinyVector <int, NNew> outer_shape, outer_stride;
00789     if (N-1 == 0)
00790     {
00791         outer_shape [0] = 1;
00792         outer_stride [0] = 0;
00793     }
00794     else
00795     {
00796         outer_shape.init (m_shape.begin () + 1, m_shape.end ());
00797         outer_stride.init (m_stride.begin () + 1, m_stride.end ());
00798     }
00799     return MultiArrayView <N-1, T, StridedArrayTag>
00800         (outer_shape, outer_stride, m_ptr + d * m_stride [0]);
00801 }
00802 
00803 template <unsigned int N, class T, class C>
00804 MultiArrayView <N - 1, T, StridedArrayTag>
00805 MultiArrayView <N, T, C>::bindAt (int n, int d) const
00806 {
00807     vigra_precondition (
00808         n < static_cast <int> (N),
00809         "MultiArrayView <N, T, C>::bindAt(): dimension out of range.");
00810     static const int NNew = (N-1 == 0) ? 1 : N-1;
00811     TinyVector <int, NNew> shape, stride;
00812     // the remaining dimensions are 0..n-1,n+1..N-1
00813     if (N-1 == 0)
00814     {
00815         shape [0] = 1;
00816         stride [0] = 0;
00817     }
00818     else
00819     {
00820         std::copy (m_shape.begin (), m_shape.begin () + n, shape.begin ());
00821         std::copy (m_shape.begin () + n+1, m_shape.end (),
00822                    shape.begin () + n);
00823         std::copy (m_stride.begin (), m_stride.begin () + n, stride.begin ());
00824         std::copy (m_stride.begin () + n+1, m_stride.end (),
00825                    stride.begin () + n);
00826     }
00827     return MultiArrayView <N-1, T, StridedArrayTag>
00828         (shape, stride, m_ptr + d * m_stride[n]);
00829 }
00830 
00831 template <unsigned int N, class T, class C>
00832 MultiArrayView <N-1, T, StridedArrayTag>
00833 MultiArrayView <N, T, C>::bindRow (int d) const
00834 {
00835     return this->bindInner (d);
00836 }
00837 
00838 template <unsigned int N, class T, class C>
00839 MultiArrayView <N-1, T, C>
00840 MultiArrayView <N, T, C>::bindColumn (int d) const
00841 {
00842     return this->bindOuter (d);
00843 }
00844 
00845 /********************************************************/
00846 /*                                                      */
00847 /*                       MultiArray                     */
00848 /*                                                      */
00849 /********************************************************/
00850 
00851 /** \brief Main <TT>MultiArray</TT> class containing the memory
00852     management.
00853 
00854     This class inherits the interface of MultiArrayView, and implements
00855     the memory ownership.
00856     MultiArray's are always unstrided, striding them creates a MultiArrayView.
00857 
00858     <b>\#include</b>
00859     "<a href="multi_array_8hxx-source.html">vigra/multi_array.hxx</a>"
00860 
00861     Namespace: vigra
00862 */
00863 template <unsigned int N, class T, class A /* default already declared above */>
00864 class MultiArray : public MultiArrayView <N, T>
00865 {
00866 
00867 public:
00868 
00869         /** the allocator type used to allocate the memory
00870          */
00871     typedef A allocator_type;
00872 
00873         /** the view type associated with this array.
00874          */
00875     typedef MultiArrayView <N, T> view_type;
00876 
00877         /** the matrix type associated with this array.
00878          */
00879     typedef MultiArray <N, T> matrix_type;
00880 
00881         /** the array's value type
00882          */
00883     typedef typename view_type::value_type value_type;
00884 
00885         /** pointer type
00886          */
00887     typedef typename view_type::pointer pointer;
00888 
00889         /** const pointer type
00890          */
00891     typedef typename view_type::const_pointer const_pointer;
00892 
00893         /** reference type (result of operator[])
00894          */
00895     typedef typename view_type::reference reference;
00896 
00897         /** const reference type (result of operator[] const)
00898          */
00899     typedef typename view_type::const_reference const_reference;
00900 
00901         /** size type
00902          */
00903     typedef typename view_type::size_type size_type;
00904 
00905         /** difference type (used for offsetting)
00906          */
00907     typedef typename view_type::difference_type difference_type;
00908 
00909         /** traverser type
00910          */
00911     typedef typename detail::MultiIteratorChooser <
00912         UnstridedArrayTag>::template Traverser <N, T, T &, T *>::type 
00913     traverser;
00914 
00915         /** traverser type to const data
00916          */
00917     typedef typename detail::MultiIteratorChooser <
00918         UnstridedArrayTag>::template Traverser <N, T, T const &, T const *>::type 
00919     const_traverser;
00920 
00921         /** sequential (random access) iterator type
00922          */
00923     typedef T * iterator;
00924 
00925         /** sequential (random access) const iterator type
00926          */
00927     typedef T * const_iterator;
00928 
00929 protected:
00930 
00931         /** the allocator used to allocate the memory
00932          */
00933     allocator_type m_alloc;
00934 
00935         /** allocate memory for s pixels, write its address into the given
00936             pointer and initialize the pixels with init.
00937         */
00938     void allocate (pointer &ptr, std::size_t s, const_reference init);
00939 
00940         /** allocate memory for s pixels, write its address into the given
00941             pointer and initialize the linearized pixels to the values of init.
00942         */
00943     void allocate (pointer &ptr, std::size_t s, const_pointer init);
00944 
00945         /** deallocate the memory (of length s) starting at the given address.
00946          */
00947     void deallocate (pointer &ptr, std::size_t s);
00948 
00949 public:
00950 
00951         /** default constructor
00952          */
00953     MultiArray ();
00954 
00955         /** construct with given shape
00956          */
00957     MultiArray (const difference_type &shape);
00958 
00959         /** construct from shape with an initial value
00960          */
00961     MultiArray (const difference_type &shape, const_reference init);
00962 
00963         /** construct from shape and copy values from the given array
00964          */
00965     MultiArray (const difference_type &shape, const_pointer init);
00966 
00967         /** copy constructor
00968          */
00969     MultiArray (const MultiArray &rhs);
00970  
00971         /** assignment.<br>
00972             <em>Note:</em> this operation invalidates all dependent objects
00973             (array views and iterators)
00974          */
00975     MultiArray &operator= (const MultiArray &rhs);
00976 
00977         /** destructor
00978          */
00979    ~MultiArray ();
00980 
00981 
00982         /** change the shape and allocate new memory.<br>
00983             <em>Note:</em> this operation invalidates all dependent objects
00984             (array views and iterators)
00985          */
00986     void reshape (const difference_type &shape)
00987     {
00988         reshape (shape, NumericTraits <T>::zero ());
00989     }
00990 
00991         /** change the shape, allocate new memory and initialize it 
00992             with the given value.<br>
00993             <em>Note:</em> this operation invalidates all dependent objects
00994             (array views and iterators)
00995          */
00996     void reshape (const difference_type &shape, const_reference init);
00997 
00998         /** sequential iterator pointing to the first array element.
00999          */
01000     iterator begin ()
01001     {
01002         return data();
01003     }
01004 
01005         /** sequential iterator pointing beyond the last array element.
01006          */
01007     iterator end ()
01008     {
01009         return data() + elementCount();
01010     }
01011 
01012         /** sequential const iterator pointing to the first array element.
01013          */
01014     const_iterator begin () const 
01015     {
01016         return data();
01017     }
01018 
01019         /** sequential const iterator pointing beyond the last array element.
01020          */
01021     const_iterator end () const
01022     {
01023         return data() + elementCount();
01024     }
01025 };
01026 
01027 template <unsigned int N, class T, class A>
01028 MultiArray <N, T, A>::MultiArray ()
01029     : MultiArrayView <N, T> (difference_type (0), difference_type (0), 0)
01030 {}
01031 
01032 template <unsigned int N, class T, class A>
01033 MultiArray <N, T, A>::MultiArray (const difference_type &shape)
01034     : MultiArrayView <N, T> (shape, detail::defaultStride <actual_dimension> (shape), 0)
01035 {
01036     if (N == 0)
01037     {
01038         m_shape [0] = 1;
01039         m_stride [0] = 0;
01040     }
01041     allocate (m_ptr, elementCount (), NumericTraits<T>::zero ());
01042 }
01043 
01044 template <unsigned int N, class T, class A>
01045 MultiArray <N, T, A>::MultiArray (const difference_type &shape,
01046                                   const_reference init)
01047     : MultiArrayView <N, T> (shape, detail::defaultStride <actual_dimension> (shape), 0)
01048 {
01049     if (N == 0)
01050     {
01051         m_shape [0] = 1;
01052         m_stride [0] = 0;
01053     }
01054     allocate (m_ptr, elementCount (), init);
01055 }
01056 
01057 template <unsigned int N, class T, class A>
01058 MultiArray <N, T, A>::MultiArray (const difference_type &shape,
01059                                   const_pointer init)
01060     : MultiArrayView <N, T> (shape, detail::defaultStride <actual_dimension> (shape), 0)
01061 {
01062     if (N == 0)
01063     {
01064         m_shape [0] = 1;
01065         m_stride [0] = 0;
01066     }
01067     allocate (m_ptr, elementCount (), init);
01068 }
01069 
01070 template <unsigned int N, class T, class A>
01071 MultiArray <N, T, A>::MultiArray (const MultiArray &rhs)
01072     : MultiArrayView <N, T> (rhs.m_shape, rhs.m_stride, 0),
01073     m_alloc (rhs.m_alloc)
01074 {
01075     allocate (m_ptr, elementCount (), rhs.data ());
01076 }
01077 
01078 template <unsigned int N, class T, class A>
01079 MultiArray <N, T, A>::~MultiArray ()
01080 {
01081     deallocate (m_ptr, elementCount ());
01082 }
01083 
01084 template <unsigned int N, class T, class A>
01085 MultiArray <N, T, A> &
01086 MultiArray <N, T, A>::operator= (const MultiArray &rhs)
01087 {
01088     if (this == &rhs)
01089         return *this;
01090     pointer new_ptr;
01091     allocate (new_ptr, rhs.elementCount (), rhs.data ());
01092     deallocate (m_ptr, elementCount ());
01093     m_alloc = rhs.m_alloc;
01094     m_shape = rhs.m_shape;
01095     m_stride = rhs.m_stride;
01096     m_ptr = new_ptr;
01097     return *this;
01098 }
01099 
01100 template <unsigned int N, class T, class A>
01101 void MultiArray <N, T, A>::reshape (const difference_type & new_shape,
01102                                     const_reference init)
01103 {
01104     if (N== 0)
01105         return;
01106 
01107     difference_type new_stride = detail::defaultStride <actual_dimension> (new_shape);
01108     std::size_t new_size = new_shape [actual_dimension-1] * new_stride [actual_dimension-1];
01109     T *new_ptr;
01110     allocate (new_ptr, new_size, init);
01111     deallocate (m_ptr, elementCount ());
01112     m_ptr = new_ptr;
01113     m_shape = new_shape;
01114     m_stride = new_stride;
01115 }
01116 
01117 template <unsigned int N, class T, class A>
01118 void MultiArray <N, T, A>::allocate (pointer & ptr, std::size_t s,
01119                                      const_reference init)
01120 {
01121     ptr = m_alloc.allocate (s);
01122     std::size_t i;
01123     try {
01124         for (i = 0; i < s; ++i)
01125             m_alloc.construct (ptr + i, init);
01126     }
01127     catch (...) {
01128         for (std::size_t j = 0; j < i; ++j)
01129             m_alloc.destroy (ptr + j);
01130         m_alloc.deallocate (ptr, s);
01131         throw;
01132     }
01133 }
01134 
01135 template <unsigned int N, class T, class A>
01136 void MultiArray <N, T, A>::allocate (pointer & ptr, std::size_t s,
01137                                      const_pointer init)
01138 {
01139     ptr = m_alloc.allocate (s);
01140     std::size_t i;
01141     try {
01142         for (i = 0; i < s; ++i, ++init)
01143             m_alloc.construct (ptr + i, *init);
01144     }
01145     catch (...) {
01146         for (std::size_t j = 0; j < i; ++j)
01147             m_alloc.destroy (ptr + j);
01148         m_alloc.deallocate (ptr, s);
01149         throw;
01150     }
01151 }
01152 
01153 template <unsigned int N, class T, class A>
01154 void MultiArray <N, T, A>::deallocate (pointer & ptr, std::size_t s)
01155 {
01156     if (ptr == 0)
01157         return;
01158     for (std::size_t i = 0; i < s; ++i)
01159         m_alloc.destroy (ptr + i);
01160     m_alloc.deallocate (ptr, s);
01161     ptr = 0;
01162 }
01163 
01164 template <class T>
01165 BasicImageView <T>
01166 makeBasicImageView (MultiArrayView <2, T, UnstridedArrayTag> &array)
01167 {
01168     return BasicImageView <T> (array.data (), array.shape (0),
01169                                array.shape (1));
01170 }
01171 
01172 template <class T>
01173 BasicImageView <T>
01174 makeBasicImageView (MultiArray <3, T> &array)
01175 {
01176     vigra_precondition (
01177         array.shape (0) == 1, "makeBasicImageView(): array.shape(0) must be 1.");
01178     return BasicImageView <T> (array.data (), 
01179                                array.shape (1), array.shape (2));
01180 }
01181 
01182 template <class T>
01183 BasicImageView <RGBValue<T> >
01184 makeRGBImageView (MultiArray<3, T> &array)
01185 {
01186     vigra_precondition (
01187         array.shape (0) == 3, "makeRGBImageView(): array.shape(0) must be 3.");
01188     return BasicImageView <RGBValue<T> > (
01189         reinterpret_cast <RGBValue <T> *> (array.data ()), 
01190         array.shape (1), array.shape (2));
01191 }
01192 
01193 } // namespace vigra
01194 
01195 #endif // VIGRA_MULTI_ARRAY_HXX

© Ullrich Köthe (koethe@informatik.uni-hamburg.de)
Cognitive Systems Group, University of Hamburg, Germany

html generated using doxygen and Python
VIGRA 1.2.0 (7 Aug 2003)