Ardour  9.0-rc1-54-g6eeed82fb3
stack_allocator.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2020 Robin Gareus <robin@gareus.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #ifndef PBD_STACK_ALLOCATOR_H
20 #define PBD_STACK_ALLOCATOR_H
21 
22 #include <boost/type_traits/aligned_storage.hpp>
23 #include <limits>
24 
25 #include "pbd/libpbd_visibility.h"
26 
27 #if 0
28 # include <cstdio>
29 # define DEBUG_STACK_ALLOC(...) printf (__VA_ARGS__)
30 #else
31 # define DEBUG_STACK_ALLOC(...)
32 #endif
33 
34 #ifdef COMPILER_MSVC
35 #undef max
36 #endif
37 
38 namespace PBD {
39 
40 template <class T, std::size_t stack_capacity>
41 class /*LIBPBD_API*/ StackAllocator
42 {
43 public:
44 #if 0 /* may be needed for compatibility */
45  typedef typename std::allocator<T>::value_type value_type;
46  typedef typename std::allocator<T>::size_type size_type;
47  typedef typename std::allocator<T>::difference_type difference_type;
48  typedef typename std::allocator<T>::pointer pointer;
49  typedef typename std::allocator<T>::const_pointer const_pointer;
50  typedef typename std::allocator<T>::reference reference;
51  typedef typename std::allocator<T>::const_reference const_reference;
52 #else
53  typedef T value_type;
54  typedef std::size_t size_type;
55  typedef std::ptrdiff_t difference_type;
56  typedef value_type* pointer;
57  typedef const value_type* const_pointer;
59  typedef const value_type& const_reference;
60 #endif
61 
62  template <class U>
63  struct rebind {
65  };
66 
68  : _ptr ((pointer)&_buf)
69  { }
70 
72  : _ptr ((pointer)&_buf)
73  { }
74 
75  template <typename U, size_t other_capacity>
77  : _ptr ((pointer)&_buf)
78  { }
79 
80  /* inspired by http://howardhinnant.github.io/stack_alloc.h */
81  pointer allocate (size_type n, void* hint = 0)
82  {
83  if ((pointer)&_buf + stack_capacity >= _ptr + n) {
84  DEBUG_STACK_ALLOC ("[%p] Allocate %ld item(s) of size %zu on the stack. used: %ld\n", (pointer)&_buf, n, sizeof (T), (_ptr - (pointer)&_buf));
85  pointer rv = _ptr;
86  _ptr += n;
87  return rv;
88  } else {
89  DEBUG_STACK_ALLOC ("[%p] Allocate using new (%ld * %zu)\n", (pointer)&_buf, n, sizeof (T));
90  return static_cast<pointer> (::operator new (n * sizeof (T)));
91  }
92  }
93 
95  {
96  DEBUG_STACK_ALLOC ("[%p] Deallocate: %ld item(s), at %p (offset: %ld) used: %ld\n", (pointer)&_buf, n, p, p - (pointer)&_buf, (_ptr - (pointer)&_buf));
97  if (pointer_in_buffer (p)) {
98  if (p + n == _ptr) {
99  DEBUG_STACK_ALLOC ("[%p] Deallocate: pop item from the top of the stack %ld\n", (pointer)&_buf, n);
100  _ptr = p;
101  } else {
102  DEBUG_STACK_ALLOC ("[%p] Deallocate: ignored. Item is not at the top of the stack %ld\n", (pointer)&_buf, n);
103  }
104  } else {
105  DEBUG_STACK_ALLOC ("[%p] Deallocate: using delete %p %ld\n", (pointer)&_buf, p, n);
106  ::operator delete (p);
107  }
108  }
109 
110  size_type max_size () const throw ()
111  {
112  return std::numeric_limits<size_type>::max () / sizeof (T);
113  }
114 
115  bool operator== (StackAllocator const& a) const
116  {
117  return &_buf == &a._buf;
118  }
119 
120  bool operator!= (StackAllocator const& a) const
121  {
122  return &_buf != &a._buf;
123  }
124 
125  template <class U>
126  void destroy (U* const p)
127  {
128  p->~U ();
129  }
130 
131  template <class U>
132  void construct (U* const p)
133  {
134  new (p) U ();
135  }
136 
137 #if __cplusplus > 201103L || defined __clang__
138  template <class U, class A>
139  void construct (U* const p, A* const a)
140  {
141  new (p) U (a);
142  }
143 #else
144  template <class U, class A>
145  void construct (U* const p, A const& a)
146  {
147  new (p) U (a);
148  }
149 #endif
150 
151 private:
153 
154  bool pointer_in_buffer (pointer const p)
155  {
156  return ((pointer const)&_buf <= p && p < (pointer const)&_buf + stack_capacity);
157  }
158 
159  typedef typename boost::aligned_storage<sizeof (T) * stack_capacity, 16>::type align_t;
160 
163 };
164 
165 } // namespace PBD
166 
167 #endif
void construct(U *const p)
boost::aligned_storage< sizeof(T) *stack_capacity, 16 >::type align_t
size_type max_size() const
pointer allocate(size_type n, void *hint=0)
StackAllocator & operator=(const StackAllocator &)
const value_type & const_reference
value_type * pointer
StackAllocator(const StackAllocator< U, other_capacity > &)
void construct(U *const p, A const &a)
bool pointer_in_buffer(pointer const p)
void destroy(U *const p)
std::ptrdiff_t difference_type
value_type & reference
void deallocate(pointer p, size_type n)
const value_type * const_pointer
bool operator!=(StackAllocator const &a) const
StackAllocator(const StackAllocator &)
bool operator==(StackAllocator const &a) const
Definition: axis_view.h:42
#define DEBUG_STACK_ALLOC(...)
StackAllocator< U, stack_capacity > other