xref: /aosp_15_r20/external/pigweed/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/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_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