// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2023 Jason Volk // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. #pragma once #define HAVE_IRCD_ALLOCATOR_DYNAMIC_H namespace ircd::allocator { template struct dynamic; } /// The dynamic allocator provides a pool of a fixed size known at runtime. /// /// This allocator conducts a single new and delete for a pool allowing an STL /// container to operate without interacting with the rest of the system and /// without fragmentation. This is not as useful as the allocator::fixed in /// practice as the standard allocator is as good as this in many cases. This /// is still available as an analog to the fixed allocator in this suite. /// template struct ircd::allocator::dynamic :state { struct allocator; size_t head_size, data_size; std::unique_ptr arena; T *buf; public: allocator operator()(); operator allocator(); dynamic(const size_t &size) :state{size} ,head_size{size / 8} ,data_size{sizeof(T) * size + 16} ,arena { new __attribute__((aligned(16))) uint8_t[head_size + data_size] } ,buf { reinterpret_cast(arena.get() + head_size + (head_size % 16)) } { state::avail = reinterpret_cast(arena.get()); } }; /// The actual template passed to containers for using the dynamic allocator. /// /// See the notes for ircd::allocator::fixed::allocator for details. /// template struct ircd::allocator::dynamic::allocator { using value_type = T; using pointer = T *; using const_pointer = const T *; using reference = T &; using const_reference = const T &; using size_type = std::size_t; using difference_type = std::ptrdiff_t; dynamic *s; public: template struct rebind { using other = typename dynamic::allocator; }; size_type max_size() const { return s->size; } auto address(reference x) const { return &x; } auto address(const_reference x) const { return &x; } pointer __attribute__((malloc, returns_nonnull, warn_unused_result)) allocate(const size_type &n, const const_pointer &hint = nullptr) { const uint hintpos(hint? hint - s->buf : -1); return s->buf + s->state::allocate(n, hintpos); } void deallocate(const pointer &p, const size_type &n) { const uint pos(p - s->buf); s->state::deallocate(pos, n); } template allocator(const typename dynamic::allocator &s) noexcept :s{reinterpret_cast(s.s)} {} allocator(dynamic &s) noexcept :s{&s} {} allocator(allocator &&) = default; allocator(const allocator &) = default; friend bool operator==(const allocator &a, const allocator &b) { return &a == &b; } friend bool operator!=(const allocator &a, const allocator &b) { return &a == &b; } }; template inline typename ircd::allocator::dynamic::allocator ircd::allocator::dynamic::operator()() { return ircd::allocator::dynamic::allocator(*this); } template inline ircd::allocator::dynamic::operator allocator() { return ircd::allocator::dynamic::allocator(*this); }