Welcome, guest! Login / Register - Why register?
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

Your Name: Code Language: