/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2015-2018 Danny Robson */ #ifndef CRUFT_UTIL_ALLOC_ARENA_HPP #define CRUFT_UTIL_ALLOC_ARENA_HPP #include "../memory/deleter.hpp" #include "../cast.hpp" #include "../view.hpp" #include #include namespace cruft::alloc { /// wraps a block allocator with an interface suitable for allocating /// individual objects. template class arena { public: explicit arena (T &store): m_store (store) { ; } //--------------------------------------------------------------------- template U* acquire (Args&&... args) { U *data = m_store.template allocate (1).data (); try { new (data) U (std::forward (args)...); } catch (...) { m_store.template deallocate ({data,1}); throw; } return data; } //--------------------------------------------------------------------- template void release (U *u) { u->~U (); m_store.template deallocate (cruft::view {u,1u}); } //--------------------------------------------------------------------- template using deleter_t = cruft::memory::owner_deleter< U,arena,&arena::release >; template using unique_t = std::unique_ptr>; // the return type must be auto and the implementation must be inline // otherwise we trigger an internal compiler error in gcc-5.2.0 // "sorry, unimplemented: mangling offset_ref" template auto unique (Args&& ...args) { return unique_t { acquire (std::forward (args)...), deleter_t (*this) }; } private: T &m_store; }; /// A simple allocator that contains a raw allocator and a forwarded /// allocator. /// /// The raw allocator handles the memory allocation, the forwarded /// allocator performs the initialisation, and we control the construction /// of both. /// /// Ideally we wouldn't forward calls manually and instead do something /// like inherit from arena, but that makes it difficult to initialise /// the raw allocator before we have to supply the reference to the arena. template class owned { public: template owned (ArgsT &&...args): m_store (std::forward (args)...), m_arena {m_store} { ; } template decltype(auto) acquire (ArgsT &&...args) { return m_arena.template acquire (std::forward (args)...); } template decltype(auto) release (ArgsT &&...args) { return m_arena.release (std::forward (args)...); } template decltype(auto) unique (ArgsT &&...args) { return m_arena.template unique (std::forward (args)...); } template decltype(auto) reset (Args&&...args) { return m_store.reset (std::forward (args)...); } private: AllocT m_store; arena m_arena; }; }; #endif