Program Listing for File static_allocator.hpp¶
↰ Return to documentation for file (stream-client/stream/detail/static_allocator.hpp
)
#pragma once
#include <cstddef>
#include <new>
namespace stream_client {
namespace stream {
namespace detail {
class static_pool
{
public:
static static_pool& construct(std::size_t size)
{
auto* p = new char[sizeof(static_pool) + size];
return *(::new (p) static_pool{size});
}
static_pool& share()
{
++refs_;
return *this;
}
void destroy()
{
if (--refs_) {
return;
}
this->~static_pool();
delete[] reinterpret_cast<char*>(this);
}
void* alloc(std::size_t n)
{
auto* last = p_ + n;
if (last >= end()) {
throw std::bad_alloc{};
}
++count_;
auto* p = p_;
p_ = last;
return p;
}
void dealloc()
{
if (--count_) {
return;
}
p_ = reinterpret_cast<char*>(this + 1);
}
private:
char* end()
{
return reinterpret_cast<char*>(this + 1) + size_;
}
explicit static_pool(std::size_t size)
: size_(size)
, p_(reinterpret_cast<char*>(this + 1))
{
}
std::size_t size_;
std::size_t refs_ = 1;
std::size_t count_ = 0;
char* p_;
};
template <typename T>
class static_allocator
{
public:
using value_type = T;
using pointer = T*;
using reference = T&;
using const_pointer = const T*;
using const_reference = const T&;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
static_allocator() = default;
explicit static_allocator(std::size_t size)
: pool_(&static_pool::construct(size))
{
}
static_allocator(const static_allocator& other)
: pool_(&other.pool_->share())
{
}
template <typename U>
static_allocator(const static_allocator<U>& other)
: pool_(&other.pool_->share())
{
}
~static_allocator()
{
pool_->destroy();
}
value_type* allocate(size_type n)
{
return static_cast<value_type*>(pool_->alloc(n * sizeof(T)));
}
void deallocate(value_type* /*unused*/, size_type /*unused*/)
{
pool_->dealloc();
}
void deallocate(value_type* /*unused*/)
{
pool_->dealloc();
}
template <typename U>
friend bool operator==(const static_allocator& lhs, const static_allocator<U>& rhs)
{
return &lhs.pool_ == &rhs.pool_;
}
template <typename U>
friend bool operator!=(const static_allocator& lhs, const static_allocator<U>& rhs)
{
return !(lhs == rhs);
}
private:
template <typename U>
friend class static_allocator;
static_pool* pool_;
};
} // namespace detail
} // namespace stream
} // namespace stream_client