summaryrefslogtreecommitdiffstats
path: root/deps/include/entt/core/tuple.hpp
blob: a64c51c1322b294d70ff7d58b8ec19f78c3328d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#ifndef ENTT_CORE_TUPLE_HPP
#define ENTT_CORE_TUPLE_HPP

#include <tuple>
#include <type_traits>
#include <utility>

namespace entt {

/*! @cond TURN_OFF_DOXYGEN */
namespace internal {

template<typename>
struct is_tuple_impl: std::false_type {};

template<typename... Args>
struct is_tuple_impl<std::tuple<Args...>>: std::true_type {};

} // namespace internal
/*! @endcond */

/**
 * @brief Provides the member constant `value` to true if a given type is a
 * tuple, false otherwise.
 * @tparam Type The type to test.
 */
template<typename Type>
struct is_tuple: internal::is_tuple_impl<std::remove_cv_t<Type>> {};

/**
 * @brief Helper variable template.
 * @tparam Type The type to test.
 */
template<typename Type>
inline constexpr bool is_tuple_v = is_tuple<Type>::value;

/**
 * @brief Utility function to unwrap tuples of a single element.
 * @tparam Type Tuple type of any sizes.
 * @param value A tuple object of the given type.
 * @return The tuple itself if it contains more than one element, the first
 * element otherwise.
 */
template<typename Type>
constexpr decltype(auto) unwrap_tuple(Type &&value) noexcept {
    if constexpr(std::tuple_size_v<std::remove_reference_t<Type>> == 1u) {
        return std::get<0>(std::forward<Type>(value));
    } else {
        return std::forward<Type>(value);
    }
}

/**
 * @brief Utility class to forward-and-apply tuple objects.
 * @tparam Func Type of underlying invocable object.
 */
template<typename Func>
struct forward_apply: private Func {
    /**
     * @brief Constructs a forward-and-apply object.
     * @tparam Args Types of arguments to use to construct the new instance.
     * @param args Parameters to use to construct the instance.
     */
    template<typename... Args>
    constexpr forward_apply(Args &&...args) noexcept(std::is_nothrow_constructible_v<Func, Args...>)
        : Func{std::forward<Args>(args)...} {}

    /**
     * @brief Forwards and applies the arguments with the underlying function.
     * @tparam Type Tuple-like type to forward to the underlying function.
     * @param args Parameters to forward to the underlying function.
     * @return Return value of the underlying function, if any.
     */
    template<typename Type>
    constexpr decltype(auto) operator()(Type &&args) noexcept(noexcept(std::apply(std::declval<Func &>(), args))) {
        return std::apply(static_cast<Func &>(*this), std::forward<Type>(args));
    }

    /*! @copydoc operator()() */
    template<typename Type>
    constexpr decltype(auto) operator()(Type &&args) const noexcept(noexcept(std::apply(std::declval<const Func &>(), args))) {
        return std::apply(static_cast<const Func &>(*this), std::forward<Type>(args));
    }
};

/**
 * @brief Deduction guide.
 * @tparam Func Type of underlying invocable object.
 */
template<typename Func>
forward_apply(Func) -> forward_apply<std::remove_reference_t<std::remove_cv_t<Func>>>;

} // namespace entt

#endif