#pragma once
#include "pool.h"
#include "alloc.h"
#include <util/generic/utility.h>
#include <util/generic/intrlist.h>
class TFixedSizeAllocator {
struct TAlloc: public TIntrusiveSListItem<TAlloc> {
inline void* ToPointer() noexcept {
return this;
}
static inline TAlloc* FromPointer(void* ptr) noexcept {
return (TAlloc*)ptr;
}
static constexpr size_t EntitySize(size_t alloc) noexcept {
return Max(sizeof(TAlloc), alloc);
}
static constexpr size_t EntityAlign(size_t align) noexcept {
return Max(alignof(TAlloc), align);
}
static inline TAlloc* Construct(void* ptr) noexcept {
return (TAlloc*)ptr;
}
};
public:
using IGrowPolicy = TMemoryPool::IGrowPolicy;
TFixedSizeAllocator(size_t allocSize, IAllocator* alloc)
: TFixedSizeAllocator(allocSize, alignof(TAlloc), TMemoryPool::TExpGrow::Instance(), alloc)
{
}
TFixedSizeAllocator(size_t allocSize, size_t alignSize, IAllocator* alloc)
: TFixedSizeAllocator(allocSize, alignSize, TMemoryPool::TExpGrow::Instance(), alloc)
{
}
TFixedSizeAllocator(size_t allocSize, IGrowPolicy* grow, IAllocator* alloc)
: TFixedSizeAllocator(allocSize, alignof(TAlloc), grow, alloc)
{
}
TFixedSizeAllocator(size_t allocSize, size_t alignSize, IGrowPolicy* grow, IAllocator* alloc)
: Pool_(allocSize, grow, alloc)
, AlignSize_(TAlloc::EntityAlign(alignSize))
, AllocSize_(TAlloc::EntitySize(allocSize))
{
}
inline void* Allocate() {
if (Y_UNLIKELY(Free_.Empty())) {
return Pool_.Allocate(AllocSize_, AlignSize_);
}
return Free_.PopFront()->ToPointer();
}
inline void Release(void* ptr) noexcept {
Free_.PushFront(TAlloc::FromPointer(ptr));
}
inline size_t Size() const noexcept {
return AllocSize_;
}
private:
TMemoryPool Pool_;
const size_t AlignSize_;
const size_t AllocSize_;
TIntrusiveSList<TAlloc> Free_;
};
template <class T>
class TSmallObjAllocator {
public:
using IGrowPolicy = TFixedSizeAllocator::IGrowPolicy;
inline TSmallObjAllocator(IAllocator* alloc)
: Alloc_(sizeof(T), alignof(T), alloc)
{
}
inline TSmallObjAllocator(IGrowPolicy* grow, IAllocator* alloc)
: Alloc_(sizeof(T), alignof(T), grow, alloc)
{
}
inline T* Allocate() {
return (T*)Alloc_.Allocate();
}
inline void Release(T* t) noexcept {
Alloc_.Release(t);
}
private:
TFixedSizeAllocator Alloc_;
};
template <class T>
class TObjectFromPool {
public:
struct THeader {
void* Pool;
// Can't just use T because THeader must be standard layout type for offsetof to work.
alignas(T) char Obj[sizeof(T)];
};
using TPool = TSmallObjAllocator<THeader>;
inline void* operator new(size_t, TPool* pool) {
THeader* ret = pool->Allocate();
ret->Pool = pool;
return &ret->Obj;
}
inline void operator delete(void* ptr, size_t) noexcept {
DoDelete(ptr);
}
inline void operator delete(void* ptr, TPool*) noexcept {
/*
* this delete operator can be called automagically by compiler
*/
DoDelete(ptr);
}
private:
static inline void DoDelete(void* ptr) noexcept {
static_assert(std::is_standard_layout<THeader>::value, "offsetof is only defined for standard layout types");
THeader* header = (THeader*)((char*)ptr - offsetof(THeader, Obj));
((TPool*)header->Pool)->Release(header);
}
};