TooN 2.0.0-beta8
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     protected:
00281 
00282         Precision* data() {
00283             return &numbers[0];
00284         }
00285 
00286         const Precision* data()const  {
00287             return &numbers[0];
00288         }
00289 
00290     private:
00291         //Dymmy class for implementing sfinae
00292         //in order to test for a .size() member
00293         template<int S> struct SFINAE_dummy{typedef void type;};
00294     
00295     protected:
00296 
00297         //SFINAE implementation of try_destructive_resize
00298         //to avoid calling .size if it does not exist!
00299 
00300         //Force the function TYPE to depend on a property
00301         //of the Operator<Op> type, so that it simply does
00302         //not exist if the property is missing.
00303         //Therefore this method only uses .size() if it exists.
00304         template<class Op> 
00305         typename SFINAE_dummy<sizeof(&Operator<Op>::size)>::type try_destructive_resize(const Operator<Op>& op) 
00306         {
00307             try_destructive_resize(op.size());
00308         }
00309         
00310         //Catch-all do nothing for operators with no size method.
00311         template<class Op>
00312         void try_destructive_resize(const Op&)
00313         {}
00314 
00315         void try_destructive_resize(int newsize)
00316         {
00317             numbers.resize(newsize);
00318             debug_initialize(data(), newsize);
00319         }
00320 
00321     public:
00322 
00323         void resize(int s)
00324         {
00325             int old_size = size();
00326             numbers.resize(s);
00327             if(s > old_size)
00328                 debug_initialize(data()+old_size, s-old_size);
00329         }
00330 };
00331 
00332 ///@internal
00333 ///@brief Hold a pointer to yield a statically sized slice of a Vector.
00334 ///Not resizable.
00335 ///@ingroup gInternal
00336 //template<int S, class Precision, class PtrType=Precision*, class ConstPtrType=const Precision*, class RefType=Precision&, class ConstRefType=const Precision&> struct VectorSlice
00337 template<int S, class Precision, class PtrType=Precision*, class ConstPtrType=const Precision*, class RefType=Precision&, class ConstRefType=const Precision&> struct VectorSlice
00338 {
00339     int size() const {
00340         return S;
00341     }
00342 
00343     //Optional Constructors
00344     
00345     const PtrType my_data;
00346     VectorSlice(PtrType p)
00347     :my_data(p){}
00348 
00349     VectorSlice(PtrType p, int /*size*/)
00350     :my_data(p){}
00351 
00352     template<class Op>
00353     VectorSlice(const Operator<Op>& op) : my_data(op.data()) {}
00354     
00355     protected:
00356         PtrType data()
00357         {
00358             return my_data;
00359         };
00360 
00361         ConstPtrType data() const
00362         {
00363             return my_data;
00364         };
00365 
00366         void try_destructive_resize(int)
00367         {}
00368 
00369         template<class Op> void try_destructive_resize(const Operator<Op>&) 
00370         {}
00371 
00372     public:
00373         typedef PtrType PointerType;
00374         typedef ConstPtrType ConstPointerType;
00375         typedef RefType ReferenceType;
00376         typedef ConstRefType ConstReferenceType;
00377 };
00378 
00379 ///@internal
00380 ///@brief Hold a pointer to yield a dynamically sized slice of a Vector.
00381 ///Not resizable.
00382 ///@ingroup gInternal
00383 template<class Precision, class PtrType, class ConstPtrType, class RefType, class ConstRefType> struct VectorSlice<Dynamic, Precision, PtrType, ConstPtrType, RefType, ConstRefType>
00384 {
00385     const PtrType my_data;
00386     const int my_size;
00387 
00388     VectorSlice(PtrType d, int s)
00389     :my_data(d), my_size(s)
00390     { }
00391 
00392     template<class Op>
00393     VectorSlice(const Operator<Op>& op) : my_data(op.data()), my_size(op.size()) {}
00394 
00395     int size() const {
00396         return my_size;
00397     }
00398 
00399     protected:
00400 
00401         PtrType data()
00402         {
00403             return my_data;
00404         };
00405 
00406         ConstPtrType data() const
00407         {
00408             return my_data;
00409         };
00410 
00411         void try_destructive_resize(int)
00412         {}
00413 
00414         template<class Op> void try_destructive_resize(const Operator<Op>&) 
00415         {}
00416 
00417     public:
00418         typedef PtrType PointerType;
00419         typedef ConstPtrType ConstPointerType;
00420         typedef RefType ReferenceType;
00421         typedef ConstRefType ConstReferenceType;
00422 };
00423 
00424 ////////////////////////////////////////////////////////////////////////////////
00425 //
00426 // A class similar to StrideHolder, but to hold the size information for matrices.
00427 
00428 ///@internal
00429 ///@brief This struct holds a size using no data for static sizes.
00430 ///This struct holds a size is the size is dynamic,
00431 ///or simply recorcs the number in the type system if
00432 ///the size is static.
00433 ///@ingroup gInternal
00434 template<int s> struct SizeHolder
00435 {
00436     //Constructors ignore superfluous arguments
00437     SizeHolder(){}    ///<Default constrution
00438     SizeHolder(int){} ///<Construct from an int and discard it.
00439 
00440     ///Simply return the statcally known size
00441     int size() const{
00442         return s;
00443     }
00444 };
00445 
00446 ///@internal
00447 ///@brief This struct holds a size integer for dynamic sizes.
00448 ///@ingroup gInternal
00449 template<> struct SizeHolder<-1>
00450 {
00451     ///@name Construction
00452     ///@{
00453     SizeHolder(int s)
00454     :my_size(s){}
00455     ///@}
00456 
00457     const int my_size; ///<The size
00458     ///Return the size
00459     int size() const {
00460         return my_size;
00461     }
00462 };
00463 
00464 ///@internal
00465 ///This struct holds the number of rows, only allocating space if
00466 ///necessary.
00467 ///@ingroup gInternal
00468 template<int S> struct RowSizeHolder: private SizeHolder<S>
00469 {
00470     ///Construct from an int to provide a run time size if
00471     ///necessary. 
00472     ///@param i The size, which is discarded for the static case.
00473     RowSizeHolder(int i)
00474     :SizeHolder<S>(i){}
00475 
00476     RowSizeHolder()
00477     {}
00478     
00479     ///Construct from an Operator, taking the size from the operator.
00480     ///The size is only used in the dynamic case.
00481     ///@param op Operator from which to determine the size.
00482     template<typename Op>
00483     RowSizeHolder(const Operator<Op>& op) : SizeHolder<S>(op.num_rows()) {}
00484     
00485     ///Return the number of rows.
00486     int num_rows() const {return SizeHolder<S>::size();}
00487 };
00488 
00489 
00490 ///@internal
00491 ///This struct holds the number of columns, only allocating space if
00492 ///necessary.
00493 ///@ingroup gInternal
00494 template<int S> struct ColSizeHolder: private SizeHolder<S>
00495 {
00496     ///Construct from an int to provide a run time size if
00497     ///necessary. 
00498     ///@param i The size, which is discarded for the static case.
00499     ColSizeHolder(int i)
00500     :SizeHolder<S>(i){}
00501 
00502     ColSizeHolder()
00503     {}
00504 
00505     ///Construct from an Operator, taking the size from the operator.
00506     ///The size is only used in the dynamic case.
00507     ///@param op Operator from which to determine the size.
00508     template<typename Op>
00509     ColSizeHolder(const Operator<Op>& op) : SizeHolder<S>(op.num_cols()) {}
00510 
00511     ///Return the number of columns.
00512     int num_cols() const {return SizeHolder<S>::size();}    
00513 };
00514 
00515 
00516 
00517 template<int R, int C, class Precision, bool FullyStatic=(R>=0 && C>=0)> 
00518 struct MatrixAlloc: public StaticSizedAllocator<R*C, Precision>
00519 {
00520     MatrixAlloc(int,int)
00521     {}
00522 
00523     MatrixAlloc()
00524     {}
00525 
00526     template <class Op>
00527     MatrixAlloc(const Operator<Op>&)
00528     {}
00529 
00530     int num_rows() const {
00531         return R;
00532     }
00533 
00534     int num_cols() const {
00535         return C;
00536     }
00537 
00538     using  StaticSizedAllocator<R*C, Precision>::my_data;
00539 
00540     Precision* get_data_ptr()
00541     {
00542         return my_data;
00543     }
00544 
00545     const Precision* get_data_ptr() const 
00546     {
00547         return my_data;
00548     }
00549 };
00550 
00551 
00552 template<int R, int C, class Precision> struct MatrixAlloc<R, C, Precision, false>
00553     : public RowSizeHolder<R>,
00554     ColSizeHolder<C>
00555 {
00556     Precision* const my_data;
00557 
00558     using RowSizeHolder<R>::num_rows;
00559     using ColSizeHolder<C>::num_cols;
00560     
00561     // copy constructor so guaranteed contiguous
00562     MatrixAlloc(const MatrixAlloc& m)
00563         :RowSizeHolder<R>(m.num_rows()),
00564          ColSizeHolder<C>(m.num_cols()),
00565          my_data(new Precision[num_rows()*num_cols()]) {
00566         const int size=num_rows()*num_cols();
00567         for(int i=0; i < size; i++) {
00568             my_data[i] = m.my_data[i];
00569         }
00570     }
00571 
00572     MatrixAlloc(int r, int c)
00573     :RowSizeHolder<R>(r),
00574      ColSizeHolder<C>(c),
00575      my_data(new Precision[num_rows()*num_cols()]) 
00576     {
00577         debug_initialize(my_data, num_rows()*num_cols());   
00578     }
00579 
00580     template <class Op> MatrixAlloc(const Operator<Op>& op)
00581         :RowSizeHolder<R>(op),
00582          ColSizeHolder<C>(op),
00583          my_data(new Precision[num_rows()*num_cols()])
00584     {
00585         debug_initialize(my_data, num_rows()*num_cols());   
00586     }
00587 
00588     ~MatrixAlloc() {
00589         delete[] my_data;
00590     }
00591 
00592     Precision* get_data_ptr()
00593     {
00594         return my_data;
00595     }
00596 
00597     const Precision* get_data_ptr() const 
00598     {
00599         return my_data;
00600     }
00601 };
00602 
00603 
00604 template<int R, int C, class Precision> struct MatrixSlice
00605     : public RowSizeHolder<R>,
00606     ColSizeHolder<C>
00607 {
00608     Precision* const my_data;
00609 
00610     using RowSizeHolder<R>::num_rows;
00611     using ColSizeHolder<C>::num_cols;
00612 
00613     //Optional Constructors
00614     MatrixSlice(Precision* p)
00615     :my_data(p){}
00616 
00617     MatrixSlice(Precision* p, int r, int c)
00618         :RowSizeHolder<R>(r),
00619          ColSizeHolder<C>(c),
00620          my_data(p){}
00621     
00622     template<class Op>
00623     MatrixSlice(const Operator<Op>& op)
00624         :RowSizeHolder<R>(op),
00625          ColSizeHolder<C>(op),
00626          my_data(op.data())
00627     {}
00628 };
00629 
00630 
00631 ////////////////////////////////////////////////////////////////////////////////
00632 //
00633 // A class similar to mem, but to hold the stride information. It is only needed
00634 // for -1. For +int and -2, the stride is part fo teh type, or implicit.
00635 
00636 template<int s> struct StrideHolder
00637 {
00638     //Constructos ignore superfluous arguments
00639     StrideHolder(){}
00640     StrideHolder(int){}
00641 
00642     template<class Op>
00643     StrideHolder(const Operator<Op>&) {}
00644 
00645     int stride() const{
00646         return s;
00647     }
00648 };
00649 
00650 template<> struct StrideHolder<-1>
00651 {
00652     StrideHolder(int s)
00653     :my_stride(s){}
00654 
00655     template<class Op>
00656     StrideHolder(const Operator<Op>& op) : my_stride(op.stride()) {}
00657 
00658     const int my_stride;
00659     int stride() const {
00660         return my_stride;
00661     }
00662 };
00663 
00664 
00665 template<int S> struct RowStrideHolder: public StrideHolder<S>
00666 {
00667     RowStrideHolder(int i)
00668     :StrideHolder<S>(i){}
00669 
00670     RowStrideHolder()
00671     {}
00672 
00673     template<class Op>
00674     RowStrideHolder(const Operator<Op>& op)
00675         : StrideHolder<S>(op)
00676     {}
00677 
00678 };
00679 
00680 
00681 template<int S> struct ColStrideHolder: public StrideHolder<S>
00682 {
00683     ColStrideHolder(int i)
00684     :StrideHolder<S>(i){}
00685 
00686     ColStrideHolder()
00687     {}
00688 
00689     template<class Op>
00690     ColStrideHolder(const Operator<Op>& op)
00691         : StrideHolder<S>(op)
00692     {}
00693 };
00694 
00695 }
00696 
00697 }
00698 
00699 
00700 #undef TOON_ALIGN8