123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- #pragma once
- #include "alloc.h"
- #include <util/system/align.h>
- #include <util/system/yassert.h>
- #include <util/generic/bitops.h>
- #include <util/generic/utility.h>
- #include <util/generic/intrlist.h>
- #include <util/generic/strbuf.h>
- #include <util/generic/singleton.h>
- #include <new>
- #include <string>
- #include <utility>
- /**
- * Memory pool implements a memory allocation scheme that is very fast, but
- * limited in its usage.
- *
- * A common use case is when you want to allocate a bunch of small objects, and
- * then release them all at some point of your program. Using memory pool, you
- * can just drop them off into oblivion without calling any destructors,
- * provided that all associated memory was allocated on the pool.
- */
- class TMemoryPool {
- private:
- using TBlock = IAllocator::TBlock;
- class TChunk: public TIntrusiveListItem<TChunk> {
- public:
- inline TChunk(size_t len = 0) noexcept
- : Cur_((char*)(this + 1))
- , Left_(len)
- {
- Y_ASSERT((((size_t)Cur_) % PLATFORM_DATA_ALIGN) == 0);
- }
- inline void* Allocate(size_t len) noexcept {
- if (Left_ >= len) {
- char* ret = Cur_;
- Cur_ += len;
- Left_ -= len;
- return ret;
- }
- return nullptr;
- }
- inline void* Allocate(size_t len, size_t align) noexcept {
- size_t pad = AlignUp(Cur_, align) - Cur_;
- void* ret = Allocate(pad + len);
- if (ret) {
- return static_cast<char*>(ret) + pad;
- }
- return nullptr;
- }
- inline size_t BlockLength() const noexcept {
- return (Cur_ + Left_) - (char*)this;
- }
- inline size_t Used() const noexcept {
- return Cur_ - (const char*)this;
- }
- inline size_t Left() const noexcept {
- return Left_;
- }
- inline const char* Data() const noexcept {
- return (const char*)(this + 1);
- }
- inline char* Data() noexcept {
- return (char*)(this + 1);
- }
- inline size_t DataSize() const noexcept {
- return Cur_ - Data();
- }
- inline void ResetChunk() noexcept {
- size_t total = DataSize() + Left();
- Cur_ = Data();
- Left_ = total;
- }
- private:
- char* Cur_;
- size_t Left_;
- };
- using TChunkList = TIntrusiveList<TChunk>;
- public:
- class IGrowPolicy {
- public:
- virtual ~IGrowPolicy() = default;
- virtual size_t Next(size_t prev) const noexcept = 0;
- };
- class TLinearGrow: public IGrowPolicy {
- public:
- size_t Next(size_t prev) const noexcept override {
- return prev;
- }
- static IGrowPolicy* Instance() noexcept;
- };
- class TExpGrow: public IGrowPolicy {
- public:
- size_t Next(size_t prev) const noexcept override {
- return prev * 2;
- }
- static IGrowPolicy* Instance() noexcept;
- };
- struct TOptions {
- bool RoundUpToNextPowerOfTwo;
- TOptions()
- : RoundUpToNextPowerOfTwo(true)
- {
- }
- };
- inline TMemoryPool(size_t initial, IGrowPolicy* grow = TExpGrow::Instance(), IAllocator* alloc = TDefaultAllocator::Instance(), const TOptions& options = TOptions())
- : Current_(&Empty_)
- , BlockSize_(initial)
- , GrowPolicy_(grow)
- , Alloc_(alloc)
- , Options_(options)
- , Origin_(initial)
- , MemoryAllocatedBeforeCurrent_(0)
- , MemoryWasteBeforeCurrent_(0)
- {
- }
- inline ~TMemoryPool() {
- Clear();
- }
- inline void* Allocate(size_t len) {
- return RawAllocate(AlignUp<size_t>(len, PLATFORM_DATA_ALIGN));
- }
- inline void* Allocate(size_t len, size_t align) {
- return RawAllocate(AlignUp<size_t>(len, PLATFORM_DATA_ALIGN), align);
- }
- template <typename T>
- inline T* Allocate() {
- return (T*)this->Allocate(sizeof(T), alignof(T));
- }
- template <typename T>
- inline T* Allocate(size_t align) {
- return (T*)this->Allocate(sizeof(T), Max(align, alignof(T)));
- }
- template <typename T>
- inline T* AllocateArray(size_t count) {
- return (T*)this->Allocate(sizeof(T) * count, alignof(T));
- }
- template <typename T>
- inline T* AllocateArray(size_t count, size_t align) {
- return (T*)this->Allocate(sizeof(T) * count, Max(align, alignof(T)));
- }
- template <typename T>
- inline T* AllocateZeroArray(size_t count) {
- T* ptr = AllocateArray<T>(count);
- memset(ptr, 0, count * sizeof(T));
- return ptr;
- }
- template <typename T>
- inline T* AllocateZeroArray(size_t count, size_t align) {
- T* ptr = AllocateArray<T>(count, align);
- memset(ptr, 0, count * sizeof(T));
- return ptr;
- }
- template <typename T, typename... Args>
- inline T* New(Args&&... args) {
- return new (Allocate<T>()) T(std::forward<Args>(args)...);
- }
- template <typename T>
- inline T* NewArray(size_t count) {
- T* arr = (T*)AllocateArray<T>(count);
- for (T *ptr = arr, *end = arr + count; ptr != end; ++ptr) {
- new (ptr) T;
- }
- return arr;
- }
- template <typename TChar>
- inline TChar* Append(const TChar* str) {
- return Append(str, std::char_traits<TChar>::length(str) + 1); // include terminating zero byte
- }
- template <typename TChar>
- inline TChar* Append(const TChar* str, size_t len) {
- TChar* ret = AllocateArray<TChar>(len);
- std::char_traits<TChar>::copy(ret, str, len);
- return ret;
- }
- template <typename TChar>
- inline TBasicStringBuf<TChar> AppendString(const TBasicStringBuf<TChar>& buf) {
- return TBasicStringBuf<TChar>(Append(buf.data(), buf.size()), buf.size());
- }
- template <typename TChar>
- inline TBasicStringBuf<TChar> AppendCString(const TBasicStringBuf<TChar>& buf) {
- TChar* ret = static_cast<TChar*>(Allocate((buf.size() + 1) * sizeof(TChar)));
- std::char_traits<TChar>::copy(ret, buf.data(), buf.size());
- *(ret + buf.size()) = 0;
- return TBasicStringBuf<TChar>(ret, buf.size());
- }
- inline size_t Available() const noexcept {
- return Current_->Left();
- }
- inline void Clear() noexcept {
- DoClear(false);
- }
- inline void ClearKeepFirstChunk() noexcept {
- DoClear(true);
- }
- inline size_t ClearReturnUsedChunkCount(bool keepFirstChunk) noexcept {
- return DoClear(keepFirstChunk);
- }
- inline size_t MemoryAllocated() const noexcept {
- return MemoryAllocatedBeforeCurrent_ + (Current_ != &Empty_ ? Current_->Used() : 0);
- }
- inline size_t MemoryWaste() const noexcept {
- return MemoryWasteBeforeCurrent_ + (Current_ != &Empty_ ? Current_->Left() : 0);
- }
- template <class TOp>
- inline void Traverse(TOp& op) const noexcept {
- for (TChunkList::TConstIterator i = Chunks_.Begin(); i != Chunks_.End(); ++i) {
- op(i->Data(), i->DataSize());
- }
- }
- inline IAllocator* RealAllocator() const noexcept {
- return Alloc_;
- }
- protected:
- inline void* RawAllocate(size_t len) {
- void* ret = Current_->Allocate(len);
- if (ret) {
- return ret;
- }
- AddChunk(len);
- return Current_->Allocate(len);
- }
- inline void* RawAllocate(size_t len, size_t align) {
- Y_ASSERT(align > 0);
- void* ret = Current_->Allocate(len, align);
- if (ret) {
- return ret;
- }
- AddChunk(len + align - 1);
- return Current_->Allocate(len, align);
- }
- private:
- void AddChunk(size_t hint);
- size_t DoClear(bool keepfirst) noexcept;
- private:
- TChunk Empty_;
- TChunk* Current_;
- size_t BlockSize_;
- IGrowPolicy* GrowPolicy_;
- IAllocator* Alloc_;
- TOptions Options_;
- TChunkList Chunks_;
- const size_t Origin_;
- size_t MemoryAllocatedBeforeCurrent_;
- size_t MemoryWasteBeforeCurrent_;
- };
- template <typename TPool>
- struct TPoolableBase {
- inline void* operator new(size_t bytes, TPool& pool) {
- return pool.Allocate(bytes);
- }
- inline void* operator new(size_t bytes, std::align_val_t align, TPool& pool) {
- return pool.Allocate(bytes, (size_t)align);
- }
- inline void operator delete(void*, size_t) noexcept {
- }
- inline void operator delete(void*, TPool&) noexcept {
- }
- private:
- inline void* operator new(size_t); // disallow default allocation
- };
- struct TPoolable: public TPoolableBase<TMemoryPool> {
- };
- class TMemoryPoolAllocator: public IAllocator {
- public:
- inline TMemoryPoolAllocator(TMemoryPool* pool)
- : Pool_(pool)
- {
- }
- TBlock Allocate(size_t len) override {
- TBlock ret = {Pool_->Allocate(len), len};
- return ret;
- }
- void Release(const TBlock& block) override {
- (void)block;
- }
- private:
- TMemoryPool* Pool_;
- };
- template <class T, class TPool>
- class TPoolAllocBase {
- public:
- using pointer = T*;
- using const_pointer = const T*;
- using reference = T&;
- using const_reference = const T&;
- using size_type = size_t;
- using difference_type = ptrdiff_t;
- using value_type = T;
- inline TPoolAllocBase(TPool* pool)
- : Pool_(pool)
- {
- }
- template <typename TOther>
- inline TPoolAllocBase(const TPoolAllocBase<TOther, TPool>& o)
- : Pool_(o.GetPool())
- {
- }
- inline T* allocate(size_t n) {
- return (T*)Pool_->Allocate(n * sizeof(T), alignof(T));
- }
- inline void deallocate(pointer /*p*/, size_t /*n*/) {
- }
- template <class T1>
- struct rebind {
- using other = TPoolAllocBase<T1, TPool>;
- };
- inline size_type max_size() const noexcept {
- return size_type(-1) / sizeof(T);
- }
- template <typename... Args>
- inline void construct(pointer p, Args&&... args) {
- new (p) T(std::forward<Args>(args)...);
- }
- inline void destroy(pointer p) noexcept {
- (void)p; /* Make MSVC happy. */
- p->~T();
- }
- inline TPool* GetPool() const {
- return Pool_;
- }
- inline friend bool operator==(const TPoolAllocBase& l, const TPoolAllocBase& r) {
- return l.Pool_ == r.Pool_;
- }
- inline friend bool operator!=(const TPoolAllocBase& l, const TPoolAllocBase& r) {
- return !(l == r);
- }
- private:
- TPool* Pool_;
- };
- template <class T>
- using TPoolAlloc = TPoolAllocBase<T, TMemoryPool>;
- // Any type since it is supposed to be rebound anyway.
- using TPoolAllocator = TPoolAlloc<int>;
- template <class T>
- inline bool operator==(const TPoolAlloc<T>&, const TPoolAlloc<T>&) noexcept {
- return true;
- }
- template <class T>
- inline bool operator!=(const TPoolAlloc<T>&, const TPoolAlloc<T>&) noexcept {
- return false;
- }
|