| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686 | //// Copyright 2019 The Abseil Authors.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at////      https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.#ifndef ABSL_FLAGS_INTERNAL_FLAG_H_#define ABSL_FLAGS_INTERNAL_FLAG_H_#include <stdint.h>#include <atomic>#include <cstring>#include <memory>#include <string>#include <type_traits>#include <typeinfo>#include "absl/base/call_once.h"#include "absl/base/config.h"#include "absl/base/thread_annotations.h"#include "absl/flags/config.h"#include "absl/flags/internal/commandlineflag.h"#include "absl/flags/internal/registry.h"#include "absl/memory/memory.h"#include "absl/meta/type_traits.h"#include "absl/strings/str_cat.h"#include "absl/strings/string_view.h"#include "absl/synchronization/mutex.h"namespace absl {ABSL_NAMESPACE_BEGINnamespace flags_internal {///////////////////////////////////////////////////////////////////////////////// Flag value type operations, eg., parsing, copying, etc. are provided// by function specific to that type with a signature matching FlagOpFn.enum class FlagOp {  kAlloc,  kDelete,  kCopy,  kCopyConstruct,  kSizeof,  kFastTypeId,  kRuntimeTypeId,  kParse,  kUnparse,  kValueOffset,};using FlagOpFn = void* (*)(FlagOp, const void*, void*, void*);// Forward declaration for Flag value specific operations.template <typename T>void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3);// Allocate aligned memory for a flag value.inline void* Alloc(FlagOpFn op) {  return op(FlagOp::kAlloc, nullptr, nullptr, nullptr);}// Deletes memory interpreting obj as flag value type pointer.inline void Delete(FlagOpFn op, void* obj) {  op(FlagOp::kDelete, nullptr, obj, nullptr);}// Copies src to dst interpreting as flag value type pointers.inline void Copy(FlagOpFn op, const void* src, void* dst) {  op(FlagOp::kCopy, src, dst, nullptr);}// Construct a copy of flag value in a location pointed by dst// based on src - pointer to the flag's value.inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) {  op(FlagOp::kCopyConstruct, src, dst, nullptr);}// Makes a copy of flag value pointed by obj.inline void* Clone(FlagOpFn op, const void* obj) {  void* res = flags_internal::Alloc(op);  flags_internal::CopyConstruct(op, obj, res);  return res;}// Returns true if parsing of input text is successfull.inline bool Parse(FlagOpFn op, absl::string_view text, void* dst,                  std::string* error) {  return op(FlagOp::kParse, &text, dst, error) != nullptr;}// Returns string representing supplied value.inline std::string Unparse(FlagOpFn op, const void* val) {  std::string result;  op(FlagOp::kUnparse, val, &result, nullptr);  return result;}// Returns size of flag value type.inline size_t Sizeof(FlagOpFn op) {  // This sequence of casts reverses the sequence from  // `flags_internal::FlagOps()`  return static_cast<size_t>(reinterpret_cast<intptr_t>(      op(FlagOp::kSizeof, nullptr, nullptr, nullptr)));}// Returns fast type id coresponding to the value type.inline FlagFastTypeId FastTypeId(FlagOpFn op) {  return reinterpret_cast<FlagFastTypeId>(      op(FlagOp::kFastTypeId, nullptr, nullptr, nullptr));}// Returns fast type id coresponding to the value type.inline const std::type_info* RuntimeTypeId(FlagOpFn op) {  return reinterpret_cast<const std::type_info*>(      op(FlagOp::kRuntimeTypeId, nullptr, nullptr, nullptr));}// Returns offset of the field value_ from the field impl_ inside of// absl::Flag<T> data. Given FlagImpl pointer p you can get the// location of the corresponding value as://      reinterpret_cast<char*>(p) + ValueOffset().inline ptrdiff_t ValueOffset(FlagOpFn op) {  // This sequence of casts reverses the sequence from  // `flags_internal::FlagOps()`  return static_cast<ptrdiff_t>(reinterpret_cast<intptr_t>(      op(FlagOp::kValueOffset, nullptr, nullptr, nullptr)));}// Returns an address of RTTI's typeid(T).template <typename T>inline const std::type_info* GenRuntimeTypeId() {#if defined(ABSL_FLAGS_INTERNAL_HAS_RTTI)  return &typeid(T);#else  return nullptr;#endif}///////////////////////////////////////////////////////////////////////////////// Flag help auxiliary structs.// This is help argument for absl::Flag encapsulating the string literal pointer// or pointer to function generating it as well as enum descriminating two// cases.using HelpGenFunc = std::string (*)();union FlagHelpMsg {  constexpr explicit FlagHelpMsg(const char* help_msg) : literal(help_msg) {}  constexpr explicit FlagHelpMsg(HelpGenFunc help_gen) : gen_func(help_gen) {}  const char* literal;  HelpGenFunc gen_func;};enum class FlagHelpKind : uint8_t { kLiteral = 0, kGenFunc = 1 };struct FlagHelpArg {  FlagHelpMsg source;  FlagHelpKind kind;};extern const char kStrippedFlagHelp[];// HelpConstexprWrap is used by struct AbslFlagHelpGenFor##name generated by// ABSL_FLAG macro. It is only used to silence the compiler in the case where// help message expression is not constexpr and does not have type const char*.// If help message expression is indeed constexpr const char* HelpConstexprWrap// is just a trivial identity function.template <typename T>const char* HelpConstexprWrap(const T&) {  return nullptr;}constexpr const char* HelpConstexprWrap(const char* p) { return p; }constexpr const char* HelpConstexprWrap(char* p) { return p; }// These two HelpArg overloads allows us to select at compile time one of two// way to pass Help argument to absl::Flag. We'll be passing// AbslFlagHelpGenFor##name as T and integer 0 as a single argument to prefer// first overload if possible. If T::Const is evaluatable on constexpr// context (see non template int parameter below) we'll choose first overload.// In this case the help message expression is immediately evaluated and is used// to construct the absl::Flag. No additionl code is generated by ABSL_FLAG.// Otherwise SFINAE kicks in and first overload is dropped from the// consideration, in which case the second overload will be used. The second// overload does not attempt to evaluate the help message expression// immediately and instead delays the evaluation by returing the function// pointer (&T::NonConst) genering the help message when necessary. This is// evaluatable in constexpr context, but the cost is an extra function being// generated in the ABSL_FLAG code.template <typename T, int = (T::Const(), 1)>constexpr FlagHelpArg HelpArg(int) {  return {FlagHelpMsg(T::Const()), FlagHelpKind::kLiteral};}template <typename T>constexpr FlagHelpArg HelpArg(char) {  return {FlagHelpMsg(&T::NonConst), FlagHelpKind::kGenFunc};}///////////////////////////////////////////////////////////////////////////////// Flag default value auxiliary structs.// Signature for the function generating the initial flag value (usually// based on default value supplied in flag's definition)using FlagDfltGenFunc = void (*)(void*);union FlagDefaultSrc {  constexpr explicit FlagDefaultSrc(FlagDfltGenFunc gen_func_arg)      : gen_func(gen_func_arg) {}  void* dynamic_value;  FlagDfltGenFunc gen_func;};enum class FlagDefaultKind : uint8_t { kDynamicValue = 0, kGenFunc = 1 };///////////////////////////////////////////////////////////////////////////////// Flag current value auxiliary structs.constexpr int64_t UninitializedFlagValue() { return 0xababababababababll; }template <typename T>using FlagUseOneWordStorage = std::integral_constant<    bool, absl::type_traits_internal::is_trivially_copyable<T>::value &&              (sizeof(T) <= 8)>;#if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD)// Clang does not always produce cmpxchg16b instruction when alignment of a 16// bytes type is not 16.struct alignas(16) AlignedTwoWords {  int64_t first;  int64_t second;  bool IsInitialized() const {    return first != flags_internal::UninitializedFlagValue();  }};template <typename T>using FlagUseTwoWordsStorage = std::integral_constant<    bool, absl::type_traits_internal::is_trivially_copyable<T>::value &&              (sizeof(T) > 8) && (sizeof(T) <= 16)>;#else// This is actually unused and only here to avoid ifdefs in other palces.struct AlignedTwoWords {  constexpr AlignedTwoWords() noexcept : dummy() {}  constexpr AlignedTwoWords(int64_t, int64_t) noexcept : dummy() {}  char dummy;  bool IsInitialized() const {    std::abort();    return true;  }};// This trait should be type dependent, otherwise SFINAE below will failtemplate <typename T>using FlagUseTwoWordsStorage =    std::integral_constant<bool, sizeof(T) != sizeof(T)>;#endiftemplate <typename T>using FlagUseBufferStorage =    std::integral_constant<bool, !FlagUseOneWordStorage<T>::value &&                                     !FlagUseTwoWordsStorage<T>::value>;enum class FlagValueStorageKind : uint8_t {  kAlignedBuffer = 0,  kOneWordAtomic = 1,  kTwoWordsAtomic = 2};template <typename T>static constexpr FlagValueStorageKind StorageKind() {  return FlagUseBufferStorage<T>::value             ? FlagValueStorageKind::kAlignedBuffer             : FlagUseOneWordStorage<T>::value                   ? FlagValueStorageKind::kOneWordAtomic                   : FlagValueStorageKind::kTwoWordsAtomic;}struct FlagOneWordValue {  constexpr FlagOneWordValue() : value(UninitializedFlagValue()) {}  std::atomic<int64_t> value;};struct FlagTwoWordsValue {  constexpr FlagTwoWordsValue()      : value(AlignedTwoWords{UninitializedFlagValue(), 0}) {}  std::atomic<AlignedTwoWords> value;};template <typename T,          FlagValueStorageKind Kind = flags_internal::StorageKind<T>()>struct FlagValue;template <typename T>struct FlagValue<T, FlagValueStorageKind::kAlignedBuffer> {  bool Get(T*) const { return false; }  alignas(T) char value[sizeof(T)];};template <typename T>struct FlagValue<T, FlagValueStorageKind::kOneWordAtomic> : FlagOneWordValue {  bool Get(T* dst) const {    int64_t one_word_val = value.load(std::memory_order_acquire);    if (ABSL_PREDICT_FALSE(one_word_val == UninitializedFlagValue())) {      return false;    }    std::memcpy(dst, static_cast<const void*>(&one_word_val), sizeof(T));    return true;  }};template <typename T>struct FlagValue<T, FlagValueStorageKind::kTwoWordsAtomic> : FlagTwoWordsValue {  bool Get(T* dst) const {    AlignedTwoWords two_words_val = value.load(std::memory_order_acquire);    if (ABSL_PREDICT_FALSE(!two_words_val.IsInitialized())) {      return false;    }    std::memcpy(dst, static_cast<const void*>(&two_words_val), sizeof(T));    return true;  }};///////////////////////////////////////////////////////////////////////////////// Flag callback auxiliary structs.// Signature for the mutation callback used by watched Flags// The callback is noexcept.// TODO(rogeeff): add noexcept after C++17 support is added.using FlagCallbackFunc = void (*)();struct FlagCallback {  FlagCallbackFunc func;  absl::Mutex guard;  // Guard for concurrent callback invocations.};///////////////////////////////////////////////////////////////////////////////// Flag implementation, which does not depend on flag value type.// The class encapsulates the Flag's data and access to it.struct DynValueDeleter {  explicit DynValueDeleter(FlagOpFn op_arg = nullptr);  void operator()(void* ptr) const;  FlagOpFn op;};class FlagState;class FlagImpl final : public flags_internal::CommandLineFlag { public:  constexpr FlagImpl(const char* name, const char* filename, FlagOpFn op,                     FlagHelpArg help, FlagValueStorageKind value_kind,                     FlagDfltGenFunc default_value_gen)      : name_(name),        filename_(filename),        op_(op),        help_(help.source),        help_source_kind_(static_cast<uint8_t>(help.kind)),        value_storage_kind_(static_cast<uint8_t>(value_kind)),        def_kind_(static_cast<uint8_t>(FlagDefaultKind::kGenFunc)),        modified_(false),        on_command_line_(false),        counter_(0),        callback_(nullptr),        default_value_(default_value_gen),        data_guard_{} {}  // Constant access methods  void Read(void* dst) const override ABSL_LOCKS_EXCLUDED(*DataGuard());  // Mutating access methods  void Write(const void* src) ABSL_LOCKS_EXCLUDED(*DataGuard());  // Interfaces to operate on callbacks.  void SetCallback(const FlagCallbackFunc mutation_callback)      ABSL_LOCKS_EXCLUDED(*DataGuard());  void InvokeCallback() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());  // Used in read/write operations to validate source/target has correct type.  // For example if flag is declared as absl::Flag<int> FLAGS_foo, a call to  // absl::GetFlag(FLAGS_foo) validates that the type of FLAGS_foo is indeed  // int. To do that we pass the "assumed" type id (which is deduced from type  // int) as an argument `type_id`, which is in turn is validated against the  // type id stored in flag object by flag definition statement.  void AssertValidType(FlagFastTypeId type_id,                       const std::type_info* (*gen_rtti)()) const; private:  template <typename T>  friend class Flag;  friend class FlagState;  // Ensures that `data_guard_` is initialized and returns it.  absl::Mutex* DataGuard() const ABSL_LOCK_RETURNED((absl::Mutex*)&data_guard_);  // Returns heap allocated value of type T initialized with default value.  std::unique_ptr<void, DynValueDeleter> MakeInitValue() const      ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());  // Flag initialization called via absl::call_once.  void Init();  // Offset value access methods. One per storage kind. These methods to not  // respect const correctness, so be very carefull using them.  // This is a shared helper routine which encapsulates most of the magic. Since  // it is only used inside the three routines below, which are defined in  // flag.cc, we can define it in that file as well.  template <typename StorageT>  StorageT* OffsetValue() const;  // This is an accessor for a value stored in an aligned buffer storage.  // Returns a mutable pointer to the start of a buffer.  void* AlignedBufferValue() const;  // This is an accessor for a value stored as one word atomic. Returns a  // mutable reference to an atomic value.  std::atomic<int64_t>& OneWordValue() const;  // This is an accessor for a value stored as two words atomic. Returns a  // mutable reference to an atomic value.  std::atomic<AlignedTwoWords>& TwoWordsValue() const;  // Attempts to parse supplied `value` string. If parsing is successful,  // returns new value. Otherwise returns nullptr.  std::unique_ptr<void, DynValueDeleter> TryParse(absl::string_view value,                                                  std::string* err) const      ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());  // Stores the flag value based on the pointer to the source.  void StoreValue(const void* src) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());  FlagHelpKind HelpSourceKind() const {    return static_cast<FlagHelpKind>(help_source_kind_);  }  FlagValueStorageKind ValueStorageKind() const {    return static_cast<FlagValueStorageKind>(value_storage_kind_);  }  FlagDefaultKind DefaultKind() const      ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()) {    return static_cast<FlagDefaultKind>(def_kind_);  }  // CommandLineFlag interface implementation  absl::string_view Name() const override;  std::string Filename() const override;  absl::string_view Typename() const override;  std::string Help() const override;  FlagFastTypeId TypeId() const override;  bool IsModified() const override ABSL_LOCKS_EXCLUDED(*DataGuard());  bool IsSpecifiedOnCommandLine() const override      ABSL_LOCKS_EXCLUDED(*DataGuard());  std::string DefaultValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard());  std::string CurrentValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard());  bool ValidateInputValue(absl::string_view value) const override      ABSL_LOCKS_EXCLUDED(*DataGuard());  void CheckDefaultValueParsingRoundtrip() const override      ABSL_LOCKS_EXCLUDED(*DataGuard());  // Interfaces to save and restore flags to/from persistent state.  // Returns current flag state or nullptr if flag does not support  // saving and restoring a state.  std::unique_ptr<FlagStateInterface> SaveState() override      ABSL_LOCKS_EXCLUDED(*DataGuard());  // Restores the flag state to the supplied state object. If there is  // nothing to restore returns false. Otherwise returns true.  bool RestoreState(const FlagState& flag_state)      ABSL_LOCKS_EXCLUDED(*DataGuard());  bool ParseFrom(absl::string_view value, FlagSettingMode set_mode,                 ValueSource source, std::string* error) override      ABSL_LOCKS_EXCLUDED(*DataGuard());  // Immutable flag's state.  // Flags name passed to ABSL_FLAG as second arg.  const char* const name_;  // The file name where ABSL_FLAG resides.  const char* const filename_;  // Type-specific operations "vtable".  const FlagOpFn op_;  // Help message literal or function to generate it.  const FlagHelpMsg help_;  // Indicates if help message was supplied as literal or generator func.  const uint8_t help_source_kind_ : 1;  // Kind of storage this flag is using for the flag's value.  const uint8_t value_storage_kind_ : 2;  uint8_t : 0;  // The bytes containing the const bitfields must not be                // shared with bytes containing the mutable bitfields.  // Mutable flag's state (guarded by `data_guard_`).  // If def_kind_ == kDynamicValue, default_value_ holds a dynamically allocated  // value.  uint8_t def_kind_ : 1 ABSL_GUARDED_BY(*DataGuard());  // Has this flag's value been modified?  bool modified_ : 1 ABSL_GUARDED_BY(*DataGuard());  // Has this flag been specified on command line.  bool on_command_line_ : 1 ABSL_GUARDED_BY(*DataGuard());  // Unique tag for absl::call_once call to initialize this flag.  absl::once_flag init_control_;  // Mutation counter  int64_t counter_ ABSL_GUARDED_BY(*DataGuard());  // Optional flag's callback and absl::Mutex to guard the invocations.  FlagCallback* callback_ ABSL_GUARDED_BY(*DataGuard());  // Either a pointer to the function generating the default value based on the  // value specified in ABSL_FLAG or pointer to the dynamically set default  // value via SetCommandLineOptionWithMode. def_kind_ is used to distinguish  // these two cases.  FlagDefaultSrc default_value_;  // This is reserved space for an absl::Mutex to guard flag data. It will be  // initialized in FlagImpl::Init via placement new.  // We can't use "absl::Mutex data_guard_", since this class is not literal.  // We do not want to use "absl::Mutex* data_guard_", since this would require  // heap allocation during initialization, which is both slows program startup  // and can fail. Using reserved space + placement new allows us to avoid both  // problems.  alignas(absl::Mutex) mutable char data_guard_[sizeof(absl::Mutex)];};///////////////////////////////////////////////////////////////////////////////// The Flag object parameterized by the flag's value type. This class implements// flag reflection handle interface.template <typename T>class Flag { public:  constexpr Flag(const char* name, const char* filename, const FlagHelpArg help,                 const FlagDfltGenFunc default_value_gen)      : impl_(name, filename, &FlagOps<T>, help,              flags_internal::StorageKind<T>(), default_value_gen),        value_() {}  T Get() const {    // See implementation notes in CommandLineFlag::Get().    union U {      T value;      U() {}      ~U() { value.~T(); }    };    U u;#if !defined(NDEBUG)    impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);#endif    if (!value_.Get(&u.value)) impl_.Read(&u.value);    return std::move(u.value);  }  void Set(const T& v) {    impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);    impl_.Write(&v);  }  void SetCallback(const FlagCallbackFunc mutation_callback) {    impl_.SetCallback(mutation_callback);  }  // CommandLineFlag interface  absl::string_view Name() const { return impl_.Name(); }  std::string Filename() const { return impl_.Filename(); }  absl::string_view Typename() const { return ""; }  std::string Help() const { return impl_.Help(); }  bool IsModified() const { return impl_.IsModified(); }  bool IsSpecifiedOnCommandLine() const {    return impl_.IsSpecifiedOnCommandLine();  }  std::string DefaultValue() const { return impl_.DefaultValue(); }  std::string CurrentValue() const { return impl_.CurrentValue(); } private:  template <typename U, bool do_register>  friend class FlagRegistrar;  // Flag's data  // The implementation depends on value_ field to be placed exactly after the  // impl_ field, so that impl_ can figure out the offset to the value and  // access it.  FlagImpl impl_;  FlagValue<T> value_;};///////////////////////////////////////////////////////////////////////////////// Implementation of Flag value specific operations routine.template <typename T>void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) {  switch (op) {    case FlagOp::kAlloc: {      std::allocator<T> alloc;      return std::allocator_traits<std::allocator<T>>::allocate(alloc, 1);    }    case FlagOp::kDelete: {      T* p = static_cast<T*>(v2);      p->~T();      std::allocator<T> alloc;      std::allocator_traits<std::allocator<T>>::deallocate(alloc, p, 1);      return nullptr;    }    case FlagOp::kCopy:      *static_cast<T*>(v2) = *static_cast<const T*>(v1);      return nullptr;    case FlagOp::kCopyConstruct:      new (v2) T(*static_cast<const T*>(v1));      return nullptr;    case FlagOp::kSizeof:      return reinterpret_cast<void*>(static_cast<uintptr_t>(sizeof(T)));    case FlagOp::kFastTypeId:      return const_cast<void*>(base_internal::FastTypeId<T>());    case FlagOp::kRuntimeTypeId:      return const_cast<std::type_info*>(GenRuntimeTypeId<T>());    case FlagOp::kParse: {      // Initialize the temporary instance of type T based on current value in      // destination (which is going to be flag's default value).      T temp(*static_cast<T*>(v2));      if (!absl::ParseFlag<T>(*static_cast<const absl::string_view*>(v1), &temp,                              static_cast<std::string*>(v3))) {        return nullptr;      }      *static_cast<T*>(v2) = std::move(temp);      return v2;    }    case FlagOp::kUnparse:      *static_cast<std::string*>(v2) =          absl::UnparseFlag<T>(*static_cast<const T*>(v1));      return nullptr;    case FlagOp::kValueOffset: {      // Round sizeof(FlagImp) to a multiple of alignof(FlagValue<T>) to get the      // offset of the data.      ptrdiff_t round_to = alignof(FlagValue<T>);      ptrdiff_t offset =          (sizeof(FlagImpl) + round_to - 1) / round_to * round_to;      return reinterpret_cast<void*>(offset);    }  }  return nullptr;}///////////////////////////////////////////////////////////////////////////////// This class facilitates Flag object registration and tail expression-based// flag definition, for example:// ABSL_FLAG(int, foo, 42, "Foo help").OnUpdate(NotifyFooWatcher);struct FlagRegistrarEmpty {};template <typename T, bool do_register>class FlagRegistrar { public:  explicit FlagRegistrar(Flag<T>* flag) : flag_(flag) {    if (do_register) flags_internal::RegisterCommandLineFlag(&flag_->impl_);  }  FlagRegistrar& OnUpdate(FlagCallbackFunc cb) && {    flag_->SetCallback(cb);    return *this;  }  // Make the registrar "die" gracefully as an empty struct on a line where  // registration happens. Registrar objects are intended to live only as  // temporary.  operator FlagRegistrarEmpty() const { return {}; }  // NOLINT private:  Flag<T>* flag_;  // Flag being registered (not owned).};// This struct and corresponding overload to MakeDefaultValue are used to// facilitate usage of {} as default value in ABSL_FLAG macro.struct EmptyBraces {};template <typename T>void MakeFromDefaultValue(void* dst, T t) {  new (dst) T(std::move(t));}template <typename T>void MakeFromDefaultValue(void* dst, EmptyBraces) {  new (dst) T{};}}  // namespace flags_internalABSL_NAMESPACE_END}  // namespace absl#endif  // ABSL_FLAGS_INTERNAL_FLAG_H_
 |