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