about summary refs log tree commit diff
path: root/absl/flags
diff options
context:
space:
mode:
Diffstat (limited to 'absl/flags')
-rw-r--r--absl/flags/flag.h61
-rw-r--r--absl/flags/flag_test.cc67
-rw-r--r--absl/flags/internal/commandlineflag.cc15
-rw-r--r--absl/flags/internal/commandlineflag.h46
-rw-r--r--absl/flags/internal/commandlineflag_test.cc3
-rw-r--r--absl/flags/internal/flag.cc61
-rw-r--r--absl/flags/internal/flag.h99
-rw-r--r--absl/flags/internal/registry.cc12
-rw-r--r--absl/flags/internal/type_erased.cc4
-rw-r--r--absl/flags/internal/type_erased.h2
-rw-r--r--absl/flags/internal/usage.cc32
11 files changed, 240 insertions, 162 deletions
diff --git a/absl/flags/flag.h b/absl/flags/flag.h
index 194a9d314fc5..8dd1b9be7af8 100644
--- a/absl/flags/flag.h
+++ b/absl/flags/flag.h
@@ -118,11 +118,12 @@ class Flag {
         return impl_;
       }
 
-      impl_ =
-          new flags_internal::Flag<T>(name_, filename_,
-                                      {flags_internal::FlagHelpMsg(help_gen_),
-                                       flags_internal::FlagHelpKind::kGenFunc},
-                                      default_value_gen_);
+      impl_ = new flags_internal::Flag<T>(
+          name_, filename_,
+          {flags_internal::FlagHelpMsg(help_gen_),
+           flags_internal::FlagHelpKind::kGenFunc},
+          {flags_internal::FlagDefaultSrc(default_value_gen_),
+           flags_internal::FlagDefaultKind::kGenFunc});
       inited_.store(true, std::memory_order_release);
     }
 
@@ -132,14 +133,12 @@ class Flag {
   // Public methods of `absl::Flag<T>` are NOT part of the Abseil Flags API.
   // See https://abseil.io/docs/cpp/guides/flags
   bool IsRetired() const { return GetImpl()->IsRetired(); }
-  bool IsAbseilFlag() const { return GetImpl()->IsAbseilFlag(); }
   absl::string_view Name() const { return GetImpl()->Name(); }
   std::string Help() const { return GetImpl()->Help(); }
   bool IsModified() const { return GetImpl()->IsModified(); }
   bool IsSpecifiedOnCommandLine() const {
     return GetImpl()->IsSpecifiedOnCommandLine();
   }
-  absl::string_view Typename() const { return GetImpl()->Typename(); }
   std::string Filename() const { return GetImpl()->Filename(); }
   std::string DefaultValue() const { return GetImpl()->DefaultValue(); }
   std::string CurrentValue() const { return GetImpl()->CurrentValue(); }
@@ -311,9 +310,12 @@ ABSL_NAMESPACE_END
     static std::string NonConst() { return ABSL_FLAG_IMPL_FLAGHELP(txt); } \
   }
 
-#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \
-  static void AbslFlagsInitFlag##name(void* dst) {                        \
-    absl::flags_internal::MakeFromDefaultValue<Type>(dst, default_value); \
+#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value)     \
+  struct AbslFlagDefaultGenFor##name {                                        \
+    Type value = absl::flags_internal::InitDefaultValue<Type>(default_value); \
+    static void Gen(void* p) {                                                \
+      new (p) Type(AbslFlagDefaultGenFor##name{}.value);                      \
+    }                                                                         \
   }
 
 // ABSL_FLAG_IMPL
@@ -322,29 +324,30 @@ ABSL_NAMESPACE_END
 // global name for FLAGS_no<flag_name> symbol, thus preventing the possibility
 // of defining two flags with names foo and nofoo.
 #if !defined(_MSC_VER) || defined(__clang__)
