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