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; 54 typedef value_type& reference; 55 typedef const value_type& const_reference; 56 #endif 57 58 template <class U> 59 struct rebind { 60 typedef StackAllocator<U, stack_capacity> other; 61 }; 62 StackAllocator()63 StackAllocator () 64 : _ptr ((pointer)&_buf) 65 { } 66 StackAllocator(const StackAllocator &)67 StackAllocator (const StackAllocator&) 68 : _ptr ((pointer)&_buf) 69 { } 70 71 template <typename U, size_t other_capacity> StackAllocator(const StackAllocator<U,other_capacity> &)72 StackAllocator (const StackAllocator<U, 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 ("Allocate %ld item(s) of size %zu on the stack\n", n, sizeof (T)); 81 pointer rv = _ptr; 82 _ptr += n; 83 return rv; 84 } else { 85 DEBUG_STACK_ALLOC ("Allocate using new (%ld * %zu)\n", n, sizeof (T)); 86 return static_cast<pointer> (::operator new (n * sizeof (T))); 87 } 88 } 89 deallocate(pointer p,size_type n)90 void deallocate (pointer p, size_type n) 91 { 92 if (pointer_in_buffer (p)) { 93 if (p + n == _ptr) { 94 DEBUG_STACK_ALLOC ("Deallocate: pop item from the top of the stack\n"); 95 _ptr = p; 96 } else { 97 DEBUG_STACK_ALLOC ("Deallocate: ignored. Item is not at the top of the stack \n"); 98 } 99 } else { 100 ::operator delete (p); 101 } 102 } 103 max_size()104 size_type max_size () const throw () 105 { 106 return std::numeric_limits<size_type>::max () / sizeof (T); 107 } 108 109 bool operator== (StackAllocator const& a) const 110 { 111 return &_buf == &a._buf; 112 } 113 114 bool operator!= (StackAllocator const& a) const 115 { 116 return &_buf != &a._buf; 117 } 118 119 template <class U> destroy(U * const p)120 void destroy (U* const p) 121 { 122 p->~U (); 123 } 124 125 template <class U> construct(U * const p)126 void construct (U* const p) 127 { 128 new (p) U (); 129 } 130 131 #if __cplusplus > 201103L || defined __clang__ 132 template <class U, class A> construct(U * const p,A * const a)133 void construct (U* const p, A* const a) 134 { 135 new (p) U (a); 136 } 137 #else 138 template <class U, class A> construct(U * const p,A const & a)139 void construct (U* const p, A const& a) 140 { 141 new (p) U (a); 142 } 143 #endif 144 145 private: 146 StackAllocator& operator= (const StackAllocator&); 147 pointer_in_buffer(pointer const p)148 bool pointer_in_buffer (pointer const p) 149 { 150 return ((pointer const)&_buf <= p && p < (pointer const)&_buf + stack_capacity); 151 } 152 153 typedef typename boost::aligned_storage<sizeof (T) * stack_capacity, 16>::type align_t; 154 155 align_t _buf; 156 pointer _ptr; 157 }; 158 159 } // namespace PBD 160 161 #endif 162