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<typename Tp, typename... Types>
24 struct index_of : std::integral_constant<size_t, 0> {};
25 
26 template<typename Tp, typename... Types>
27 inline constexpr size_t index_of_v = index_of<Tp, Types...>::value;
28 
29 template<typename Tp, typename First, typename... 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<typename T, typename... 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<typename T, typename... Types>
40 inline constexpr bool same_in_v = (same_index_of_v<T, Types...> < sizeof...(Types));
41 
42 template<typename Tp, typename... 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<typename Tp, typename... Types>
48 inline constexpr size_t convertible_index_of_v = convertible_index_of<Tp, Types...>::value;
49 
50 template<typename Tp, typename First, typename... 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<typename T, typename... Types>
56 inline constexpr bool convertible_in_v = (convertible_index_of_v<T, Types...> < sizeof...(Types));
57 
58 template<typename... Types>
59 struct variant_size_of {
60     static constexpr size_t value = sizeof...(Types);
61 };
62 
63 template<typename T, typename... Types>
64 struct variant_index_of {
65     static constexpr size_t value = same_index_of_v<T, Types...>;
66 };
67 
68 template<typename... Types>
69 variant_size_of<Types...> variant_size_test(const std::variant<Types...> &);
70 
71 template<typename T, typename... 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<typename 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<typename T, typename 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<typename T, typename... 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<typename T, typename... 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<typename T, typename... Types,
102 size_t NP = convertible_in_v<T, Types...> ? convertible_index_of_v<T, Types...> : 0>
103 constexpr std::enable_if_t<!same_in_v<T, Types...> && convertible_in_v<T, Types...>,
104 std::add_pointer_t<std::variant_alternative_t<NP, std::variant<Types...>>>>
105 get_if(std::variant<Types...> *input)
106 {
107 return std::get_if<NP>(input);
108 }
109 
110 template<typename T, typename... Types,
111 size_t NP = convertible_in_v<T, Types...> ? convertible_index_of_v<T, Types...> : 0>
112 constexpr std::enable_if_t<!same_in_v<T, Types...> && convertible_in_v<T, Types...>,
113 std::add_pointer_t<const std::variant_alternative_t<NP, std::variant<Types...>>>>
114 get_if(const std::variant<Types...> *input)
115 {
116     return std::get_if<NP>(input);
117 }
118 
119 template<typename T, typename... Types>
120 std::enable_if_t<!same_in_v<T, Types...> && !convertible_in_v<T, Types...>, T *> get_if(std::variant<Types...> *input)
121 {
122 (void)input;
123 return nullptr;
124 }
125 
126 template<typename T, typename... Types>
127 std::enable_if_t<!same_in_v<T, Types...> && !convertible_in_v<T, Types...>, const T *> get_if(
128     const std::variant<Types...> *input)
129 {
130     (void)input;
131     return nullptr;
132 }
133 } // namespace Traits
134 } // namespace OHOS
135 #endif // OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_TRAITS_H
136