about summary refs log tree commit diff
path: root/absl/flags/internal/commandlineflag.h
diff options
context:
space:
mode:
Diffstat (limited to 'absl/flags/internal/commandlineflag.h')
-rw-r--r--absl/flags/internal/commandlineflag.h187
1 files changed, 64 insertions, 123 deletions
diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h
index 528d3106bfa8..13a3352e80f4 100644
--- a/absl/flags/internal/commandlineflag.h
+++ b/absl/flags/internal/commandlineflag.h
@@ -16,12 +16,10 @@
 #ifndef ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
 #define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
 
-#include <atomic>
 #include <memory>
 
 #include "absl/base/macros.h"
 #include "absl/flags/marshalling.h"
-#include "absl/synchronization/mutex.h"
 #include "absl/types/optional.h"
 
 namespace absl {
@@ -151,14 +149,6 @@ inline size_t Sizeof(FlagOpFn op) {
       op(flags_internal::kSizeof, nullptr, nullptr)));
 }
 
-// The following struct contains the locks in a CommandLineFlag struct.
-// They are in a separate struct that is lazily allocated to avoid problems
-// with static initialization and to avoid multiple allocations.
-struct CommandLineFlagLocks {
-  absl::Mutex primary_mu;   // protects several fields in CommandLineFlag
-  absl::Mutex callback_mu;  // used to serialize callbacks
-};
-
 // Holds either a pointer to help text or a function which produces it.  This is
 // needed for supporting both static initialization of Flags while supporting
 // the legacy registration framework.  We can't use absl::variant<const char*,
