flag.h (36462B)
1 // 2 // Copyright 2019 The Abseil Authors. 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 // https://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 #ifndef ABSL_FLAGS_INTERNAL_FLAG_H_ 17 #define ABSL_FLAGS_INTERNAL_FLAG_H_ 18 19 #include <stddef.h> 20 #include <stdint.h> 21 22 #include <atomic> 23 #include <cstring> 24 #include <memory> 25 #include <string> 26 #include <type_traits> 27 #include <typeinfo> 28 29 #include "absl/base/attributes.h" 30 #include "absl/base/call_once.h" 31 #include "absl/base/casts.h" 32 #include "absl/base/config.h" 33 #include "absl/base/optimization.h" 34 #include "absl/base/thread_annotations.h" 35 #include "absl/flags/commandlineflag.h" 36 #include "absl/flags/config.h" 37 #include "absl/flags/internal/commandlineflag.h" 38 #include "absl/flags/internal/registry.h" 39 #include "absl/flags/internal/sequence_lock.h" 40 #include "absl/flags/marshalling.h" 41 #include "absl/meta/type_traits.h" 42 #include "absl/strings/string_view.h" 43 #include "absl/synchronization/mutex.h" 44 #include "absl/utility/utility.h" 45 46 namespace absl { 47 ABSL_NAMESPACE_BEGIN 48 49 /////////////////////////////////////////////////////////////////////////////// 50 // Forward declaration of absl::Flag<T> public API. 51 namespace flags_internal { 52 template <typename T> 53 class Flag; 54 } // namespace flags_internal 55 56 template <typename T> 57 using Flag = flags_internal::Flag<T>; 58 59 template <typename T> 60 [[nodiscard]] T GetFlag(const absl::Flag<T>& flag); 61 62 template <typename T> 63 void SetFlag(absl::Flag<T>* flag, const T& v); 64 65 template <typename T, typename V> 66 void SetFlag(absl::Flag<T>* flag, const V& v); 67 68 template <typename U> 69 const CommandLineFlag& GetFlagReflectionHandle(const absl::Flag<U>& f); 70 71 /////////////////////////////////////////////////////////////////////////////// 72 // Flag value type operations, eg., parsing, copying, etc. are provided 73 // by function specific to that type with a signature matching FlagOpFn. 74 75 namespace flags_internal { 76 77 enum class FlagOp { 78 kAlloc, 79 kDelete, 80 kCopy, 81 kCopyConstruct, 82 kSizeof, 83 kFastTypeId, 84 kRuntimeTypeId, 85 kParse, 86 kUnparse, 87 kValueOffset, 88 }; 89 using FlagOpFn = void* (*)(FlagOp, const void*, void*, void*); 90 91 // Forward declaration for Flag value specific operations. 92 template <typename T> 93 void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3); 94 95 // Allocate aligned memory for a flag value. 96 inline void* Alloc(FlagOpFn op) { 97 return op(FlagOp::kAlloc, nullptr, nullptr, nullptr); 98 } 99 // Deletes memory interpreting obj as flag value type pointer. 100 inline void Delete(FlagOpFn op, void* obj) { 101 op(FlagOp::kDelete, nullptr, obj, nullptr); 102 } 103 // Copies src to dst interpreting as flag value type pointers. 104 inline void Copy(FlagOpFn op, const void* src, void* dst) { 105 op(FlagOp::kCopy, src, dst, nullptr); 106 } 107 // Construct a copy of flag value in a location pointed by dst 108 // based on src - pointer to the flag's value. 109 inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) { 110 op(FlagOp::kCopyConstruct, src, dst, nullptr); 111 } 112 // Makes a copy of flag value pointed by obj. 113 inline void* Clone(FlagOpFn op, const void* obj) { 114 void* res = flags_internal::Alloc(op); 115 flags_internal::CopyConstruct(op, obj, res); 116 return res; 117 } 118 // Returns true if parsing of input text is successful. 119 inline bool Parse(FlagOpFn op, absl::string_view text, void* dst, 120 std::string* error) { 121 return op(FlagOp::kParse, &text, dst, error) != nullptr; 122 } 123 // Returns string representing supplied value. 124 inline std::string Unparse(FlagOpFn op, const void* val) { 125 std::string result; 126 op(FlagOp::kUnparse, val, &result, nullptr); 127 return result; 128 } 129 // Returns size of flag value type. 130 inline size_t Sizeof(FlagOpFn op) { 131 // This sequence of casts reverses the sequence from 132 // `flags_internal::FlagOps()` 133 return static_cast<size_t>(reinterpret_cast<intptr_t>( 134 op(FlagOp::kSizeof, nullptr, nullptr, nullptr))); 135 } 136 // Returns fast type id corresponding to the value type. 137 inline FlagFastTypeId FastTypeId(FlagOpFn op) { 138 return reinterpret_cast<FlagFastTypeId>( 139 op(FlagOp::kFastTypeId, nullptr, nullptr, nullptr)); 140 } 141 // Returns fast type id corresponding to the value type. 142 inline const std::type_info* RuntimeTypeId(FlagOpFn op) { 143 return reinterpret_cast<const std::type_info*>( 144 op(FlagOp::kRuntimeTypeId, nullptr, nullptr, nullptr)); 145 } 146 // Returns offset of the field value_ from the field impl_ inside of 147 // absl::Flag<T> data. Given FlagImpl pointer p you can get the 148 // location of the corresponding value as: 149 // reinterpret_cast<char*>(p) + ValueOffset(). 150 inline ptrdiff_t ValueOffset(FlagOpFn op) { 151 // This sequence of casts reverses the sequence from 152 // `flags_internal::FlagOps()` 153 return static_cast<ptrdiff_t>(reinterpret_cast<intptr_t>( 154 op(FlagOp::kValueOffset, nullptr, nullptr, nullptr))); 155 } 156 157 // Returns an address of RTTI's typeid(T). 158 template <typename T> 159 inline const std::type_info* GenRuntimeTypeId() { 160 #ifdef ABSL_INTERNAL_HAS_RTTI 161 return &typeid(T); 162 #else 163 return nullptr; 164 #endif 165 } 166 167 /////////////////////////////////////////////////////////////////////////////// 168 // Flag help auxiliary structs. 169 170 // This is help argument for absl::Flag encapsulating the string literal pointer 171 // or pointer to function generating it as well as enum descriminating two 172 // cases. 173 using HelpGenFunc = std::string (*)(); 174 175 template <size_t N> 176 struct FixedCharArray { 177 char value[N]; 178 179 template <size_t... I> 180 static constexpr FixedCharArray<N> FromLiteralString( 181 absl::string_view str, absl::index_sequence<I...>) { 182 return (void)str, FixedCharArray<N>({{str[I]..., '\0'}}); 183 } 184 }; 185 186 template <typename Gen, size_t N = Gen::Value().size()> 187 constexpr FixedCharArray<N + 1> HelpStringAsArray(int) { 188 return FixedCharArray<N + 1>::FromLiteralString( 189 Gen::Value(), absl::make_index_sequence<N>{}); 190 } 191 192 template <typename Gen> 193 constexpr std::false_type HelpStringAsArray(char) { 194 return std::false_type{}; 195 } 196 197 union FlagHelpMsg { 198 constexpr explicit FlagHelpMsg(const char* help_msg) : literal(help_msg) {} 199 constexpr explicit FlagHelpMsg(HelpGenFunc help_gen) : gen_func(help_gen) {} 200 201 const char* literal; 202 HelpGenFunc gen_func; 203 }; 204 205 enum class FlagHelpKind : uint8_t { kLiteral = 0, kGenFunc = 1 }; 206 207 struct FlagHelpArg { 208 FlagHelpMsg source; 209 FlagHelpKind kind; 210 }; 211 212 extern const char kStrippedFlagHelp[]; 213 214 // These two HelpArg overloads allows us to select at compile time one of two 215 // way to pass Help argument to absl::Flag. We'll be passing 216 // AbslFlagHelpGenFor##name as Gen and integer 0 as a single argument to prefer 217 // first overload if possible. If help message is evaluatable on constexpr 218 // context We'll be able to make FixedCharArray out of it and we'll choose first 219 // overload. In this case the help message expression is immediately evaluated 220 // and is used to construct the absl::Flag. No additional code is generated by 221 // ABSL_FLAG Otherwise SFINAE kicks in and first overload is dropped from the 222 // consideration, in which case the second overload will be used. The second 223 // overload does not attempt to evaluate the help message expression 224 // immediately and instead delays the evaluation by returning the function 225 // pointer (&T::NonConst) generating the help message when necessary. This is 226 // evaluatable in constexpr context, but the cost is an extra function being 227 // generated in the ABSL_FLAG code. 228 template <typename Gen, size_t N> 229 constexpr FlagHelpArg HelpArg(const FixedCharArray<N>& value) { 230 return {FlagHelpMsg(value.value), FlagHelpKind::kLiteral}; 231 } 232 233 template <typename Gen> 234 constexpr FlagHelpArg HelpArg(std::false_type) { 235 return {FlagHelpMsg(&Gen::NonConst), FlagHelpKind::kGenFunc}; 236 } 237 238 /////////////////////////////////////////////////////////////////////////////// 239 // Flag default value auxiliary structs. 240 241 // Signature for the function generating the initial flag value (usually 242 // based on default value supplied in flag's definition) 243 using FlagDfltGenFunc = void (*)(void*); 244 245 union FlagDefaultSrc { 246 constexpr explicit FlagDefaultSrc(FlagDfltGenFunc gen_func_arg) 247 : gen_func(gen_func_arg) {} 248 249 #define ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE(T, name) \ 250 T name##_value; \ 251 constexpr explicit FlagDefaultSrc(T value) : name##_value(value) {} // NOLINT 252 ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE) 253 #undef ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE 254 255 void* dynamic_value; 256 FlagDfltGenFunc gen_func; 257 }; 258 259 enum class FlagDefaultKind : uint8_t { 260 kDynamicValue = 0, 261 kGenFunc = 1, 262 kOneWord = 2 // for default values UP to one word in size 263 }; 264 265 struct FlagDefaultArg { 266 FlagDefaultSrc source; 267 FlagDefaultKind kind; 268 }; 269 270 // This struct and corresponding overload to InitDefaultValue are used to 271 // facilitate usage of {} as default value in ABSL_FLAG macro. 272 // TODO(rogeeff): Fix handling types with explicit constructors. 273 struct EmptyBraces {}; 274 275 template <typename T> 276 constexpr T InitDefaultValue(T t) { 277 return t; 278 } 279 280 template <typename T> 281 constexpr T InitDefaultValue(EmptyBraces) { 282 return T{}; 283 } 284 285 template <typename ValueT, typename GenT, 286 typename std::enable_if<std::is_integral<ValueT>::value, int>::type = 287 ((void)GenT{}, 0)> 288 constexpr FlagDefaultArg DefaultArg(int) { 289 return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kOneWord}; 290 } 291 292 template <typename ValueT, typename GenT> 293 constexpr FlagDefaultArg DefaultArg(char) { 294 return {FlagDefaultSrc(&GenT::Gen), FlagDefaultKind::kGenFunc}; 295 } 296 297 /////////////////////////////////////////////////////////////////////////////// 298 // Flag storage selector traits. Each trait indicates what kind of storage kind 299 // to use for the flag value. 300 301 template <typename T> 302 using FlagUseValueAndInitBitStorage = 303 std::integral_constant<bool, std::is_trivially_copyable<T>::value && 304 std::is_default_constructible<T>::value && 305 (sizeof(T) < 8)>; 306 307 template <typename T> 308 using FlagUseOneWordStorage = 309 std::integral_constant<bool, std::is_trivially_copyable<T>::value && 310 (sizeof(T) <= 8)>; 311 312 template <class T> 313 using FlagUseSequenceLockStorage = 314 std::integral_constant<bool, std::is_trivially_copyable<T>::value && 315 (sizeof(T) > 8)>; 316 317 enum class FlagValueStorageKind : uint8_t { 318 kValueAndInitBit = 0, 319 kOneWordAtomic = 1, 320 kSequenceLocked = 2, 321 kHeapAllocated = 3, 322 }; 323 324 // This constexpr function returns the storage kind for the given flag value 325 // type. 326 template <typename T> 327 static constexpr FlagValueStorageKind StorageKind() { 328 return FlagUseValueAndInitBitStorage<T>::value 329 ? FlagValueStorageKind::kValueAndInitBit 330 : FlagUseOneWordStorage<T>::value 331 ? FlagValueStorageKind::kOneWordAtomic 332 : FlagUseSequenceLockStorage<T>::value 333 ? FlagValueStorageKind::kSequenceLocked 334 : FlagValueStorageKind::kHeapAllocated; 335 } 336 337 // This is a base class for the storage classes used by kOneWordAtomic and 338 // kValueAndInitBit storage kinds. It literally just stores the one word value 339 // as an atomic. By default, it is initialized to a magic value that is unlikely 340 // a valid value for the flag value type. 341 struct FlagOneWordValue { 342 constexpr static int64_t Uninitialized() { 343 return static_cast<int64_t>(0xababababababababll); 344 } 345 346 constexpr FlagOneWordValue() : value(Uninitialized()) {} 347 constexpr explicit FlagOneWordValue(int64_t v) : value(v) {} 348 std::atomic<int64_t> value; 349 }; 350 351 // This class represents a memory layout used by kValueAndInitBit storage kind. 352 template <typename T> 353 struct alignas(8) FlagValueAndInitBit { 354 T value; 355 // Use an int instead of a bool to guarantee that a non-zero value has 356 // a bit set. 357 uint8_t init; 358 }; 359 360 // This class implements an aligned pointer with two options stored via masks 361 // in unused bits of the pointer value (due to alignment requirement). 362 // - IsUnprotectedReadCandidate - indicates that the value can be switched to 363 // unprotected read without a lock. 364 // - HasBeenRead - indicates that the value has been read at least once. 365 // - AllowsUnprotectedRead - combination of the two options above and indicates 366 // that the value can now be read without a lock. 367 // Further details of these options and their use is covered in the description 368 // of the FlagValue<T, FlagValueStorageKind::kHeapAllocated> specialization. 369 class MaskedPointer { 370 public: 371 using mask_t = uintptr_t; 372 using ptr_t = void*; 373 374 static constexpr int RequiredAlignment() { return 4; } 375 376 constexpr MaskedPointer() : ptr_(nullptr) {} 377 constexpr explicit MaskedPointer(ptr_t rhs) : ptr_(rhs) {} 378 MaskedPointer(ptr_t rhs, bool is_candidate); 379 380 MaskedPointer(const MaskedPointer& rhs) = default; 381 MaskedPointer& operator=(const MaskedPointer& rhs) = default; 382 383 void* Ptr() const { 384 return reinterpret_cast<void*>(reinterpret_cast<mask_t>(ptr_) & 385 kPtrValueMask); 386 } 387 bool AllowsUnprotectedRead() const { 388 return (reinterpret_cast<mask_t>(ptr_) & kAllowsUnprotectedRead) == 389 kAllowsUnprotectedRead; 390 } 391 bool IsUnprotectedReadCandidate() const; 392 bool HasBeenRead() const; 393 394 void Set(FlagOpFn op, const void* src, bool is_candidate); 395 void MarkAsRead(); 396 397 private: 398 // Masks 399 // Indicates that the flag value either default or originated from command 400 // line. 401 static constexpr mask_t kUnprotectedReadCandidate = 0x1u; 402 // Indicates that flag has been read. 403 static constexpr mask_t kHasBeenRead = 0x2u; 404 static constexpr mask_t kAllowsUnprotectedRead = 405 kUnprotectedReadCandidate | kHasBeenRead; 406 static constexpr mask_t kPtrValueMask = ~kAllowsUnprotectedRead; 407 408 void ApplyMask(mask_t mask); 409 bool CheckMask(mask_t mask) const; 410 411 ptr_t ptr_; 412 }; 413 414 // This class implements a type erased storage of the heap allocated flag value. 415 // It is used as a base class for the storage class for kHeapAllocated storage 416 // kind. The initial_buffer is expected to have an alignment of at least 417 // MaskedPointer::RequiredAlignment(), so that the bits used by the 418 // MaskedPointer to store masks are set to 0. This guarantees that value starts 419 // in an uninitialized state. 420 struct FlagMaskedPointerValue { 421 constexpr explicit FlagMaskedPointerValue(MaskedPointer::ptr_t initial_buffer) 422 : value(MaskedPointer(initial_buffer)) {} 423 424 std::atomic<MaskedPointer> value; 425 }; 426 427 // This is the forward declaration for the template that represents a storage 428 // for the flag values. This template is expected to be explicitly specialized 429 // for each storage kind and it does not have a generic default 430 // implementation. 431 template <typename T, 432 FlagValueStorageKind Kind = flags_internal::StorageKind<T>()> 433 struct FlagValue; 434 435 // This specialization represents the storage of flag values types with the 436 // kValueAndInitBit storage kind. It is based on the FlagOneWordValue class 437 // and relies on memory layout in FlagValueAndInitBit<T> to indicate that the 438 // value has been initialized or not. 439 template <typename T> 440 struct FlagValue<T, FlagValueStorageKind::kValueAndInitBit> : FlagOneWordValue { 441 constexpr FlagValue() : FlagOneWordValue(0) {} 442 bool Get(const SequenceLock&, T& dst) const { 443 int64_t storage = value.load(std::memory_order_acquire); 444 if (ABSL_PREDICT_FALSE(storage == 0)) { 445 // This assert is to ensure that the initialization inside FlagImpl::Init 446 // is able to set init member correctly. 447 static_assert(offsetof(FlagValueAndInitBit<T>, init) == sizeof(T), 448 "Unexpected memory layout of FlagValueAndInitBit"); 449 return false; 450 } 451 dst = absl::bit_cast<FlagValueAndInitBit<T>>(storage).value; 452 return true; 453 } 454 }; 455 456 // This specialization represents the storage of flag values types with the 457 // kOneWordAtomic storage kind. It is based on the FlagOneWordValue class 458 // and relies on the magic uninitialized state of default constructed instead of 459 // FlagOneWordValue to indicate that the value has been initialized or not. 460 template <typename T> 461 struct FlagValue<T, FlagValueStorageKind::kOneWordAtomic> : FlagOneWordValue { 462 constexpr FlagValue() : FlagOneWordValue() {} 463 bool Get(const SequenceLock&, T& dst) const { 464 int64_t one_word_val = value.load(std::memory_order_acquire); 465 if (ABSL_PREDICT_FALSE(one_word_val == FlagOneWordValue::Uninitialized())) { 466 return false; 467 } 468 std::memcpy(&dst, static_cast<const void*>(&one_word_val), sizeof(T)); 469 return true; 470 } 471 }; 472 473 // This specialization represents the storage of flag values types with the 474 // kSequenceLocked storage kind. This storage is used by trivially copyable 475 // types with size greater than 8 bytes. This storage relies on uninitialized 476 // state of the SequenceLock to indicate that the value has been initialized or 477 // not. This storage also provides lock-free read access to the underlying 478 // value once it is initialized. 479 template <typename T> 480 struct FlagValue<T, FlagValueStorageKind::kSequenceLocked> { 481 bool Get(const SequenceLock& lock, T& dst) const { 482 return lock.TryRead(&dst, value_words, sizeof(T)); 483 } 484 485 static constexpr int kNumWords = 486 flags_internal::AlignUp(sizeof(T), sizeof(uint64_t)) / sizeof(uint64_t); 487 488 alignas(T) alignas( 489 std::atomic<uint64_t>) std::atomic<uint64_t> value_words[kNumWords]; 490 }; 491 492 // This specialization represents the storage of flag values types with the 493 // kHeapAllocated storage kind. This is a storage of last resort and is used 494 // if none of other storage kinds are applicable. 495 // 496 // Generally speaking the values with this storage kind can't be accessed 497 // atomically and thus can't be read without holding a lock. If we would ever 498 // want to avoid the lock, we'd need to leak the old value every time new flag 499 // value is being set (since we are in danger of having a race condition 500 // otherwise). 501 // 502 // Instead of doing that, this implementation attempts to cater to some common 503 // use cases by allowing at most 2 values to be leaked - default value and 504 // value set from the command line. 505 // 506 // This specialization provides an initial buffer for the first flag value. This 507 // is where the default value is going to be stored. We attempt to reuse this 508 // buffer if possible, including storing the value set from the command line 509 // there. 510 // 511 // As long as we only read this value, we can access it without a lock (in 512 // practice we still use the lock for the very first read to be able set 513 // "has been read" option on this flag). 514 // 515 // If flag is specified on the command line we store the parsed value either 516 // in the internal buffer (if the default value never been read) or we leak the 517 // default value and allocate the new storage for the parse value. This value is 518 // also a candidate for an unprotected read. If flag is set programmatically 519 // after the command line is parsed, the storage for this value is going to be 520 // leaked. Note that in both scenarios we are not going to have a real leak. 521 // Instead we'll store the leaked value pointers in the internal freelist to 522 // avoid triggering the memory leak checker complains. 523 // 524 // If the flag is ever set programmatically, it stops being the candidate for an 525 // unprotected read, and any follow up access to the flag value requires a lock. 526 // Note that if the value if set programmatically before the command line is 527 // parsed, we can switch back to enabling unprotected reads for that value. 528 template <typename T> 529 struct FlagValue<T, FlagValueStorageKind::kHeapAllocated> 530 : FlagMaskedPointerValue { 531 // We const initialize the value with unmasked pointer to the internal buffer, 532 // making sure it is not a candidate for unprotected read. This way we can 533 // ensure Init is done before any access to the flag value. 534 constexpr FlagValue() : FlagMaskedPointerValue(&buffer[0]) {} 535 536 bool Get(const SequenceLock&, T& dst) const { 537 MaskedPointer ptr_value = value.load(std::memory_order_acquire); 538 539 if (ABSL_PREDICT_TRUE(ptr_value.AllowsUnprotectedRead())) { 540 ::new (static_cast<void*>(&dst)) T(*static_cast<T*>(ptr_value.Ptr())); 541 return true; 542 } 543 return false; 544 } 545 546 alignas(MaskedPointer::RequiredAlignment()) alignas( 547 T) char buffer[sizeof(T)]{}; 548 }; 549 550 /////////////////////////////////////////////////////////////////////////////// 551 // Flag callback auxiliary structs. 552 553 // Signature for the mutation callback used by watched Flags 554 // The callback is noexcept. 555 // TODO(rogeeff): add noexcept after C++17 support is added. 556 using FlagCallbackFunc = void (*)(); 557 558 struct FlagCallback { 559 FlagCallbackFunc func; 560 absl::Mutex guard; // Guard for concurrent callback invocations. 561 }; 562 563 /////////////////////////////////////////////////////////////////////////////// 564 // Flag implementation, which does not depend on flag value type. 565 // The class encapsulates the Flag's data and access to it. 566 567 struct DynValueDeleter { 568 explicit DynValueDeleter(FlagOpFn op_arg = nullptr); 569 void operator()(void* ptr) const; 570 571 FlagOpFn op; 572 }; 573 574 class FlagState; 575 576 // These are only used as constexpr global objects. 577 // They do not use a virtual destructor to simplify their implementation. 578 // They are not destroyed except at program exit, so leaks do not matter. 579 #if defined(__GNUC__) && !defined(__clang__) 580 #pragma GCC diagnostic push 581 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" 582 #endif 583 class FlagImpl final : public CommandLineFlag { 584 public: 585 constexpr FlagImpl(const char* name, const char* type_name, 586 const char* filename, FlagOpFn op, FlagHelpArg help, 587 FlagValueStorageKind value_kind, 588 FlagDefaultArg default_arg) 589 : name_(name), 590 type_name_(type_name), 591 filename_(filename), 592 op_(op), 593 help_(help.source), 594 help_source_kind_(static_cast<uint8_t>(help.kind)), 595 value_storage_kind_(static_cast<uint8_t>(value_kind)), 596 def_kind_(static_cast<uint8_t>(default_arg.kind)), 597 modified_(false), 598 on_command_line_(false), 599 callback_(nullptr), 600 default_value_(default_arg.source), 601 data_guard_{} {} 602 603 // Constant access methods 604 int64_t ReadOneWord() const ABSL_LOCKS_EXCLUDED(*DataGuard()); 605 bool ReadOneBool() const ABSL_LOCKS_EXCLUDED(*DataGuard()); 606 void Read(void* dst) const override ABSL_LOCKS_EXCLUDED(*DataGuard()); 607 void Read(bool* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) { 608 *value = ReadOneBool(); 609 } 610 template <typename T, 611 absl::enable_if_t<flags_internal::StorageKind<T>() == 612 FlagValueStorageKind::kOneWordAtomic, 613 int> = 0> 614 void Read(T* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) { 615 int64_t v = ReadOneWord(); 616 std::memcpy(value, static_cast<const void*>(&v), sizeof(T)); 617 } 618 template <typename T, 619 typename std::enable_if<flags_internal::StorageKind<T>() == 620 FlagValueStorageKind::kValueAndInitBit, 621 int>::type = 0> 622 void Read(T* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) { 623 *value = absl::bit_cast<FlagValueAndInitBit<T>>(ReadOneWord()).value; 624 } 625 626 // Mutating access methods 627 void Write(const void* src) ABSL_LOCKS_EXCLUDED(*DataGuard()); 628 629 // Interfaces to operate on callbacks. 630 void SetCallback(const FlagCallbackFunc mutation_callback) 631 ABSL_LOCKS_EXCLUDED(*DataGuard()); 632 void InvokeCallback() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); 633 634 // Used in read/write operations to validate source/target has correct type. 635 // For example if flag is declared as absl::Flag<int> FLAGS_foo, a call to 636 // absl::GetFlag(FLAGS_foo) validates that the type of FLAGS_foo is indeed 637 // int. To do that we pass the assumed type id (which is deduced from type 638 // int) as an argument `type_id`, which is in turn is validated against the 639 // type id stored in flag object by flag definition statement. 640 void AssertValidType(FlagFastTypeId type_id, 641 const std::type_info* (*gen_rtti)()) const; 642 643 private: 644 template <typename T> 645 friend class Flag; 646 friend class FlagState; 647 648 // Ensures that `data_guard_` is initialized and returns it. 649 absl::Mutex* DataGuard() const 650 ABSL_LOCK_RETURNED(reinterpret_cast<absl::Mutex*>(data_guard_)); 651 // Returns heap allocated value of type T initialized with default value. 652 std::unique_ptr<void, DynValueDeleter> MakeInitValue() const 653 ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); 654 // Flag initialization called via absl::call_once. 655 void Init(); 656 657 // Offset value access methods. One per storage kind. These methods to not 658 // respect const correctness, so be very careful using them. 659 660 // This is a shared helper routine which encapsulates most of the magic. Since 661 // it is only used inside the three routines below, which are defined in 662 // flag.cc, we can define it in that file as well. 663 template <typename StorageT> 664 StorageT* OffsetValue() const; 665 666 // The same as above, but used for sequencelock-protected storage. 667 std::atomic<uint64_t>* AtomicBufferValue() const; 668 669 // This is an accessor for a value stored as one word atomic. Returns a 670 // mutable reference to an atomic value. 671 std::atomic<int64_t>& OneWordValue() const; 672 673 std::atomic<MaskedPointer>& PtrStorage() const; 674 675 // Attempts to parse supplied `value` string. If parsing is successful, 676 // returns new value. Otherwise returns nullptr. 677 std::unique_ptr<void, DynValueDeleter> TryParse(absl::string_view value, 678 std::string& err) const 679 ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); 680 // Stores the flag value based on the pointer to the source. 681 void StoreValue(const void* src, ValueSource source) 682 ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); 683 684 // Copy the flag data, protected by `seq_lock_` into `dst`. 685 // 686 // REQUIRES: ValueStorageKind() == kSequenceLocked. 687 void ReadSequenceLockedData(void* dst) const 688 ABSL_LOCKS_EXCLUDED(*DataGuard()); 689 690 FlagHelpKind HelpSourceKind() const { 691 return static_cast<FlagHelpKind>(help_source_kind_); 692 } 693 FlagValueStorageKind ValueStorageKind() const { 694 return static_cast<FlagValueStorageKind>(value_storage_kind_); 695 } 696 FlagDefaultKind DefaultKind() const 697 ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()) { 698 return static_cast<FlagDefaultKind>(def_kind_); 699 } 700 701 // CommandLineFlag interface implementation 702 absl::string_view Name() const override; 703 absl::string_view TypeName() const override; 704 std::string Filename() const override; 705 std::string Help() const override; 706 FlagFastTypeId TypeId() const override; 707 bool IsSpecifiedOnCommandLine() const override 708 ABSL_LOCKS_EXCLUDED(*DataGuard()); 709 std::string DefaultValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard()); 710 std::string CurrentValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard()); 711 bool ValidateInputValue(absl::string_view value) const override 712 ABSL_LOCKS_EXCLUDED(*DataGuard()); 713 void CheckDefaultValueParsingRoundtrip() const override 714 ABSL_LOCKS_EXCLUDED(*DataGuard()); 715 716 int64_t ModificationCount() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); 717 718 // Interfaces to save and restore flags to/from persistent state. 719 // Returns current flag state or nullptr if flag does not support 720 // saving and restoring a state. 721 std::unique_ptr<FlagStateInterface> SaveState() override 722 ABSL_LOCKS_EXCLUDED(*DataGuard()); 723 724 // Restores the flag state to the supplied state object. If there is 725 // nothing to restore returns false. Otherwise returns true. 726 bool RestoreState(const FlagState& flag_state) 727 ABSL_LOCKS_EXCLUDED(*DataGuard()); 728 729 bool ParseFrom(absl::string_view value, FlagSettingMode set_mode, 730 ValueSource source, std::string& error) override 731 ABSL_LOCKS_EXCLUDED(*DataGuard()); 732 733 // Immutable flag's state. 734 735 // Flags name passed to ABSL_FLAG as second arg. 736 const char* const name_; 737 738 // Flags type passed to ABSL_FLAG as first arg. 739 const char* const type_name_; 740 741 // The file name where ABSL_FLAG resides. 742 const char* const filename_; 743 // Type-specific operations vtable. 744 const FlagOpFn op_; 745 // Help message literal or function to generate it. 746 const FlagHelpMsg help_; 747 // Indicates if help message was supplied as literal or generator func. 748 const uint8_t help_source_kind_ : 1; 749 // Kind of storage this flag is using for the flag's value. 750 const uint8_t value_storage_kind_ : 2; 751 752 uint8_t : 0; // The bytes containing the const bitfields must not be 753 // shared with bytes containing the mutable bitfields. 754 755 // Mutable flag's state (guarded by `data_guard_`). 756 757 // def_kind_ is not guard by DataGuard() since it is accessed in Init without 758 // locks. 759 uint8_t def_kind_ : 2; 760 // Has this flag's value been modified? 761 bool modified_ : 1 ABSL_GUARDED_BY(*DataGuard()); 762 // Has this flag been specified on command line. 763 bool on_command_line_ : 1 ABSL_GUARDED_BY(*DataGuard()); 764 765 // Unique tag for absl::call_once call to initialize this flag. 766 absl::once_flag init_control_; 767 768 // Sequence lock / mutation counter. 769 flags_internal::SequenceLock seq_lock_; 770 771 // Optional flag's callback and absl::Mutex to guard the invocations. 772 FlagCallback* callback_ ABSL_GUARDED_BY(*DataGuard()); 773 // Either a pointer to the function generating the default value based on the 774 // value specified in ABSL_FLAG or pointer to the dynamically set default 775 // value via SetCommandLineOptionWithMode. def_kind_ is used to distinguish 776 // these two cases. 777 FlagDefaultSrc default_value_; 778 779 // This is reserved space for an absl::Mutex to guard flag data. It will be 780 // initialized in FlagImpl::Init via placement new. 781 // We can't use "absl::Mutex data_guard_", since this class is not literal. 782 // We do not want to use "absl::Mutex* data_guard_", since this would require 783 // heap allocation during initialization, which is both slows program startup 784 // and can fail. Using reserved space + placement new allows us to avoid both 785 // problems. 786 alignas(absl::Mutex) mutable unsigned char data_guard_[sizeof(absl::Mutex)]; 787 }; 788 #if defined(__GNUC__) && !defined(__clang__) 789 #pragma GCC diagnostic pop 790 #endif 791 792 /////////////////////////////////////////////////////////////////////////////// 793 // The Flag object parameterized by the flag's value type. This class implements 794 // flag reflection handle interface. 795 796 template <typename T> 797 class Flag { 798 public: 799 constexpr Flag(const char* name, const char* type_name, const char* filename, 800 FlagHelpArg help, const FlagDefaultArg default_arg) 801 : impl_(name, type_name, filename, &FlagOps<T>, help, 802 flags_internal::StorageKind<T>(), default_arg), 803 value_() {} 804 805 // CommandLineFlag interface 806 absl::string_view Name() const { return impl_.Name(); } 807 std::string Filename() const { return impl_.Filename(); } 808 std::string Help() const { return impl_.Help(); } 809 // Do not use. To be removed. 810 bool IsSpecifiedOnCommandLine() const { 811 return impl_.IsSpecifiedOnCommandLine(); 812 } 813 std::string DefaultValue() const { return impl_.DefaultValue(); } 814 std::string CurrentValue() const { return impl_.CurrentValue(); } 815 816 private: 817 template <typename, bool> 818 friend class FlagRegistrar; 819 friend class FlagImplPeer; 820 821 T Get() const { 822 // See implementation notes in CommandLineFlag::Get(). 823 union U { 824 T value; 825 U() {} 826 ~U() { value.~T(); } 827 }; 828 U u; 829 830 #if !defined(NDEBUG) 831 impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>); 832 #endif 833 834 if (ABSL_PREDICT_FALSE(!value_.Get(impl_.seq_lock_, u.value))) { 835 impl_.Read(&u.value); 836 } 837 return std::move(u.value); 838 } 839 void Set(const T& v) { 840 impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>); 841 impl_.Write(&v); 842 } 843 844 // Access to the reflection. 845 const CommandLineFlag& Reflect() const { return impl_; } 846 847 // Flag's data 848 // The implementation depends on value_ field to be placed exactly after the 849 // impl_ field, so that impl_ can figure out the offset to the value and 850 // access it. 851 FlagImpl impl_; 852 FlagValue<T> value_; 853 }; 854 855 /////////////////////////////////////////////////////////////////////////////// 856 // Trampoline for friend access 857 858 class FlagImplPeer { 859 public: 860 template <typename T, typename FlagType> 861 static T InvokeGet(const FlagType& flag) { 862 return flag.Get(); 863 } 864 template <typename FlagType, typename T> 865 static void InvokeSet(FlagType& flag, const T& v) { 866 flag.Set(v); 867 } 868 template <typename FlagType> 869 static const CommandLineFlag& InvokeReflect(const FlagType& f) { 870 return f.Reflect(); 871 } 872 }; 873 874 /////////////////////////////////////////////////////////////////////////////// 875 // Implementation of Flag value specific operations routine. 876 template <typename T> 877 void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) { 878 struct AlignedSpace { 879 alignas(MaskedPointer::RequiredAlignment()) alignas( 880 T) unsigned char buf[sizeof(T)]; 881 }; 882 using Allocator = std::allocator<AlignedSpace>; 883 switch (op) { 884 case FlagOp::kAlloc: { 885 Allocator alloc; 886 return std::allocator_traits<Allocator>::allocate(alloc, 1); 887 } 888 case FlagOp::kDelete: { 889 T* p = static_cast<T*>(v2); 890 p->~T(); 891 Allocator alloc; 892 std::allocator_traits<Allocator>::deallocate( 893 alloc, reinterpret_cast<AlignedSpace*>(p), 1); 894 return nullptr; 895 } 896 case FlagOp::kCopy: 897 *static_cast<T*>(v2) = *static_cast<const T*>(v1); 898 return nullptr; 899 case FlagOp::kCopyConstruct: 900 new (v2) T(*static_cast<const T*>(v1)); 901 return nullptr; 902 case FlagOp::kSizeof: 903 return reinterpret_cast<void*>(static_cast<uintptr_t>(sizeof(T))); 904 case FlagOp::kFastTypeId: 905 return const_cast<void*>(base_internal::FastTypeId<T>()); 906 case FlagOp::kRuntimeTypeId: 907 return const_cast<std::type_info*>(GenRuntimeTypeId<T>()); 908 case FlagOp::kParse: { 909 // Initialize the temporary instance of type T based on current value in 910 // destination (which is going to be flag's default value). 911 T temp(*static_cast<T*>(v2)); 912 if (!absl::ParseFlag<T>(*static_cast<const absl::string_view*>(v1), &temp, 913 static_cast<std::string*>(v3))) { 914 return nullptr; 915 } 916 *static_cast<T*>(v2) = std::move(temp); 917 return v2; 918 } 919 case FlagOp::kUnparse: 920 *static_cast<std::string*>(v2) = 921 absl::UnparseFlag<T>(*static_cast<const T*>(v1)); 922 return nullptr; 923 case FlagOp::kValueOffset: { 924 // Round sizeof(FlagImp) to a multiple of alignof(FlagValue<T>) to get the 925 // offset of the data. 926 size_t round_to = alignof(FlagValue<T>); 927 size_t offset = (sizeof(FlagImpl) + round_to - 1) / round_to * round_to; 928 return reinterpret_cast<void*>(offset); 929 } 930 } 931 return nullptr; 932 } 933 934 /////////////////////////////////////////////////////////////////////////////// 935 // This class facilitates Flag object registration and tail expression-based 936 // flag definition, for example: 937 // ABSL_FLAG(int, foo, 42, "Foo help").OnUpdate(NotifyFooWatcher); 938 struct FlagRegistrarEmpty {}; 939 template <typename T, bool do_register> 940 class FlagRegistrar { 941 public: 942 constexpr explicit FlagRegistrar(Flag<T>& flag, const char* filename) 943 : flag_(flag) { 944 if (do_register) 945 flags_internal::RegisterCommandLineFlag(flag_.impl_, filename); 946 } 947 948 FlagRegistrar OnUpdate(FlagCallbackFunc cb) && { 949 flag_.impl_.SetCallback(cb); 950 return *this; 951 } 952 953 // Makes the registrar die gracefully as an empty struct on a line where 954 // registration happens. Registrar objects are intended to live only as 955 // temporary. 956 constexpr operator FlagRegistrarEmpty() const { return {}; } // NOLINT 957 958 private: 959 Flag<T>& flag_; // Flag being registered (not owned). 960 }; 961 962 /////////////////////////////////////////////////////////////////////////////// 963 // Test only API 964 uint64_t NumLeakedFlagValues(); 965 966 } // namespace flags_internal 967 ABSL_NAMESPACE_END 968 } // namespace absl 969 970 #endif // ABSL_FLAGS_INTERNAL_FLAG_H_