|
|
@ -2,13 +2,134 @@ |
|
|
|
#include "gp/exception.hpp"
|
|
|
|
#include "gp/algorithm/tmp_manip.hpp"
|
|
|
|
#include "gp/algorithm/move.hpp"
|
|
|
|
#include "gp/algorithm/modifiers.hpp"
|
|
|
|
|
|
|
|
namespace gp{ |
|
|
|
|
|
|
|
template <typename> |
|
|
|
template <typename fn, typename allocator, bool copy_allocator = false> |
|
|
|
class function; |
|
|
|
|
|
|
|
template <typename ret, typename ...args> |
|
|
|
template <typename ret, typename allocator, bool copy_allocator, typename ...args> |
|
|
|
class function<ret(args...), allocator, copy_allocator>{ |
|
|
|
using fn_ptr = char*; |
|
|
|
|
|
|
|
using invoke_fn_t = ret (*)(fn_ptr, args&&...); |
|
|
|
using condestruct_fn_t = void (*) (fn_ptr, fn_ptr); |
|
|
|
using allocator_t = typename gp::either< |
|
|
|
copy_allocator, |
|
|
|
allocator, |
|
|
|
gp::reference_wrapper<allocator> |
|
|
|
>::type; |
|
|
|
|
|
|
|
allocator_t alloc; |
|
|
|
invoke_fn_t invokator; |
|
|
|
condestruct_fn_t condestructor; |
|
|
|
fn_ptr data_ptr; |
|
|
|
size_t data_size; |
|
|
|
|
|
|
|
|
|
|
|
template<typename func> |
|
|
|
static ret invoke(func* fn, args&&... fw_args) { |
|
|
|
return (*fn)(gp::forward<args>(fw_args)...); |
|
|
|
} |
|
|
|
|
|
|
|
template<typename func> |
|
|
|
static void condestruct(func* dest, func* src) { |
|
|
|
if(dest != nullptr) { |
|
|
|
new (dest) func(*src); |
|
|
|
} else { |
|
|
|
src->~func(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void nop_condestruct(char*, char*) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
public: |
|
|
|
#pragma clang diagnostic push
|
|
|
|
#pragma clang diagnostic ignored "-Wnull-dereference"
|
|
|
|
#pragma gcc diagnostic push
|
|
|
|
#pragma gcc diagnostic ignored "-Wnull-dereference"
|
|
|
|
function(allocator_t alloc_v = gp::reference_wrapper<allocator_t>{*reinterpret_cast<allocator_t*>(0)}) |
|
|
|
#pragma gcc pop
|
|
|
|
#pragma clang pop
|
|
|
|
: alloc(alloc_v) |
|
|
|
, invokator(nullptr) |
|
|
|
, condestructor(nullptr) |
|
|
|
, data_ptr(nullptr) |
|
|
|
, data_size(0) |
|
|
|
{} |
|
|
|
|
|
|
|
template<typename func> |
|
|
|
function(func f, allocator_t alloc_v) |
|
|
|
: alloc(alloc_v) |
|
|
|
, invokator(reinterpret_cast<invoke_fn_t>(invoke<func>)) |
|
|
|
, condestructor(reinterpret_cast<condestruct_fn_t>(condestruct<func>)) |
|
|
|
, data_ptr((char*)((allocator&)alloc).allocate(sizeof(func))) |
|
|
|
, data_size(sizeof(func)) |
|
|
|
{ |
|
|
|
gp_config::assertion(data_ptr != nullptr, "allocator failed in function"); |
|
|
|
if(data_ptr != nullptr) this->condestructor(data_ptr, reinterpret_cast<char*>(&f)); |
|
|
|
} |
|
|
|
|
|
|
|
function(function const& rhs) |
|
|
|
: alloc(rhs.alloc) |
|
|
|
, invokator(rhs.invokator) |
|
|
|
, condestructor(rhs.condestructor) |
|
|
|
, data_ptr(rhs.data_size != 0 ? (char*)((allocator&)alloc).allocate(rhs.data_size) : nullptr) |
|
|
|
, data_size(rhs.data_size) |
|
|
|
{ |
|
|
|
gp_config::assertion(data_ptr != nullptr, "allocator failed in function"); |
|
|
|
if( |
|
|
|
data_ptr != nullptr |
|
|
|
and rhs.data_ptr != nullptr |
|
|
|
) this->condestructor(data_ptr, rhs.data_ptr); |
|
|
|
} |
|
|
|
|
|
|
|
function(function&& rhs) |
|
|
|
: alloc(rhs.alloc) |
|
|
|
, invokator(rhs.invokator) |
|
|
|
, condestructor(rhs.condestructor) |
|
|
|
, data_ptr(rhs.data_ptr) |
|
|
|
, data_size(rhs.data_size) |
|
|
|
{ |
|
|
|
rhs.data_ptr = nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
constexpr function(ret(*fn)(args...), allocator_t alloc_v = allocator_t{}) |
|
|
|
: alloc(alloc_v) |
|
|
|
, invokator(reinterpret_cast<invoke_fn_t>(invoke<ret(args...)>)) |
|
|
|
, condestructor(nop_condestruct) |
|
|
|
, data_ptr(reinterpret_cast<char*>(fn)) |
|
|
|
, data_size(0) |
|
|
|
{} |
|
|
|
|
|
|
|
~function(){ |
|
|
|
if(data_size == 0) { |
|
|
|
return; |
|
|
|
} |
|
|
|
if(data_ptr != nullptr) { |
|
|
|
condestructor(nullptr, data_ptr); |
|
|
|
((allocator&)alloc).deallocate(data_ptr); |
|
|
|
data_ptr = nullptr; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function& operator=(function&& rhs) { |
|
|
|
gp::swap(alloc, rhs.alloc); |
|
|
|
gp::swap(invokator, rhs.invokator); |
|
|
|
gp::swap(condestructor, rhs.condestructor); |
|
|
|
gp::swap(data_ptr,rhs.data_ptr); |
|
|
|
gp::swap(data_size,rhs.data_size); |
|
|
|
return *this; |
|
|
|
} |
|
|
|
|
|
|
|
ret operator()(args&&... argv) { |
|
|
|
return invokator(data_ptr, gp::forward<args>(argv)...); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
/*template <typename ret, typename ...args>
|
|
|
|
class function<ret(args...)>{ |
|
|
|
struct virtual_callable |
|
|
|
{ |
|
|
@ -66,7 +187,7 @@ namespace gp{ |
|
|
|
state_t state{}; |
|
|
|
union{ |
|
|
|
virtual_callable* functor = nullptr; |
|
|
|
char inplace[12]; |
|
|
|
char inplace[16]; |
|
|
|
} self; |
|
|
|
|
|
|
|
public: |
|
|
@ -211,6 +332,6 @@ namespace gp{ |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
}; |
|
|
|
};*/ |
|
|
|
|
|
|
|
} |