Skip to content

Instantly share code, notes, and snippets.

@matovitch
Last active October 20, 2018 15:26
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/445364514aa191b4bfb5e0313ba8b3e1 to your computer and use it in GitHub Desktop.
Save matovitch/445364514aa191b4bfb5e0313ba8b3e1 to your computer and use it in GitHub Desktop.
#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