@@ -200,25 +190,9 @@ class FlagStateInterface {
 // Holds all information for a flag.
 class CommandLineFlag {
  public:
-  constexpr CommandLineFlag(
-      const char* name, HelpText help_text, const char* filename,
-      const flags_internal::FlagOpFn op,
-      const flags_internal::FlagMarshallingOpFn marshalling_op,
-      const flags_internal::InitialValGenFunc initial_value_gen, void* def,
-      void* cur)
-      : name_(name),
-        help_(help_text),
-        filename_(filename),
-        op_(op),
-        marshalling_op_(marshalling_op),
-        make_init_value_(initial_value_gen),
-        inited_(false),
-        modified_(false),
-        on_command_line_(false),
-        def_(def),
-        cur_(cur),
-        counter_(0),
-        locks_(nullptr) {}
+  constexpr CommandLineFlag(const char* name, HelpText help_text,
+                            const char* filename)
+      : name_(name), help_(help_text), filename_(filename) {}
 
   // Virtual destructor
   virtual void Destroy() const = 0;
@@ -227,60 +201,73 @@ class CommandLineFlag {
   CommandLineFlag(const CommandLineFlag&) = delete;
   CommandLineFlag& operator=(const CommandLineFlag&) = delete;
 
-  // Access methods.
-
-  // Returns true iff this object corresponds to retired flag
-  virtual bool IsRetired() const { return false; }
-  // Returns true iff this is a handle to an Abseil Flag.
-  virtual bool IsAbseilFlag() const { return true; }
-
+  // Non-polymorphic access methods.
   absl::string_view Name() const { return name_; }
   std::string Help() const { return help_.GetHelpText(); }
-  bool IsModified() const;
-  void SetModified(bool is_modified);
-  bool IsSpecifiedOnCommandLine() const;
-
   absl::string_view Typename() const;
   std::string Filename() const;
-  std::string DefaultValue() const;
-  std::string CurrentValue() const;
-
-  // Interface to store the value in atomic if one used. This is short term
-  // interface. To be reworked once cur_ is moved.
-  virtual void StoreAtomic() {}
-
-  // Interfaces to operate on validators.
-  virtual bool InvokeValidator(const void* /*value*/) const { return true; }
-  // Invoke the flag validators for old flags.
-  // TODO(rogeeff): implement proper validators for Abseil Flags
-  bool ValidateDefaultValue() const;
-  bool ValidateInputValue(absl::string_view value) const;
 
   // Return true iff flag has type T.
   template <typename T>
   inline bool IsOfType() const {
-    return op_ == &flags_internal::FlagOps<T>;
+    return TypeId() == &flags_internal::FlagOps<T>;
   }
 
   // Attempts to retrieve the flag value. Returns value on success,
   // absl::nullopt otherwise.
   template <typename T>
   absl::optional<T> Get() const {
-    if (IsRetired() || flags_internal::FlagOps<T> != op_) return absl::nullopt;
-
-    T res;
-    Read(&res, flags_internal::FlagOps<T>);
+    if (IsRetired() || !IsOfType<T>()) {
+      return absl::nullopt;
+    }
 
-    return res;
+    // Implementation notes:
+    //
+    // We are wrapping a union around the value of `T` to serve three purposes:
+    //
+    //  1. `U.value` has correct size and alignment for a value of type `T`
+    //  2. The `U.value` constructor is not invoked since U's constructor does
+    //  not
+    //     do it explicitly.
+    //  3. The `U.value` destructor is invoked since U's destructor does it
+    //     explicitly. This makes `U` a kind of RAII wrapper around non default
+    //     constructible value of T, which is destructed when we leave the
+    //     scope. We do need to destroy U.value, which is constructed by
+    //     CommandLineFlag::Read even though we left it in a moved-from state
+    //     after std::move.
+    //
+    // All of this serves to avoid requiring `T` being default constructible.
+    union U {
+      T value;
+      U() {}
+      ~U() { value.~T(); }
+    };
+    U u;
+
+    Read(&u.value);
+    return std::move(u.value);
   }
 
+  // Polymorphic access methods
+
+  // Returns true iff this object corresponds to retired flag
+  virtual bool IsRetired() const { return false; }
+  // Returns true iff this is a handle to an Abseil Flag.
+  virtual bool IsAbseilFlag() const { return true; }
+  // Returns id of the flag's value type.
+  virtual flags_internal::FlagOpFn TypeId() const = 0;
+  virtual bool IsModified() const = 0;
+  virtual bool IsSpecifiedOnCommandLine() const = 0;
+  virtual std::string DefaultValue() const = 0;
+  virtual std::string CurrentValue() const = 0;
+
+  // Interfaces to operate on validators.
+  virtual bool ValidateInputValue(absl::string_view value) const = 0;
+
   // Interface to save flag to some persistent state. Returns current flag state
   // or nullptr if flag does not support saving and restoring a state.
   virtual std::unique_ptr<FlagStateInterface> SaveState() = 0;
 
-  // Interfaces to overate on callbacks.
-  virtual void InvokeCallback() {}
-
   // Sets the value of the flag based on specified std::string `value`. If the flag
   // was successfully set to new value, it returns true. Otherwise, sets `error`
   // to indicate the error, leaves the flag unchanged, and returns false. There
@@ -289,74 +276,28 @@ class CommandLineFlag {
   //  * Update the flag's default value
   //  * Update the current flag value if it was never set before
   // The mode is selected based on `set_mode` parameter.
-  bool SetFromString(absl::string_view value,
-                     flags_internal::FlagSettingMode set_mode,
-                     flags_internal::ValueSource source, std::string* error);
+  virtual bool SetFromString(absl::string_view value,
+                             flags_internal::FlagSettingMode set_mode,
+                             flags_internal::ValueSource source,
+                             std::string* error) = 0;
 
-  void CheckDefaultValueParsingRoundtrip() const;
+  // Checks that flags default value can be converted to std::string and back to the
+  // flag's value type.
+  virtual void CheckDefaultValueParsingRoundtrip() const = 0;
 
   // Constant configuration for a particular flag.
  protected:
   ~CommandLineFlag() = default;
 
-  // Thread safe access to mutation counter.
-  int64_t MutationCounter() const;
-
-  const char* const name_;
-  const HelpText help_;
-  const char* const filename_;
-
-  const FlagOpFn op_;                         // Type-specific handler
-  const FlagMarshallingOpFn marshalling_op_;  // Marshalling ops handler
-  const InitialValGenFunc make_init_value_;  // Makes initial value for the flag
-  std::atomic<bool> inited_;  // fields have been lazily initialized
-
-  // Mutable state (guarded by locks_->primary_mu).
-  bool modified_;         // Has flag value been modified?
-  bool on_command_line_;  // Specified on command line.
-  void* def_;             // Lazily initialized pointer to default value
-  void* cur_;             // Lazily initialized pointer to current value
-  int64_t counter_;         // Mutation counter
-
-  // Lazily initialized mutexes for this flag value.  We cannot inline a
-  // SpinLock or Mutex here because those have non-constexpr constructors and
-  // so would prevent constant initialization of this type.
-  // TODO(rogeeff): fix it once Mutex has constexpr constructor
-  struct CommandLineFlagLocks* locks_;  // locks, laziliy allocated.
-
-  // Ensure that the lazily initialized fields of *flag have been initialized,
-  // and return the lock which should be locked when flag's state is mutated.
-  absl::Mutex* InitFlagIfNecessary() const ABSL_LOCK_RETURNED(locks_->primary_mu);
-
-  // copy construct new value of flag's type in a memory referenced by dst
-  // based on current flag's value
-  void Read(void* dst, const flags_internal::FlagOpFn dst_op) const;
-  // updates flag's value to *src (locked)
-  void Write(const void* src, const flags_internal::FlagOpFn src_op);
-
-  friend class FlagRegistry;
-  friend class FlagPtrMap;
-  friend class FlagSaverImpl;
-  friend bool TryParseLocked(CommandLineFlag* flag, void* dst,
-                             absl::string_view value, std::string* err);
-  friend absl::Mutex* InitFlag(CommandLineFlag* flag);
-};
+  const char* const name_;      // Flags name passed to ABSL_FLAG as second arg.
+  const HelpText help_;         // The function generating help message.
+  const char* const filename_;  // The file name where ABSL_FLAG resides.
 
-// Update any copy of the flag value that is stored in an atomic word.
-// In addition if flag has a mutation callback this function invokes it. While
-// callback is being invoked the primary flag's mutex is unlocked and it is
-// re-locked back after call to callback is completed. Callback invocation is
-// guarded by flag's secondary mutex instead which prevents concurrent callback
-// invocation. Note that it is possible for other thread to grab the primary
-// lock and update flag's value at any time during the callback invocation.
-// This is by design. Callback can get a value of the flag if necessary, but it
-// might be different from the value initiated the callback and it also can be
-// different by the time the callback invocation is completed.
-// Requires that *primary_lock be held in exclusive mode; it may be released
-// and reacquired by the implementation.
-void UpdateCopy(CommandLineFlag* flag);
-// Return true iff flag value was changed via direct-access.
-bool ChangedDirectly(CommandLineFlag* flag, const void* a, const void* b);
+ private:
+  // Copy-construct a new value of the flag's type in a memory referenced by
+  // the dst based on the current flag's value.
+  virtual void Read(void* dst) const = 0;
+};
 
 // This macro is the "source of truth" for the list of supported flag types we
 // expect to perform lock free operations on. Specifically it generates code,