Last active
October 20, 2018 15:26
-
-
Save matovitch/445364514aa191b4bfb5e0313ba8b3e1 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 <iostream> | |
namespace buffer | |
{ | |
template <class Type> | |
struct TView | |
{ | |
Type* const head = nullptr; | |
const Type* const tail = nullptr; | |
}; | |
template <class Traits> | |
class TAbstract | |
{ | |
using View = typename Traits::View; | |
using Heap = typename Traits::Heap; | |
public: | |
virtual View makeView() = 0; | |
virtual std::unique_ptr<Heap> makeLargeHeap() const = 0; | |
}; | |
template <class Traits> | |
class THeap : public Traits::Abstract | |
{ | |
using Type = typename Traits::Type; | |
using View = typename Traits::View; | |
public: | |
THeap(const std::size_t size) : | |
_memory{new Type[size]}, | |
_size{size} | |
{} | |
View makeView() override | |
{ | |
return {_memory, _memory + _size}; | |
} | |
std::unique_ptr<THeap> makeLargeHeap() const override | |
{ | |
return std::make_unique<THeap>(_size << 1); | |
} | |
std::unique_ptr<THeap> makeSmallHeap() const | |
{ | |
return std::make_unique<THeap>(_size >> 2); | |
} | |
~THeap() | |
{ | |
delete[] _memory; | |
_memory = nullptr; | |
} | |
private: | |
Type* _memory; | |
std::size_t _size; | |
}; | |
template <class Traits> | |
class TStack : public Traits::Abstract | |
{ | |
using Memory = typename Traits::Memory; | |
using View = typename Traits::View; | |
using Heap = typename Traits::Heap; | |
static constexpr auto MAKE_VIEW = Traits::MAKE_VIEW; | |
static constexpr auto MAKE_LARGE_HEAP = Traits::MAKE_LARGE_HEAP; | |
public: | |
View makeView() override | |
{ | |
return MAKE_VIEW(_memory); | |
} | |
std::unique_ptr<Heap> makeLargeHeap() const override | |
{ | |
return MAKE_LARGE_HEAP(); | |
} | |
private: | |
Memory _memory; | |
}; | |
namespace abstract | |
{ | |
template <class> | |
struct TTraits; | |
} // namespace abstract | |
template <class Type> | |
using TMakeAbstract = TAbstract<abstract::TTraits<Type>>; | |
namespace heap | |
{ | |
template <class TraitsType> | |
struct TTraits | |
{ | |
using Type = TraitsType; | |
using View = TView<Type>; | |
using Abstract = TMakeAbstract<Type>; | |
}; | |
} // namespace heap | |
template <class Type> | |
using TMakeHeap = THeap<heap::TTraits<Type>>; | |
namespace abstract | |
{ | |
template <class Type> | |
struct TTraits | |
{ | |
using View = TView<Type>; | |
using Heap = TMakeHeap<Type>; | |
}; | |
} // namespace abstract | |
namespace stack | |
{ | |
template <class Type, std::size_t SIZE> | |
struct TTraits | |
{ | |
using View = TView <Type>; | |
using Abstract = TMakeAbstract <Type>; | |
using Heap = TMakeHeap <Type>; | |
using Memory = std::aligned_storage_t<sizeof(Type) * SIZE, alignof(Type)>; | |
static constexpr auto MAKE_VIEW = | |
[](Memory& memory) | |
{ | |
return View{ reinterpret_cast<Type*>(&memory), | |
reinterpret_cast<Type*>(&memory) + SIZE }; | |
}; | |
static constexpr auto MAKE_LARGE_HEAP = | |
[]() | |
{ | |
return std::make_unique<Heap>(SIZE << 1); | |
}; | |
}; | |
} // namespace stack | |
template <class Type, std::size_t SIZE> | |
using TMakeStack = TStack<stack::TTraits<Type, SIZE>>; | |
} // namespace buffer | |
template <class Traits> | |
class TSwapAmortizedAllocator | |
{ | |
using AbstractBuffer = typename Traits::AbstractBuffer; | |
using StackBuffer = typename Traits:: StackBuffer; | |
using HeapBuffer = typename Traits:: HeapBuffer; | |
using View = typename Traits::View; | |
public: | |
enum | |
{ | |
LARGE, | |
SMALL | |
}; | |
TSwapAmortizedAllocator() : | |
_bufferPtr{&_stackBuffer} | |
{} | |
View makeView() | |
{ | |
return _bufferPtr->makeView(); | |
} | |
template <int VIEW_TYPE> | |
View makeView() | |
{ | |
_swapBufferPtr = std::move(_heapBufferPtr); | |
if constexpr (VIEW_TYPE == LARGE) | |
{ | |
_heapBufferPtr = _bufferPtr->makeLargeHeap(); | |
} | |
if constexpr (VIEW_TYPE == SMALL) | |
{ | |
_heapBufferPtr = _swapBufferPtr->makeSmallHeap(); | |
} | |
return _heapBufferPtr->makeView(); | |
} | |
void swap() | |
{ | |
_bufferPtr = _heapBufferPtr.get(); | |
} | |
private: | |
AbstractBuffer* _bufferPtr; | |
StackBuffer _stackBuffer; | |
std::unique_ptr<HeapBuffer> _heapBufferPtr; | |
std::unique_ptr<HeapBuffer> _swapBufferPtr; | |
}; | |
namespace swap_amortized_allocator | |
{ | |
template <class Type, std::size_t SIZE> | |
struct TTraits | |
{ | |
using StackBuffer = buffer::TMakeStack <Type, SIZE>; | |
using AbstractBuffer = buffer::TMakeAbstract <Type>; | |
using HeapBuffer = buffer::TMakeHeap <Type>; | |
using View = buffer::TView <Type>; | |
}; | |
} // namespace swap_amortizer_allocator | |
int main() | |
{ | |
using Allocator = TSwapAmortizedAllocator<swap_amortized_allocator::TTraits<int, 4>>; | |
Allocator allocator; | |
auto view1 = allocator.makeView(); | |
auto view2 = allocator.makeView<Allocator::LARGE>(); | |
allocator.swap(); | |
auto view3 = allocator.makeView<Allocator::LARGE>(); | |
allocator.swap(); | |
auto view4 = allocator.makeView<Allocator::SMALL>(); | |
std::cout << view1.head << " - " << view1.tail << std::endl; | |
std::cout << view2.head << " - " << view2.tail << std::endl; | |
std::cout << view3.head << " - " << view3.tail << std::endl; | |
std::cout << view4.head << " - " << view4.tail << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment