#ifndef __Recycled__
#define __Recycled__
#include "Forwards.hpp"
#include "Stack.hpp"
#include <memory>
#include "Lib/Reflection.hpp"
#include "Lib/Hash.hpp"
namespace Lib
{
struct DefaultReset
{
template<class T> void operator()(T& t) { t.reset(); }
template<unsigned i, unsigned sz, class Tup>
struct __ResetTuple
{
static void apply(Tup& self)
{
std::get<i>(self).reset();
__ResetTuple<i + 1, sz, Tup>::apply(self);
}
};
template<unsigned i, class Tup>
struct __ResetTuple<i, i, Tup> {
static void apply(Tup& self)
{ std::get<i>(self).reset(); }
};
void operator()(std::tuple<>& t) {}
template<class A, class... As>
void operator()(std::tuple<A, As...>& t)
{ __ResetTuple<0, std::tuple_size<std::tuple<A, As...>>::value - 1, std::tuple<A, As...>>::apply(t); }
};
struct DefaultKeepRecycled
{
template<class T> bool operator()(T const& t) { return t.keepRecycled(); }
template<unsigned i, unsigned sz, class Tup>
struct __KeepRecycledTuple
{
static bool apply(Tup const& self)
{ return std::get<i>(self).keepRecycled()
|| __KeepRecycledTuple<i + 1, sz, Tup>::apply(self); }
};
template<unsigned i, class Tup>
struct __KeepRecycledTuple<i, i, Tup> {
static bool apply(Tup const& self)
{ return std::get<i>(self).keepRecycled(); }
};
bool operator()(std::tuple<> const& t) { return false; }
template<class A, class... As>
bool operator()(std::tuple<A, As...> const& t)
{ return __KeepRecycledTuple<0, std::tuple_size<std::tuple<A, As...>>::value - 1, std::tuple<A, As...>>::apply(t); }
};
struct NoReset
{ template<class T> void operator()(T& t) { } };
template<class T>
struct MaybeAlive
{
T _self;
bool* _alive;
MaybeAlive(T self, bool* alive)
: _self(std::move(self)), _alive(alive)
{ *_alive = true; }
~MaybeAlive() { *_alive = false; }
T const& operator* () const { return _self; }
T const* operator->() const { return &_self; }
T& operator* () { return _self; }
T* operator->() { return &_self; }
};
#define USE_PTRS 1
#if USE_PTRS
#define IF_USE_PTRS(l, r) l
#else
#define IF_USE_PTRS(l, r) r
#endif
template<class T, class Reset = DefaultReset, class Keep = DefaultKeepRecycled>
class Recycled
{
using Self = IF_USE_PTRS(std::unique_ptr<T>,T);
Self _self;
Reset _reset;
Keep _keep;
static bool memAlive;
static Stack<Self>& mem() {
static MaybeAlive<Stack<Self>> mem(Stack<Self>(), &memAlive);
return *mem;
}
Recycled(Recycled const&) = delete;
T & self() { ASS(alive()) return IF_USE_PTRS(*, )_self; }
T const& self() const { ASS(alive()) return IF_USE_PTRS(*, )_self; }
struct EmptyConstructMarker {};
public:
Recycled()
: _self(mem().isNonEmpty() ? mem().pop() : IF_USE_PTRS(std::make_unique<T>(), T()))
{ }
template<class A, class... As>
Recycled(A a, As... as)
: _self([&](){
if (mem().isNonEmpty()) {
auto elem = mem().pop();
elem->init(std::move(a), std::move(as)...);
return elem;
} else {
return IF_USE_PTRS(std::make_unique<T>, T)(std::move(a), std::move(as)...);
}
}())
{ }
template<class Clone>
Recycled clone(Clone cloneFn) const
{
Recycled c;
T const& from = **this;
T& to = *c;
cloneFn(to, from);
return c;
}
bool alive() const { return IF_USE_PTRS(bool(_self), true); }
auto asTuple() const -> decltype(auto) { return std::make_tuple(someIf(alive(), [this]() -> decltype(auto) { return self(); })); }
IMPL_COMPARISONS_FROM_TUPLE(Recycled);
IMPL_HASH_FROM_TUPLE(Recycled);
Recycled(Recycled&& other) = default;
Recycled& operator=(Recycled&& other) = default;
~Recycled()
{
if (IF_USE_PTRS(_self, true) && _keep(self()) && memAlive) {
_reset(self());
mem().push(std::move(_self));
}
}
T const& operator* () const { return self(); }
T const* operator->() const { return &self(); }
T& operator* () { return self(); }
T* operator->() { return &self(); }
auto size() const { return self().size(); }
template<class Idx> decltype(auto) operator[](Idx idx) const { return self()[idx]; }
template<class Idx> decltype(auto) operator[](Idx idx) { return self()[idx]; }
friend std::ostream& operator<<(std::ostream& out, Recycled const& self)
{ if (self.alive())return out << self.self(); else return out << "Recycled(NULL)"; }
};
template<class T, class Reset, class Keep>
bool Recycled<T, Reset, Keep>::memAlive = true;
};
template<class T>
using RStack = Recycled<Stack<T>>;
template<class T>
Recycled<Stack<T>> recycledStack()
{ return Recycled<Stack<T>>(); }
template<class T, class... Ts>
Recycled<Stack<T>> recycledStack(T t, Ts... ts)
{
Recycled<Stack<T>> out;
out->pushMany(std::move(t), std::move(ts)...);
return out;
}
#endif