///
// function_ref - A low-overhead non-owning function
// Written in 2017 by Simon Brand (@TartanLlama)
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to the
// public domain worldwide. This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software. If not, see
// .
///
#ifndef TL_FUNCTION_REF_HPP
#define TL_FUNCTION_REF_HPP
#define TL_FUNCTION_REF_VERSION_MAJOR 1
#define TL_FUNCTION_REF_VERSION_MINOR 0
#define TL_FUNCTION_REF_VERSION_PATCH 0
#if (defined(_MSC_VER) && _MSC_VER == 1900)
/// \exclude
#define TL_FUNCTION_REF_MSVC2015
#endif
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
!defined(__clang__))
/// \exclude
#define TL_FUNCTION_REF_GCC49
#endif
#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
!defined(__clang__))
/// \exclude
#define TL_FUNCTION_REF_GCC54
#endif
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
!defined(__clang__))
// GCC < 5 doesn't support overloading on const&& for member functions
/// \exclude
#define TL_FUNCTION_REF_NO_CONSTRR
#endif
#if __cplusplus > 201103L
/// \exclude
#define TL_FUNCTION_REF_CXX14
#endif
// constexpr implies const in C++11, not C++14
#if (__cplusplus == 201103L || defined(TL_FUNCTION_REF_MSVC2015) || \
defined(TL_FUNCTION_REF_GCC49)) && \
!defined(TL_FUNCTION_REF_GCC54)
/// \exclude
#define TL_FUNCTION_REF_11_CONSTEXPR
#else
/// \exclude
#define TL_FUNCTION_REF_11_CONSTEXPR constexpr
#endif
#include
#include
namespace tl {
namespace detail {
namespace fnref {
// C++14-style aliases for brevity
template using remove_const_t = typename std::remove_const::type;
template
using remove_reference_t = typename std::remove_reference::type;
template using decay_t = typename std::decay::type;
template
using enable_if_t = typename std::enable_if::type;
template
using conditional_t = typename std::conditional::type;
// std::invoke from C++17
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
template >::value>,
int = 0>
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
noexcept(std::mem_fn(f)(std::forward(args)...)))
-> decltype(std::mem_fn(f)(std::forward(args)...)) {
return std::mem_fn(f)(std::forward(args)...);
}
template >{}>>
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
noexcept(std::forward(f)(std::forward(args)...)))
-> decltype(std::forward(f)(std::forward(args)...)) {
return std::forward(f)(std::forward(args)...);
}
// std::invoke_result from C++17
template struct invoke_result_impl;
template
struct invoke_result_impl<
F, decltype(tl::detail::fnref::invoke(std::declval(), std::declval()...), void()),
Us...> {
using type = decltype(tl::detail::fnref::invoke(std::declval(), std::declval()...));
};
template
using invoke_result = invoke_result_impl;
template
using invoke_result_t = typename invoke_result::type;
template
struct is_invocable_r_impl : std::false_type {};
template
struct is_invocable_r_impl<
typename std::is_convertible, R>::type, R, F, Args...>
: std::true_type {};
template
using is_invocable_r = is_invocable_r_impl;
} // namespace detail
} // namespace fnref
/// A lightweight non-owning reference to a callable.
///
/// Example usage:
///
/// ```cpp
/// void foo (function_ref func) {
/// std::cout << "Result is " << func(21); //42
/// }
///
/// foo([](int i) { return i*2; });
template class function_ref;
/// Specialization for function types.
template class function_ref {
public:
constexpr function_ref() noexcept = delete;
/// Creates a `function_ref` which refers to the same callable as `rhs`.
constexpr function_ref(const function_ref &rhs) noexcept = default;
/// Constructs a `function_ref` referring to `f`.
///
/// \synopsis template constexpr function_ref(F &&f) noexcept
template , function_ref>::value &&
detail::fnref::is_invocable_r::value> * = nullptr>
TL_FUNCTION_REF_11_CONSTEXPR function_ref(F &&f) noexcept
: obj_(const_cast(reinterpret_cast(std::addressof(f)))) {
callback_ = [](void *obj, Args... args) -> R {
return detail::fnref::invoke(
*reinterpret_cast::type>(obj),
std::forward(args)...);
};
}
/// Makes `*this` refer to the same callable as `rhs`.
TL_FUNCTION_REF_11_CONSTEXPR function_ref &
operator=(const function_ref &rhs) noexcept = default;
/// Makes `*this` refer to `f`.
///
/// \synopsis template constexpr function_ref &operator=(F &&f) noexcept;
template ::value>
* = nullptr>
TL_FUNCTION_REF_11_CONSTEXPR function_ref &operator=(F &&f) noexcept {
obj_ = reinterpret_cast(std::addressof(f));
callback_ = [](void *obj, Args... args) {
return detail::fnref::invoke(
*reinterpret_cast::type>(obj),
std::forward(args)...);
};
return *this;
}
/// Swaps the referred callables of `*this` and `rhs`.
constexpr void swap(function_ref &rhs) noexcept {
std::swap(obj_, rhs.obj_);
std::swap(callback_, rhs.callback_);
}
/// Call the stored callable with the given arguments.
R operator()(Args... args) const {
return callback_(obj_, std::forward(args)...);
}
private:
void *obj_ = nullptr;
R (*callback_)(void *, Args...) = nullptr;
};
/// Swaps the referred callables of `lhs` and `rhs`.
template
constexpr void swap(function_ref &lhs,
function_ref &rhs) noexcept {
lhs.swap(rhs);
}
#if __cplusplus >= 201703L
template
function_ref(R (*)(Args...))->function_ref;
// TODO, will require some kind of callable traits
// template
// function_ref(F) -> function_ref* deduced if possible */>;
#endif
} // namespace tl
#endif