diff --git a/include/ircd/allocator.h b/include/ircd/allocator.h index afd48ddf5..0d2041112 100644 --- a/include/ircd/allocator.h +++ b/include/ircd/allocator.h @@ -22,6 +22,7 @@ namespace ircd::allocator struct state; struct scope; struct profile; + template struct callback; template struct dynamic; template struct fixed; template struct twolevel; @@ -139,6 +140,101 @@ struct ircd::allocator::state {} }; +/// The callback allocator is a shell around the pre-c++17/20 boilerplate +/// jumble for allocator template creation. This is an alternative to virtual +/// functions to accomplish the same thing here. Implement the principal +/// allocate and deallocate functions and maintain an instance of +/// allocator::callback with them somewhere. +template +struct ircd::allocator::callback +{ + struct allocator; + + public: + using allocate_callback = std::function; + using deallocate_callback = std::function; + + allocate_callback ac; + deallocate_callback dc; + + allocator operator()(); + operator allocator(); + + callback(allocate_callback ac, deallocate_callback dc) + :ac{std::move(ac)} + ,dc{std::move(dc)} + {} +}; + +template +struct ircd::allocator::callback::allocator +{ + using value_type = T; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using is_always_equal = std::true_type; + using propagate_on_container_move_assignment = std::true_type; + + callback *s; + + public: + template struct rebind + { + typedef ircd::allocator::callback::allocator other; + }; + + T * + __attribute__((malloc, returns_nonnull, warn_unused_result)) + allocate(const size_type n, const T *const hint = nullptr) + { + assert(s && s->ac); + return s->ac(n, hint); + } + + void deallocate(T *const p, const size_type n = 1) + { + assert(s && s->dc); + return s->dc(p, n); + } + + template + allocator(const typename ircd::allocator::callback::allocator &s) noexcept + :s{s.s} + {} + + allocator(callback &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 +typename ircd::allocator::callback::allocator +ircd::allocator::callback::operator()() +{ + return ircd::allocator::callback::allocator(*this); +} + +template +ircd::allocator::callback::operator +allocator() +{ + return ircd::allocator::callback::allocator(*this); +} + /// The fixed allocator creates a block of data with a size known at compile- /// time. This structure itself is the state object for the actual allocator /// instance used in the container. Create an instance of this structure,