Skip to content

Instantly share code, notes, and snippets.

@matovitch
Last active October 20, 2018 16:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matovitch/b6988b785f875af596b3b6b6c08a093b to your computer and use it in GitHub Desktop.
Save matovitch/b6988b785f875af596b3b6b6c08a093b to your computer and use it in GitHub Desktop.
#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