Last active
October 20, 2018 16:43
-
-
Save matovitch/b6988b785f875af596b3b6b6c08a093b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
#include <memory> | |
#include <vector> | |
#include <iostream> | |
namespace buffer | |
{ | |
template <class Type> | |
struct TAbstract | |
{ | |
virtual Type* allocate() = 0; | |
}; | |
template <class Traits> | |
class TStack : public Traits::Abstract | |
{ | |
using Memory = typename Traits::Memory; | |
using Type = typename Traits::Type; | |
static constexpr auto head = Traits::head; | |
static constexpr auto tail = Traits::tail; | |
public: | |
TStack() : | |
_head{head(&_memory)}, | |
_tail{tail(&_memory)} | |
{} | |
Type* allocate() override | |
{ | |
if (_head == _tail) | |
{ | |
return nullptr; | |
} | |
return _head++; | |
} | |
void clean() | |
{ | |
auto temp = head(&_memory); | |
while (temp != _head) | |
{ | |
temp->~Type(); | |
temp++; | |
} | |
_head = head(&_memory); | |
} | |
~TStack() | |
{ | |
clean(); | |
} | |
private: | |
Type* _head; | |
const Type* const _tail; | |
Memory _memory; | |
}; | |
namespace stack | |
{ | |
template <class StackType, std::size_t SIZE> | |
struct TTraits | |
{ | |
using Type = StackType; | |
using Abstract = TAbstract<Type>; | |
using Memory = std::aligned_storage_t<sizeof(Type) * SIZE, alignof(Type)>; | |
static constexpr auto head = [](Memory* memoryPtr) { return reinterpret_cast<Type*>(memoryPtr) ; }; | |
static constexpr auto tail = [](Memory* memoryPtr) { return reinterpret_cast<Type*>(memoryPtr) + SIZE ; }; | |
}; | |
} // namespace stack | |
template <class Type, std::size_t SIZE> | |
using TMakeStack = TStack<stack::TTraits<Type, SIZE>>; | |
template <class Traits> | |
class THeap : public Traits::Abstract | |
{ | |
using Type = typename Traits::Type; | |
public: | |
THeap(const std::size_t size) : | |
_memory{new Type[size]} | |
{ | |
_head = _memory; | |
_tail = _memory + size; | |
} | |
Type* allocate() override | |
{ | |
if (_head == _tail) | |
{ | |
return nullptr; | |
} | |
return _head++; | |
} | |
void clean() | |
{ | |
auto temp = _memory; | |
while (temp != _head) | |
{ | |
temp->~Type(); | |
temp++; | |
} | |
_head = _memory; | |
} | |
~THeap() | |
{ | |
clean(); | |
delete[] _memory; | |
_memory = nullptr; | |
} | |
private: | |
Type* _head; | |
const Type* _tail; | |
Type* _memory; | |
}; | |
namespace heap | |
{ | |
template <class HeapType> | |
struct TTraits | |
{ | |
using Type = HeapType; | |
using Abstract = TAbstract<Type>; | |
}; | |
} // namespace heap | |
template <class Type> | |
using TMakeHeap = THeap<heap::TTraits<Type>>; | |
} // namespace buffer | |
template <class Traits> | |
class TStableAddressAmortizedAllocator | |
{ | |
using Type = typename Traits::Type; | |
using AbstractBuffer = typename Traits::AbstractBuffer; | |
using StackBuffer = typename Traits:: StackBuffer; | |
using HeapBuffer = typename Traits:: HeapBuffer; | |
static constexpr std::size_t SIZE = Traits::SIZE; | |
public: | |
TStableAddressAmortizedAllocator() : | |
_bufferPtr{&_stackBuffer}, | |
_size{SIZE} | |
{} | |
Type* allocate() | |
{ | |
if (!_recycleds.empty()) | |
{ | |
Type* const ptr = _recycleds.back(); | |
_recycleds.pop_back(); | |
return ptr; | |
} | |
Type* const ptr = _bufferPtr->allocate(); | |
if (!ptr) | |
{ | |
_heapBuffers.emplace_back(std::make_unique<HeapBuffer>(_size <<= 1)); | |
_bufferPtr = _heapBuffers.back().get(); | |
return _heapBuffers.back()->allocate(); | |
} | |
return ptr; | |
} | |
void recycle(Type* ptr) | |
{ | |
_recycleds.emplace_back(ptr); | |
} | |
void clean() | |
{ | |
_stackBuffer.clean(); | |
for (auto& heapBuffer : _heapBuffers) | |
{ | |
heapBuffer.clean(); | |
} | |
} | |
void freeMemory() | |
{ | |
_stackBuffer.clean(); | |
_heapBuffers.clear(); | |
_bufferPtr = &_stackBuffer; | |
} | |
private: | |
AbstractBuffer* _bufferPtr; | |
StackBuffer _stackBuffer; | |
std::vector<Type*> _recycleds; | |
std::vector<std::unique_ptr<HeapBuffer>> _heapBuffers; | |
std::size_t _size; | |
}; | |
namespace stable_address_amortized_allocator | |
{ | |
template <class TraitsType, std::size_t TRAITS_SIZE> | |
struct TTraits | |
{ | |
static constexpr std::size_t SIZE = TRAITS_SIZE; | |
using Type = TraitsType; | |
using StackBuffer = buffer::TMakeStack <Type, SIZE>; | |
using AbstractBuffer = buffer::TAbstract <Type>; | |
using HeapBuffer = buffer::TMakeHeap <Type>; | |
}; | |
} // namespace stable_address_amortized_allocator | |
template <class Type, std::size_t SIZE> | |
using TMakeStableAddressAmortizedAllocator = TStableAddressAmortizedAllocator<stable_address_amortized_allocator::TTraits<Type, SIZE>>; | |
template <class Traits> | |
class TStableAddressAmortizedFactory | |
{ | |
using Type = typename Traits::Type; | |
using Allocator = typename Traits::Allocator; | |
public: | |
template <class... Args> | |
Type& make(Args&&... args) | |
{ | |
return *(new(static_cast<void *>(_allocator.allocate())) Type(std::forward<Args>(args)...)); | |
} | |
void recycle(Type& value) | |
{ | |
value.~Type(); | |
_allocator.recycle(&value); | |
} | |
private: | |
Allocator _allocator; | |
}; | |
namespace stable_address_amortized_factory | |
{ | |
template <class TraitsType, std::size_t SIZE> | |
struct TTraits | |
{ | |
using Type = TraitsType; | |
using Allocator = TMakeStableAddressAmortizedAllocator<Type, SIZE>; | |
}; | |
} // namespace stable_address_amortized_factory | |
template <class Type, std::size_t SIZE> | |
using TMakeStableAddressAmortizedFactory = TStableAddressAmortizedFactory<stable_address_amortized_factory::TTraits<Type, SIZE>>; | |
template <class Traits> | |
class TStableAddressAmortized | |
{ | |
using Factory = typename Traits::Factory; | |
using Type = typename Traits::Type; | |
public: | |
template <class... Args> | |
TStableAddressAmortized(Args&&... args) : | |
value{_factory.make(args...)} | |
{ | |
} | |
~TStableAddressAmortized() | |
{ | |
_factory.recycle(value); | |
} | |
Type& value; | |
private: | |
static Factory _factory; | |
}; | |
namespace stable_address_amortized | |
{ | |
template <class TraitsType, std::size_t SIZE> | |
struct TTraits | |
{ | |
using Type = TraitsType; | |
using Factory = TMakeStableAddressAmortizedFactory<Type, SIZE>; | |
}; | |
} // namespace stable_address_amortized | |
template <class Type, std::size_t SIZE> | |
using TMakeStableAddressAmortized = TStableAddressAmortized<stable_address_amortized::TTraits<Type, SIZE>>; | |
using Int = TMakeStableAddressAmortized<int, 2>; | |
template <> | |
typename Int::Factory Int::_factory{}; | |
int main() | |
{ | |
Int i1{42}; | |
Int i2{43}; | |
Int i3{44}; | |
Int i4{45}; | |
Int i5{46}; | |
Int i6{47}; | |
Int i7{48}; | |
Int i8{49}; | |
std::cout << &(i1.value) << " : " << i1.value << std::endl; | |
std::cout << &(i2.value) << " : " << i2.value << std::endl; | |
std::cout << &(i3.value) << " : " << i3.value << std::endl; | |
std::cout << &(i4.value) << " : " << i4.value << std::endl; | |
std::cout << &(i5.value) << " : " << i5.value << std::endl; | |
std::cout << &(i6.value) << " : " << i6.value << std::endl; | |
std::cout << &(i7.value) << " : " << i7.value << std::endl; | |
std::cout << &(i8.value) << " : " << i8.value << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment