|
|
- #pragma once
- #include "gp/exception.hpp"
- #include "gp/algorithm/tmp_manip.hpp"
- #include "gp/algorithm/move.hpp"
-
- namespace gp{
-
- template <typename>
- class function;
-
- template <typename ret, typename ...args>
- class function<ret(args...)>{
- struct virtual_callable
- {
- virtual void inplace_move(char*) = 0;
- virtual virtual_callable* all_copy() = 0;
- virtual void inplace_copy(char*) = 0;
- virtual virtual_callable* all_move() = 0;
- virtual ~virtual_callable() = default;
- virtual ret operator() (args...) = 0;
- };
-
- template<typename fn>
- class callable final : public virtual_callable{
- typename gp::remove_reference<fn>::type internal_representation;
- public:
- callable(const fn func)
- : internal_representation{gp::move(func)}
- {}
-
- callable(callable&) = default;
- 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);
- }
-
- virtual void inplace_move(char* ptr) override {
- new(ptr) callable(gp::move(*this));
- }
-
- virtual virtual_callable* all_move() override {
- return new callable(gp::move(*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))
- {
- state = INACTIVE;
- return;
- }
- if constexpr (!std::is_same_v<T, function<ret(args...)>>) {
- 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);
- }
- } else {
- if(t.state & SOO)
- {
- auto& ref = t.self.functor;
- ref->inplace_copy((char*)&self);
- state = (state_t)(ACTIVE | SOO);
- }
- else
- {
- self.functor = t.self.functor->all_copy();
- state = (state_t)(ACTIVE | NO_SOO);
- }
- }
- }
-
- function()
- {
- state = INACTIVE;
- }
-
- template<typename T>
- function<>(T& t)
- {
- if constexpr (!std::is_same_v<T, function<ret(args...)>>) {
- 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);
- }
- } else {
- 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 (!std::is_same_v<T, function<ret(args...)>>) {
- if constexpr (sizeof(callable<T>) <= sizeof(self))
- {
- new((void*)self.inplace) callable<T>(gp::move(t));
- state = (state_t)(ACTIVE | SOO);
- }
- else
- {
- self.functor = new callable<T>(gp::move(t));
- state = (state_t)(ACTIVE | NO_SOO);
- }
- } else {
- if(t.state & SOO)
- {
- auto& ref = t.self.functor;
- ref->inplace_move((char*)&self);
- state = (state_t)(ACTIVE | SOO);
- }
- else
- {
- self.functor = t.self.functor->all_move();
- 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;
- }
- }
-
- }
- };
-
- }
|