-#define ABSL_FLAG_IMPL(Type, name, default_value, help)             \
-  namespace absl /* block flags in namespaces */ {}                 \
-  ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \
-  ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help);                  \
-  ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{                    \
-      ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(),    \
-      absl::flags_internal::HelpArg<AbslFlagHelpGenFor##name>(0),   \
-      &AbslFlagsInitFlag##name};                                    \
-  extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name;   \
-  absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name =         \
+
+#define ABSL_FLAG_IMPL(Type, name, default_value, help)                        \
+  namespace absl /* block flags in namespaces */ {}                            \
+  ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value);           \
+  ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help);                             \
+  ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{                               \
+      ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(),               \
+      absl::flags_internal::HelpArg<AbslFlagHelpGenFor##name>(0),              \
+      absl::flags_internal::DefaultArg<Type, AbslFlagDefaultGenFor##name>(0)}; \
+  extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name;              \
+  absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name =                    \
       ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
 #else
 // MSVC version uses aggregate initialization. We also do not try to
 // optimize away help wrapper.
-#define ABSL_FLAG_IMPL(Type, name, default_value, help)               \
-  namespace absl /* block flags in namespaces */ {}                   \
-  ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value)   \
-  ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help);                    \
-  ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{                      \
-      ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(),      \
-      &AbslFlagHelpGenFor##name::NonConst, &AbslFlagsInitFlag##name}; \
-  extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name;     \
-  absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name =           \
+#define ABSL_FLAG_IMPL(Type, name, default_value, help)                        \
+  namespace absl /* block flags in namespaces */ {}                            \
+  ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value);           \
+  ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help);                             \
+  ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{                               \
+      ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(),               \
+      &AbslFlagHelpGenFor##name::NonConst, &AbslFlagDefaultGenFor##name::Gen}; \
+  extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name;              \
+  absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name =                    \
       ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
 #endif
 
diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc
index 6fa178f1f0b9..015b1fc9dc5d 100644
--- a/absl/flags/flag_test.cc
+++ b/absl/flags/flag_test.cc
@@ -128,26 +128,27 @@ constexpr flags::FlagHelpArg help_arg{flags::FlagHelpMsg("literal help"),
 
 using String = std::string;
 
-#define DEFINE_CONSTRUCTED_FLAG(T)                                          \
-  constexpr flags::Flag<T> f1##T("f1", "file", help_arg, &TestMakeDflt<T>); \
-  ABSL_CONST_INIT flags::Flag<T> f2##T(                                     \
-      "f2", "file",                                                         \
-      {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc},    \
-      &TestMakeDflt<T>)
-
-#define TEST_CONSTRUCTED_FLAG(T) TestConstructionFor(f1##T, &f2##T);
-
-DEFINE_CONSTRUCTED_FLAG(bool);
-DEFINE_CONSTRUCTED_FLAG(int16_t);
-DEFINE_CONSTRUCTED_FLAG(uint16_t);
-DEFINE_CONSTRUCTED_FLAG(int32_t);
-DEFINE_CONSTRUCTED_FLAG(uint32_t);
-DEFINE_CONSTRUCTED_FLAG(int64_t);
-DEFINE_CONSTRUCTED_FLAG(uint64_t);
-DEFINE_CONSTRUCTED_FLAG(float);
-DEFINE_CONSTRUCTED_FLAG(double);
-DEFINE_CONSTRUCTED_FLAG(String);
-DEFINE_CONSTRUCTED_FLAG(UDT);
+#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind)                      \
+  constexpr flags::FlagDefaultArg f1default##T{                          \
+      flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind};   \
+  constexpr flags::Flag<T> f1##T("f1", "file", help_arg, f1default##T);  \
+  ABSL_CONST_INIT flags::Flag<T> f2##T(                                  \
+      "f2", "file",                                                      \
+      {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \
+      flags::FlagDefaultArg{flags::FlagDefaultSrc(&TestMakeDflt<T>),     \
+                            flags::FlagDefaultKind::kGenFunc})
+
+DEFINE_CONSTRUCTED_FLAG(bool, true, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(int16_t, 1, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(uint16_t, 2, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(int32_t, 3, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(uint32_t, 4, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(int64_t, 5, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(uint64_t, 6, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(float, 7.8, kFloat);
+DEFINE_CONSTRUCTED_FLAG(double, 9.10, kDouble);
+DEFINE_CONSTRUCTED_FLAG(String, &TestMakeDflt<String>, kGenFunc);
+DEFINE_CONSTRUCTED_FLAG(UDT, &TestMakeDflt<UDT>, kGenFunc);
 
 template <typename T>
 bool TestConstructionFor(const flags::Flag<T>& f1, flags::Flag<T>* f2) {
@@ -164,6 +165,8 @@ bool TestConstructionFor(const flags::Flag<T>& f1, flags::Flag<T>* f2) {
   return true;
 }
 
+#define TEST_CONSTRUCTED_FLAG(T) TestConstructionFor(f1##T, &f2##T);
+
 TEST_F(FlagTest, TestConstruction) {
   TEST_CONSTRUCTED_FLAG(bool);
   TEST_CONSTRUCTED_FLAG(int16_t);
@@ -443,29 +446,29 @@ TEST_F(FlagTest, TestGetSet) {
 
 TEST_F(FlagTest, TestGetViaReflection) {
   auto* handle = flags::FindCommandLineFlag("test_flag_01");
-  EXPECT_EQ(*handle->Get<bool>(), true);
+  EXPECT_EQ(*handle->TryGet<bool>(), true);
   handle = flags::FindCommandLineFlag("test_flag_02");
-  EXPECT_EQ(*handle->Get<int>(), 1234);
+  EXPECT_EQ(*handle->TryGet<int>(), 1234);
   handle = flags::FindCommandLineFlag("test_flag_03");
-  EXPECT_EQ(*handle->Get<int16_t>(), -34);
+  EXPECT_EQ(*handle->TryGet<int16_t>(), -34);
   handle = flags::FindCommandLineFlag("test_flag_04");
-  EXPECT_EQ(*handle->Get<uint16_t>(), 189);
+  EXPECT_EQ(*handle->TryGet<uint16_t>(), 189);
   handle = flags::FindCommandLineFlag("test_flag_05");
-  EXPECT_EQ(*handle->Get<int32_t>(), 10765);
+  EXPECT_EQ(*handle->TryGet<int32_t>(), 10765);
   handle = flags::FindCommandLineFlag("test_flag_06");
-  EXPECT_EQ(*handle->Get<uint32_t>(), 40000);
+  EXPECT_EQ(*handle->TryGet<uint32_t>(), 40000);
   handle = flags::FindCommandLineFlag("test_flag_07");
-  EXPECT_EQ(*handle->Get<int64_t>(), -1234567);
+  EXPECT_EQ(*handle->TryGet<int64_t>(), -1234567);
   handle = flags::FindCommandLineFlag("test_flag_08");
-  EXPECT_EQ(*handle->Get<uint64_t>(), 9876543);
+  EXPECT_EQ(*handle->TryGet<uint64_t>(), 9876543);
   handle = flags::FindCommandLineFlag("test_flag_09");
-  EXPECT_NEAR(*handle->Get<double>(), -9.876e-50, 1e-55);
+  EXPECT_NEAR(*handle->TryGet<double>(), -9.876e-50, 1e-55);
   handle = flags::FindCommandLineFlag("test_flag_10");
-  EXPECT_NEAR(*handle->Get<float>(), 1.234e12f, 1e5f);
+  EXPECT_NEAR(*handle->TryGet<float>(), 1.234e12f, 1e5f);
   handle = flags::FindCommandLineFlag("test_flag_11");
-  EXPECT_EQ(*handle->Get<std::string>(), "");
+  EXPECT_EQ(*handle->TryGet<std::string>(), "");
   handle = flags::FindCommandLineFlag("test_flag_12");
-  EXPECT_EQ(*handle->Get<absl::Duration>(), absl::Minutes(10));
+  EXPECT_EQ(*handle->TryGet<absl::Duration>(), absl::Minutes(10));
 }
 
 // --------------------------------------------------------------------
diff --git a/absl/flags/internal/commandlineflag.cc b/absl/flags/internal/commandlineflag.cc
index 90765a3eb6f3..de588c13166b 100644
--- a/absl/flags/internal/commandlineflag.cc
+++ b/absl/flags/internal/commandlineflag.cc
@@ -22,7 +22,20 @@ namespace flags_internal {
 FlagStateInterface::~FlagStateInterface() {}
 
 bool CommandLineFlag::IsRetired() const { return false; }
-bool CommandLineFlag::IsAbseilFlag() const { return true; }
+
+FlagFastTypeId PrivateHandleInterface::TypeId(const CommandLineFlag& flag) {
+  return flag.TypeId();
+}
+
+std::unique_ptr<FlagStateInterface> PrivateHandleInterface::SaveState(
+    CommandLineFlag* flag) {
+  return flag->SaveState();
+}
+
+bool PrivateHandleInterface::ValidateInputValue(const CommandLineFlag& flag,
+                                                absl::string_view value) {
+  return flag.ValidateInputValue(value);
+}
 
 }  // namespace flags_internal
 ABSL_NAMESPACE_END
diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h
index ef992f7f478d..f807fb9ab650 100644
--- a/absl/flags/internal/commandlineflag.h
+++ b/absl/flags/internal/commandlineflag.h
@@ -93,7 +93,7 @@ class CommandLineFlag {
   // Attempts to retrieve the flag value. Returns value on success,
   // absl::nullopt otherwise.
   template <typename T>
-  absl::optional<T> Get() const {
+  absl::optional<T> TryGet() const {
     if (IsRetired() || !IsOfType<T>()) {
       return absl::nullopt;
     }
@@ -130,29 +130,14 @@ class CommandLineFlag {
   virtual absl::string_view Name() const = 0;
   // Returns name of the file where this flag is defined.
   virtual std::string Filename() const = 0;
-  // Returns name of the flag's value type for some built-in types or empty
-  // string.
-  virtual absl::string_view Typename() const = 0;
   // Returns help message associated with this flag.
   virtual std::string Help() const = 0;
   // Returns true iff this object corresponds to retired flag.
   virtual bool IsRetired() const;
-  // Returns true iff this is a handle to an Abseil Flag.
-  virtual bool IsAbseilFlag() const;
-  // Returns id of the flag's value type.
-  virtual FlagFastTypeId 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;
-
   // Sets the value of the flag based on specified 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
@@ -174,9 +159,38 @@ class CommandLineFlag {
   ~CommandLineFlag() = default;
 
  private:
+  friend class PrivateHandleInterface;
+
+  // Returns id of the flag's value type.
+  virtual FlagFastTypeId TypeId() 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;
+
   // 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;
+
+  // Interfaces to operate on validators.
+  // Validates supplied value usign validator or parseflag routine
+  virtual bool ValidateInputValue(absl::string_view value) const = 0;
+};
+
+// This class serves as a trampoline to access private methods of
+// CommandLineFlag. This class is intended for use exclusively internally inside
+// of the Abseil Flags implementation
+class PrivateHandleInterface {
+ public:
+  // Access to CommandLineFlag::TypeId.
+  static FlagFastTypeId TypeId(const CommandLineFlag& flag);
+
+  // Access to CommandLineFlag::SaveState.
+  static std::unique_ptr<FlagStateInterface> SaveState(CommandLineFlag* flag);
+
+  // Access to CommandLineFlag::ValidateInputValue.
+  static bool ValidateInputValue(const CommandLineFlag& flag,
+                                 absl::string_view value);
 };
 
 // This macro is the "source of truth" for the list of supported flag built-in
diff --git a/absl/flags/internal/commandlineflag_test.cc b/absl/flags/internal/commandlineflag_test.cc
index c1142b7c5720..c31679f95e7a 100644
--- a/absl/flags/internal/commandlineflag_test.cc
+++ b/absl/flags/internal/commandlineflag_test.cc
@@ -67,7 +67,6 @@ TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) {
   ASSERT_TRUE(flag_01);
   EXPECT_EQ(flag_01->Name(), "int_flag");
   EXPECT_EQ(flag_01->Help(), "int_flag help");
-  EXPECT_EQ(flag_01->Typename(), "");
   EXPECT_TRUE(!flag_01->IsRetired());
   EXPECT_TRUE(flag_01->IsOfType<int>());
   EXPECT_TRUE(
@@ -80,7 +79,6 @@ TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) {
   ASSERT_TRUE(flag_02);
   EXPECT_EQ(flag_02->Name(), "string_flag");
   EXPECT_EQ(flag_02->Help(), "string_flag help");
-  EXPECT_EQ(flag_02->Typename(), "");
   EXPECT_TRUE(!flag_02->IsRetired());
   EXPECT_TRUE(flag_02->IsOfType<std::string>());
   EXPECT_TRUE(
@@ -93,7 +91,6 @@ TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) {
   ASSERT_TRUE(flag_03);
   EXPECT_EQ(flag_03->Name(), "bool_retired_flag");
   EXPECT_EQ(flag_03->Help(), "");
-  EXPECT_EQ(flag_03->Typename(), "");
   EXPECT_TRUE(flag_03->IsRetired());
   EXPECT_TRUE(flag_03->IsOfType<bool>());
   EXPECT_EQ(flag_03->Filename(), "RETIRED");
diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc
index 089567f7ae50..8f0777fa1dc1 100644
--- a/absl/flags/internal/flag.cc
+++ b/absl/flags/internal/flag.cc
@@ -139,19 +139,43 @@ void DynValueDeleter::operator()(void* ptr) const {
 void FlagImpl::Init() {
   new (&data_guard_) absl::Mutex;
 
-  // At this point the default_value_ always points to gen_func.
+  auto def_kind = static_cast<FlagDefaultKind>(def_kind_);
+
   switch (ValueStorageKind()) {
     case FlagValueStorageKind::kAlignedBuffer:
+      // For this storage kind the default_value_ always points to gen_func
+      // during initialization.
+      assert(def_kind == FlagDefaultKind::kGenFunc);
       (*default_value_.gen_func)(AlignedBufferValue());
       break;
     case FlagValueStorageKind::kOneWordAtomic: {
       alignas(int64_t) std::array<char, sizeof(int64_t)> buf{};
-      (*default_value_.gen_func)(buf.data());
-      auto value = absl::bit_cast<int64_t>(buf);
-      OneWordValue().store(value, std::memory_order_release);
+      switch (def_kind) {
+        case FlagDefaultKind::kOneWord:
+          std::memcpy(buf.data(), &default_value_.one_word,
+                      sizeof(default_value_.one_word));
+          break;
+        case FlagDefaultKind::kFloat:
+          std::memcpy(buf.data(), &default_value_.float_value,
+                      sizeof(default_value_.float_value));
+          break;
+        case FlagDefaultKind::kDouble:
+          std::memcpy(buf.data(), &default_value_.double_value,
+                      sizeof(default_value_.double_value));
+          break;
+        default:
+          assert(def_kind == FlagDefaultKind::kGenFunc);
+          (*default_value_.gen_func)(buf.data());
+          break;
+      }
+      OneWordValue().store(absl::bit_cast<int64_t>(buf),
+                           std::memory_order_release);
       break;
     }
     case FlagValueStorageKind::kTwoWordsAtomic: {
+      // For this storage kind the default_value_ always points to gen_func
+      // during initialization.
+      assert(def_kind == FlagDefaultKind::kGenFunc);
       alignas(AlignedTwoWords) std::array<char, sizeof(AlignedTwoWords)> buf{};
       (*default_value_.gen_func)(buf.data());
       auto atomic_value = absl::bit_cast<AlignedTwoWords>(buf);
@@ -196,11 +220,23 @@ void FlagImpl::AssertValidType(FlagFastTypeId rhs_type_id,
 
 std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const {
   void* res = nullptr;
-  if (DefaultKind() == FlagDefaultKind::kDynamicValue) {
-    res = flags_internal::Clone(op_, default_value_.dynamic_value);
-  } else {
-    res = flags_internal::Alloc(op_);
-    (*default_value_.gen_func)(res);
+  switch (DefaultKind()) {
+    case FlagDefaultKind::kDynamicValue:
+      res = flags_internal::Clone(op_, default_value_.dynamic_value);
+      break;
+    case FlagDefaultKind::kGenFunc:
+      res = flags_internal::Alloc(op_);
+      (*default_value_.gen_func)(res);
+      break;
+    case FlagDefaultKind::kOneWord:
+      res = flags_internal::Clone(op_, &default_value_.one_word);
+      break;
+    case FlagDefaultKind::kFloat:
+      res = flags_internal::Clone(op_, &default_value_.float_value);
+      break;
+    case FlagDefaultKind::kDouble:
+      res = flags_internal::Clone(op_, &default_value_.double_value);
+      break;
   }
   return {res, DynValueDeleter{op_}};
 }
@@ -235,8 +271,6 @@ std::string FlagImpl::Filename() const {
   return flags_internal::GetUsageConfig().normalize_filename(filename_);
 }
 
-absl::string_view FlagImpl::Typename() const { return ""; }
-
 std::string FlagImpl::Help() const {
   return HelpSourceKind() == FlagHelpKind::kLiteral ? help_.literal
                                                     : help_.gen_func();
@@ -246,11 +280,6 @@ FlagFastTypeId FlagImpl::TypeId() const {
   return flags_internal::FastTypeId(op_);
 }
 
-bool FlagImpl::IsModified() const {
-  absl::MutexLock l(DataGuard());
-  return modified_;
-}
-
 bool FlagImpl::IsSpecifiedOnCommandLine() const {
   absl::MutexLock l(DataGuard());
   return on_command_line_;
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index 6da25aa9454a..b2208824508d 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -206,12 +206,72 @@ using FlagDfltGenFunc = void (*)(void*);
 union FlagDefaultSrc {
   constexpr explicit FlagDefaultSrc(FlagDfltGenFunc gen_func_arg)
       : gen_func(gen_func_arg) {}
+  template <typename T>
+  constexpr explicit FlagDefaultSrc(T one_word_value)
+      : one_word(static_cast<int64_t>(one_word_value)) {}
+  constexpr explicit FlagDefaultSrc(float f) : float_value(f) {}
+  constexpr explicit FlagDefaultSrc(double d) : double_value(d) {}
 
   void* dynamic_value;
   FlagDfltGenFunc gen_func;
+  int64_t one_word;
+  float float_value;
+  double double_value;
+};
+
+enum class FlagDefaultKind : uint8_t {
+  kDynamicValue = 0,
+  kGenFunc = 1,
+  kOneWord = 2,
+  kFloat = 3,
+  kDouble = 4
+};
+
+struct FlagDefaultArg {
+  FlagDefaultSrc source;
+  FlagDefaultKind kind;
 };
 
-enum class FlagDefaultKind : uint8_t { kDynamicValue = 0, kGenFunc = 1 };
+// This struct and corresponding overload to InitDefaultValue are used to
+// facilitate usage of {} as default value in ABSL_FLAG macro.
+// TODO(rogeeff): Fix handling types with explicit constructors.
+struct EmptyBraces {};
+
+template <typename T>
+constexpr T InitDefaultValue(T t) {
+  return t;
+}
+
+template <typename T>
+constexpr T InitDefaultValue(EmptyBraces) {
+  return T{};
+}
+
+template <typename ValueT, typename GenT,
+          typename std::enable_if<std::is_integral<ValueT>::value, int>::type =
+              (GenT{}, 0)>
+constexpr FlagDefaultArg DefaultArg(int) {
+  return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kOneWord};
+}
+
+template <typename ValueT, typename GenT,
+          typename std::enable_if<std::is_same<ValueT, float>::value,
+                                  int>::type = (GenT{}, 0)>
+constexpr FlagDefaultArg DefaultArg(int) {
+  return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kFloat};
+}
+
+template <typename ValueT, typename GenT,
+          typename std::enable_if<std::is_same<ValueT, double>::value,
+                                  int>::type = (GenT{}, 0)>
+constexpr FlagDefaultArg DefaultArg(int) {
+  return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kDouble};
+}
+
+template <typename ValueT, typename GenT>
+constexpr FlagDefaultArg DefaultArg(char) {
+  return {FlagDefaultSrc(&GenT::Gen), FlagDefaultKind::kGenFunc};
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 // Flag current value auxiliary structs.
@@ -356,19 +416,19 @@ 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)
+                     FlagDefaultArg default_arg)
       : 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)),
+        def_kind_(static_cast<uint8_t>(default_arg.kind)),
         modified_(false),
         on_command_line_(false),
         counter_(0),
         callback_(nullptr),
-        default_value_(default_value_gen),
+        default_value_(default_arg.source),
         data_guard_{} {}
 
   // Constant access methods
@@ -444,10 +504,8 @@ class FlagImpl final : public flags_internal::CommandLineFlag {
   // 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());
@@ -492,9 +550,10 @@ class FlagImpl final : public flags_internal::CommandLineFlag {
 
   // 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());
+  // def_kind_ is not guard by DataGuard() since it is accessed in Init without
+  // locks. If necessary we can decrease number of bits used to 2 by folding
+  // one_word storage cases.
+  uint8_t def_kind_ : 3;
   // Has this flag's value been modified?
   bool modified_ : 1 ABSL_GUARDED_BY(*DataGuard());
   // Has this flag been specified on command line.
@@ -530,10 +589,10 @@ class FlagImpl final : public flags_internal::CommandLineFlag {
 template <typename T>
 class Flag {
  public:
-  constexpr Flag(const char* name, const char* filename, const FlagHelpArg help,
-                 const FlagDfltGenFunc default_value_gen)
+  constexpr Flag(const char* name, const char* filename, FlagHelpArg help,
+                 const FlagDefaultArg default_arg)
       : impl_(name, filename, &FlagOps<T>, help,
-              flags_internal::StorageKind<T>(), default_value_gen),
+              flags_internal::StorageKind<T>(), default_arg),
         value_() {}
 
   T Get() const {
@@ -560,9 +619,7 @@ class Flag {
   // 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();
   }
@@ -662,20 +719,6 @@ class FlagRegistrar {
   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_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/flags/internal/registry.cc b/absl/flags/internal/registry.cc
index eb619c7086ad..62b5b40d88b8 100644
--- a/absl/flags/internal/registry.cc
+++ b/absl/flags/internal/registry.cc
@@ -127,14 +127,13 @@ void FlagRegistry::RegisterFlag(CommandLineFlag* flag) {
               (flag->IsRetired() ? old_flag->Filename() : flag->Filename()),
               "'."),
           true);
-    } else if (flag->TypeId() != old_flag->TypeId()) {
+    } else if (flags_internal::PrivateHandleInterface::TypeId(*flag) !=
+               flags_internal::PrivateHandleInterface::TypeId(*old_flag)) {
       flags_internal::ReportUsageError(
           absl::StrCat("Flag '", flag->Name(),
                        "' was defined more than once but with "
                        "differing types. Defined in files '",
-                       old_flag->Filename(), "' and '", flag->Filename(),
-                       "' with types '", old_flag->Typename(), "' and '",
-                       flag->Typename(), "', respectively."),
+                       old_flag->Filename(), "' and '", flag->Filename(), "'."),
           true);
     } else if (old_flag->IsRetired()) {
       // Retired flag can just be deleted.
@@ -206,7 +205,8 @@ class FlagSaverImpl {
   void SaveFromRegistry() {
     assert(backup_registry_.empty());  // call only once!
     flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) {
-      if (auto flag_state = flag->SaveState()) {
+      if (auto flag_state =
+              flags_internal::PrivateHandleInterface::SaveState(flag)) {
         backup_registry_.emplace_back(std::move(flag_state));
       }
     });
@@ -290,11 +290,9 @@ class RetiredFlagObj final : public flags_internal::CommandLineFlag {
  private:
   absl::string_view Name() const override { return name_; }
   std::string Filename() const override { return "RETIRED"; }
-  absl::string_view Typename() const override { return ""; }
   FlagFastTypeId TypeId() const override { return type_id_; }
   std::string Help() const override { return ""; }
   bool IsRetired() const override { return true; }
-  bool IsModified() const override { return false; }
   bool IsSpecifiedOnCommandLine() const override { return false; }
   std::string DefaultValue() const override { return ""; }
   std::string CurrentValue() const override { return ""; }
diff --git a/absl/flags/internal/type_erased.cc b/absl/flags/internal/type_erased.cc
index 75b4cdf891a8..5038625be761 100644
--- a/absl/flags/internal/type_erased.cc
+++ b/absl/flags/internal/type_erased.cc
@@ -72,7 +72,9 @@ bool IsValidFlagValue(absl::string_view name, absl::string_view value) {
   CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
 
   return flag != nullptr &&
-         (flag->IsRetired() || flag->ValidateInputValue(value));
+         (flag->IsRetired() ||
+          flags_internal::PrivateHandleInterface::ValidateInputValue(*flag,
+                                                                     value));
 }
 
 // --------------------------------------------------------------------
diff --git a/absl/flags/internal/type_erased.h b/absl/flags/internal/type_erased.h
index 188429c77129..ffe319bad945 100644
--- a/absl/flags/internal/type_erased.h
+++ b/absl/flags/internal/type_erased.h
@@ -75,7 +75,7 @@ inline bool GetByName(absl::string_view name, T* dst) {
   CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
   if (!flag) return false;
 
-  if (auto val = flag->Get<T>()) {
+  if (auto val = flag->TryGet<T>()) {
     *dst = *val;
     return true;
   }
diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc
index a9a5cba94de8..9d856c87a6c0 100644
--- a/absl/flags/internal/usage.cc
+++ b/absl/flags/internal/usage.cc
@@ -54,27 +54,6 @@ ABSL_NAMESPACE_BEGIN
 namespace flags_internal {
 namespace {
 
-absl::string_view TypenameForHelp(const flags_internal::CommandLineFlag& flag) {
-  // Only report names of v1 built-in types
-#define HANDLE_V1_BUILTIN_TYPE(t) \
-  if (flag.IsOfType<t>()) {       \
-    return #t;                    \
-  }
-
-  HANDLE_V1_BUILTIN_TYPE(bool);
-  HANDLE_V1_BUILTIN_TYPE(int32_t);
-  HANDLE_V1_BUILTIN_TYPE(int64_t);
-  HANDLE_V1_BUILTIN_TYPE(uint64_t);
-  HANDLE_V1_BUILTIN_TYPE(double);
-#undef HANDLE_V1_BUILTIN_TYPE
-
-  if (flag.IsOfType<std::string>()) {
-    return "string";
-  }
-
-  return "";
-}
-
 // This class is used to emit an XML element with `tag` and `text`.
 // It adds opening and closing tags and escapes special characters in the text.
 // For example:
@@ -212,23 +191,20 @@ void FlagHelpHumanReadable(const flags_internal::CommandLineFlag& flag,
   // Flag help.
   printer.Write(absl::StrCat("(", flag.Help(), ");"), /*wrap_line=*/true);
 
-  // Flag data type (for V1 flags only).
-  if (!flag.IsAbseilFlag() && !flag.IsRetired()) {
-    printer.Write(absl::StrCat("type: ", TypenameForHelp(flag), ";"));
-  }
-
   // The listed default value will be the actual default from the flag
   // definition in the originating source file, unless the value has
   // subsequently been modified using SetCommandLineOption() with mode
   // SET_FLAGS_DEFAULT.
   std::string dflt_val = flag.DefaultValue();
+  std::string curr_val = flag.CurrentValue();
+  bool is_modified = curr_val != dflt_val;
+
   if (flag.IsOfType<std::string>()) {
     dflt_val = absl::StrCat("\"", dflt_val, "\"");
   }
   printer.Write(absl::StrCat("default: ", dflt_val, ";"));
 
-  if (flag.IsModified()) {
-    std::string curr_val = flag.CurrentValue();
+  if (is_modified) {
     if (flag.IsOfType<std::string>()) {
       curr_val = absl::StrCat("\"", curr_val, "\"");
     }