• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 gRPC authors.
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 #ifndef GRPC_SRC_CORE_LIB_GPRPP_TABLE_H
16 #define GRPC_SRC_CORE_LIB_GPRPP_TABLE_H
17 
18 #include <grpc/support/port_platform.h>
19 
20 #include <stddef.h>
21 
22 #include <initializer_list>
23 #include <new>
24 #include <type_traits>
25 #include <utility>
26 
27 #include "absl/meta/type_traits.h"
28 #include "absl/utility/utility.h"
29 
30 #include "src/core/lib/gprpp/bitset.h"
31 
32 namespace grpc_core {
33 
34 // Meta-programming detail types to aid in building up a Table
35 namespace table_detail {
36 
37 // A tuple-like type that contains manually constructed elements.
38 template <typename... Ts>
39 struct Elements;
40 
41 template <typename T, typename... Ts>
42 struct Elements<T, Ts...> : Elements<Ts...> {
43   union U {
44     U() {}
45     ~U() {}
46     GPR_NO_UNIQUE_ADDRESS T x;
47   };
48   U u;
49 };
50 template <>
51 struct Elements<> {};
52 
53 // Element accessor for Elements<>
54 // Provides a static method f that returns a pointer to the value of element I
55 // for Elements<Ts...>
56 template <size_t I, typename... Ts>
57 struct GetElem;
58 
59 template <typename T, typename... Ts>
60 struct GetElem<0, T, Ts...> {
61   static T* f(Elements<T, Ts...>* e) { return &e->u.x; }
62   static const T* f(const Elements<T, Ts...>* e) { return &e->u.x; }
63 };
64 
65 template <size_t I, typename T, typename... Ts>
66 struct GetElem<I, T, Ts...> {
67   static auto f(Elements<T, Ts...>* e)
68       -> decltype(GetElem<I - 1, Ts...>::f(e)) {
69     return GetElem<I - 1, Ts...>::f(e);
70   }
71   static auto f(const Elements<T, Ts...>* e)
72       -> decltype(GetElem<I - 1, Ts...>::f(e)) {
73     return GetElem<I - 1, Ts...>::f(e);
74   }
75 };
76 
77 // CountIncludedStruct is the backing for the CountIncluded function below.
78 // Sets a member constant N to the number of times Needle is in Haystack.
79 template <typename Needle, typename... Haystack>
80 struct CountIncludedStruct;
81 
82 template <typename Needle, typename Straw, typename... RestOfHaystack>
83 struct CountIncludedStruct<Needle, Straw, RestOfHaystack...> {
84   static constexpr size_t N =
85       static_cast<size_t>(std::is_same<Needle, Straw>::value) +
86       CountIncludedStruct<Needle, RestOfHaystack...>::N;
87 };
88 template <typename Needle>
89 struct CountIncludedStruct<Needle> {
90   static constexpr size_t N = 0;
91 };
92 // Returns the number of times Needle is in Haystack.
93 template <typename Needle, typename... Haystack>
94 constexpr size_t CountIncluded() {
95   return CountIncludedStruct<Needle, Haystack...>::N;
96 }
97 
98 // IndexOfStruct is the backing for IndexOf below.
99 // Set a member constant N to the index of Needle in Haystack.
100 // Ignored should be void always, and is used for enable_if_t.
101 template <typename Ignored, typename Needle, typename... Haystack>
102 struct IndexOfStruct;
103 
104 template <typename Needle, typename Straw, typename... RestOfHaystack>
105 struct IndexOfStruct<absl::enable_if_t<std::is_same<Needle, Straw>::value>,
106                      Needle, Straw, RestOfHaystack...> {
107   // The first element is the one we're looking for. Done.
108   static constexpr size_t N = 0;
109 };
110 template <typename Needle, typename Straw, typename... RestOfHaystack>
111 struct IndexOfStruct<absl::enable_if_t<!std::is_same<Needle, Straw>::value>,
112                      Needle, Straw, RestOfHaystack...> {
113   // The first element is not the one we're looking for, recurse looking at the
114   // tail, and sum the number of recursions.
115   static constexpr size_t N =
116       1 + IndexOfStruct<void, Needle, RestOfHaystack...>::N;
117 };
118 // Return the index of Needle in Haystack.
119 // Guarded by CountIncluded to ensure that the return type is unambiguous.
120 // If you got here from a compiler error using Table, it's likely that you've
121 // used the type-based accessor/mutators, but the type you're using is repeated
122 // more than once in the Table type arguments. Consider either using the indexed
123 // accessor/mutator variants, or eliminating the ambiguity in type resolution.
124 template <typename Needle, typename... Haystack>
125 constexpr absl::enable_if_t<CountIncluded<Needle, Haystack...>() == 1, size_t>
126 IndexOf() {
127   return IndexOfStruct<void, Needle, Haystack...>::N;
128 }
129 
130 // TypeIndexStruct is the backing for TypeIndex below.
131 // Sets member type Type to the type at index I in Ts.
132 // Implemented as a simple type recursion.
133 template <size_t I, typename... Ts>
134 struct TypeIndexStruct;
135 
136 template <typename T, typename... Ts>
137 struct TypeIndexStruct<0, T, Ts...> {
138   using Type = T;
139 };
140 template <size_t I, typename T, typename... Ts>
141 struct TypeIndexStruct<I, T, Ts...> : TypeIndexStruct<I - 1, Ts...> {};
142 // TypeIndex is the type at index I in Ts.
143 template <size_t I, typename... Ts>
144 using TypeIndex = typename TypeIndexStruct<I, Ts...>::Type;
145 
146 // Helper to call the destructor of p if p is non-null.
147 template <typename T>
148 void DestructIfNotNull(T* p) {
149   if (p) p->~T();
150 }
151 
152 // Helper function... just ignore the initializer list passed into it.
153 // Allows doing 'statements' via parameter pack expansion in C++11 - given
154 // template <typename... Ts>:
155 //  do_these_things({(foo<Ts>(), 1)});
156 // will execute foo<T>() for each T in Ts.
157 // In this example we also leverage the comma operator to make the resultant
158 // type of each statement be a consistant int so that C++ type deduction works
159 // as we'd like (note that in the expression (a, 1) in C++, the 'result' of the
160 // expression is the value after the right-most ',' -- in this case 1, with a
161 // executed as a side effect.
162 template <typename T>
163 void do_these_things(std::initializer_list<T>) {}
164 
165 }  // namespace table_detail
166 
167 // A Table<Ts> is much like a tuple<optional<Ts>...> - a set of values that are
168 // optionally present. Table efficiently packs the presence bits for size, and
169 // provides a slightly more convenient interface.
170 template <typename... Ts>
171 class Table {
172   // Helper - TypeIndex<I> is the type at index I in Ts
173   template <size_t I>
174   using TypeIndex = table_detail::TypeIndex<I, Ts...>;
175 
176  public:
177   // Construct a table with no values set.
178   Table() = default;
179   // Destruct - forwards to the Destruct member with an integer sequence so we
180   // can destruct field-wise.
181   ~Table() { Destruct(absl::make_index_sequence<sizeof...(Ts)>()); }
182 
183   // Copy another table
184   Table(const Table& rhs) {
185     // Since we know all fields are clear initially, pass false for or_clear.
186     Copy<false>(absl::make_index_sequence<sizeof...(Ts)>(), rhs);
187   }
188 
189   // Copy another table
190   Table& operator=(const Table& rhs) {
191     // Since we may not be all clear, pass true for or_clear to have Copy()
192     // clear newly emptied fields.
193     Copy<true>(absl::make_index_sequence<sizeof...(Ts)>(), rhs);
194     return *this;
195   }
196 
197   // Move from another table
198   Table(Table&& rhs) noexcept {
199     // Since we know all fields are clear initially, pass false for or_clear.
200     Move<false>(absl::make_index_sequence<sizeof...(Ts)>(),
201                 std::forward<Table>(rhs));
202   }
203 
204   // Move from another table
205   Table& operator=(Table&& rhs) noexcept {
206     // Since we may not be all clear, pass true for or_clear to have Move()
207     // clear newly emptied fields.
208     Move<true>(absl::make_index_sequence<sizeof...(Ts)>(),
209                std::forward<Table>(rhs));
210     return *this;
211   }
212 
213   // Check if this table has a value for type T.
214   // Only available if there exists only one T in Ts.
215   template <typename T>
216   bool has() const {
217     return has<index_of<T>()>();
218   }
219 
220   // Check if this table has index I.
221   template <size_t I>
222   absl::enable_if_t<(I < sizeof...(Ts)), bool> has() const {
223     return present_bits_.is_set(I);
224   }
225 
226   // Return the value for type T, or nullptr if it is un-set.
227   // Only available if there exists only one T in Ts.
228   template <typename T>
229   T* get() {
230     return get<index_of<T>()>();
231   }
232 
233   // Return the value for type T, or nullptr if it is un-set.
234   // Only available if there exists only one T in Ts.
235   template <typename T>
236   const T* get() const {
237     return get<index_of<T>()>();
238   }
239 
240   // Return the value for index I, or nullptr if it is un-set.
241   template <size_t I>
242   TypeIndex<I>* get() {
243     if (has<I>()) return element_ptr<I>();
244     return nullptr;
245   }
246 
247   // Return the value for index I, or nullptr if it is un-set.
248   template <size_t I>
249   const TypeIndex<I>* get() const {
250     if (has<I>()) return element_ptr<I>();
251     return nullptr;
252   }
253 
254   // Return the value for type T, default constructing it if it is un-set.
255   template <typename T>
256   T* get_or_create() {
257     return get_or_create<index_of<T>()>();
258   }
259 
260   // Return the value for index I, default constructing it if it is un-set.
261   template <size_t I>
262   TypeIndex<I>* get_or_create() {
263     auto* p = element_ptr<I>();
264     if (!set_present<I>(true)) {
265       new (p) TypeIndex<I>();
266     }
267     return element_ptr<I>();
268   }
269 
270   // Set the value for type T - using Args as construction arguments.
271   template <typename T, typename... Args>
272   T* set(Args&&... args) {
273     return set<index_of<T>()>(std::forward<Args>(args)...);
274   }
275 
276   // Set the value for index I - using Args as construction arguments.
277   template <size_t I, typename... Args>
278   TypeIndex<I>* set(Args&&... args) {
279     auto* p = element_ptr<I>();
280     if (set_present<I>(true)) {
281       TypeIndex<I> replacement(std::forward<Args>(args)...);
282       *p = std::move(replacement);
283     } else {
284       new (p) TypeIndex<I>(std::forward<Args>(args)...);
285     }
286     return p;
287   }
288 
289   template <size_t I>
290   TypeIndex<I>* set(TypeIndex<I>&& value) {
291     auto* p = element_ptr<I>();
292     if (set_present<I>(true)) {
293       *p = std::forward<TypeIndex<I>>(value);
294     } else {
295       new (p) TypeIndex<I>(std::forward<TypeIndex<I>>(value));
296     }
297     return p;
298   }
299 
300   // Clear the value for type T, leaving it un-set.
301   template <typename T>
302   void clear() {
303     clear<index_of<T>()>();
304   }
305 
306   // Clear the value for index I, leaving it un-set.
307   template <size_t I>
308   void clear() {
309     if (set_present<I>(false)) {
310       using T = TypeIndex<I>;
311       element_ptr<I>()->~T();
312     }
313   }
314 
315   // Iterate through each set field in the table
316   template <typename F>
317   void ForEach(F f) const {
318     ForEachImpl(std::move(f), absl::make_index_sequence<sizeof...(Ts)>());
319   }
320 
321   // Iterate through each set field in the table if it exists in Vs, in the
322   // order of Vs.
323   template <typename F, typename... Vs>
324   void ForEachIn(F f) const {
325     ForEachImpl(std::move(f),
326                 absl::index_sequence<table_detail::IndexOf<Vs, Ts...>()...>());
327   }
328 
329   // Count the number of set fields in the table
330   size_t count() const { return present_bits_.count(); }
331 
332   // Check if the table is completely empty
333   bool empty() const { return present_bits_.none(); }
334 
335   // Clear all elements in the table.
336   void ClearAll() { ClearAllImpl(absl::make_index_sequence<sizeof...(Ts)>()); }
337 
338  private:
339   // Bit field for which elements of the table are set (true) or un-set (false,
340   // the default) -- one bit for each type in Ts.
341   using PresentBits = BitSet<sizeof...(Ts)>;
342   // The tuple-like backing structure for Table.
343   using Elements = table_detail::Elements<Ts...>;
344   // Extractor from Elements
345   template <size_t I>
346   using GetElem = table_detail::GetElem<I, Ts...>;
347 
348   // Given a T, return the unambiguous index of it within Ts.
349   template <typename T>
350   static constexpr size_t index_of() {
351     return table_detail::IndexOf<T, Ts...>();
352   }
353 
354   // Given an index, return a point to the (maybe uninitialized!) data value at
355   // index I.
356   template <size_t I>
357   TypeIndex<I>* element_ptr() {
358     return GetElem<I>::f(&elements_);
359   }
360 
361   // Given an index, return a point to the (maybe uninitialized!) data value at
362   // index I.
363   template <size_t I>
364   const TypeIndex<I>* element_ptr() const {
365     return GetElem<I>::f(&elements_);
366   }
367 
368   // Set the present bit to value (if true - value is present/set, if false,
369   // value is un-set). Returns the old value so that calling code can note
370   // transition edges.
371   template <size_t I>
372   bool set_present(bool value) {
373     bool out = present_bits_.is_set(I);
374     present_bits_.set(I, value);
375     return out;
376   }
377 
378   // Set the value of index I to the value held in rhs index I if it is set.
379   // If it is unset, if or_clear is true, then clear our value, otherwise do
380   // nothing.
381   template <bool or_clear, size_t I>
382   void CopyIf(const Table& rhs) {
383     if (auto* p = rhs.get<I>()) {
384       set<I>(*p);
385     } else if (or_clear) {
386       clear<I>();
387     }
388   }
389 
390   // Set the value of index I to the value moved from rhs index I if it was set.
391   // If it is unset, if or_clear is true, then clear our value, otherwise do
392   // nothing.
393   template <bool or_clear, size_t I>
394   void MoveIf(Table&& rhs) {
395     if (auto* p = rhs.get<I>()) {
396       set<I>(std::move(*p));
397     } else if (or_clear) {
398       clear<I>();
399     }
400   }
401 
402   // Call (*f)(value) if that value is in the table.
403   template <size_t I, typename F>
404   void CallIf(F* f) const {
405     if (auto* p = get<I>()) {
406       (*f)(*p);
407     }
408   }
409 
410   // For each field (element I=0, 1, ...) if that field is present, call its
411   // destructor.
412   template <size_t... I>
413   void Destruct(absl::index_sequence<I...>) {
414     table_detail::do_these_things<int>(
415         {(table_detail::DestructIfNotNull(get<I>()), 1)...});
416   }
417 
418   // For each field (element I=0, 1, ...) copy that field into this table -
419   // or_clear as per CopyIf().
420   template <bool or_clear, size_t... I>
421   void Copy(absl::index_sequence<I...>, const Table& rhs) {
422     table_detail::do_these_things<int>({(CopyIf<or_clear, I>(rhs), 1)...});
423   }
424 
425   // For each field (element I=0, 1, ...) move that field into this table -
426   // or_clear as per MoveIf().
427   template <bool or_clear, size_t... I>
428   void Move(absl::index_sequence<I...>, Table&& rhs) {
429     table_detail::do_these_things<int>(
430         {(MoveIf<or_clear, I>(std::forward<Table>(rhs)), 1)...});
431   }
432 
433   // For each field (element I=0, 1, ...) if that field is present, call f.
434   template <typename F, size_t... I>
435   void ForEachImpl(F f, absl::index_sequence<I...>) const {
436     table_detail::do_these_things<int>({(CallIf<I>(&f), 1)...});
437   }
438 
439   template <size_t... I>
440   void ClearAllImpl(absl::index_sequence<I...>) {
441     table_detail::do_these_things<int>({(clear<I>(), 1)...});
442   }
443 
444   // Bit field indicating which elements are set.
445   GPR_NO_UNIQUE_ADDRESS PresentBits present_bits_;
446   // The memory to store the elements themselves.
447   GPR_NO_UNIQUE_ADDRESS Elements elements_;
448 };
449 
450 }  // namespace grpc_core
451 
452 #endif  // GRPC_SRC_CORE_LIB_GPRPP_TABLE_H
453