1 // Copyright 2021 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Copyright 2019 The Fuchsia Authors. All rights reserved. 16 // Use of this source code is governed by a BSD-style license that can be 17 // found in the LICENSE file. 18 19 #pragma once 20 21 #include <type_traits> 22 #include <utility> 23 24 namespace gfxstream::guest { 25 namespace fit { 26 namespace internal { 27 28 // Utility to return the first type in a parameter pack. 29 template <typename... Ts> 30 struct First; 31 template <typename FirstType, typename... Rest> 32 struct First<FirstType, Rest...> { 33 using Type = FirstType; 34 }; 35 36 template <typename... Ts> 37 using First_t = typename First<Ts...>::Type; 38 39 // Utility to count the occurences of type T in the parameter pack Ts. 40 template <typename T, typename... Ts> 41 struct OccurencesOf : std::integral_constant<size_t, 0> {}; 42 template <typename T, typename U> 43 struct OccurencesOf<T, U> : std::integral_constant<size_t, std::is_same<T, U>::value> {}; 44 template <typename T, typename First, typename... Rest> 45 struct OccurencesOf<T, First, Rest...> 46 : std::integral_constant<size_t, 47 OccurencesOf<T, First>::value + OccurencesOf<T, Rest...>::value> {}; 48 49 template <typename T, typename... Ts> 50 constexpr size_t occurencesOf = OccurencesOf<T, Ts...>::value; 51 52 // Utility to remove const, volatile, and reference qualifiers. 53 template <typename T> 54 using RemoveCvref_t = std::remove_cv_t<std::remove_reference_t<T>>; 55 56 // Evaluates to truth-like when type T matches type U with cv-reference removed. 57 template <typename T, typename U> 58 using NotSameType = std::negation<std::is_same<T, RemoveCvref_t<U>>>; 59 60 // Concept helper for constructors. 61 template <typename... Conditions> 62 using RequiresConditions = std::enable_if_t<std::conjunction_v<Conditions...>, bool>; 63 64 // Concept helper for assignment operators. 65 template <typename Return, typename... Conditions> 66 using AssignmentRequiresConditions = 67 std::enable_if_t<std::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 isTriviallyDestructible = std::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 isTriviallyCopyable = 76 (std::conjunction_v<std::is_trivially_copy_assignable<Ts>...> && 77 std::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 isTriviallyMovable = 82 (std::conjunction_v<std::is_trivially_move_assignable<Ts>...> && 83 std::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 && std::conjunction_v<Conditions...>), 90 bool>; 91 92 template <typename T> 93 struct Identity { 94 using Type = T; 95 }; 96 97 // Evaluates to true when T is an unbounded array. 98 template <typename T> 99 struct IsUnboundedArray : std::conjunction<std::is_array<T>, std::negation<std::extent<T>>> {}; 100 101 // Returns true when T is a complete type or an unbounded array. 102 template <typename T, size_t = sizeof(T)> 103 constexpr bool isCompleteOrUnboundedArray(Identity<T>) { 104 return true; 105 } 106 template <typename Identity, typename T = typename Identity::Type> 107 constexpr bool isCompleteOrUnboundedArray(Identity) { 108 return std::disjunction<std::is_reference<T>, std::is_function<T>, std::is_void<T>, 109 IsUnboundedArray<T>>::value; 110 } 111 112 // Using swap for ADL. This directive is contained within the fit::internal 113 // namespace, which prevents leaking std::swap into user namespaces. Doing this 114 // at namespace scope is necessary to lookup swap via ADL while preserving the 115 // noexcept() specification of the resulting lookup. 116 using std::swap; 117 118 // Evaluates to true when T is swappable. 119 template <typename T, typename = void> 120 struct IsSwappable : std::false_type { 121 static_assert(isCompleteOrUnboundedArray(Identity<T>{}), 122 "T must be a complete type or an unbounded array!"); 123 }; 124 template <typename T> 125 struct IsSwappable<T, std::void_t<decltype(swap(std::declval<T&>(), std::declval<T&>()))>> 126 : std::true_type { 127 static_assert(isCompleteOrUnboundedArray(Identity<T>{}), 128 "T must be a complete type or an unbounded array!"); 129 }; 130 131 // Evaluates to true when T is nothrow swappable. 132 template <typename T, typename = void> 133 struct IsNothrowSwappable : std::false_type { 134 static_assert(isCompleteOrUnboundedArray(Identity<T>{}), 135 "T must be a complete type or an unbounded array!"); 136 }; 137 template <typename T> 138 struct IsNothrowSwappable<T, std::void_t<decltype(swap(std::declval<T&>(), std::declval<T&>()))>> 139 : std::integral_constant<bool, noexcept(swap(std::declval<T&>(), std::declval<T&>()))> { 140 static_assert(isCompleteOrUnboundedArray(Identity<T>{}), 141 "T must be a complete type or an unbounded array!"); 142 }; 143 144 } // namespace internal 145 } // namespace fit 146 } // namespace gfxstream::guest 147