about summary refs log tree commit diff
path: root/absl/flags/internal/flag.h
diff options
context:
space:
mode:
Diffstat (limited to 'absl/flags/internal/flag.h')
-rw-r--r--absl/flags/internal/flag.h72
1 files changed, 45 insertions, 27 deletions
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index 9b32f46735b6..bc50de5486bc 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -24,40 +24,58 @@ namespace flags_internal {
 
 // This is "unspecified" implementation of absl::Flag<T> type.
 template <typename T>
-class Flag {
+class Flag : public flags_internal::CommandLineFlag {
  public:
   constexpr Flag(const char* name, const flags_internal::HelpGenFunc help_gen,
                  const char* filename,
-                 const flags_internal::FlagMarshallingOpFn marshalling_op,
+                 const flags_internal::FlagMarshallingOpFn marshalling_op_arg,
                  const flags_internal::InitialValGenFunc initial_value_gen)
-      : internal(name, flags_internal::HelpText::FromFunctionPointer(help_gen),
-                 filename, &flags_internal::FlagOps<T>, marshalling_op,
-                 initial_value_gen,
-                 /*retired_arg=*/false, /*def_arg=*/nullptr,
-                 /*cur_arg=*/nullptr) {}
-
-  // Not copyable/assignable.
-  Flag(const Flag<T>&) = delete;
-  Flag<T>& operator=(const Flag<T>&) = delete;
-
-  absl::string_view Name() const { return internal.Name(); }
-  std::string Help() const { return internal.Help(); }
-  std::string Filename() const { return internal.Filename(); }
+      : flags_internal::CommandLineFlag(
+            name, flags_internal::HelpText::FromFunctionPointer(help_gen),
+            filename, &flags_internal::FlagOps<T>, marshalling_op_arg,
+            initial_value_gen,
+            /*retired_arg=*/false, /*def_arg=*/nullptr,
+            /*cur_arg=*/nullptr) {}
+
+  T Get() const {
+    // 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;
+
+    this->Read(&u.value, &flags_internal::FlagOps<T>);
+    return std::move(u.value);
+  }
 
-  absl::flags_internal::CommandLineFlag internal;
+  bool AtomicGet(T* v) const {
+    const int64_t r = this->atomic.load(std::memory_order_acquire);
+    if (r != flags_internal::CommandLineFlag::kAtomicInit) {
+      memcpy(v, &r, sizeof(T));
+      return true;
+    }
 
-  void SetCallback(const flags_internal::FlagCallback mutation_callback) {
-    internal.SetCallback(mutation_callback);
+    return false;
   }
 
- private:
-  // TODO(rogeeff): add these validations once UnparseFlag invocation is fixed
-  // for built-in types and when we cleanup existing code from operating on
-  // forward declared types.
-  //  auto IsCopyConstructible(const T& v) -> decltype(T(v));
-  //  auto HasAbslParseFlag(absl::string_view in, T* dst, std::string* err)
-  //      -> decltype(AbslParseFlag(in, dst, err));
-  //  auto HasAbslUnparseFlag(const T& v) -> decltype(AbslUnparseFlag(v));
+  void Set(const T& v) { this->Write(&v, &flags_internal::FlagOps<T>); }
 };
 
 // This class facilitates Flag object registration and tail expression-based
@@ -67,7 +85,7 @@ template <typename T, bool do_register>
 class FlagRegistrar {
  public:
   explicit FlagRegistrar(Flag<T>* flag) : flag_(flag) {
-    if (do_register) flags_internal::RegisterCommandLineFlag(&flag_->internal);
+    if (do_register) flags_internal::RegisterCommandLineFlag(flag_);
   }
 
   FlagRegistrar& OnUpdate(flags_internal::FlagCallback cb) && {