Ardour  9.0-pre0-1230-g49ff88fd75
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 namespace PBD {
35 
36 template <class T, std::size_t stack_capacity>
37 class /*LIBPBD_API*/ StackAllocator
38 {
39 public:
40 #if 0 /* may be needed for compatibility */
41  typedef typename std::allocator<T>::value_type value_type;
42  typedef typename std::allocator<T>::size_type size_type;
43  typedef typename std::allocator<T>::difference_type difference_type;
44  typedef typename std::allocator<T>::pointer pointer;
45  typedef typename std::allocator<T>::const_pointer const_pointer;
46  typedef typename std::allocator<T>::reference reference;
47  typedef typename std::allocator<T>::const_reference const_reference;
48 #else
49  typedef T value_type;
50  typedef std::size_t size_type;
51  typedef std::ptrdiff_t difference_type;
52  typedef value_type* pointer;
53  typedef const value_type* const_pointer;
55  typedef const value_type& const_reference;
56 #endif
57 
58  template <class U>
59  struct rebind {
61  };
62 
64  : _ptr ((pointer)&_buf)
65  { }
66 
68  : _ptr ((pointer)&_buf)
69  { }
70 
71  template <typename U, size_t other_capacity>
73  : _ptr ((pointer)&_buf)
74  { }
75 
76  /* inspired by http://howardhinnant.github.io/stack_alloc.h */
77  pointer allocate (size_type n, void* hint = 0)
78  {
79  if ((pointer)&_buf + stack_capacity >= _ptr + n) {
80  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));
81  pointer rv = _ptr;
82  _ptr += n;
83  return rv;
84  } else {
85  DEBUG_STACK_ALLOC ("[%p] Allocate using new (%ld * %zu)\n", (pointer)&_buf, n, sizeof (T));
86  return static_cast<pointer> (::operator new (n * sizeof (T)));
87  }
88  }
89 
91  {
92  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));
93  if (pointer_in_buffer (p)) {
94  if (p + n == _ptr) {
95  DEBUG_STACK_ALLOC ("[%p] Deallocate: pop item from the top of the stack %ld\n", (pointer)&_buf, n);
96  _ptr = p;
97  } else {
98  DEBUG_STACK_ALLOC ("[%p] Deallocate: ignored. Item is not at the top of the stack %ld\n", (pointer)&_buf, n);
99  }
100  } else {
101  DEBUG_STACK_ALLOC ("[%p] Deallocate: using delete %p %ld\n", (pointer)&_buf, p, n);
102  ::operator delete (p);
103  }
104  }
105 
106  size_type max_size () const throw ()
107  {
108  return std::numeric_limits<size_type>::max () / sizeof (T);
109  }
110 
111  bool operator== (StackAllocator const& a) const
112  {
113  return &_buf == &a._buf;
114  }
115 
116  bool operator!= (StackAllocator const& a) const
117  {
118  return &_buf != &a._buf;
119  }
120 
121  template <class U>
122  void destroy (U* const p)
123  {
124  p->~U ();
125  }
126 
127  template <class U>
128  void construct (U* const p)
129  {
130  new (p) U ();
131  }
132 
133 #if __cplusplus > 201103L || defined __clang__
134  template <class U, class A>
135  void construct (U* const p, A* const a)
136  {
137  new (p) U (a);
138  }
139 #else
140  template <class U, class A>
141  void construct (U* const p, A const& a)
142  {
143  new (p) U (a);
144  }
145 #endif
146 
147 private:
149 
150  bool pointer_in_buffer (pointer const p)
151  {
152  return ((pointer const)&_buf <= p && p < (pointer const)&_buf + stack_capacity);
153  }
154 
155  typedef typename boost::aligned_storage<sizeof (T) * stack_capacity, 16>::type align_t;
156 
159 };
160 
161 } // namespace PBD
162 
163 #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