table.h
Go to the documentation of this file.
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_CORE_LIB_GPRPP_TABLE_H
16 #define GRPC_CORE_LIB_GPRPP_TABLE_H
17 
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 
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() {}
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>
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) +
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>
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>
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>
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>
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>
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  // Count the number of set fields in the table
322  size_t count() const { return present_bits_.count(); }
323 
324  // Check if the table is completely empty
325  bool empty() const { return present_bits_.none(); }
326 
327  // Clear all elements in the table.
328  void ClearAll() { ClearAllImpl(absl::make_index_sequence<sizeof...(Ts)>()); }
329 
330  private:
331  // Bit field for which elements of the table are set (true) or un-set (false,
332  // the default) -- one bit for each type in Ts.
333  using PresentBits = BitSet<sizeof...(Ts)>;
334  // The tuple-like backing structure for Table.
336  // Extractor from Elements
337  template <size_t I>
338  using GetElem = table_detail::GetElem<I, Ts...>;
339 
340  // Given a T, return the unambiguous index of it within Ts.
341  template <typename T>
342  static constexpr size_t index_of() {
343  return table_detail::IndexOf<T, Ts...>();
344  }
345 
346  // Given an index, return a point to the (maybe uninitialized!) data value at
347  // index I.
348  template <size_t I>
350  return GetElem<I>::f(&elements_);
351  }
352 
353  // Given an index, return a point to the (maybe uninitialized!) data value at
354  // index I.
355  template <size_t I>
356  const TypeIndex<I>* element_ptr() const {
357  return GetElem<I>::f(&elements_);
358  }
359 
360  // Set the present bit to value (if true - value is present/set, if false,
361  // value is un-set). Returns the old value so that calling code can note
362  // transition edges.
363  template <size_t I>
364  bool set_present(bool value) {
365  bool out = present_bits_.is_set(I);
367  return out;
368  }
369 
370  // Set the value of index I to the value held in rhs index I if it is set.
371  // If it is unset, if or_clear is true, then clear our value, otherwise do
372  // nothing.
373  template <bool or_clear, size_t I>
374  void CopyIf(const Table& rhs) {
375  if (auto* p = rhs.get<I>()) {
376  set<I>(*p);
377  } else if (or_clear) {
378  clear<I>();
379  }
380  }
381 
382  // Set the value of index I to the value moved from rhs index I if it was set.
383  // If it is unset, if or_clear is true, then clear our value, otherwise do
384  // nothing.
385  template <bool or_clear, size_t I>
386  void MoveIf(Table&& rhs) {
387  if (auto* p = rhs.get<I>()) {
388  set<I>(std::move(*p));
389  } else if (or_clear) {
390  clear<I>();
391  }
392  }
393 
394  // Call (*f)(value) if that value is in the table.
395  template <size_t I, typename F>
396  void CallIf(F* f) const {
397  if (auto* p = get<I>()) {
398  (*f)(*p);
399  }
400  }
401 
402  // For each field (element I=0, 1, ...) if that field is present, call its
403  // destructor.
404  template <size_t... I>
406  table_detail::do_these_things<int>(
407  {(table_detail::DestructIfNotNull(get<I>()), 1)...});
408  }
409 
410  // For each field (element I=0, 1, ...) copy that field into this table -
411  // or_clear as per CopyIf().
412  template <bool or_clear, size_t... I>
414  table_detail::do_these_things<int>({(CopyIf<or_clear, I>(rhs), 1)...});
415  }
416 
417  // For each field (element I=0, 1, ...) move that field into this table -
418  // or_clear as per MoveIf().
419  template <bool or_clear, size_t... I>
421  table_detail::do_these_things<int>(
422  {(MoveIf<or_clear, I>(std::forward<Table>(rhs)), 1)...});
423  }
424 
425  // For each field (element I=0, 1, ...) if that field is present, call f.
426  template <typename F, size_t... I>
428  table_detail::do_these_things<int>({(CallIf<I>(&f), 1)...});
429  }
430 
431  template <size_t... I>
433  table_detail::do_these_things<int>({(clear<I>(), 1)...});
434  }
435 
436  // Bit field indicating which elements are set.
438  // The memory to store the elements themselves.
440 };
441 
442 } // namespace grpc_core
443 
444 #endif // GRPC_CORE_LIB_GPRPP_TABLE_H
Type
struct Type Type
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:673
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
grpc_core::Table::set_present
bool set_present(bool value)
Definition: table.h:364
get
absl::string_view get(const Cont &c)
Definition: abseil-cpp/absl/strings/str_replace_test.cc:185
grpc_core::Table::Destruct
void Destruct(absl::index_sequence< I... >)
Definition: table.h:405
grpc_core::BitSet::set
GRPC_BITSET_CONSTEXPR_MUTATOR void set(int i)
Definition: bitset.h:93
grpc_core::Table
Definition: table.h:171
grpc_core::table_detail::TypeIndex
typename TypeIndexStruct< I, Ts... >::Type TypeIndex
Definition: table.h:144
grpc_core::table_detail::Elements< T, Ts... >::U::~U
~U()
Definition: table.h:45
grpc_core::table_detail::TypeIndexStruct< 0, T, Ts... >::Type
T Type
Definition: table.h:138
grpc_core
Definition: call_metric_recorder.h:31
re2::Ignored
int Ignored
Definition: bloaty/third_party/re2/re2/regexp.cc:534
grpc_core::Table::CallIf
void CallIf(F *f) const
Definition: table.h:396
grpc_core::Table::Move
void Move(absl::index_sequence< I... >, Table &&rhs)
Definition: table.h:420
grpc_core::table_detail::GetElem
Definition: table.h:57
grpc_core::table_detail::IndexOfStruct
Definition: table.h:102
grpc_core::table_detail::GetElem< I, T, Ts... >::f
static auto f(const Elements< T, Ts... > *e) -> decltype(GetElem< I - 1, Ts... >::f(e))
Definition: table.h:71
grpc_core::table_detail::DestructIfNotNull
void DestructIfNotNull(T *p)
Definition: table.h:148
absl::enable_if_t
typename std::enable_if< B, T >::type enable_if_t
Definition: abseil-cpp/absl/meta/type_traits.h:631
grpc_core::table_detail::GetElem< 0, T, Ts... >::f
static const T * f(const Elements< T, Ts... > *e)
Definition: table.h:62
grpc_core::Table::ClearAll
void ClearAll()
Definition: table.h:328
xds_manager.p
p
Definition: xds_manager.py:60
T
#define T(upbtypeconst, upbtype, ctype, default_value)
grpc_core::table_detail::Elements< T, Ts... >::u
U u
Definition: table.h:48
grpc_core::BitSet::is_set
constexpr bool is_set(int i) const
Definition: bitset.h:112
grpc_core::Table::empty
bool empty() const
Definition: table.h:325
grpc_core::BitSet::count
uint32_t count() const
Definition: bitset.h:145
grpc_core::Table::ForEachImpl
void ForEachImpl(F f, absl::index_sequence< I... >) const
Definition: table.h:427
autogen_x86imm.f
f
Definition: autogen_x86imm.py:9
asyncio_get_stats.args
args
Definition: asyncio_get_stats.py:40
grpc_core::Table::CopyIf
void CopyIf(const Table &rhs)
Definition: table.h:374
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
grpc_core::Table::MoveIf
void MoveIf(Table &&rhs)
Definition: table.h:386
grpc_core::Table::Copy
void Copy(absl::index_sequence< I... >, const Table &rhs)
Definition: table.h:413
hpack_encoder_fixtures::Args
Args({0, 16384})
grpc_core::table_detail::CountIncluded
constexpr size_t CountIncluded()
Definition: table.h:94
grpc_core::table_detail::CountIncludedStruct
Definition: table.h:80
absl::make_index_sequence
make_integer_sequence< size_t, N > make_index_sequence
Definition: abseil-cpp/absl/utility/utility.h:150
grpc_core::Table::elements_
GPR_NO_UNIQUE_ADDRESS Elements elements_
Definition: table.h:439
absl::integer_sequence
Definition: abseil-cpp/absl/utility/utility.h:76
grpc_core::table_detail::Elements< T, Ts... >::U::U
U()
Definition: table.h:44
grpc_core::Table::element_ptr
const TypeIndex< I > * element_ptr() const
Definition: table.h:356
grpc_core::table_detail::GetElem< I, T, Ts... >::f
static auto f(Elements< T, Ts... > *e) -> decltype(GetElem< I - 1, Ts... >::f(e))
Definition: table.h:67
grpc_core::Table::Table
Table()=default
grpc_core::Table::operator=
Table & operator=(Table &&rhs) noexcept
Definition: table.h:205
GPR_NO_UNIQUE_ADDRESS
#define GPR_NO_UNIQUE_ADDRESS
Definition: impl/codegen/port_platform.h:692
grpc_core::Table::count
size_t count() const
Definition: table.h:322
grpc_core::Table::Table
Table(Table &&rhs) noexcept
Definition: table.h:198
F
#define F(b, c, d)
Definition: md4.c:112
value
const char * value
Definition: hpack_parser_table.cc:165
grpc_core::table_detail::Elements
Definition: table.h:39
grpc_core::Table::present_bits_
GPR_NO_UNIQUE_ADDRESS PresentBits present_bits_
Definition: table.h:437
grpc_core::table_detail::GetElem< 0, T, Ts... >::f
static T * f(Elements< T, Ts... > *e)
Definition: table.h:61
grpc_core::Table::element_ptr
TypeIndex< I > * element_ptr()
Definition: table.h:349
grpc_core::table_detail::Elements< T, Ts... >
Definition: table.h:42
grpc_core::BitSet
Definition: bitset.h:85
N
#define N
Definition: sync_test.cc:37
I
#define I(b, c, d)
Definition: md5.c:120
grpc_core::Table::ClearAllImpl
void ClearAllImpl(absl::index_sequence< I... >)
Definition: table.h:432
grpc_core::table_detail::do_these_things
void do_these_things(std::initializer_list< T >)
Definition: table.h:163
grpc_core::Table::ForEach
void ForEach(F f) const
Definition: table.h:317
cpp.gmock_class.set
set
Definition: bloaty/third_party/googletest/googlemock/scripts/generator/cpp/gmock_class.py:44
grpc_core::Table::index_of
static constexpr size_t index_of()
Definition: table.h:342
grpc_core::Table::~Table
~Table()
Definition: table.h:181
grpc_core::BitSet::none
bool none() const
Definition: bitset.h:137
grpc_core::table_detail::TypeIndexStruct
Definition: table.h:134
grpc_core::Table< grpc_core::metadata_detail::Value< Traits >... >::TypeIndex
table_detail::TypeIndex< I, Ts... > TypeIndex
Definition: table.h:174
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
grpc_core::table_detail::Elements< T, Ts... >::U::x
GPR_NO_UNIQUE_ADDRESS T x
Definition: table.h:46
grpc_core::Table::Table
Table(const Table &rhs)
Definition: table.h:184
absl::forward
constexpr T && forward(absl::remove_reference_t< T > &t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:230
grpc_core::Table::has
bool has() const
Definition: table.h:216
grpc_core::Table::operator=
Table & operator=(const Table &rhs)
Definition: table.h:190
bitset.h
port_platform.h
grpc_core::table_detail::IndexOf
constexpr absl::enable_if_t< CountIncluded< Needle, Haystack... >)==1, size_t > IndexOf()
Definition: table.h:126


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:01:29