0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-29 10:12:39 +01:00

ircd::allocator: Add simple callback allocator.

This commit is contained in:
Jason Volk 2019-03-26 14:15:01 -07:00
parent 9dac813278
commit 08479976ad

View file

@ -22,6 +22,7 @@ namespace ircd::allocator
struct state;
struct scope;
struct profile;
template<class T = void> struct callback;
template<class T = char> struct dynamic;
template<class T = char, size_t = 512> struct fixed;
template<class T = char, size_t L0_SIZE = 512> 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<class T>
struct ircd::allocator::callback
{
struct allocator;
public:
using allocate_callback = std::function<T *(const size_t &, const T *const &)>;
using deallocate_callback = std::function<void (T *const &, const size_t &)>;
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<class T>
struct ircd::allocator::callback<T>::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<class U> struct rebind
{
typedef ircd::allocator::callback<T>::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<class U>
allocator(const typename ircd::allocator::callback<U>::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<class T>
typename ircd::allocator::callback<T>::allocator
ircd::allocator::callback<T>::operator()()
{
return ircd::allocator::callback<T>::allocator(*this);
}
template<class T>
ircd::allocator::callback<T>::operator
allocator()
{
return ircd::allocator::callback<T>::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,