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_STDCOMPAT_INTERNAL_UTILITY_H_ 6 #define LIB_STDCOMPAT_INTERNAL_UTILITY_H_ 7 8 #include <cstddef> 9 #include <utility> 10 11 #include "../type_traits.h" 12 13 namespace cpp17 { 14 namespace internal { 15 16 template <typename Tag> 17 struct instantiate_templated_tag { 18 static constexpr const Tag storage{}; 19 }; 20 21 template <typename Tag> 22 constexpr const Tag instantiate_templated_tag<Tag>::storage; 23 24 template <typename T, typename ValueType, ValueType Value> 25 struct inline_storage { 26 static constexpr const ValueType storage{Value}; 27 }; 28 29 template <typename T, typename ValueType, ValueType Value> 30 constexpr const ValueType inline_storage<T, ValueType, Value>::storage; 31 32 // Utility to return the first type in a parameter pack. 33 template <typename... Ts> 34 struct first; 35 template <typename First, typename... Rest> 36 struct first<First, Rest...> { 37 using type = First; 38 }; 39 40 template <typename... Ts> 41 using first_t = typename first<Ts...>::type; 42 43 // Utility to count the occurences of type T in the parameter pack Ts. 44 template <typename T, typename... Ts> 45 struct occurences_of : std::integral_constant<std::size_t, 0> {}; 46 template <typename T, typename U> 47 struct occurences_of<T, U> : std::integral_constant<std::size_t, std::is_same<T, U>::value> {}; 48 template <typename T, typename First, typename... Rest> 49 struct occurences_of<T, First, Rest...> 50 : std::integral_constant<std::size_t, 51 occurences_of<T, First>::value + occurences_of<T, Rest...>::value> {}; 52 53 template <typename T, typename... Ts> 54 constexpr std::size_t occurences_of_v = occurences_of<T, Ts...>::value; 55 56 // Evaluates to truth-like when type T matches type U with cv-reference removed. 57 template <typename T, typename U> 58 using not_same_type = negation<std::is_same<T, ::cpp20::remove_cvref_t<U>>>; 59 60 // Concept helper for constructors. 61 template <typename... Conditions> 62 using requires_conditions = std::enable_if_t<conjunction_v<Conditions...>, bool>; 63 64 // Concept helper for assignment operators. 65 template <typename Return, typename... Conditions> 66 using assignment_requires_conditions = 67 std::enable_if_t<conjunction_v<Conditions...>, std::add_lvalue_reference_t<Return>>; 68 69 // Evaluates to true when every element type of Ts is trivially destructible. 70 template <typename... Ts> 71 constexpr bool is_trivially_destructible_v = conjunction_v<std::is_trivially_destructible<Ts>...>; 72 73 // Evaluates to true when every element type of Ts is trivially copyable. 74 template <typename... Ts> 75 constexpr bool is_trivially_copyable_v = 76 (conjunction_v<std::is_trivially_copy_assignable<Ts>...> && 77 conjunction_v<std::is_trivially_copy_constructible<Ts>...>); 78 79 // Evaluates to true when every element type of Ts is trivially movable. 80 template <typename... Ts> 81 constexpr bool is_trivially_movable_v = 82 (conjunction_v<std::is_trivially_move_assignable<Ts>...> && 83 conjunction_v<std::is_trivially_move_constructible<Ts>...>); 84 85 // Enable if relational operator is convertible to bool and the optional 86 // conditions are true. 87 template <typename Op, typename... Conditions> 88 using enable_relop_t = 89 std::enable_if_t<(std::is_convertible<Op, bool>::value && conjunction_v<Conditions...>), bool>; 90 91 // Returns true when T is a complete type or an unbounded array. 92 template <typename T, std::size_t = sizeof(T)> 93 constexpr bool is_complete_or_unbounded_array(::cpp20::type_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 disjunction<std::is_reference<T>, std::is_function<T>, std::is_void<T>, 99 ::cpp20::is_unbounded_array<T>>::value; 100 } 101 102 // Using swap for ADL. This directive is contained within the cpp17::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(::cpp20::type_identity<T>{}), 112 "T must be a complete type or an unbounded array!"); 113 }; 114 template <typename T> 115 struct is_swappable<T, void_t<decltype(swap(std::declval<T&>(), std::declval<T&>()))>> 116 : std::true_type { 117 static_assert(is_complete_or_unbounded_array(::cpp20::type_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(::cpp20::type_identity<T>{}), 125 "T must be a complete type or an unbounded array!"); 126 }; 127 template <typename T> 128 struct is_nothrow_swappable<T, void_t<decltype(swap(std::declval<T&>(), std::declval<T&>()))>> 129 : std::integral_constant<bool, noexcept(swap(std::declval<T&>(), std::declval<T&>()))> { 130 static_assert(is_complete_or_unbounded_array(::cpp20::type_identity<T>{}), 131 "T must be a complete type or an unbounded array!"); 132 }; 133 134 } // namespace internal 135 } // namespace cpp17 136 137 #endif // LIB_STDCOMPAT_INTERNAL_UTILITY_H_ 138