From 50556db40561cf75d2b72fde26c837395d54a36a Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Fri, 6 Mar 2020 19:07:01 +0100 Subject: [PATCH] Add a STL Allocator using the stack (for rt safety) This is a dumb stack allocator using LIFO allocation/free, with a fallback to new/delete. This works well for small STL containers in particular std::vector, but it's also suitable for std::map<>, in particular copy constructing small POD maps (plugin pin mappings). Eventually this could be combined with TLSF for a flexible memory arena management. This is however not currently needed for any the planned use-cases. This code is ANSI C++98 compatible, and yet also works with modern C++11, C++14 --- libs/pbd/pbd/stack_allocator.h | 159 +++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 libs/pbd/pbd/stack_allocator.h diff --git a/libs/pbd/pbd/stack_allocator.h b/libs/pbd/pbd/stack_allocator.h new file mode 100644 index 0000000000..d719b5c5f3 --- /dev/null +++ b/libs/pbd/pbd/stack_allocator.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2020 Robin Gareus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef PBD_STACK_ALLOCATOR_H +#define PBD_STACK_ALLOCATOR_H + +#include +#include + +#include "pbd/libpbd_visibility.h" + +#if 0 +# include +# define DEBUG_STACK_ALLOC(...) printf (__VA_ARGS__) +#else +# define DEBUG_STACK_ALLOC(...) +#endif + +namespace PBD { + +template +class /*LIBPBD_API*/ StackAllocator +{ +public: +#if 0 /* may be needed for compatibility */ + typedef typename std::allocator::value_type value_type; + typedef typename std::allocator::size_type size_type; + typedef typename std::allocator::difference_type difference_type; + typedef typename std::allocator::pointer pointer; + typedef typename std::allocator::const_pointer const_pointer; + typedef typename std::allocator::reference reference; + typedef typename std::allocator::const_reference const_reference; +#else + typedef T value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; +#endif + + template + struct rebind { + typedef StackAllocator other; + }; + + StackAllocator () + : _ptr ((pointer)&_buf) + { } + + StackAllocator (const StackAllocator&) + : _ptr ((pointer)&_buf) + { } + + template + StackAllocator (const StackAllocator&) + : _ptr ((pointer)&_buf) + { } + + /* inspired by http://howardhinnant.github.io/stack_alloc.h */ + pointer allocate (size_type n, void* hint = 0) + { + if ((pointer)&_buf + stack_capacity >= _ptr + n) { + DEBUG_STACK_ALLOC ("Allocate %ld item(s) of size %zu on the stack\n", n, sizeof (T)); + pointer rv = _ptr; + _ptr += n; + return rv; + } else { + DEBUG_STACK_ALLOC ("Allocate using new (%ld * %zu)\n", n, sizeof (T)); + return static_cast (::operator new (n * sizeof (T))); + } + } + + void deallocate (pointer p, size_type n) + { + if (pointer_in_buffer (p)) { + if (p + n == _ptr) { + DEBUG_STACK_ALLOC ("Deallocate: pop item from the top of the stack\n"); + _ptr = p; + } else { + DEBUG_STACK_ALLOC ("Deallocate: ignored. Item is not at the top of the stack \n"); + } + } else { + ::operator delete (p); + } + } + + size_type max_size () const throw () + { + return std::numeric_limits::max () / sizeof (T); + } + + bool operator== (StackAllocator const& a) const + { + return &_buf == &a._buf; + } + + bool operator!= (StackAllocator const& a) const + { + return &_buf != &a._buf; + } + + template + void destroy (U* const p) + { + p->~U (); + } + + template + void construct (U* const p) + { + new (p) U (); + } + + template + void construct (U* const p, A& a) + { + new (p) U (a); + } + + template + void construct (U* const p, A& a, B& b) + { + new (p) U (a, b); + } + +private: + StackAllocator& operator= (const StackAllocator&); + + bool pointer_in_buffer (pointer const p) + { + return ((pointer const)&_buf <= p && p < (pointer const)&_buf + stack_capacity); + } + + typedef typename boost::aligned_storage::type align_t; + + align_t _buf; + pointer _ptr; +}; + +} // namespace PBD + +#endif