#pragma once
|
|
#include <type_traits>
|
|
#include "gp/algorithm/move.hpp"
|
|
|
|
namespace gp {
|
|
|
|
|
|
|
|
template<typename F, typename ... Args>
|
|
auto bind_front(F&& func, Args&&... arg_parent)
|
|
{
|
|
return [&](auto&&... argv){
|
|
return func(arg_parent..., argv...);
|
|
};
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Code extrated from cppreference.com and the libc++ Library project, licensed under MIT license */
|
|
|
|
namespace detail {
|
|
template <class>
|
|
constexpr bool is_reference_wrapper_v = false;
|
|
template <class U>
|
|
constexpr bool is_reference_wrapper_v<std::reference_wrapper<U>> = true;
|
|
|
|
template <class T, class Type, class T1, class... Args>
|
|
constexpr decltype(auto) INVOKE(Type T::* f, T1&& t1, Args&&... args)
|
|
{
|
|
if constexpr (std::is_member_function_pointer_v<decltype(f)>) {
|
|
if constexpr (std::is_base_of_v<T, std::decay_t<T1>>)
|
|
return (gp::forward<T1>(t1).*f)(gp::forward<Args>(args)...);
|
|
else if constexpr (is_reference_wrapper_v<std::decay_t<T1>>)
|
|
return (t1.get().*f)(gp::forward<Args>(args)...);
|
|
else
|
|
return ((*gp::forward<T1>(t1)).*f)(gp::forward<Args>(args)...);
|
|
} else {
|
|
static_assert(std::is_member_object_pointer_v<decltype(f)>);
|
|
static_assert(sizeof...(args) == 0);
|
|
if constexpr (std::is_base_of_v<T, std::decay_t<T1>>)
|
|
return gp::forward<T1>(t1).*f;
|
|
else if constexpr (is_reference_wrapper_v<std::decay_t<T1>>)
|
|
return t1.get().*f;
|
|
else
|
|
return (*gp::forward<T1>(t1)).*f;
|
|
}
|
|
}
|
|
|
|
template <class F, class... Args>
|
|
constexpr decltype(auto) INVOKE(F&& f, Args&&... args)
|
|
{
|
|
return gp::forward<F>(f)(gp::forward<Args>(args)...);
|
|
}
|
|
} // namespace detail
|
|
|
|
template< class F, class... Args>
|
|
constexpr std::invoke_result_t<F, Args...> invoke(F&& f, Args&&... args)
|
|
noexcept(std::is_nothrow_invocable_v<F, Args...>)
|
|
{
|
|
return detail::INVOKE(gp::forward<F>(f), gp::forward<Args>(args)...);
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
|
struct remove_cvref {
|
|
typedef std::remove_cv_t<std::remove_reference_t<T>> type;
|
|
};
|
|
|
|
template< class T >
|
|
using remove_cvref_t = typename remove_cvref<T>::type;
|
|
|
|
template< class T >
|
|
T* addressof(T& arg)
|
|
{
|
|
return reinterpret_cast<T*>(
|
|
&const_cast<char&>(
|
|
reinterpret_cast<const volatile char&>(arg)));
|
|
}
|
|
|
|
namespace detail {
|
|
template <class T> constexpr T& FUN(T& t) noexcept { return t; }
|
|
template <class T> void FUN(T&&) = delete;
|
|
}
|
|
|
|
template <class T>
|
|
class reference_wrapper {
|
|
public:
|
|
// types
|
|
typedef T type;
|
|
|
|
// construct/copy/destroy
|
|
template <class U, class = decltype(
|
|
detail::FUN<T>(std::declval<U>()),
|
|
std::enable_if_t<!std::is_same_v<reference_wrapper, gp::remove_cvref_t<U>>>()
|
|
)>
|
|
constexpr reference_wrapper(U&& u) noexcept(noexcept(detail::FUN<T>(gp::forward<U>(u))))
|
|
: _ptr(gp::addressof(detail::FUN<T>(gp::forward<U>(u)))) {}
|
|
reference_wrapper(const reference_wrapper&) noexcept = default;
|
|
|
|
// assignment
|
|
reference_wrapper& operator=(const reference_wrapper& x) noexcept = default;
|
|
|
|
// access
|
|
constexpr operator T& () const noexcept { return *_ptr; }
|
|
constexpr T& get() const noexcept { return *_ptr; }
|
|
|
|
template< class... ArgTypes >
|
|
constexpr std::invoke_result_t<T&, ArgTypes...>
|
|
operator() ( ArgTypes&&... args ) const {
|
|
return gp::invoke(get(), gp::forward<ArgTypes>(args)...);
|
|
}
|
|
|
|
private:
|
|
T* _ptr;
|
|
};
|
|
|
|
// deduction guides
|
|
template<class T>
|
|
reference_wrapper(T&) -> reference_wrapper<T>;
|
|
|
|
template<typename T>
|
|
auto ref(T& vref) {
|
|
return reference_wrapper<T>(vref);
|
|
}
|
|
|
|
template <class _DecayFunc>
|
|
class __not_fn_imp {
|
|
_DecayFunc __fd;
|
|
|
|
public:
|
|
__not_fn_imp() = delete;
|
|
|
|
template <class ..._Args>
|
|
auto operator()(_Args&& ...__args) &
|
|
noexcept(noexcept(!gp::invoke(__fd, gp::forward<_Args>(__args)...)))
|
|
-> decltype( !gp::invoke(__fd, gp::forward<_Args>(__args)...))
|
|
{ return !gp::invoke(__fd, gp::forward<_Args>(__args)...); }
|
|
|
|
template <class ..._Args>
|
|
auto operator()(_Args&& ...__args) &&
|
|
noexcept(noexcept(!gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...)))
|
|
-> decltype( !gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...))
|
|
{ return !gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...); }
|
|
|
|
template <class ..._Args>
|
|
auto operator()(_Args&& ...__args) const&
|
|
noexcept(noexcept(!gp::invoke(__fd, gp::forward<_Args>(__args)...)))
|
|
-> decltype( !gp::invoke(__fd, gp::forward<_Args>(__args)...))
|
|
{ return !gp::invoke(__fd, gp::forward<_Args>(__args)...); }
|
|
|
|
|
|
template <class ..._Args>
|
|
auto operator()(_Args&& ...__args) const&&
|
|
noexcept(noexcept(!gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...)))
|
|
-> decltype( !gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...))
|
|
{ return !gp::invoke(gp::move(__fd), gp::forward<_Args>(__args)...); }
|
|
|
|
private:
|
|
template <class _RawFunc,
|
|
class = std::enable_if_t<!std::is_same<std::decay_t<_RawFunc>, __not_fn_imp>::value>>
|
|
explicit __not_fn_imp(_RawFunc&& __rf)
|
|
: __fd(gp::forward<_RawFunc>(__rf)) {}
|
|
|
|
template <class _RawFunc>
|
|
friend inline __not_fn_imp<std::decay_t<_RawFunc>> not_fn(_RawFunc&&);
|
|
};
|
|
|
|
template <class _RawFunc>
|
|
inline __not_fn_imp<std::decay_t<_RawFunc>> not_fn(_RawFunc&& __fn) {
|
|
return __not_fn_imp<std::decay_t<_RawFunc>>(gp::forward<_RawFunc>(__fn));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|