Psst.. new poll here.
Psst.. new forums here.
Microsoft is blocking us again (TY IP Reputation!) so just use oauth login instead. :)
Paste
Pasted as C++ by DarkEngine ( 6 years ago )
#pragma once
#include <cstdlib>
#include <new>
template <class T>
class StdFunc;
// Removes any reference qualifier from the specified type.
template <class T> struct StdNoRefT {using type = T;};
template <class T> struct StdNoRefT<T&> {using type = T;};
template <class T> struct StdNoRefT<T&&> {using type = T;};
template <class T> using StdNoRef = typename StdNoRefT<T>::type;
template <class T>
// Like std::forward but avoids the large header dependency to <type_traits>.
[[nodiscard]] constexpr T&& std_forward(StdNoRef<T>& args) noexcept
{
return static_cast<T&&>(args);
}
template <class T>
[[nodiscard]] constexpr T&& std_forward(StdNoRef<T>&& args) noexcept
{
return static_cast<T&&>(args);
}
// ----------------------------------------------------------------------------
// StdFunc
// ----------------------------------------------------------------------------
// Like std::function but avoids the large header dependency to <functional>.
template <class R, class... Args>
class StdFunc<R(Args...)>
{
public:
// Creates a null function wrapper.
StdFunc() = default;
// Creates a general-purpose function wrapper for the specified function
// or function object.
template <class Fn>
StdFunc(Fn f);
// Creates a copy of the specified function wrapper.
StdFunc(const StdFunc& src);
// Assigns a new function target to this one.
StdFunc& operator=(const StdFunc& src);
// Destroys the function wrapper.
~StdFunc();
// Nulls the function wrapper.
void clear();
// Invokes the function with the specified argument(s).
template <class...Args2>
R operator()(Args2&&...args);
// Returns true if the function is not null.
explicit operator bool() const noexcept;
private:
template <class Functor>
static R fn_call(void* fn, Args&&... args);
template <class Functor>
static void fn_copy_dtor(void* dst, const void* src);
alignas(32) char sbo[32] = {};
size_t size = 0;
void* ptr = nullptr;
R (*call)(void* fn, Args&&...args) = nullptr;
void (*copy_dtor)(void* dst, const void* src) = nullptr;
};
// ----------------------------------------------------------------------------
// StdFunc Implementation
// ----------------------------------------------------------------------------
template <class R, class... Args>
template <class Fn>
StdFunc<R(Args...)>::StdFunc(Fn f):
size(sizeof(Fn)), ptr((size > sizeof sbo) ? malloc(size): sbo),
call(fn_call<Fn>), copy_dtor(fn_copy_dtor<Fn>)
{
copy_dtor(ptr, reinterpret_cast<char*>(&f));
}
template <class R, class... Args>
StdFunc<R(Args...)>::StdFunc(const StdFunc<R(Args...)>& src):
size(src.size), call(src.call), copy_dtor(src.copy_dtor)
{
if (src.ptr)
{
ptr = (size > sizeof sbo) ? malloc(size): sbo;
copy_dtor(ptr, src.ptr);
}
}
template <class R, class... Args>
StdFunc<R(Args...)>::~StdFunc()
{
clear();
}
template <class R, class... Args>
void StdFunc<R(Args...)>::clear()
{
if (copy_dtor)
copy_dtor(ptr, nullptr);
if (ptr != sbo)
free(ptr);
size = 0;
ptr = nullptr;
call = nullptr;
copy_dtor = nullptr;
}
template <class R, class... Args>
StdFunc<R(Args...)>& StdFunc<R(Args...)>::operator=(const StdFunc& src)
{
if (this != &src)
{
clear();
size = src.size;
call = src.call;
copy_dtor = src.copy_dtor;
if (src.ptr)
{
ptr = (size > sizeof sbo) ? malloc(size): sbo;
if (size > sizeof sbo)
ptr = malloc(size);
copy_dtor(ptr, src.ptr);
}
}
return *this;
}
template <class R, class... Args>
template <class...Args2>
R StdFunc<R(Args...)>::operator()(Args2&&...args)
{
return call(ptr, std_forward<Args>(args)...);
}
template <class R, class... Args>
StdFunc<R(Args...)>::operator bool() const noexcept
{
return ptr != nullptr;
}
template <class R, class... Args>
template <class Functor>
R StdFunc<R(Args...)>::fn_call(void* fn, Args&&... args)
{
return (*static_cast<Functor*>(fn))(std_forward<Args>(args)...);
}
template <class R, class... Args>
template <class Functor>
void StdFunc<R(Args...)>::fn_copy_dtor(void* dst, const void* src)
{
// Copies from the source array to the destination if source is not null.
// Otherwise the function destroys the destination array. This is slightly
// confusing but avoids the need to store an additional function pointer
// in the structure and inflate its size.
if (src)
new(dst) Functor(*static_cast<const Functor*>(src));
else
static_cast<Functor*>(dst)->~Functor();
}
Revise this Paste