1 // Copyright 2019 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef LIB_FIT_INTERNAL_UTILITY_H_ 6 #define LIB_FIT_INTERNAL_UTILITY_H_ 7 8 #include <lib/stdcompat/type_traits.h> 9 10 #include <type_traits> 11 #include <utility> 12 13 namespace fit { 14 namespace internal { 15 16 // Utility to return the first type in a parameter pack. 17 template <typename... Ts> 18 struct first; 19 template <typename First, typename... Rest> 20 struct first<First, Rest...> { 21 using type = First; 22 }; 23 24 template <typename... Ts> 25 using first_t = typename first<Ts...>::type; 26 27 // Utility to count the occurences of type T in the parameter pack Ts. 28 template <typename T, typename... Ts> 29 struct occurences_of : std::integral_constant<size_t, 0> {}; 30 template <typename T, typename U> 31 struct occurences_of<T, U> : std::integral_constant<size_t, std::is_same<T, U>::value> {}; 32 template <typename T, typename First, typename... Rest> 33 struct occurences_of<T, First, Rest...> 34 : std::integral_constant<size_t, 35 occurences_of<T, First>::value + occurences_of<T, Rest...>::value> {}; 36 37 template <typename T, typename... Ts> 38 constexpr size_t occurences_of_v = occurences_of<T, Ts...>::value; 39 40 // Utility to remove const, volatile, and reference qualifiers. 41 template <typename T> 42 using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>; 43 44 // Evaluates to truth-like when type T matches type U with cv-reference removed. 45 template <typename T, typename U> 46 using not_same_type = cpp17::negation<std::is_same<T, remove_cvref_t<U>>>; 47 48 // Concept helper for constructors. 49 template <typename... Conditions> 50 using requires_conditions = std::enable_if_t<cpp17::conjunction_v<Conditions...>, bool>; 51 52 // Concept helper for assignment operators. 53 template <typename Return, typename... Conditions> 54 using assignment_requires_conditions = 55 std::enable_if_t<cpp17::conjunction_v<Conditions...>, std::add_lvalue_reference_t<Return>>; 56 57 // Evaluates to true when every element type of Ts is trivially destructible. 58 template <typename... Ts> 59 constexpr bool is_trivially_destructible_v = 60 cpp17::conjunction_v<std::is_trivially_destructible<Ts>...>; 61 62 // Evaluates to true when every element type of Ts is trivially copyable. 63 template <typename... Ts> 64 constexpr bool is_trivially_copyable_v = 65 (cpp17::conjunction_v<std::is_trivially_copy_assignable<Ts>...> && 66 cpp17::conjunction_v<std::is_trivially_copy_constructible<Ts>...>); 67 68 // Evaluates to true when every element type of Ts is trivially movable. 69 template <typename... Ts> 70 constexpr bool is_trivially_movable_v = 71 (cpp17::conjunction_v<std::is_trivially_move_assignable<Ts>...> && 72 cpp17::conjunction_v<std::is_trivially_move_constructible<Ts>...>); 73 74 // Enable if relational operator is convertible to bool and the optional 75 // conditions are true. 76 template <typename Op, typename... Conditions> 77 using enable_relop_t = 78 std::enable_if_t<(std::is_convertible<Op, bool>::value && cpp17::conjunction_v<Conditions...>), 79 bool>; 80 81 template <typename T> 82 struct identity { 83 using type = T; 84 }; 85 86 // Evaluates to true when T is an unbounded array. 87 template <typename T> 88 struct is_unbounded_array : cpp17::conjunction<std::is_array<T>, cpp17::negation<std::extent<T>>> { 89 }; 90 91 // Returns true when T is a complete type or an unbounded array. 92 template <typename T, size_t = sizeof(T)> 93 constexpr bool is_complete_or_unbounded_array(identity<T>) { 94 return true; 95 } 96 template <typename Identity, typename T = typename Identity::type> 97 constexpr bool is_complete_or_unbounded_array(Identity) { 98 return cpp17::disjunction<std::is_reference<T>, std::is_function<T>, std::is_void<T>, 99 is_unbounded_array<T>>::value; 100 } 101 102 // Using swap for ADL. This directive is contained within the fit::internal 103 // namespace, which prevents leaking std::swap into user namespaces. Doing this 104 // at namespace scope is necessary to lookup swap via ADL while preserving the 105 // noexcept() specification of the resulting lookup. 106 using std::swap; 107 108 // Evaluates to true when T is swappable. 109 template <typename T, typename = void> 110 struct is_swappable : std::false_type { 111 static_assert(is_complete_or_unbounded_array(identity<T>{}), 112 "T must be a complete type or an unbounded array!"); 113 }; 114 template <typename T> 115 struct is_swappable<T, cpp17::void_t<decltype(swap(std::declval<T&>(), std::declval<T&>()))>> 116 : std::true_type { 117 static_assert(is_complete_or_unbounded_array(identity<T>{}), 118 "T must be a complete type or an unbounded array!"); 119 }; 120 121 // Evaluates to true when T is nothrow swappable. 122 template <typename T, typename = void> 123 struct is_nothrow_swappable : std::false_type { 124 static_assert(is_complete_or_unbounded_array(identity<T>{}), 125 "T must be a complete type or an unbounded array!"); 126 }; 127 template <typename T> 128 struct is_nothrow_swappable<T, 129 cpp17::void_t<decltype(swap(std::declval<T&>(), std::declval<T&>()))>> 130 : std::integral_constant<bool, noexcept(swap(std::declval<T&>(), std::declval<T&>()))> { 131 static_assert(is_complete_or_unbounded_array(identity<T>{}), 132 "T must be a complete type or an unbounded array!"); 133 }; 134 135 } // namespace internal 136 } // namespace fit 137 138 #endif // LIB_FIT_INTERNAL_UTILITY_H_ 139