TooN 2.1
internal/allocator.hh
00001 // -*- c++ -*-
00002 
00003 // Copyright (C) 2009 Tom Drummond (twd20@cam.ac.uk),
00004 // Ed Rosten (er258@cam.ac.uk)
00005 //
00006 // This file is part of the TooN Library.  This library is free
00007 // software; you can redistribute it and/or modify it under the
00008 // terms of the GNU General Public License as published by the
00009 // Free Software Foundation; either version 2, or (at your option)
00010 // any later version.
00011 
00012 // This library is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 
00017 // You should have received a copy of the GNU General Public License along
00018 // with this library; see the file COPYING.  If not, write to the Free
00019 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
00020 // USA.
00021 
00022 // As a special exception, you may use this file as part of a free software
00023 // library without restriction.  Specifically, if other files instantiate
00024 // templates or use macros or inline functions from this file, or you compile
00025 // this file and link it with other files to produce an executable, this
00026 // file does not by itself cause the resulting executable to be covered by
00027 // the GNU General Public License.  This exception does not however
00028 // invalidate any other reasons why the executable file might be covered by
00029 // the GNU General Public License.
00030 
00031 // Allocators always copy data on copy construction.
00032 //
00033 // When a Vector/Matrix is constructed from a different, but compatible type
00034 // copying is done at a much higher level: above the level that knows how the
00035 // data is laid out in memory.
00036 //
00037 // At this level, copy construction is required since it is only known here 
00038 // whether data or a reference to data should be copied.
00039 
00040 #ifdef __GNUC__
00041 #define TOON_ALIGN8 __attribute__ ((aligned(8)))
00042 #else
00043 #define TOON_ALIGN8
00044 #endif
00045 
00046 namespace TooN {
00047 
00048 namespace Internal
00049 {
00050 
00051 template<class Precision> struct DefaultTypes
00052 {
00053     typedef Precision* PointerType;
00054     typedef const Precision* ConstPointerType;
00055     typedef Precision& ReferenceType;
00056     typedef const Precision& ConstReferenceType;
00057 };
00058 
00059 
00060 template<int Size, class Precision, bool heap> class StackOrHeap;
00061 
00062 template<int Size, class Precision> class StackOrHeap<Size,Precision,0>
00063 {
00064 public:
00065     StackOrHeap()
00066     {
00067         debug_initialize(my_data, Size);    
00068     }
00069     Precision my_data[Size];
00070 };
00071 
00072 template<int Size> class StackOrHeap<Size,double,0>
00073 {
00074 public:
00075     StackOrHeap()
00076     {
00077         debug_initialize(my_data, Size);    
00078     }
00079     double my_data[Size] TOON_ALIGN8 ;
00080 };
00081 
00082 
00083 template<int Size, class Precision> class StackOrHeap<Size, Precision, 1>
00084 {
00085     public:
00086         StackOrHeap()
00087         :my_data(new Precision[Size])
00088         {
00089             debug_initialize(my_data, Size);    
00090         }
00091 
00092 
00093         ~StackOrHeap()
00094         {
00095             delete[] my_data;
00096         }
00097 
00098         Precision *my_data;
00099 
00100         StackOrHeap(const StackOrHeap& from)
00101         :my_data(new Precision[Size])
00102         {
00103             for(int i=0; i < Size; i++)
00104                 my_data[i] = from.my_data[i];
00105         }
00106 };
00107 
00108 ///@internal
00109 ///@brief This allocator object sets aside memory for a statically sized object. 
00110 ///It will
00111 ///put all the data on the stack if there are less then TooN::max_bytes_on_stack of
00112 ///data, otherwise it will use new/delete.
00113 ///@ingroup gInternal
00114 template<int Size, class Precision> class StaticSizedAllocator: public StackOrHeap<Size, Precision, (sizeof(Precision)*Size>max_bytes_on_stack) >
00115 {
00116 };
00117 
00118 
00119 ///@internal
00120 ///@brief Allocate memory for a static sized Vector.
00121 ///The class switches to heap allocation automatically for large Vectors.
00122 ///Naturally, the vector is not resizable.
00123 ///@ingroup gInternal
00124 template<int Size, class Precision> struct VectorAlloc : public StaticSizedAllocator<Size, Precision>, DefaultTypes<Precision> {
00125     
00126     ///Default constructor (only for statically sized vectors)
00127     VectorAlloc() { }
00128 
00129     ///Construction from a size (required by damic vectors, ignored otherwise).
00130     VectorAlloc(int /*s*/) { }
00131 
00132     ///Construction from an Operator. See Operator::size().
00133     template<class Op>
00134     VectorAlloc(const Operator<Op>&) {}
00135     
00136     ///Return the size of the vector.
00137     int size() const {
00138         return Size;
00139     }
00140 
00141     using StaticSizedAllocator<Size, Precision>::my_data;
00142 
00143     Precision *get_data_ptr()
00144     {
00145         return my_data;
00146     };
00147 
00148     const Precision *get_data_ptr() const
00149     {
00150         return my_data;
00151     }
00152     
00153     protected:
00154 
00155         Precision *data()
00156         {
00157             return my_data;
00158         };
00159 
00160         const Precision *data() const
00161         {
00162             return my_data;
00163         };
00164         
00165         void try_destructive_resize(int)
00166         {}
00167 
00168         template<class Op> void try_destructive_resize(const Operator<Op>&) 
00169         {}
00170 };
00171 
00172 ///@internal
00173 ///@brief Allocate memory for a dynamic sized Vector.
00174 ///This is not resizable.
00175 ///@ingroup gInternal
00176 template<class Precision> struct VectorAlloc<Dynamic, Precision>: public DefaultTypes<Precision> {
00177     Precision * const my_data;
00178     const int my_size;
00179 
00180     VectorAlloc(const VectorAlloc& v)
00181     :my_data(new Precision[v.my_size]), my_size(v.my_size)
00182     { 
00183         for(int i=0; i < my_size; i++)
00184             my_data[i] = v.my_data[i];
00185     }
00186 
00187     VectorAlloc(int s)
00188     :my_data(new Precision[s]), my_size(s)
00189     { 
00190         debug_initialize(my_data, my_size); 
00191     }
00192 
00193     template <class Op>
00194     VectorAlloc(const Operator<Op>& op) 
00195     : my_data(new Precision[op.size()]), my_size(op.size()) 
00196     {
00197         debug_initialize(my_data, my_size); 
00198     }
00199 
00200     int size() const {
00201         return my_size;
00202     }
00203 
00204     ~VectorAlloc(){
00205         delete[] my_data;
00206     }
00207 
00208     Precision *get_data_ptr()
00209     {
00210         return my_data;
00211     };
00212 
00213     const Precision *get_data_ptr() const
00214     {
00215         return my_data;
00216     }
00217 
00218     protected:
00219 
00220         Precision *data()
00221         {
00222             return my_data;
00223         };
00224 
00225         const Precision *data() const
00226         {
00227             return my_data;
00228         };
00229 
00230         void try_destructive_resize(int)
00231         {}
00232 
00233         template<class Op> void try_destructive_resize(const Operator<Op>&) 
00234         {}
00235 };
00236 
00237 
00238 ///@internal
00239 ///@brief Allocate memory for a resizable Vector.
00240 ///New elements available after a resize are treated as
00241 ///uninitialized. 
00242 ///@ingroup gInternal
00243 template<class Precision> struct VectorAlloc<Resizable, Precision>: public DefaultTypes<Precision> {
00244     protected: 
00245         std::vector<Precision> numbers;
00246     
00247     public:
00248 
00249         VectorAlloc()
00250         { 
00251         }
00252 
00253         VectorAlloc(int s)
00254         :numbers(s)
00255         { 
00256             debug_initialize(data(), size());   
00257         }
00258 
00259         template <class Op>
00260         VectorAlloc(const Operator<Op>& op) 
00261         :numbers(op.size()) 
00262         {
00263             debug_initialize(data(), size());   
00264         }
00265 
00266         int size() const {
00267             return numbers.size();
00268         }
00269 
00270         Precision *get_data_ptr()
00271         {
00272             return data();
00273         };
00274 
00275         const Precision *get_data_ptr() const
00276         {
00277             return data();
00278         }
00279 
00280         void swap(VectorAlloc& s)
00281         {
00282             numbers.swap(s.numbers);
00283         }
00284 
00285     protected:
00286 
00287         Precision* data() {
00288             return &numbers[0];
00289         }
00290 
00291         const Precision* data()const  {
00292             return &numbers[0];
00293         }
00294 
00295     private:
00296         //Dymmy class for implementing sfinae
00297         //in order to test for a .size() member
00298         template<int S> struct SFINAE_dummy{typedef void type;};
00299     
00300     protected:
00301 
00302         //SFINAE implementation of try_destructive_resize
00303         //to avoid calling .size if it does not exist!
00304 
00305         //Force the function TYPE to depend on a property
00306         //of the Operator<Op> type, so that it simply does
00307         //not exist if the property is missing.
00308         //Therefore this method only uses .size() if it exists.
00309         template<class Op> 
00310         typename SFINAE_dummy<sizeof(&Operator<Op>::size)>::type try_destructive_resize(const Operator<Op>& op) 
00311         {
00312             try_destructive_resize(op.size());
00313         }
00314         
00315         //Catch-all do nothing for operators with no size method.
00316         template<class Op>
00317         void try_destructive_resize(const Op&)
00318         {}
00319 
00320         void try_destructive_resize(int newsize)
00321         {
00322             numbers.resize(newsize);
00323             debug_initialize(data(), newsize);
00324         }
00325 
00326     public:
00327 
00328         void resize(int s)
00329         {
00330             int old_size = size();
00331             numbers.resize(s);
00332             if(s > old_size)
00333                 debug_initialize(data()+old_size, s-old_size);
00334         }
00335 };
00336 
00337 ///@internal
00338 ///@brief Hold a pointer to yield a statically sized slice of a Vector.
00339 ///Not resizable.
00340 ///@ingroup gInternal
00341 //template<int S, class Precision, class PtrType=Precision*, class ConstPtrType=const Precision*, class RefType=Precision&, class ConstRefType=const Precision&> struct VectorSlice
00342 template<int S, class Precision, class PtrType=Precision*, class ConstPtrType=const Precision*, class RefType=Precision&, class ConstRefType=const Precision&> struct VectorSlice
00343 {
00344     int size() const {
00345         return S;
00346     }
00347 
00348     //Optional Constructors
00349     
00350     const PtrType my_data;
00351     VectorSlice(PtrType p)
00352     :my_data(p){}
00353 
00354     VectorSlice(PtrType p, int /*size*/)
00355     :my_data(p){}
00356 
00357     template<class Op>
00358     VectorSlice(const Operator<Op>& op) : my_data(op.data()) {}
00359     
00360     protected:
00361         PtrType data()
00362         {
00363             return my_data;
00364         };
00365 
00366         ConstPtrType data() const
00367         {
00368             return my_data;
00369         };
00370 
00371         void try_destructive_resize(int)
00372         {}
00373 
00374         template<class Op> void try_destructive_resize(const Operator<Op>&) 
00375         {}
00376 
00377     public:
00378         typedef PtrType PointerType;
00379         typedef ConstPtrType ConstPointerType;
00380         typedef RefType ReferenceType;
00381         typedef ConstRefType ConstReferenceType;
00382 };
00383 
00384 ///@internal
00385 ///@brief Hold a pointer to yield a dynamically sized slice of a Vector.
00386 ///Not resizable.
00387 ///@ingroup gInternal
00388 template<class Precision, class PtrType, class ConstPtrType, class RefType, class ConstRefType> struct VectorSlice<Dynamic, Precision, PtrType, ConstPtrType, RefType, ConstRefType>
00389 {
00390     const PtrType my_data;
00391     const int my_size;
00392 
00393     VectorSlice(PtrType d, int s)
00394     :my_data(d), my_size(s)
00395     { }
00396 
00397     template<class Op>
00398     VectorSlice(const Operator<Op>& op) : my_data(op.data()), my_size(op.size()) {}
00399 
00400     int size() const {
00401         return my_size;
00402     }
00403 
00404     protected:
00405 
00406         PtrType data()
00407         {
00408             return my_data;
00409         };
00410 
00411         ConstPtrType data() const
00412         {
00413             return my_data;
00414         };
00415 
00416         void try_destructive_resize(int)
00417         {}
00418 
00419         template<class Op> void try_destructive_resize(const Operator<Op>&) 
00420         {}
00421 
00422     public:
00423         typedef PtrType PointerType;
00424         typedef ConstPtrType ConstPointerType;
00425         typedef RefType ReferenceType;
00426         typedef ConstRefType ConstReferenceType;
00427 };
00428 
00429 ////////////////////////////////////////////////////////////////////////////////
00430 //
00431 // A class similar to StrideHolder, but to hold the size information for matrices.
00432 
00433 ///@internal
00434 ///@brief This struct holds a size using no data for static sizes.
00435 ///This struct holds a size is the size is dynamic,
00436 ///or simply recorcs the number in the type system if
00437 ///the size is static.
00438 ///@ingroup gInternal
00439 template<int s> struct SizeHolder
00440 {
00441     //Constructors ignore superfluous arguments
00442     SizeHolder(){}    ///<Default constrution
00443     SizeHolder(int){} ///<Construct from an int and discard it.
00444 
00445     ///Simply return the statcally known size
00446     int size() const{
00447         return s;
00448     }
00449 };
00450 
00451 ///@internal
00452 ///@brief This struct holds a size integer for dynamic sizes.
00453 ///@ingroup gInternal
00454 template<> struct SizeHolder<-1>
00455 {
00456     ///@name Construction
00457     ///@{
00458     SizeHolder(int s)
00459     :my_size(s){}
00460     ///@}
00461 
00462     const int my_size; ///<The size
00463     ///Return the size
00464     int size() const {
00465         return my_size;
00466     }
00467 };
00468 
00469 ///@internal
00470 ///This struct holds the number of rows, only allocating space if
00471 ///necessary.
00472 ///@ingroup gInternal
00473 template<int S> struct RowSizeHolder: private SizeHolder<S>
00474 {
00475     ///Construct from an int to provide a run time size if
00476     ///necessary. 
00477     ///@param i The size, which is discarded for the static case.
00478     RowSizeHolder(int i)
00479     :SizeHolder<S>(i){}
00480 
00481     RowSizeHolder()
00482     {}
00483     
00484     ///Construct from an Operator, taking the size from the operator.
00485     ///The size is only used in the dynamic case.
00486     ///@param op Operator from which to determine the size.
00487     template<typename Op>
00488     RowSizeHolder(const Operator<Op>& op) : SizeHolder<S>(op.num_rows()) {}
00489     
00490     ///Return the number of rows.
00491     int num_rows() const {return SizeHolder<S>::size();}
00492 };
00493 
00494 
00495 ///@internal
00496 ///This struct holds the number of columns, only allocating space if
00497 ///necessary.
00498 ///@ingroup gInternal
00499 template<int S> struct ColSizeHolder: private SizeHolder<S>
00500 {
00501     ///Construct from an int to provide a run time size if
00502     ///necessary. 
00503     ///@param i The size, which is discarded for the static case.
00504     ColSizeHolder(int i)
00505     :SizeHolder<S>(i){}
00506 
00507     ColSizeHolder()
00508     {}
00509 
00510     ///Construct from an Operator, taking the size from the operator.
00511     ///The size is only used in the dynamic case.
00512     ///@param op Operator from which to determine the size.
00513     template<typename Op>
00514     ColSizeHolder(const Operator<Op>& op) : SizeHolder<S>(op.num_cols()) {}
00515 
00516     ///Return the number of columns.
00517     int num_cols() const {return SizeHolder<S>::size();}    
00518 };
00519 
00520 
00521 
00522 template<int R, int C, class Precision, bool FullyStatic=(R>=0 && C>=0)> 
00523 struct MatrixAlloc: public StaticSizedAllocator<R*C, Precision>
00524 {
00525     MatrixAlloc(int,int)
00526     {}
00527 
00528     MatrixAlloc()
00529     {}
00530 
00531     template <class Op>
00532     MatrixAlloc(const Operator<Op>&)
00533     {}
00534 
00535     int num_rows() const {
00536         return R;
00537     }
00538 
00539     int num_cols() const {
00540         return C;
00541     }
00542 
00543     using  StaticSizedAllocator<R*C, Precision>::my_data;
00544 
00545     Precision* get_data_ptr()
00546     {
00547         return my_data;
00548     }
00549 
00550     const Precision* get_data_ptr() const 
00551     {
00552         return my_data;
00553     }
00554 };
00555 
00556 
00557 template<int R, int C, class Precision> struct MatrixAlloc<R, C, Precision, false>
00558     : public RowSizeHolder<R>,
00559     ColSizeHolder<C>
00560 {
00561     Precision* const my_data;
00562 
00563     using RowSizeHolder<R>::num_rows;
00564     using ColSizeHolder<C>::num_cols;
00565     
00566     // copy constructor so guaranteed contiguous
00567     MatrixAlloc(const MatrixAlloc& m)
00568         :RowSizeHolder<R>(m.num_rows()),
00569          ColSizeHolder<C>(m.num_cols()),
00570          my_data(new Precision[num_rows()*num_cols()]) {
00571         const int size=num_rows()*num_cols();
00572         for(int i=0; i < size; i++) {
00573             my_data[i] = m.my_data[i];
00574         }
00575     }
00576 
00577     MatrixAlloc(int r, int c)
00578     :RowSizeHolder<R>(r),
00579      ColSizeHolder<C>(c),
00580      my_data(new Precision[num_rows()*num_cols()]) 
00581     {
00582         debug_initialize(my_data, num_rows()*num_cols());   
00583     }
00584 
00585     template <class Op> MatrixAlloc(const Operator<Op>& op)
00586         :RowSizeHolder<R>(op),
00587          ColSizeHolder<C>(op),
00588          my_data(new Precision[num_rows()*num_cols()])
00589     {
00590         debug_initialize(my_data, num_rows()*num_cols());   
00591     }
00592 
00593     ~MatrixAlloc() {
00594         delete[] my_data;
00595     }
00596 
00597     Precision* get_data_ptr()
00598     {
00599         return my_data;
00600     }
00601 
00602     const Precision* get_data_ptr() const 
00603     {
00604         return my_data;
00605     }
00606 };
00607 
00608 
00609 template<int R, int C, class Precision> struct MatrixSlice
00610     : public RowSizeHolder<R>,
00611     ColSizeHolder<C>
00612 {
00613     Precision* const my_data;
00614 
00615     using RowSizeHolder<R>::num_rows;
00616     using ColSizeHolder<C>::num_cols;
00617 
00618     //Optional Constructors
00619     MatrixSlice(Precision* p)
00620     :my_data(p){}
00621 
00622     MatrixSlice(Precision* p, int r, int c)
00623         :RowSizeHolder<R>(r),
00624          ColSizeHolder<C>(c),
00625          my_data(p){}
00626     
00627     template<class Op>
00628     MatrixSlice(const Operator<Op>& op)
00629         :RowSizeHolder<R>(op),
00630          ColSizeHolder<C>(op),
00631          my_data(op.data())
00632     {}
00633 };
00634 
00635 
00636 ////////////////////////////////////////////////////////////////////////////////
00637 //
00638 // A class similar to mem, but to hold the stride information. It is only needed
00639 // for -1. For +int and -2, the stride is part fo teh type, or implicit.
00640 
00641 template<int s> struct StrideHolder
00642 {
00643     //Constructos ignore superfluous arguments
00644     StrideHolder(){}
00645     StrideHolder(int){}
00646 
00647     template<class Op>
00648     StrideHolder(const Operator<Op>&) {}
00649 
00650     int stride() const{
00651         return s;
00652     }
00653 };
00654 
00655 template<> struct StrideHolder<-1>
00656 {
00657     StrideHolder(int s)
00658     :my_stride(s){}
00659 
00660     template<class Op>
00661     StrideHolder(const Operator<Op>& op) : my_stride(op.stride()) {}
00662 
00663     const int my_stride;
00664     int stride() const {
00665         return my_stride;
00666     }
00667 };
00668 
00669 
00670 template<int S> struct RowStrideHolder: public StrideHolder<S>
00671 {
00672     RowStrideHolder(int i)
00673     :StrideHolder<S>(i){}
00674 
00675     RowStrideHolder()
00676     {}
00677 
00678     template<class Op>
00679     RowStrideHolder(const Operator<Op>& op)
00680         : StrideHolder<S>(op)
00681     {}
00682 
00683 };
00684 
00685 
00686 template<int S> struct ColStrideHolder: public StrideHolder<S>
00687 {
00688     ColStrideHolder(int i)
00689     :StrideHolder<S>(i){}
00690 
00691     ColStrideHolder()
00692     {}
00693 
00694     template<class Op>
00695     ColStrideHolder(const Operator<Op>& op)
00696         : StrideHolder<S>(op)
00697     {}
00698 };
00699 
00700 }
00701 
00702 }
00703 
00704 
00705 #undef TOON_ALIGN8