// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_AnY_FUNCTION_Hh_
#define DLIB_AnY_FUNCTION_Hh_
#include "../assert.h"
#include "../functional.h"
#include "any.h"
#include "any_function_abstract.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
class Storage,
class F
>
class any_function_basic;
template <
class Storage,
class R,
class... Args
>
class any_function_basic<Storage, R(Args...)>
{
private:
template<class F>
using is_valid = std::enable_if_t<!std::is_same<std::decay_t<F>, any_function_basic>::value &&
dlib::is_invocable_r<R, F, Args...>::value,
bool>;
template<typename Func>
static auto make_invoker()
{
return [](void* self, Args... args) -> R {
return dlib::invoke(*reinterpret_cast<std::add_pointer_t<Func>>(self),
std::forward<Args>(args)...);
};
}
Storage str;
R (*func)(void*, Args...) = nullptr;
public:
using result_type = R;
constexpr any_function_basic(std::nullptr_t) noexcept {}
constexpr any_function_basic() = default;
constexpr any_function_basic(const any_function_basic& other) = default;
constexpr any_function_basic& operator=(const any_function_basic& other) = default;
constexpr any_function_basic(any_function_basic&& other)
: str{std::move(other.str)},
func{std::exchange(other.func, nullptr)}
{
}
constexpr any_function_basic& operator=(any_function_basic&& other)
{
if (this != &other)
{
str = std::move(other.str);
func = std::exchange(other.func, nullptr);
}
return *this;
}
template<class F, is_valid<F> = true>
any_function_basic(
F&& f
) : str{std::forward<F>(f)},
func{make_invoker<F&&>()}
{
}
template<class F, is_valid<F> = true>
any_function_basic(
F* f
) : str{f},
func{make_invoker<F*>()}
{
}
R operator()(Args... args) const {
return func(const_cast<void*>(str.get_ptr()), std::forward<Args>(args)...);
}
void clear() { str.clear(); }
void swap (any_function_basic& item) { std::swap(*this, item); }
bool is_empty() const noexcept { return str.is_empty() || func == nullptr; }
bool is_set() const noexcept { return !is_empty(); }
explicit operator bool() const noexcept { return is_set(); }
template <typename T> bool contains() const { return str.template contains<T>();}
template <typename T> T& cast_to() { return str.template cast_to<T>(); }
template <typename T> const T& cast_to() const { return str.template cast_to<T>(); }
template <typename T> T& get() { return str.template get<T>(); }
};
// ----------------------------------------------------------------------------------------
template <class T, class Storage, class F>
T& any_cast(any_function_basic<Storage, F>& a) { return a.template cast_to<T>(); }
template <class T, class Storage, class F>
const T& any_cast(const any_function_basic<Storage, F>& a) { return a.template cast_to<T>(); }
// ----------------------------------------------------------------------------------------
template <class F>
using any_function = any_function_basic<te::storage_sbo<16>, F>;
template <class F>
using any_function_view = any_function_basic<te::storage_view, F>;
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_FUNCTION_Hh_