1 | /* |
2 | * Copyright 2011-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #pragma once |
18 | |
19 | #include <type_traits> |
20 | #include <utility> |
21 | |
22 | #include <folly/functional/Invoke.h> |
23 | |
24 | namespace folly { |
25 | namespace dptr_detail { |
26 | |
27 | /** |
28 | * Given a target type and a list of types, return the 1-based index of the |
29 | * type in the list of types. Fail to compile if the target type doesn't |
30 | * appear in the list. |
31 | * |
32 | * GetIndex<int, void, char, int>::value == 3 |
33 | * GetIndex<int, void, char>::value -> fails to compile |
34 | */ |
35 | template <typename... Types> |
36 | struct GetTypeIndex; |
37 | |
38 | // When recursing, we never reach the 0- or 1- template argument base case |
39 | // unless the target type is not in the list. If the target type is in the |
40 | // list, we stop recursing when it is at the head of the remaining type |
41 | // list via the GetTypeIndex<T, T, Types...> partial specialization. |
42 | template <typename T, typename... Types> |
43 | struct GetTypeIndex<T, T, Types...> { |
44 | static const size_t value = 1; |
45 | }; |
46 | |
47 | template <typename T, typename U, typename... Types> |
48 | struct GetTypeIndex<T, U, Types...> { |
49 | static const size_t value = 1 + GetTypeIndex<T, Types...>::value; |
50 | }; |
51 | |
52 | // Generalize std::is_same for variable number of type arguments |
53 | template <typename... Types> |
54 | struct IsSameType; |
55 | |
56 | template <> |
57 | struct IsSameType<> { |
58 | static const bool value = true; |
59 | }; |
60 | |
61 | template <typename T> |
62 | struct IsSameType<T> { |
63 | static const bool value = true; |
64 | }; |
65 | |
66 | template <typename T, typename U, typename... Types> |
67 | struct IsSameType<T, U, Types...> { |
68 | static const bool value = |
69 | std::is_same<T, U>::value && IsSameType<U, Types...>::value; |
70 | }; |
71 | |
72 | // Define type as the type of all T in (non-empty) Types..., asserting that |
73 | // all types in Types... are the same. |
74 | template <typename... Types> |
75 | struct SameType; |
76 | |
77 | template <typename T, typename... Types> |
78 | struct SameType<T, Types...> { |
79 | typedef T type; |
80 | static_assert( |
81 | IsSameType<T, Types...>::value, |
82 | "Not all types in pack are the same" ); |
83 | }; |
84 | |
85 | // Determine the result type of applying a visitor of type V on a pointer |
86 | // to type T. |
87 | template <typename V, typename T> |
88 | struct VisitorResult1 { |
89 | typedef invoke_result_t<V, T*> type; |
90 | }; |
91 | |
92 | // Determine the result type of applying a visitor of type V on a const pointer |
93 | // to type T. |
94 | template <typename V, typename T> |
95 | struct ConstVisitorResult1 { |
96 | typedef invoke_result_t<V, const T*> type; |
97 | }; |
98 | |
99 | // Determine the result type of applying a visitor of type V on pointers of |
100 | // all types in Types..., asserting that the type is the same for all types |
101 | // in Types... |
102 | template <typename V, typename... Types> |
103 | struct VisitorResult { |
104 | typedef |
105 | typename SameType<typename VisitorResult1<V, Types>::type...>::type type; |
106 | }; |
107 | |
108 | // Determine the result type of applying a visitor of type V on const pointers |
109 | // of all types in Types..., asserting that the type is the same for all types |
110 | // in Types... |
111 | template <typename V, typename... Types> |
112 | struct ConstVisitorResult { |
113 | typedef |
114 | typename SameType<typename ConstVisitorResult1<V, Types>::type...>::type |
115 | type; |
116 | }; |
117 | |
118 | template <size_t index, typename V, typename R, typename... Types> |
119 | struct ApplyVisitor1; |
120 | |
121 | template <typename V, typename R, typename T, typename... Types> |
122 | struct ApplyVisitor1<1, V, R, T, Types...> { |
123 | R operator()(size_t, V&& visitor, void* ptr) const { |
124 | return visitor(static_cast<T*>(ptr)); |
125 | } |
126 | }; |
127 | |
128 | template <size_t index, typename V, typename R, typename T, typename... Types> |
129 | struct ApplyVisitor1<index, V, R, T, Types...> { |
130 | R operator()(size_t runtimeIndex, V&& visitor, void* ptr) const { |
131 | return runtimeIndex == 1 |
132 | ? visitor(static_cast<T*>(ptr)) |
133 | : ApplyVisitor1<index - 1, V, R, Types...>()( |
134 | runtimeIndex - 1, std::forward<V>(visitor), ptr); |
135 | } |
136 | }; |
137 | |
138 | template <size_t index, typename V, typename R, typename... Types> |
139 | struct ApplyConstVisitor1; |
140 | |
141 | template <typename V, typename R, typename T, typename... Types> |
142 | struct ApplyConstVisitor1<1, V, R, T, Types...> { |
143 | R operator()(size_t, V&& visitor, void* ptr) const { |
144 | return visitor(static_cast<const T*>(ptr)); |
145 | } |
146 | }; |
147 | |
148 | template <size_t index, typename V, typename R, typename T, typename... Types> |
149 | struct ApplyConstVisitor1<index, V, R, T, Types...> { |
150 | R operator()(size_t runtimeIndex, V&& visitor, void* ptr) const { |
151 | return runtimeIndex == 1 |
152 | ? visitor(static_cast<const T*>(ptr)) |
153 | : ApplyConstVisitor1<index - 1, V, R, Types...>()( |
154 | runtimeIndex - 1, std::forward<V>(visitor), ptr); |
155 | } |
156 | }; |
157 | |
158 | template <typename V, typename... Types> |
159 | using ApplyVisitor = ApplyVisitor1< |
160 | sizeof...(Types), |
161 | V, |
162 | typename VisitorResult<V, Types...>::type, |
163 | Types...>; |
164 | |
165 | template <typename V, typename... Types> |
166 | using ApplyConstVisitor = ApplyConstVisitor1< |
167 | sizeof...(Types), |
168 | V, |
169 | typename ConstVisitorResult<V, Types...>::type, |
170 | Types...>; |
171 | |
172 | } // namespace dptr_detail |
173 | } // namespace folly |
174 | |