about summary refs log tree commit diff
path: root/absl/flags/internal/flag.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/flags/internal/flag.cc')
-rw-r--r--absl/flags/internal/flag.cc71
1 files changed, 42 insertions, 29 deletions
diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc
index d087f79e891c..435cc362478f 100644
--- a/absl/flags/internal/flag.cc
+++ b/absl/flags/internal/flag.cc
@@ -49,12 +49,11 @@ void FlagImpl::Init() {
 
   absl::MutexLock lock(&locks_->primary_mu);
 
-  if (def_ != nullptr) {
+  if (cur_ != nullptr) {
     inited_.store(true, std::memory_order_release);
   } else {
-    // Need to initialize def and cur fields.
-    def_ = (*initial_value_gen_)();
-    cur_ = Clone(op_, def_);
+    // Need to initialize cur field.
+    cur_ = MakeInitValue().release();
     StoreAtomic();
     inited_.store(true, std::memory_order_release);
     InvokeCallback();
@@ -63,8 +62,7 @@ void FlagImpl::Init() {
 
 // Ensures that the lazily initialized data is initialized,
 // and returns pointer to the mutex guarding flags data.
-absl::Mutex* FlagImpl::DataGuard() const
-    ABSL_LOCK_RETURNED(locks_->primary_mu) {
+absl::Mutex* FlagImpl::DataGuard() const {
   if (ABSL_PREDICT_FALSE(!inited_.load(std::memory_order_acquire))) {
     const_cast<FlagImpl*>(this)->Init();
   }
@@ -79,12 +77,23 @@ void FlagImpl::Destroy() const {
 
     // Values are heap allocated for Abseil Flags.
     if (cur_) Delete(op_, cur_);
-    if (def_) Delete(op_, def_);
+    if (def_kind_ == FlagDefaultSrcKind::kDynamicValue)
+      Delete(op_, default_src_.dynamic_value);
   }
 
   delete locks_;
 }
 
+std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const {
+  void* res = nullptr;
+  if (def_kind_ == FlagDefaultSrcKind::kDynamicValue) {
+    res = Clone(op_, default_src_.dynamic_value);
+  } else {
+    res = (*default_src_.gen_func)();
+  }
+  return {res, DynValueDeleter{op_}};
+}
+
 std::string FlagImpl::Help() const {
   return help_source_kind_ == FlagHelpSrcKind::kLiteral ? help_.literal
                                                         : help_.gen_func();
@@ -103,7 +112,8 @@ bool FlagImpl::IsSpecifiedOnCommandLine() const {
 std::string FlagImpl::DefaultValue() const {
   absl::MutexLock l(DataGuard());
 
-  return Unparse(marshalling_op_, def_);
+  auto obj = MakeInitValue();
+  return Unparse(marshalling_op_, obj.get());
 }
 
 std::string FlagImpl::CurrentValue() const {
@@ -121,8 +131,7 @@ void FlagImpl::SetCallback(
   InvokeCallback();
 }
 
-void FlagImpl::InvokeCallback() const
-    ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
+void FlagImpl::InvokeCallback() const {
   if (!callback_) return;
 
   // If the flag has a mutation callback this function invokes it. While the
@@ -172,23 +181,20 @@ bool FlagImpl::RestoreState(const CommandLineFlag& flag, const void* value,
 // 'dst' assuming it is a pointer to the flag's value type. In case if any error
 // is encountered in either step, the error message is stored in 'err'
 bool FlagImpl::TryParse(const CommandLineFlag& flag, void* dst,
-                        absl::string_view value, std::string* err) const
-    ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
-  void* tentative_value = Clone(op_, def_);
+                        absl::string_view value, std::string* err) const {
+  auto tentative_value = MakeInitValue();
   std::string parse_err;
-  if (!Parse(marshalling_op_, value, tentative_value, &parse_err)) {
+  if (!Parse(marshalling_op_, value, tentative_value.get(), &parse_err)) {
     auto type_name = flag.Typename();
     absl::string_view err_sep = parse_err.empty() ? "" : "; ";
     absl::string_view typename_sep = type_name.empty() ? "" : " ";
     *err = absl::StrCat("Illegal value '", value, "' specified for",
                         typename_sep, type_name, " flag '", flag.Name(), "'",
                         err_sep, parse_err);
-    Delete(op_, tentative_value);
     return false;
   }
 
-  Copy(op_, tentative_value, dst);
-  Delete(op_, tentative_value);
+  Copy(op_, tentative_value.get(), dst);
   return true;
 }
 
@@ -208,7 +214,7 @@ void FlagImpl::Read(const CommandLineFlag& flag, void* dst,
   CopyConstruct(op_, cur_, dst);
 }
 
-void FlagImpl::StoreAtomic() ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
+void FlagImpl::StoreAtomic() {
   size_t data_size = Sizeof(op_);
 
   if (data_size <= sizeof(int64_t)) {
@@ -299,12 +305,22 @@ bool FlagImpl::SetFromString(const CommandLineFlag& flag,
       break;
     }
     case SET_FLAGS_DEFAULT: {
-      // modify the flag's default-value
-      if (!TryParse(flag, def_, value, err)) return false;
+      // Flag's new default-value.
+      auto new_default_value = MakeInitValue();
+
+      if (!TryParse(flag, new_default_value.get(), value, err)) return false;
+
+      if (def_kind_ == FlagDefaultSrcKind::kDynamicValue) {
+        // Release old default value.
+        Delete(op_, default_src_.dynamic_value);
+      }
+
+      default_src_.dynamic_value = new_default_value.release();
+      def_kind_ = FlagDefaultSrcKind::kDynamicValue;
 
       if (!modified_) {
         // Need to set both default value *and* current, in this case
-        Copy(op_, def_, cur_);
+        Copy(op_, default_src_.dynamic_value, cur_);
         StoreAtomic();
         InvokeCallback();
       }
@@ -321,9 +337,9 @@ void FlagImpl::CheckDefaultValueParsingRoundtrip(
 
   absl::MutexLock lock(DataGuard());
 
-  void* dst = Clone(op_, def_);
+  auto dst = MakeInitValue();
   std::string error;
-  if (!flags_internal::Parse(marshalling_op_, v, dst, &error)) {
+  if (!flags_internal::Parse(marshalling_op_, v, dst.get(), &error)) {
     ABSL_INTERNAL_LOG(
         FATAL,
         absl::StrCat("Flag ", flag.Name(), " (from ", flag.Filename(),
@@ -333,18 +349,15 @@ void FlagImpl::CheckDefaultValueParsingRoundtrip(
 
   // We do not compare dst to def since parsing/unparsing may make
   // small changes, e.g., precision loss for floating point types.
-  Delete(op_, dst);
 }
 
 bool FlagImpl::ValidateInputValue(absl::string_view value) const {
   absl::MutexLock l(DataGuard());
 
-  void* obj = Clone(op_, def_);
+  auto obj = MakeInitValue();
   std::string ignored_error;
-  const bool result =
-      flags_internal::Parse(marshalling_op_, value, obj, &ignored_error);
-  Delete(op_, obj);
-  return result;
+  return flags_internal::Parse(marshalling_op_, value, obj.get(),
+                               &ignored_error);
 }
 
 }  // namespace flags_internal