diff --git a/func.hpp b/func.hpp new file mode 100644 index 0000000..0cbf654 --- /dev/null +++ b/func.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include "util.hpp" + +#include "../type/type.hpp" + +namespace util { + +// + +// clang-format off + +namespace detail { + +template constexpr bool is_reference_wrapper_v = false; +template constexpr bool is_reference_wrapper_v> = true; + +template +constexpr decltype(auto) INVOKE(Type T::*f, T1 &&t1, Args &&... args) +{ + if constexpr (type::is_member_function_pointer_v) { + if constexpr (type::is_base_of_v>) + return (util::forward(t1).*f)(util::forward(args)...); + else if constexpr (is_reference_wrapper_v>) + return (t1.get().*f)(util::forward(args)...); + else + return ((*util::forward(t1)).*f)(util::forward(args)...); + } else { + static_assert(type::is_member_object_pointer_v); + static_assert(sizeof...(args) == 0); + if constexpr (type::is_base_of_v>) + return util::forward(t1).*f; + else if constexpr (is_reference_wrapper_v>) + return t1.get().*f; + else + return (*util::forward(t1)).*f; + } +} + +template +constexpr decltype(auto) INVOKE(Fn &&f, Args &&... args) +{ + return util::forward(f)(util::forward(args)...); +} + +template constexpr T &FUN(T &t) noexcept { return t; } +template void FUN(T &&) = delete; + +} // namespace detail + +template +constexpr type::invoke_result_t invoke(Fn &&f, Args &&... args) + noexcept(type::is_nothrow_invocable_v) +{ + return detail::INVOKE(util::forward(f), util::forward(args)...); +} + +template +class reference_wrapper { + public: + // construct/copy/destroy + template (util::declval()), + type::enable_if_t>>())> + constexpr reference_wrapper(U &&u) noexcept(noexcept(detail::FUN(util::forward(u)))) + : _ptr(util::addressof(detail::FUN(util::forward(u)))) + {} + reference_wrapper(const reference_wrapper &) noexcept = default; + + // assignment + reference_wrapper &operator=(const reference_wrapper &) noexcept = default; + + // access + constexpr operator T &() const noexcept { return *_ptr; } + constexpr T &get() const noexcept { return *_ptr; } + + template + constexpr type::invoke_result_t operator()(ArgTypes &&... args) const + { + return invoke(get(), util::forward(args)...); + } + + // types + using type = T; + + private: + T *_ptr; +}; + +// deduction guides +template reference_wrapper(T &) -> reference_wrapper; + +// clang-format on + +} // namespace util diff --git a/util.hpp b/util.hpp index 4b2e85a..42f2edd 100644 --- a/util.hpp +++ b/util.hpp @@ -6,6 +6,26 @@ namespace util { +// + +// clang-format off + +template +type::enable_if_t, T *> addressof(T &arg) noexcept +{ + return reinterpret_cast(&const_cast(reinterpret_cast(arg))); +} + +template +type::enable_if_t, T *> addressof(T &arg) noexcept +{ + return &arg; +} + +// + +template type::add_rvalue_reference_t declval() noexcept; + template inline constexpr type::remove_reference_t &&move(T &&t) noexcept { @@ -36,33 +56,26 @@ struct integer_sequence { } }; -template -using index_sequence = integer_sequence; +template using index_sequence = integer_sequence; namespace detail { -template -struct concat; +template struct concat; template struct concat, integer_sequence> - : integer_sequence { -}; + : integer_sequence +{}; // uint64_t because this must be able to hold all possible sizes and cannot be T, because then the specialization for 0 // and 1 are not possible template struct gen_integer_sequence : detail::concat::__type, - typename gen_integer_sequence::__type> { -}; + typename gen_integer_sequence::__type> +{}; -template -struct gen_integer_sequence : integer_sequence { -}; - -template -struct gen_integer_sequence : integer_sequence { -}; +template struct gen_integer_sequence : integer_sequence {}; +template struct gen_integer_sequence : integer_sequence {}; } // namespace detail @@ -71,21 +84,16 @@ struct make_integer_sequence : detail::gen_integer_sequence { static_assert(N >= 0, "Integer sequence cannot be negative"); }; -template -using make_index_sequence = make_integer_sequence; +template using make_index_sequence = make_integer_sequence; -template -using index_sequence_for = make_index_sequence; +template using index_sequence_for = make_index_sequence; // Not part of , but very useful namespace detail { template -inline constexpr integer_sequence add_offset(integer_sequence) -{ - return {}; -} +inline constexpr integer_sequence add_offset(integer_sequence) { return {}; } } // namespace detail @@ -101,10 +109,18 @@ inline constexpr auto make_offset_index_sequence() return make_offset_integer_sequence(); } -template -void for_constexpr(Fn &&func, index_sequence) +template +auto for_constexpr(Fn &&func, index_sequence) { - (func(type::integral_constant{}), ...); + if constexpr (type::is_void_v>>) { + (func(type::integral_constant{}), ...); + } else { + if ((func(type::integral_constant{}) && ...)) + return true; + return false; + } } +// clang-format on + } // namespace util