// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved. #pragma once #include "../Collections/Array.h" #include "Engine/Platform/CriticalSection.h" namespace CollectionPoolCacheUtils { /// /// Clear callback used to initialize the given collection container type (clear array, etc.). Called when pool item is being reused or initialized. /// template using ClearCallback = void(*)(T*); /// /// Create callback spawns a new entry of the pooled collection /// template using CreateCallback = T * (*)(); template inline void DefaultClearCallback(T* obj) { obj->Clear(); } template inline T* DefaultCreateCallback() { return New(); } } /// /// Cache container that holds a list of cached collections to allow reuse and reduced memory allocation amount. Helps with sharing data across code and usages. It's thread-safe. /// template ClearCallback = CollectionPoolCacheUtils::DefaultClearCallback, CollectionPoolCacheUtils::CreateCallback CreateCallback = CollectionPoolCacheUtils::DefaultCreateCallback> class CollectionPoolCache { public: /// /// Helper object used to access the pooled collection and return it to the pool after usage (on code scope execution end). /// struct ScopeCache { friend CollectionPoolCache; private: CollectionPoolCache* _pool; ScopeCache(CollectionPoolCache* pool, T* value) { _pool = pool; Value = value; } public: T* Value; ~ScopeCache() { _pool->Release(Value); } T* operator->() { return Value; } const T* operator->() const { return Value; } T& operator*() { return *Value; } const T& operator*() const { return *Value; } }; private: CriticalSection _locker; Array> _pool; void Release(T* value) { _locker.Lock(); _pool.Add(value); _locker.Unlock(); } public: /// /// Finalizes an instance of the class. /// ~CollectionPoolCache() { _pool.ClearDelete(); } public: /// /// Gets the collection instance from the pool. Can reuse the object from the pool or create a new one. Returns collection is always cleared and ready to use. /// /// The collection (cleared). ScopeCache Get() { T* result; _locker.Lock(); if (_pool.HasItems()) result = _pool.Pop(); else result = CreateCallback(); _locker.Unlock(); ClearCallback(result); return ScopeCache(this, result); } /// /// Releases all the allocated resources (existing in the pool that are not during usage). /// void Release() { _locker.Lock(); _pool.ClearDelete(); _pool.Resize(0); _locker.Unlock(); } };