xref: /aosp_15_r20/external/pigweed/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/utility.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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