File indexing completed on 2025-01-30 09:31:43
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #ifndef ABSL_FLAGS_INTERNAL_FLAG_H_
0017 #define ABSL_FLAGS_INTERNAL_FLAG_H_
0018
0019 #include <stddef.h>
0020 #include <stdint.h>
0021
0022 #include <atomic>
0023 #include <cstring>
0024 #include <memory>
0025 #include <string>
0026 #include <type_traits>
0027 #include <typeinfo>
0028
0029 #include "absl/base/attributes.h"
0030 #include "absl/base/call_once.h"
0031 #include "absl/base/casts.h"
0032 #include "absl/base/config.h"
0033 #include "absl/base/optimization.h"
0034 #include "absl/base/thread_annotations.h"
0035 #include "absl/flags/commandlineflag.h"
0036 #include "absl/flags/config.h"
0037 #include "absl/flags/internal/commandlineflag.h"
0038 #include "absl/flags/internal/registry.h"
0039 #include "absl/flags/internal/sequence_lock.h"
0040 #include "absl/flags/marshalling.h"
0041 #include "absl/meta/type_traits.h"
0042 #include "absl/strings/string_view.h"
0043 #include "absl/synchronization/mutex.h"
0044 #include "absl/utility/utility.h"
0045
0046 namespace absl {
0047 ABSL_NAMESPACE_BEGIN
0048
0049
0050
0051 namespace flags_internal {
0052 template <typename T>
0053 class Flag;
0054 }
0055
0056 template <typename T>
0057 using Flag = flags_internal::Flag<T>;
0058
0059 template <typename T>
0060 ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag);
0061
0062 template <typename T>
0063 void SetFlag(absl::Flag<T>* flag, const T& v);
0064
0065 template <typename T, typename V>
0066 void SetFlag(absl::Flag<T>* flag, const V& v);
0067
0068 template <typename U>
0069 const CommandLineFlag& GetFlagReflectionHandle(const absl::Flag<U>& f);
0070
0071
0072
0073
0074
0075 namespace flags_internal {
0076
0077 enum class FlagOp {
0078 kAlloc,
0079 kDelete,
0080 kCopy,
0081 kCopyConstruct,
0082 kSizeof,
0083 kFastTypeId,
0084 kRuntimeTypeId,
0085 kParse,
0086 kUnparse,
0087 kValueOffset,
0088 };
0089 using FlagOpFn = void* (*)(FlagOp, const void*, void*, void*);
0090
0091
0092 template <typename T>
0093 void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3);
0094
0095
0096 inline void* Alloc(FlagOpFn op) {
0097 return op(FlagOp::kAlloc, nullptr, nullptr, nullptr);
0098 }
0099
0100 inline void Delete(FlagOpFn op, void* obj) {
0101 op(FlagOp::kDelete, nullptr, obj, nullptr);
0102 }
0103
0104 inline void Copy(FlagOpFn op, const void* src, void* dst) {
0105 op(FlagOp::kCopy, src, dst, nullptr);
0106 }
0107
0108
0109 inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) {
0110 op(FlagOp::kCopyConstruct, src, dst, nullptr);
0111 }
0112
0113 inline void* Clone(FlagOpFn op, const void* obj) {
0114 void* res = flags_internal::Alloc(op);
0115 flags_internal::CopyConstruct(op, obj, res);
0116 return res;
0117 }
0118
0119 inline bool Parse(FlagOpFn op, absl::string_view text, void* dst,
0120 std::string* error) {
0121 return op(FlagOp::kParse, &text, dst, error) != nullptr;
0122 }
0123
0124 inline std::string Unparse(FlagOpFn op, const void* val) {
0125 std::string result;
0126 op(FlagOp::kUnparse, val, &result, nullptr);
0127 return result;
0128 }
0129
0130 inline size_t Sizeof(FlagOpFn op) {
0131
0132
0133 return static_cast<size_t>(reinterpret_cast<intptr_t>(
0134 op(FlagOp::kSizeof, nullptr, nullptr, nullptr)));
0135 }
0136
0137 inline FlagFastTypeId FastTypeId(FlagOpFn op) {
0138 return reinterpret_cast<FlagFastTypeId>(
0139 op(FlagOp::kFastTypeId, nullptr, nullptr, nullptr));
0140 }
0141
0142 inline const std::type_info* RuntimeTypeId(FlagOpFn op) {
0143 return reinterpret_cast<const std::type_info*>(
0144 op(FlagOp::kRuntimeTypeId, nullptr, nullptr, nullptr));
0145 }
0146
0147
0148
0149
0150 inline ptrdiff_t ValueOffset(FlagOpFn op) {
0151
0152
0153 return static_cast<ptrdiff_t>(reinterpret_cast<intptr_t>(
0154 op(FlagOp::kValueOffset, nullptr, nullptr, nullptr)));
0155 }
0156
0157
0158 template <typename T>
0159 inline const std::type_info* GenRuntimeTypeId() {
0160 #ifdef ABSL_INTERNAL_HAS_RTTI
0161 return &typeid(T);
0162 #else
0163 return nullptr;
0164 #endif
0165 }
0166
0167
0168
0169
0170
0171
0172
0173 using HelpGenFunc = std::string (*)();
0174
0175 template <size_t N>
0176 struct FixedCharArray {
0177 char value[N];
0178
0179 template <size_t... I>
0180 static constexpr FixedCharArray<N> FromLiteralString(
0181 absl::string_view str, absl::index_sequence<I...>) {
0182 return (void)str, FixedCharArray<N>({{str[I]..., '\0'}});
0183 }
0184 };
0185
0186 template <typename Gen, size_t N = Gen::Value().size()>
0187 constexpr FixedCharArray<N + 1> HelpStringAsArray(int) {
0188 return FixedCharArray<N + 1>::FromLiteralString(
0189 Gen::Value(), absl::make_index_sequence<N>{});
0190 }
0191
0192 template <typename Gen>
0193 constexpr std::false_type HelpStringAsArray(char) {
0194 return std::false_type{};
0195 }
0196
0197 union FlagHelpMsg {
0198 constexpr explicit FlagHelpMsg(const char* help_msg) : literal(help_msg) {}
0199 constexpr explicit FlagHelpMsg(HelpGenFunc help_gen) : gen_func(help_gen) {}
0200
0201 const char* literal;
0202 HelpGenFunc gen_func;
0203 };
0204
0205 enum class FlagHelpKind : uint8_t { kLiteral = 0, kGenFunc = 1 };
0206
0207 struct FlagHelpArg {
0208 FlagHelpMsg source;
0209 FlagHelpKind kind;
0210 };
0211
0212 extern const char kStrippedFlagHelp[];
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228 template <typename Gen, size_t N>
0229 constexpr FlagHelpArg HelpArg(const FixedCharArray<N>& value) {
0230 return {FlagHelpMsg(value.value), FlagHelpKind::kLiteral};
0231 }
0232
0233 template <typename Gen>
0234 constexpr FlagHelpArg HelpArg(std::false_type) {
0235 return {FlagHelpMsg(&Gen::NonConst), FlagHelpKind::kGenFunc};
0236 }
0237
0238
0239
0240
0241
0242
0243 using FlagDfltGenFunc = void (*)(void*);
0244
0245 union FlagDefaultSrc {
0246 constexpr explicit FlagDefaultSrc(FlagDfltGenFunc gen_func_arg)
0247 : gen_func(gen_func_arg) {}
0248
0249 #define ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE(T, name) \
0250 T name##_value; \
0251 constexpr explicit FlagDefaultSrc(T value) : name##_value(value) {}
0252 ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE)
0253 #undef ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE
0254
0255 void* dynamic_value;
0256 FlagDfltGenFunc gen_func;
0257 };
0258
0259 enum class FlagDefaultKind : uint8_t {
0260 kDynamicValue = 0,
0261 kGenFunc = 1,
0262 kOneWord = 2
0263 };
0264
0265 struct FlagDefaultArg {
0266 FlagDefaultSrc source;
0267 FlagDefaultKind kind;
0268 };
0269
0270
0271
0272
0273 struct EmptyBraces {};
0274
0275 template <typename T>
0276 constexpr T InitDefaultValue(T t) {
0277 return t;
0278 }
0279
0280 template <typename T>
0281 constexpr T InitDefaultValue(EmptyBraces) {
0282 return T{};
0283 }
0284
0285 template <typename ValueT, typename GenT,
0286 typename std::enable_if<std::is_integral<ValueT>::value, int>::type =
0287 ((void)GenT{}, 0)>
0288 constexpr FlagDefaultArg DefaultArg(int) {
0289 return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kOneWord};
0290 }
0291
0292 template <typename ValueT, typename GenT>
0293 constexpr FlagDefaultArg DefaultArg(char) {
0294 return {FlagDefaultSrc(&GenT::Gen), FlagDefaultKind::kGenFunc};
0295 }
0296
0297
0298
0299
0300
0301 template <typename T>
0302 using FlagUseValueAndInitBitStorage =
0303 std::integral_constant<bool, std::is_trivially_copyable<T>::value &&
0304 std::is_default_constructible<T>::value &&
0305 (sizeof(T) < 8)>;
0306
0307 template <typename T>
0308 using FlagUseOneWordStorage =
0309 std::integral_constant<bool, std::is_trivially_copyable<T>::value &&
0310 (sizeof(T) <= 8)>;
0311
0312 template <class T>
0313 using FlagUseSequenceLockStorage =
0314 std::integral_constant<bool, std::is_trivially_copyable<T>::value &&
0315 (sizeof(T) > 8)>;
0316
0317 enum class FlagValueStorageKind : uint8_t {
0318 kValueAndInitBit = 0,
0319 kOneWordAtomic = 1,
0320 kSequenceLocked = 2,
0321 kHeapAllocated = 3,
0322 };
0323
0324
0325
0326 template <typename T>
0327 static constexpr FlagValueStorageKind StorageKind() {
0328 return FlagUseValueAndInitBitStorage<T>::value
0329 ? FlagValueStorageKind::kValueAndInitBit
0330 : FlagUseOneWordStorage<T>::value
0331 ? FlagValueStorageKind::kOneWordAtomic
0332 : FlagUseSequenceLockStorage<T>::value
0333 ? FlagValueStorageKind::kSequenceLocked
0334 : FlagValueStorageKind::kHeapAllocated;
0335 }
0336
0337
0338
0339
0340
0341 struct FlagOneWordValue {
0342 constexpr static int64_t Uninitialized() {
0343 return static_cast<int64_t>(0xababababababababll);
0344 }
0345
0346 constexpr FlagOneWordValue() : value(Uninitialized()) {}
0347 constexpr explicit FlagOneWordValue(int64_t v) : value(v) {}
0348 std::atomic<int64_t> value;
0349 };
0350
0351
0352 template <typename T>
0353 struct alignas(8) FlagValueAndInitBit {
0354 T value;
0355
0356
0357 uint8_t init;
0358 };
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369 class MaskedPointer {
0370 public:
0371 using mask_t = uintptr_t;
0372 using ptr_t = void*;
0373
0374 static constexpr int RequiredAlignment() { return 4; }
0375
0376 constexpr explicit MaskedPointer(ptr_t rhs) : ptr_(rhs) {}
0377 MaskedPointer(ptr_t rhs, bool is_candidate);
0378
0379 void* Ptr() const {
0380 return reinterpret_cast<void*>(reinterpret_cast<mask_t>(ptr_) &
0381 kPtrValueMask);
0382 }
0383 bool AllowsUnprotectedRead() const {
0384 return (reinterpret_cast<mask_t>(ptr_) & kAllowsUnprotectedRead) ==
0385 kAllowsUnprotectedRead;
0386 }
0387 bool IsUnprotectedReadCandidate() const;
0388 bool HasBeenRead() const;
0389
0390 void Set(FlagOpFn op, const void* src, bool is_candidate);
0391 void MarkAsRead();
0392
0393 private:
0394
0395
0396
0397 static constexpr mask_t kUnprotectedReadCandidate = 0x1u;
0398
0399 static constexpr mask_t kHasBeenRead = 0x2u;
0400 static constexpr mask_t kAllowsUnprotectedRead =
0401 kUnprotectedReadCandidate | kHasBeenRead;
0402 static constexpr mask_t kPtrValueMask = ~kAllowsUnprotectedRead;
0403
0404 void ApplyMask(mask_t mask);
0405 bool CheckMask(mask_t mask) const;
0406
0407 ptr_t ptr_;
0408 };
0409
0410
0411
0412
0413
0414
0415
0416 struct FlagMaskedPointerValue {
0417 constexpr explicit FlagMaskedPointerValue(MaskedPointer::ptr_t initial_buffer)
0418 : value(MaskedPointer(initial_buffer)) {}
0419
0420 std::atomic<MaskedPointer> value;
0421 };
0422
0423
0424
0425
0426
0427 template <typename T,
0428 FlagValueStorageKind Kind = flags_internal::StorageKind<T>()>
0429 struct FlagValue;
0430
0431
0432
0433
0434
0435 template <typename T>
0436 struct FlagValue<T, FlagValueStorageKind::kValueAndInitBit> : FlagOneWordValue {
0437 constexpr FlagValue() : FlagOneWordValue(0) {}
0438 bool Get(const SequenceLock&, T& dst) const {
0439 int64_t storage = value.load(std::memory_order_acquire);
0440 if (ABSL_PREDICT_FALSE(storage == 0)) {
0441
0442
0443 static_assert(offsetof(FlagValueAndInitBit<T>, init) == sizeof(T),
0444 "Unexpected memory layout of FlagValueAndInitBit");
0445 return false;
0446 }
0447 dst = absl::bit_cast<FlagValueAndInitBit<T>>(storage).value;
0448 return true;
0449 }
0450 };
0451
0452
0453
0454
0455
0456 template <typename T>
0457 struct FlagValue<T, FlagValueStorageKind::kOneWordAtomic> : FlagOneWordValue {
0458 constexpr FlagValue() : FlagOneWordValue() {}
0459 bool Get(const SequenceLock&, T& dst) const {
0460 int64_t one_word_val = value.load(std::memory_order_acquire);
0461 if (ABSL_PREDICT_FALSE(one_word_val == FlagOneWordValue::Uninitialized())) {
0462 return false;
0463 }
0464 std::memcpy(&dst, static_cast<const void*>(&one_word_val), sizeof(T));
0465 return true;
0466 }
0467 };
0468
0469
0470
0471
0472
0473
0474
0475 template <typename T>
0476 struct FlagValue<T, FlagValueStorageKind::kSequenceLocked> {
0477 bool Get(const SequenceLock& lock, T& dst) const {
0478 return lock.TryRead(&dst, value_words, sizeof(T));
0479 }
0480
0481 static constexpr int kNumWords =
0482 flags_internal::AlignUp(sizeof(T), sizeof(uint64_t)) / sizeof(uint64_t);
0483
0484 alignas(T) alignas(
0485 std::atomic<uint64_t>) std::atomic<uint64_t> value_words[kNumWords];
0486 };
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524 template <typename T>
0525 struct FlagValue<T, FlagValueStorageKind::kHeapAllocated>
0526 : FlagMaskedPointerValue {
0527
0528
0529
0530 constexpr FlagValue() : FlagMaskedPointerValue(&buffer[0]) {}
0531
0532 bool Get(const SequenceLock&, T& dst) const {
0533 MaskedPointer ptr_value = value.load(std::memory_order_acquire);
0534
0535 if (ABSL_PREDICT_TRUE(ptr_value.AllowsUnprotectedRead())) {
0536 ::new (static_cast<void*>(&dst)) T(*static_cast<T*>(ptr_value.Ptr()));
0537 return true;
0538 }
0539 return false;
0540 }
0541
0542 alignas(MaskedPointer::RequiredAlignment()) alignas(
0543 T) char buffer[sizeof(T)]{};
0544 };
0545
0546
0547
0548
0549
0550
0551
0552 using FlagCallbackFunc = void (*)();
0553
0554 struct FlagCallback {
0555 FlagCallbackFunc func;
0556 absl::Mutex guard;
0557 };
0558
0559
0560
0561
0562
0563 struct DynValueDeleter {
0564 explicit DynValueDeleter(FlagOpFn op_arg = nullptr);
0565 void operator()(void* ptr) const;
0566
0567 FlagOpFn op;
0568 };
0569
0570 class FlagState;
0571
0572
0573
0574
0575 #if defined(__GNUC__) && !defined(__clang__)
0576 #pragma GCC diagnostic push
0577 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
0578 #endif
0579 class FlagImpl final : public CommandLineFlag {
0580 public:
0581 constexpr FlagImpl(const char* name, const char* filename, FlagOpFn op,
0582 FlagHelpArg help, FlagValueStorageKind value_kind,
0583 FlagDefaultArg default_arg)
0584 : name_(name),
0585 filename_(filename),
0586 op_(op),
0587 help_(help.source),
0588 help_source_kind_(static_cast<uint8_t>(help.kind)),
0589 value_storage_kind_(static_cast<uint8_t>(value_kind)),
0590 def_kind_(static_cast<uint8_t>(default_arg.kind)),
0591 modified_(false),
0592 on_command_line_(false),
0593 callback_(nullptr),
0594 default_value_(default_arg.source),
0595 data_guard_{} {}
0596
0597
0598 int64_t ReadOneWord() const ABSL_LOCKS_EXCLUDED(*DataGuard());
0599 bool ReadOneBool() const ABSL_LOCKS_EXCLUDED(*DataGuard());
0600 void Read(void* dst) const override ABSL_LOCKS_EXCLUDED(*DataGuard());
0601 void Read(bool* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) {
0602 *value = ReadOneBool();
0603 }
0604 template <typename T,
0605 absl::enable_if_t<flags_internal::StorageKind<T>() ==
0606 FlagValueStorageKind::kOneWordAtomic,
0607 int> = 0>
0608 void Read(T* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) {
0609 int64_t v = ReadOneWord();
0610 std::memcpy(value, static_cast<const void*>(&v), sizeof(T));
0611 }
0612 template <typename T,
0613 typename std::enable_if<flags_internal::StorageKind<T>() ==
0614 FlagValueStorageKind::kValueAndInitBit,
0615 int>::type = 0>
0616 void Read(T* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) {
0617 *value = absl::bit_cast<FlagValueAndInitBit<T>>(ReadOneWord()).value;
0618 }
0619
0620
0621 void Write(const void* src) ABSL_LOCKS_EXCLUDED(*DataGuard());
0622
0623
0624 void SetCallback(const FlagCallbackFunc mutation_callback)
0625 ABSL_LOCKS_EXCLUDED(*DataGuard());
0626 void InvokeCallback() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
0627
0628
0629
0630
0631
0632
0633
0634 void AssertValidType(FlagFastTypeId type_id,
0635 const std::type_info* (*gen_rtti)()) const;
0636
0637 private:
0638 template <typename T>
0639 friend class Flag;
0640 friend class FlagState;
0641
0642
0643 absl::Mutex* DataGuard() const
0644 ABSL_LOCK_RETURNED(reinterpret_cast<absl::Mutex*>(data_guard_));
0645
0646 std::unique_ptr<void, DynValueDeleter> MakeInitValue() const
0647 ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
0648
0649 void Init();
0650
0651
0652
0653
0654
0655
0656
0657 template <typename StorageT>
0658 StorageT* OffsetValue() const;
0659
0660
0661 std::atomic<uint64_t>* AtomicBufferValue() const;
0662
0663
0664
0665 std::atomic<int64_t>& OneWordValue() const;
0666
0667 std::atomic<MaskedPointer>& PtrStorage() const;
0668
0669
0670
0671 std::unique_ptr<void, DynValueDeleter> TryParse(absl::string_view value,
0672 std::string& err) const
0673 ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
0674
0675 void StoreValue(const void* src, ValueSource source)
0676 ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
0677
0678
0679
0680
0681 void ReadSequenceLockedData(void* dst) const
0682 ABSL_LOCKS_EXCLUDED(*DataGuard());
0683
0684 FlagHelpKind HelpSourceKind() const {
0685 return static_cast<FlagHelpKind>(help_source_kind_);
0686 }
0687 FlagValueStorageKind ValueStorageKind() const {
0688 return static_cast<FlagValueStorageKind>(value_storage_kind_);
0689 }
0690 FlagDefaultKind DefaultKind() const
0691 ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()) {
0692 return static_cast<FlagDefaultKind>(def_kind_);
0693 }
0694
0695
0696 absl::string_view Name() const override;
0697 std::string Filename() const override;
0698 std::string Help() const override;
0699 FlagFastTypeId TypeId() const override;
0700 bool IsSpecifiedOnCommandLine() const override
0701 ABSL_LOCKS_EXCLUDED(*DataGuard());
0702 std::string DefaultValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
0703 std::string CurrentValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
0704 bool ValidateInputValue(absl::string_view value) const override
0705 ABSL_LOCKS_EXCLUDED(*DataGuard());
0706 void CheckDefaultValueParsingRoundtrip() const override
0707 ABSL_LOCKS_EXCLUDED(*DataGuard());
0708
0709 int64_t ModificationCount() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
0710
0711
0712
0713
0714 std::unique_ptr<FlagStateInterface> SaveState() override
0715 ABSL_LOCKS_EXCLUDED(*DataGuard());
0716
0717
0718
0719 bool RestoreState(const FlagState& flag_state)
0720 ABSL_LOCKS_EXCLUDED(*DataGuard());
0721
0722 bool ParseFrom(absl::string_view value, FlagSettingMode set_mode,
0723 ValueSource source, std::string& error) override
0724 ABSL_LOCKS_EXCLUDED(*DataGuard());
0725
0726
0727
0728
0729 const char* const name_;
0730
0731 const char* const filename_;
0732
0733 const FlagOpFn op_;
0734
0735 const FlagHelpMsg help_;
0736
0737 const uint8_t help_source_kind_ : 1;
0738
0739 const uint8_t value_storage_kind_ : 2;
0740
0741 uint8_t : 0;
0742
0743
0744
0745
0746
0747
0748 uint8_t def_kind_ : 2;
0749
0750 bool modified_ : 1 ABSL_GUARDED_BY(*DataGuard());
0751
0752 bool on_command_line_ : 1 ABSL_GUARDED_BY(*DataGuard());
0753
0754
0755 absl::once_flag init_control_;
0756
0757
0758 flags_internal::SequenceLock seq_lock_;
0759
0760
0761 FlagCallback* callback_ ABSL_GUARDED_BY(*DataGuard());
0762
0763
0764
0765
0766 FlagDefaultSrc default_value_;
0767
0768
0769
0770
0771
0772
0773
0774
0775 alignas(absl::Mutex) mutable char data_guard_[sizeof(absl::Mutex)];
0776 };
0777 #if defined(__GNUC__) && !defined(__clang__)
0778 #pragma GCC diagnostic pop
0779 #endif
0780
0781
0782
0783
0784
0785 template <typename T>
0786 class Flag {
0787 public:
0788 constexpr Flag(const char* name, const char* filename, FlagHelpArg help,
0789 const FlagDefaultArg default_arg)
0790 : impl_(name, filename, &FlagOps<T>, help,
0791 flags_internal::StorageKind<T>(), default_arg),
0792 value_() {}
0793
0794
0795 absl::string_view Name() const { return impl_.Name(); }
0796 std::string Filename() const { return impl_.Filename(); }
0797 std::string Help() const { return impl_.Help(); }
0798
0799 bool IsSpecifiedOnCommandLine() const {
0800 return impl_.IsSpecifiedOnCommandLine();
0801 }
0802 std::string DefaultValue() const { return impl_.DefaultValue(); }
0803 std::string CurrentValue() const { return impl_.CurrentValue(); }
0804
0805 private:
0806 template <typename, bool>
0807 friend class FlagRegistrar;
0808 friend class FlagImplPeer;
0809
0810 T Get() const {
0811
0812 union U {
0813 T value;
0814 U() {}
0815 ~U() { value.~T(); }
0816 };
0817 U u;
0818
0819 #if !defined(NDEBUG)
0820 impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);
0821 #endif
0822
0823 if (ABSL_PREDICT_FALSE(!value_.Get(impl_.seq_lock_, u.value))) {
0824 impl_.Read(&u.value);
0825 }
0826 return std::move(u.value);
0827 }
0828 void Set(const T& v) {
0829 impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);
0830 impl_.Write(&v);
0831 }
0832
0833
0834 const CommandLineFlag& Reflect() const { return impl_; }
0835
0836
0837
0838
0839
0840 FlagImpl impl_;
0841 FlagValue<T> value_;
0842 };
0843
0844
0845
0846
0847 class FlagImplPeer {
0848 public:
0849 template <typename T, typename FlagType>
0850 static T InvokeGet(const FlagType& flag) {
0851 return flag.Get();
0852 }
0853 template <typename FlagType, typename T>
0854 static void InvokeSet(FlagType& flag, const T& v) {
0855 flag.Set(v);
0856 }
0857 template <typename FlagType>
0858 static const CommandLineFlag& InvokeReflect(const FlagType& f) {
0859 return f.Reflect();
0860 }
0861 };
0862
0863
0864
0865 template <typename T>
0866 void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) {
0867 struct AlignedSpace {
0868 alignas(MaskedPointer::RequiredAlignment()) alignas(T) char buf[sizeof(T)];
0869 };
0870 using Allocator = std::allocator<AlignedSpace>;
0871 switch (op) {
0872 case FlagOp::kAlloc: {
0873 Allocator alloc;
0874 return std::allocator_traits<Allocator>::allocate(alloc, 1);
0875 }
0876 case FlagOp::kDelete: {
0877 T* p = static_cast<T*>(v2);
0878 p->~T();
0879 Allocator alloc;
0880 std::allocator_traits<Allocator>::deallocate(
0881 alloc, reinterpret_cast<AlignedSpace*>(p), 1);
0882 return nullptr;
0883 }
0884 case FlagOp::kCopy:
0885 *static_cast<T*>(v2) = *static_cast<const T*>(v1);
0886 return nullptr;
0887 case FlagOp::kCopyConstruct:
0888 new (v2) T(*static_cast<const T*>(v1));
0889 return nullptr;
0890 case FlagOp::kSizeof:
0891 return reinterpret_cast<void*>(static_cast<uintptr_t>(sizeof(T)));
0892 case FlagOp::kFastTypeId:
0893 return const_cast<void*>(base_internal::FastTypeId<T>());
0894 case FlagOp::kRuntimeTypeId:
0895 return const_cast<std::type_info*>(GenRuntimeTypeId<T>());
0896 case FlagOp::kParse: {
0897
0898
0899 T temp(*static_cast<T*>(v2));
0900 if (!absl::ParseFlag<T>(*static_cast<const absl::string_view*>(v1), &temp,
0901 static_cast<std::string*>(v3))) {
0902 return nullptr;
0903 }
0904 *static_cast<T*>(v2) = std::move(temp);
0905 return v2;
0906 }
0907 case FlagOp::kUnparse:
0908 *static_cast<std::string*>(v2) =
0909 absl::UnparseFlag<T>(*static_cast<const T*>(v1));
0910 return nullptr;
0911 case FlagOp::kValueOffset: {
0912
0913
0914 size_t round_to = alignof(FlagValue<T>);
0915 size_t offset = (sizeof(FlagImpl) + round_to - 1) / round_to * round_to;
0916 return reinterpret_cast<void*>(offset);
0917 }
0918 }
0919 return nullptr;
0920 }
0921
0922
0923
0924
0925
0926 struct FlagRegistrarEmpty {};
0927 template <typename T, bool do_register>
0928 class FlagRegistrar {
0929 public:
0930 constexpr explicit FlagRegistrar(Flag<T>& flag, const char* filename)
0931 : flag_(flag) {
0932 if (do_register)
0933 flags_internal::RegisterCommandLineFlag(flag_.impl_, filename);
0934 }
0935
0936 FlagRegistrar OnUpdate(FlagCallbackFunc cb) && {
0937 flag_.impl_.SetCallback(cb);
0938 return *this;
0939 }
0940
0941
0942
0943
0944 constexpr operator FlagRegistrarEmpty() const { return {}; }
0945
0946 private:
0947 Flag<T>& flag_;
0948 };
0949
0950
0951
0952 uint64_t NumLeakedFlagValues();
0953
0954 }
0955 ABSL_NAMESPACE_END
0956 }
0957
0958 #endif