TooN
allocator.hh
1 // -*- c++ -*-
2 
3 // Copyright (C) 2009 Tom Drummond (twd20@cam.ac.uk),
4 // Ed Rosten (er258@cam.ac.uk)
5 
6 //All rights reserved.
7 //
8 //Redistribution and use in source and binary forms, with or without
9 //modification, are permitted provided that the following conditions
10 //are met:
11 //1. Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //2. Redistributions in binary form must reproduce the above copyright
14 // notice, this list of conditions and the following disclaimer in the
15 // documentation and/or other materials provided with the distribution.
16 //
17 //THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
18 //AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 //IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 //ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
21 //LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 //CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 //SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 //INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 //CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 //ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 //POSSIBILITY OF SUCH DAMAGE.
28 
29 // Allocators always copy data on copy construction.
30 //
31 // When a Vector/Matrix is constructed from a different, but compatible type
32 // copying is done at a much higher level: above the level that knows how the
33 // data is laid out in memory.
34 //
35 // At this level, copy construction is required since it is only known here
36 // whether data or a reference to data should be copied.
37 
38 #ifdef __GNUC__
39 #define TOON_ALIGN8 __attribute__ ((aligned(8)))
40 #else
41 #define TOON_ALIGN8
42 #endif
43 
44 namespace TooN {
45 
46 namespace Internal
47 {
48 
49 template<class Precision> struct DefaultTypes
50 {
51  typedef Precision* PointerType;
52  typedef const Precision* ConstPointerType;
53  typedef Precision& ReferenceType;
54  typedef const Precision& ConstReferenceType;
55 };
56 
57 
58 template<int Size, class Precision, bool heap> class StackOrHeap;
59 
60 template<int Size, class Precision> class StackOrHeap<Size,Precision,0>
61 {
62 public:
63  StackOrHeap()
64  {
65  debug_initialize(my_data, Size);
66  }
67  Precision my_data[Size];
68 };
69 
70 template<int Size> class StackOrHeap<Size,double,0>
71 {
72 public:
73  StackOrHeap()
74  {
75  debug_initialize(my_data, Size);
76  }
77  double my_data[Size] TOON_ALIGN8 ;
78 };
79 
80 
81 template<int Size, class Precision> class StackOrHeap<Size, Precision, 1>
82 {
83  public:
84  StackOrHeap()
85  :my_data(new Precision[Size])
86  {
87  debug_initialize(my_data, Size);
88  }
89 
90 
91  ~StackOrHeap()
92  {
93  delete[] my_data;
94  }
95 
96  Precision *my_data;
97 
98  StackOrHeap(const StackOrHeap& from)
99  :my_data(new Precision[Size])
100  {
101  for(int i=0; i < Size; i++)
102  my_data[i] = from.my_data[i];
103  }
104 };
105 
112 template<int Size, class Precision> class StaticSizedAllocator: public StackOrHeap<Size, Precision, (sizeof(Precision)*Size>max_bytes_on_stack) >
113 {
114 };
115 
116 
122 template<int Size, class Precision> struct VectorAlloc : public StaticSizedAllocator<Size, Precision>, DefaultTypes<Precision> {
123 
126 
128  VectorAlloc(int /*s*/) { }
129 
130  template<class Precision2, int Size2>
131  VectorAlloc(const Precision2(&i)[Size2])
132  {
133  static_assert(Size == Size2, "Wrong number of elements to initialize static vector");
134  for(int j=0; j < Size; j++)
135  my_data[j] = i[j];
136  }
137 
139  template<class Op>
141 
143  int size() const {
144  return Size;
145  }
146 
148 
149  Precision *get_data_ptr()
150  {
151  return my_data;
152  };
153 
154  const Precision *get_data_ptr() const
155  {
156  return my_data;
157  }
158 
159  protected:
160 
161  Precision *data()
162  {
163  return my_data;
164  };
165 
166  const Precision *data() const
167  {
168  return my_data;
169  };
170 
171  void try_destructive_resize(int)
172  {}
173 
174  template<class Op> void try_destructive_resize(const Operator<Op>&)
175  {}
176 };
177 
182 template<class Precision> struct VectorAlloc<Dynamic, Precision>: public DefaultTypes<Precision> {
183  Precision * my_data;
184  const int my_size;
185 
186  VectorAlloc(std::initializer_list<Precision> i)
187  :VectorAlloc(i.size())
188  {
189  std::copy(i.begin(), i.end(), my_data);
190  }
191 
192  VectorAlloc(const VectorAlloc& v)
193  :my_data(new Precision[v.my_size]), my_size(v.my_size)
194  {
195  for(int i=0; i < my_size; i++)
196  my_data[i] = v.my_data[i];
197  }
198 
199  VectorAlloc(VectorAlloc&& from) noexcept
200  : my_data(from.my_data), my_size(from.my_size)
201  {
202  from.my_data = 0;
203  }
204 
205  VectorAlloc(int s)
206  :my_data(new Precision[s]), my_size(s)
207  {
208  debug_initialize(my_data, my_size);
209  }
210 
211  template <class Op>
212  VectorAlloc(const Operator<Op>& op)
213  : my_data(new Precision[op.size()]), my_size(op.size())
214  {
215  debug_initialize(my_data, my_size);
216  }
217 
218  int size() const {
219  return my_size;
220  }
221 
222  ~VectorAlloc(){
223  delete[] my_data;
224  }
225 
226  Precision *get_data_ptr()
227  {
228  return my_data;
229  };
230 
231  const Precision *get_data_ptr() const
232  {
233  return my_data;
234  }
235 
236  void swap(VectorAlloc& v)
237  {
238  SizeMismatch<Dynamic, Dynamic>::test(my_size, v.my_size);
239  std::swap(my_data, v.my_data);
240  }
241 
242  protected:
243 
244  Precision *data()
245  {
246  return my_data;
247  };
248 
249  const Precision *data() const
250  {
251  return my_data;
252  };
253 
254  void try_destructive_resize(int)
255  {}
256 
257  template<class Op> void try_destructive_resize(const Operator<Op>&)
258  {}
259 };
260 
261 
267 template<class Precision> struct VectorAlloc<Resizable, Precision>: public DefaultTypes<Precision> {
268  protected:
269  std::vector<Precision> numbers;
270 
271  public:
272 
273  VectorAlloc()
274  {
275  }
276 
277  VectorAlloc(std::initializer_list<Precision> i)
278  :numbers(i)
279  {
280  }
281 
282  VectorAlloc(int s)
283  :numbers(s)
284  {
285  debug_initialize(data(), size());
286  }
287 
288  template <class Op>
289  VectorAlloc(const Operator<Op>& op)
290  :numbers(op.size())
291  {
292  debug_initialize(data(), size());
293  }
294 
295  int size() const {
296  return numbers.size();
297  }
298 
299  Precision *get_data_ptr()
300  {
301  return data();
302  };
303 
304  const Precision *get_data_ptr() const
305  {
306  return data();
307  }
308 
309  void swap(VectorAlloc& s)
310  {
311  numbers.swap(s.numbers);
312  }
313 
314  protected:
315 
316  Precision* data() {
317  return &numbers[0];
318  }
319 
320  const Precision* data()const {
321  return &numbers[0];
322  }
323 
324  private:
325  //Dymmy class for implementing sfinae
326  //in order to test for a .size() member
327  template<int S> struct SFINAE_dummy{typedef void type;};
328 
329  protected:
330 
331  //SFINAE implementation of try_destructive_resize
332  //to avoid calling .size if it does not exist!
333 
334  //Force the function TYPE to depend on a property
335  //of the Operator<Op> type, so that it simply does
336  //not exist if the property is missing.
337  //Therefore this method only uses .size() if it exists.
338  template<class Op>
339  typename SFINAE_dummy<sizeof(&Operator<Op>::size)>::type try_destructive_resize(const Operator<Op>& op)
340  {
341  try_destructive_resize(op.size());
342  }
343 
344  //Catch-all do nothing for operators with no size method.
345  template<class Op>
346  void try_destructive_resize(const Op&)
347  {}
348 
349  void try_destructive_resize(int newsize)
350  {
351  numbers.resize(newsize);
352  debug_initialize(data(), newsize);
353  }
354 
355  public:
356 
357  void resize(int s)
358  {
359  int old_size = size();
360  numbers.resize(s);
361  if(s > old_size)
362  debug_initialize(data()+old_size, s-old_size);
363  }
364 };
365 
370 //template<int S, class Precision, class PtrType=Precision*, class ConstPtrType=const Precision*, class RefType=Precision&, class ConstRefType=const Precision&> struct VectorSlice
371 template<int S, class Precision, class PtrType=Precision*, class ConstPtrType=const Precision*, class RefType=Precision&, class ConstRefType=const Precision&> struct VectorSlice
372 {
373  int size() const {
374  return S;
375  }
376 
377  //Optional Constructors
378 
379  const PtrType my_data;
380  VectorSlice(PtrType p)
381  :my_data(p){}
382 
383  VectorSlice(PtrType p, int /*size*/)
384  :my_data(p){}
385 
386  template<class Op>
387  VectorSlice(const Operator<Op>& op) : my_data(op.data()) {}
388 
389  protected:
390  PtrType data()
391  {
392  return my_data;
393  };
394 
395  ConstPtrType data() const
396  {
397  return my_data;
398  };
399 
400  void try_destructive_resize(int)
401  {}
402 
403  template<class Op> void try_destructive_resize(const Operator<Op>&)
404  {}
405 
406  public:
407  typedef PtrType PointerType;
408  typedef ConstPtrType ConstPointerType;
409  typedef RefType ReferenceType;
410  typedef ConstRefType ConstReferenceType;
411 };
412 
417 template<class Precision, class PtrType, class ConstPtrType, class RefType, class ConstRefType> struct VectorSlice<Dynamic, Precision, PtrType, ConstPtrType, RefType, ConstRefType>
418 {
419  const PtrType my_data;
420  const int my_size;
421 
422  VectorSlice(PtrType d, int s)
423  :my_data(d), my_size(s)
424  { }
425 
426  template<class Op>
427  VectorSlice(const Operator<Op>& op) : my_data(op.data()), my_size(op.size()) {}
428 
429  int size() const {
430  return my_size;
431  }
432 
433  protected:
434 
435  PtrType data()
436  {
437  return my_data;
438  };
439 
440  ConstPtrType data() const
441  {
442  return my_data;
443  };
444 
445  void try_destructive_resize(int)
446  {}
447 
448  template<class Op> void try_destructive_resize(const Operator<Op>&)
449  {}
450 
451  public:
452  typedef PtrType PointerType;
453  typedef ConstPtrType ConstPointerType;
454  typedef RefType ReferenceType;
455  typedef ConstRefType ConstReferenceType;
456 };
457 
459 //
460 // A class similar to StrideHolder, but to hold the size information for matrices.
461 
468 template<int s> struct SizeHolder
469 {
470  //Constructors ignore superfluous arguments
472  SizeHolder(int){}
473 
475  int size() const{
476  return s;
477  }
478 };
479 
483 template<> struct SizeHolder<-1>
484 {
487  SizeHolder(int s)
488  :my_size(s){}
490 
491  const int my_size;
492  int size() const {
494  return my_size;
495  }
496 };
497 
502 template<int S> struct RowSizeHolder: private SizeHolder<S>
503 {
508  :SizeHolder<S>(i){}
509 
510  RowSizeHolder()
511  {}
512 
516  template<typename Op>
517  RowSizeHolder(const Operator<Op>& op) : SizeHolder<S>(op.num_rows()) {}
518 
520  int num_rows() const {return SizeHolder<S>::size();}
521 };
522 
523 
528 template<int S> struct ColSizeHolder: private SizeHolder<S>
529 {
534  :SizeHolder<S>(i){}
535 
536  ColSizeHolder()
537  {}
538 
542  template<typename Op>
543  ColSizeHolder(const Operator<Op>& op) : SizeHolder<S>(op.num_cols()) {}
544 
546  int num_cols() const {return SizeHolder<S>::size();}
547 };
548 
549 
550 
551 template<int R, int C, class Precision, bool FullyStatic=(R>=0 && C>=0)>
553 {
554  MatrixAlloc(int,int)
555  {}
556 
557  MatrixAlloc()
558  {}
559 
560  template <class Op>
561  MatrixAlloc(const Operator<Op>&)
562  {}
563 
564  int num_rows() const {
565  return R;
566  }
567 
568  int num_cols() const {
569  return C;
570  }
571 
573 
574  Precision* get_data_ptr()
575  {
576  return my_data;
577  }
578 
579  const Precision* get_data_ptr() const
580  {
581  return my_data;
582  }
583 };
584 
585 
586 template<int R, int C, class Precision> struct MatrixAlloc<R, C, Precision, false>
587  : public RowSizeHolder<R>,
588  ColSizeHolder<C>
589 {
590  Precision* const my_data;
591 
594 
595  // copy constructor so guaranteed contiguous
596  MatrixAlloc(const MatrixAlloc& m)
597  :RowSizeHolder<R>(m.num_rows()),
598  ColSizeHolder<C>(m.num_cols()),
599  my_data(new Precision[num_rows()*num_cols()]) {
600  const int size=num_rows()*num_cols();
601  for(int i=0; i < size; i++) {
602  my_data[i] = m.my_data[i];
603  }
604  }
605 
606  MatrixAlloc(int r, int c)
607  :RowSizeHolder<R>(r),
608  ColSizeHolder<C>(c),
609  my_data(new Precision[num_rows()*num_cols()])
610  {
611  debug_initialize(my_data, num_rows()*num_cols());
612  }
613 
614  template <class Op> MatrixAlloc(const Operator<Op>& op)
615  :RowSizeHolder<R>(op),
616  ColSizeHolder<C>(op),
617  my_data(new Precision[num_rows()*num_cols()])
618  {
619  debug_initialize(my_data, num_rows()*num_cols());
620  }
621 
622  ~MatrixAlloc() {
623  delete[] my_data;
624  }
625 
626  Precision* get_data_ptr()
627  {
628  return my_data;
629  }
630 
631  const Precision* get_data_ptr() const
632  {
633  return my_data;
634  }
635 };
636 
637 
638 template<int R, int C, class Precision> struct MatrixSlice
639  : public RowSizeHolder<R>,
640  ColSizeHolder<C>
641 {
642  Precision* const my_data;
643 
646 
647  //Optional Constructors
648  MatrixSlice(Precision* p)
649  :my_data(p){}
650 
651  MatrixSlice(Precision* p, int r, int c)
652  :RowSizeHolder<R>(r),
653  ColSizeHolder<C>(c),
654  my_data(p){}
655 
656  template<class Op>
657  MatrixSlice(const Operator<Op>& op)
658  :RowSizeHolder<R>(op),
659  ColSizeHolder<C>(op),
660  my_data(op.data())
661  {}
662 };
663 
664 
666 //
667 // A class similar to mem, but to hold the stride information. It is only needed
668 // for -1. For +int and -2, the stride is part fo teh type, or implicit.
669 
670 template<int s> struct StrideHolder
671 {
672  //Constructos ignore superfluous arguments
673  StrideHolder(){}
674  StrideHolder(int){}
675 
676  template<class Op>
677  StrideHolder(const Operator<Op>&) {}
678 
679  int stride() const{
680  return s;
681  }
682 };
683 
684 template<> struct StrideHolder<-1>
685 {
686  StrideHolder(int s)
687  :my_stride(s){}
688 
689  template<class Op>
690  StrideHolder(const Operator<Op>& op) : my_stride(op.stride()) {}
691 
692  const int my_stride;
693  int stride() const {
694  return my_stride;
695  }
696 };
697 
698 
699 template<int S> struct RowStrideHolder: public StrideHolder<S>
700 {
701  RowStrideHolder(int i)
702  :StrideHolder<S>(i){}
703 
704  RowStrideHolder()
705  {}
706 
707  template<class Op>
708  RowStrideHolder(const Operator<Op>& op)
709  : StrideHolder<S>(op)
710  {}
711 
712 };
713 
714 
715 template<int S> struct ColStrideHolder: public StrideHolder<S>
716 {
717  ColStrideHolder(int i)
718  :StrideHolder<S>(i){}
719 
720  ColStrideHolder()
721  {}
722 
723  template<class Op>
724  ColStrideHolder(const Operator<Op>& op)
725  : StrideHolder<S>(op)
726  {}
727 };
728 
729 }
730 
731 }
732 
733 
734 #undef TOON_ALIGN8
Definition: allocator.hh:528
Definition: allocator.hh:58
Pretty generic SFINAE introspection generator.
Definition: vec_test.cc:21
Definition: allocator.hh:699
Definition: allocator.hh:49
VectorAlloc(int)
Construction from a size (required by damic vectors, ignored otherwise).
Definition: allocator.hh:128
Definition: allocator.hh:715
const int my_size
The size.
Definition: allocator.hh:491
RowSizeHolder(int i)
Construct from an int to provide a run time size if necessary.
Definition: allocator.hh:507
VectorAlloc()
Default constructor (only for statically sized vectors)
Definition: allocator.hh:125
Definition: operators.hh:119
int num_rows() const
Return the number of rows.
Definition: allocator.hh:520
SizeHolder(int)
Construct from an int and discard it.
Definition: allocator.hh:472
int num_cols() const
Return the number of columns.
Definition: allocator.hh:546
int size() const
Simply return the statcally known size.
Definition: allocator.hh:475
ColSizeHolder(int i)
Construct from an int to provide a run time size if necessary.
Definition: allocator.hh:533
int size() const
Return the size of the vector.
Definition: allocator.hh:143
VectorAlloc(const Operator< Op > &)
Construction from an Operator. See Operator::size().
Definition: allocator.hh:140
RowSizeHolder(const Operator< Op > &op)
Construct from an Operator, taking the size from the operator.
Definition: allocator.hh:517
ColSizeHolder(const Operator< Op > &op)
Construct from an Operator, taking the size from the operator.
Definition: allocator.hh:543
Definition: size_mismatch.hh:103
Definition: allocator.hh:638
Definition: allocator.hh:670
Definition: allocator.hh:371
SizeHolder()
Default constrution.
Definition: allocator.hh:471
Definition: introspection.hh:55
Definition: allocator.hh:122
Definition: allocator.hh:502
Definition: allocator.hh:112
Definition: allocator.hh:552
Definition: allocator.hh:468