General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

176 lines
3.1 KiB

#pragma once
#include "gp/exception.hpp"
#include "gp/algorithm/tmp_manip.hpp"
namespace gp{
template <typename>
class function;
template <typename ret, typename ...args>
class function<ret(args...)>{
struct virtual_callable
{
virtual void inplace_copy(char*) = 0;
virtual virtual_callable* all_copy() = 0;
virtual ~virtual_callable() = default;
virtual ret operator() (args...) = 0;
};
template<typename fn>
class callable : public virtual_callable{
fn internal_representation;
public:
callable(const fn& func)
: internal_representation{func}
{}
callable(callable&) = default;
virtual ~callable() override = default;
virtual void inplace_copy(char* ptr) override {
new(ptr) callable(*this);
}
virtual virtual_callable* all_copy() override {
return new callable(*this);
}
ret operator() (args... arg_list) override
{
return internal_representation(arg_list...);
}
};
// tweak a way to store a size in there for trivial copy
enum state_t : uint8_t{
INACTIVE = 0,
ACTIVE = 1,
NO_SOO = 0,
SOO = 2
};
state_t state{};
union{
virtual_callable* functor = nullptr;
char inplace[12];
} self;
public:
template <typename T>
function& operator=(T& t)
{
if(state & ACTIVE)
{
if(state & SOO)
{
((virtual_callable*)self.inplace)->~virtual_callable();
}
else
{
delete self.functor;
}
}
if(t.state | ACTIVE)
{
if constexpr (sizeof(callable<T>) <= sizeof(self))
{
t.self.functor->inplace_copy(self.inplace);
state = (state_t)(ACTIVE | SOO);
}
else
{
self.functor = t.self.functor->all_copy();
state = (state_t)(ACTIVE | NO_SOO);
}
return;
}
state = INACTIVE;
}
function()
{
state = INACTIVE;
}
template <typename T>
function(T t)
{
if constexpr (sizeof(callable<T>) <= sizeof(self))
{
new((void*)self.inplace) callable<T>(t);
state = (state_t)(ACTIVE | SOO);
}
else
{
self.functor = new callable<T>(t);
state = (state_t)(ACTIVE | NO_SOO);
}
}
template<>
function<function>(function& t) {
if(t.state & SOO)
{
t.self.functor->inplace_copy(self.inplace);
state = (state_t)(ACTIVE | SOO);
}
else
{
self.functor = t.self.functor->all_copy();
state = (state_t)(ACTIVE | NO_SOO);
}
}
template <typename T>
function(T& t)
{
if constexpr (sizeof(callable<T>) <= sizeof(self))
{
new((void*)&self) callable<T>(t);
state = (state_t)(ACTIVE | SOO);
}
else
{
self.functor = new callable<T>(t);
state = (state_t)(ACTIVE | NO_SOO);
}
}
ret operator()(args... arg_list) const {
if constexpr (gp_config::has_exceptions)
{
if(!(state & ACTIVE))
{
throw bad_functor{};
}
}
if(state & SOO)
{
return (*(virtual_callable*)&self)(arg_list...);
}
else
{
return (*self.functor)(arg_list...);
}
}
~function()
{
if(state & ACTIVE)
{
if(state & SOO)
{
((virtual_callable*)&self)->~virtual_callable();
}
else
{
delete self.functor;
}
}
}
};
}