1 /* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 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 16 #ifndef OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_TRAITS_H 17 #define OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_TRAITS_H 18 #include <cstddef> 19 #include <type_traits> 20 #include <variant> 21 namespace OHOS { 22 namespace Traits { 23 template<class Tp, class... Types> 24 struct index_of : std::integral_constant<size_t, 0> {}; 25 26 template<class Tp, class... Types> 27 inline constexpr size_t index_of_v = index_of<Tp, Types...>::value; 28 29 template<class Tp, class First, class... Rest> 30 struct index_of<Tp, First, Rest...> 31 : std::integral_constant<size_t, std::is_same_v<Tp, First> ? 0 : index_of_v<Tp, Rest...> + 1> {}; 32 33 // If there is one in the ...Types, that is equal to T. same_index_of_v is the index. 34 // If there is no one in the ...Types, that is equal to T. same_index_of_v is sizeof ...(Types) 35 template<class T, class... Types> 36 inline constexpr size_t same_index_of_v = index_of<T, Types...>::value; 37 38 // There is one in the ...Types, that is equal to T. If not, the same_in_v will be false. 39 template<class T, class... Types> 40 inline constexpr bool same_in_v = (same_index_of_v<T, Types...> < sizeof...(Types)); 41 42 template<class Tp, class... Types> 43 struct convertible_index_of : std::integral_constant<size_t, 0> {}; 44 45 // If there is one in the ...Types that can convert to T implicitly, convertible_index_v is the index. 46 // If there is no one in the ...Types that can convert to T implicitly, convertible_index_v is sizeof ...(Types) 47 template<class Tp, class... Types> 48 inline constexpr size_t convertible_index_of_v = convertible_index_of<Tp, Types...>::value; 49 50 template<class Tp, class First, class... Rest> 51 struct convertible_index_of<Tp, First, Rest...> 52 : std::integral_constant<size_t, std::is_convertible_v<First, Tp> ? 0 : convertible_index_of_v<Tp, Rest...> + 1> {}; 53 54 // There is one in the ...Types, that can convert to T implicitly. If not, the convertible_in_v will be false. 55 template<class T, class... Types> 56 inline constexpr bool convertible_in_v = (convertible_index_of_v<T, Types...> < sizeof...(Types)); 57 58 template<class... Types> 59 struct variant_size_of { 60 static constexpr size_t value = sizeof...(Types); 61 }; 62 63 template<class T, class... Types> 64 struct variant_index_of { 65 static constexpr size_t value = same_index_of_v<T, Types...>; 66 }; 67 68 template<class... Types> 69 variant_size_of<Types...> variant_size_test(const std::variant<Types...> &); 70 71 template<class T, class... Types> 72 variant_index_of<T, Types...> variant_index_test(const T &, const std::variant<Types...> &); 73 74 // variant_index_of_v is the count of the variant V's types. 75 template<class V> 76 inline constexpr size_t variant_size_of_v = decltype(variant_size_test(std::declval<V>()))::value; 77 78 // If T is one type of the variant V, variant_index_of_v is the index. If not, variant_index_of_v is the size. 79 template<class T, class V> 80 inline constexpr size_t variant_index_of_v = decltype(variant_index_test(std::declval<T>(), std::declval<V>()))::value; 81 82 /* 83 * Extend the template<typename _Tp, typename... _Types> std::get_if(variant<_Types...>*) function to support these: 84 * 1. When the _Tp is a type in the ..._Types, the get_if is equal to the std::get_if. 85 * 2. When the _Tp is not a type in the ..._Types but someone in the ...Types can convert to _Tp implicitly, 86 * the get_if will return it. 87 * 3. When the _Tp is not a type in the ..._Types and can't convert, the get_if will return nullptr. 88 * */ 89 template<class T, class... Types> 90 std::enable_if_t<same_in_v<T, Types...>, T *> get_if(std::variant<Types...> *input) 91 { 92 return std::get_if<T>(input); 93 } 94 95 template<class T, class... Types> 96 std::enable_if_t<same_in_v<T, Types...>, const T *> get_if(const std::variant<Types...> *input) 97 { 98 return std::get_if<T>(input); 99 } 100 101 template<class T, class... Types, size_t NP = convertible_in_v<T, Types...> ? convertible_index_of_v<T, Types...> : 0> 102 constexpr std::enable_if_t<!same_in_v<T, Types...> && (std::is_class_v<T> && convertible_in_v<T, Types...>), 103 std::add_pointer_t<std::variant_alternative_t<NP, std::variant<Types...>>>> 104 get_if(std::variant<Types...> *input) 105 { 106 return std::get_if<NP>(input); 107 } 108 109 template<class T, class... Types, size_t NP = convertible_in_v<T, Types...> ? convertible_index_of_v<T, Types...> : 0> 110 constexpr std::enable_if_t<!same_in_v<T, Types...> && (std::is_class_v<T> && convertible_in_v<T, Types...>), 111 std::add_pointer_t<const std::variant_alternative_t<NP, std::variant<Types...>>>> 112 get_if(const std::variant<Types...> *input) 113 { 114 return std::get_if<NP>(input); 115 } 116 117 template<class T, class... Types> 118 std::enable_if_t<!same_in_v<T, Types...> && (!std::is_class_v<T> || !convertible_in_v<T, Types...>), T *> get_if( 119 std::variant<Types...> *input) 120 { 121 (void)input; 122 return nullptr; 123 } 124 125 template<class T, class... Types> 126 std::enable_if_t<!same_in_v<T, Types...> && !convertible_in_v<T, Types...>, const T *> get_if( 127 const std::variant<Types...> *input) 128 { 129 (void)input; 130 return nullptr; 131 } 132 } // namespace Traits 133 } // namespace OHOS 134 #endif // OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_TRAITS_H 135