aboutsummaryrefslogtreecommitdiffhomepage
path: root/absl/flags/internal
diff options
context:
space:
mode:
Diffstat (limited to 'absl/flags/internal')
-rw-r--r--absl/flags/internal/commandlineflag.h124
-rw-r--r--absl/flags/internal/flag.cc76
-rw-r--r--absl/flags/internal/flag.h113
-rw-r--r--absl/flags/internal/registry.cc12
-rw-r--r--absl/flags/internal/registry.h4
5 files changed, 162 insertions, 167 deletions
diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h
index 4ac5019..6363c66 100644
--- a/absl/flags/internal/commandlineflag.h
+++ b/absl/flags/internal/commandlineflag.h
@@ -34,22 +34,23 @@ namespace absl {
ABSL_NAMESPACE_BEGIN
namespace flags_internal {
-// Type-specific operations, eg., parsing, copying, etc. are provided
-// by function specific to that type with a signature matching FlagOpFn.
-enum FlagOp {
- kDelete,
- kClone,
- kCopy,
- kCopyConstruct,
- kSizeof,
- kParse,
- kUnparse,
+// An alias for flag static type id. Values of type identify the flag value type
+// simialarly to typeid(T), but without relying on RTTI being available. In most
+// cases this id is enough to uniquely identify the flag's value type. In a few
+// cases we'll have to resort to using actual RTTI implementation if it is
+// available.
+using FlagStaticTypeId = void* (*)();
+
+// Address of this function template is used in current implementation as a flag
+// static type id.
+template <typename T>
+void* FlagStaticTypeIdGen() {
#if defined(ABSL_FLAGS_INTERNAL_HAS_RTTI)
- kRuntimeTypeId
+ return const_cast<std::type_info*>(&typeid(T));
+#else
+ return nullptr;
#endif
-};
-using FlagOpFn = void* (*)(FlagOp, const void*, void*);
-using FlagMarshallingOpFn = void* (*)(FlagOp, const void*, void*, void*);
+}
// Options that control SetCommandLineOptionWithMode.
enum FlagSettingMode {
@@ -72,97 +73,6 @@ enum ValueSource {
kProgrammaticChange,
};
-// The per-type function
-template <typename T>
-void* FlagOps(FlagOp op, const void* v1, void* v2) {
- switch (op) {
- case kDelete:
- delete static_cast<const T*>(v1);
- return nullptr;
- case kClone:
- return new T(*static_cast<const T*>(v1));
- case kCopy:
- *static_cast<T*>(v2) = *static_cast<const T*>(v1);
- return nullptr;
- case kCopyConstruct:
- new (v2) T(*static_cast<const T*>(v1));
- return nullptr;
- case kSizeof:
- return reinterpret_cast<void*>(sizeof(T));
-#if defined(ABSL_FLAGS_INTERNAL_HAS_RTTI)
- case kRuntimeTypeId:
- return const_cast<std::type_info*>(&typeid(T));
- break;
-#endif
- default:
- return nullptr;
- }
-}
-
-template <typename T>
-void* FlagMarshallingOps(FlagOp op, const void* v1, void* v2, void* v3) {
- switch (op) {
- case 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 kUnparse:
- *static_cast<std::string*>(v2) =
- absl::UnparseFlag<T>(*static_cast<const T*>(v1));
- return nullptr;
- default:
- return nullptr;
- }
-}
-
-// Functions that invoke flag-type-specific operations.
-inline void Delete(FlagOpFn op, const void* obj) {
- op(flags_internal::kDelete, obj, nullptr);
-}
-
-inline void* Clone(FlagOpFn op, const void* obj) {
- return op(flags_internal::kClone, obj, nullptr);
-}
-
-inline void Copy(FlagOpFn op, const void* src, void* dst) {
- op(flags_internal::kCopy, src, dst);
-}
-
-inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) {
- op(flags_internal::kCopyConstruct, src, dst);
-}
-
-inline bool Parse(FlagMarshallingOpFn op, absl::string_view text, void* dst,
- std::string* error) {
- return op(flags_internal::kParse, &text, dst, error) != nullptr;
-}
-
-inline std::string Unparse(FlagMarshallingOpFn op, const void* val) {
- std::string result;
- op(flags_internal::kUnparse, val, &result, nullptr);
- return result;
-}
-
-inline size_t Sizeof(FlagOpFn op) {
- // This sequence of casts reverses the sequence from base::internal::FlagOps()
- return static_cast<size_t>(reinterpret_cast<intptr_t>(
- op(flags_internal::kSizeof, nullptr, nullptr)));
-}
-
-#if defined(ABSL_FLAGS_INTERNAL_HAS_RTTI)
-inline const std::type_info& RuntimeTypeId(FlagOpFn op) {
- return *static_cast<const std::type_info*>(
- op(flags_internal::kRuntimeTypeId, nullptr, nullptr));
-}
-#endif
-
// Handle to FlagState objects. Specific flag state objects will restore state
// of a flag produced this flag state from method CommandLineFlag::SaveState().
class FlagStateInterface {
@@ -187,7 +97,7 @@ class CommandLineFlag {
// Return true iff flag has type T.
template <typename T>
inline bool IsOfType() const {
- return TypeId() == &flags_internal::FlagOps<T>;
+ return TypeId() == &flags_internal::FlagStaticTypeIdGen<T>;
}
// Attempts to retrieve the flag value. Returns value on success,
@@ -240,7 +150,7 @@ class CommandLineFlag {
// 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 FlagStaticTypeId TypeId() const = 0;
virtual bool IsModified() const = 0;
virtual bool IsSpecifiedOnCommandLine() const = 0;
virtual std::string DefaultValue() const = 0;
diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc
index 721e411..83ec8df 100644
--- a/absl/flags/internal/flag.cc
+++ b/absl/flags/internal/flag.cc
@@ -47,23 +47,15 @@ const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001";
namespace {
// Currently we only validate flag values for user-defined flag types.
-bool ShouldValidateFlagValue(FlagOpFn flag_type_id) {
+bool ShouldValidateFlagValue(FlagStaticTypeId flag_type_id) {
#define DONT_VALIDATE(T) \
- if (flag_type_id == &flags_internal::FlagOps<T>) return false;
+ if (flag_type_id == &FlagStaticTypeIdGen<T>) return false;
ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(DONT_VALIDATE)
#undef DONT_VALIDATE
return true;
}
-#if defined(ABSL_FLAGS_INTERNAL_HAS_RTTI)
-bool MatchRuntimeTypeId(FlagOpFn lhs_type_id, FlagOpFn rhs_type_id) {
- return RuntimeTypeId(lhs_type_id) == RuntimeTypeId(rhs_type_id);
-}
-#else
-bool MatchRuntimeTypeId(FlagOpFn, FlagOpFn) { return true; }
-#endif
-
// RAII helper used to temporarily unlock and relock `absl::Mutex`.
// This is used when we need to ensure that locks are released while
// invoking user supplied callbacks and then reacquired, since callbacks may
@@ -101,22 +93,35 @@ absl::Mutex* FlagImpl::DataGuard() const {
return reinterpret_cast<absl::Mutex*>(&data_guard_);
}
-void FlagImpl::AssertValidType(const flags_internal::FlagOpFn op) const {
- // `op` is the unmarshaling operation corresponding to the declaration
- // visibile at the call site. `op_` is the Flag's defined unmarshalling
- // operation. They must match for this operation to be well-defined.
- if (ABSL_PREDICT_FALSE(op != op_) && !MatchRuntimeTypeId(op, op_)) {
- ABSL_INTERNAL_LOG(
- FATAL,
- absl::StrCat("Flag '", Name(),
- "' is defined as one type and declared as another"));
- }
+void FlagImpl::AssertValidType(FlagStaticTypeId type_id) const {
+ FlagStaticTypeId this_type_id = flags_internal::StaticTypeId(op_);
+
+ // `type_id` is the type id corresponding to the declaration visibile at the
+ // call site. `this_type_id` is the type id corresponding to the type stored
+ // during flag definition. They must match for this operation to be
+ // well-defined.
+ if (ABSL_PREDICT_TRUE(type_id == this_type_id)) return;
+
+ void* lhs_runtime_type_id = type_id();
+ void* rhs_runtime_type_id = this_type_id();
+
+ if (lhs_runtime_type_id == rhs_runtime_type_id) return;
+
+#if defined(ABSL_FLAGS_INTERNAL_HAS_RTTI)
+ if (*reinterpret_cast<std::type_info*>(lhs_runtime_type_id) ==
+ *reinterpret_cast<std::type_info*>(rhs_runtime_type_id))
+ return;
+#endif
+
+ ABSL_INTERNAL_LOG(
+ FATAL, absl::StrCat("Flag '", Name(),
+ "' is defined as one type and declared as another"));
}
std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const {
void* res = nullptr;
if (DefaultKind() == FlagDefaultKind::kDynamicValue) {
- res = Clone(op_, default_src_.dynamic_value);
+ res = flags_internal::Clone(op_, default_src_.dynamic_value);
} else {
res = (*default_src_.gen_func)();
}
@@ -148,13 +153,13 @@ std::string FlagImpl::DefaultValue() const {
absl::MutexLock l(DataGuard());
auto obj = MakeInitValue();
- return Unparse(marshalling_op_, obj.get());
+ return flags_internal::Unparse(op_, obj.get());
}
std::string FlagImpl::CurrentValue() const {
absl::MutexLock l(DataGuard());
- return Unparse(marshalling_op_, value_.dynamic);
+ return flags_internal::Unparse(op_, value_.dynamic);
}
void FlagImpl::SetCallback(const FlagCallbackFunc mutation_callback) {
@@ -220,7 +225,7 @@ bool FlagImpl::TryParse(void** dst, absl::string_view value,
auto tentative_value = MakeInitValue();
std::string parse_err;
- if (!Parse(marshalling_op_, value, tentative_value.get(), &parse_err)) {
+ if (!flags_internal::Parse(op_, value, tentative_value.get(), &parse_err)) {
absl::string_view err_sep = parse_err.empty() ? "" : "; ";
*err = absl::StrCat("Illegal value '", value, "' specified for flag '",
Name(), "'", err_sep, parse_err);
@@ -237,11 +242,11 @@ bool FlagImpl::TryParse(void** dst, absl::string_view value,
void FlagImpl::Read(void* dst) const {
absl::ReaderMutexLock l(DataGuard());
- CopyConstruct(op_, value_.dynamic, dst);
+ flags_internal::CopyConstruct(op_, value_.dynamic, dst);
}
void FlagImpl::StoreAtomic() {
- size_t data_size = Sizeof(op_);
+ size_t data_size = flags_internal::Sizeof(op_);
if (data_size <= sizeof(int64_t)) {
int64_t t = 0;
@@ -260,20 +265,20 @@ void FlagImpl::StoreAtomic() {
void FlagImpl::Write(const void* src) {
absl::MutexLock l(DataGuard());
- if (ShouldValidateFlagValue(op_)) {
- void* obj = Clone(op_, src);
+ if (ShouldValidateFlagValue(flags_internal::StaticTypeId(op_))) {
+ void* obj = flags_internal::Clone(op_, src);
std::string ignored_error;
- std::string src_as_str = Unparse(marshalling_op_, src);
- if (!Parse(marshalling_op_, src_as_str, obj, &ignored_error)) {
+ std::string src_as_str = flags_internal::Unparse(op_, src);
+ if (!flags_internal::Parse(op_, src_as_str, obj, &ignored_error)) {
ABSL_INTERNAL_LOG(ERROR, absl::StrCat("Attempt to set flag '", Name(),
"' to invalid value ", src_as_str));
}
- Delete(op_, obj);
+ flags_internal::Delete(op_, obj);
}
modified_ = true;
counter_++;
- Copy(op_, src, value_.dynamic);
+ flags_internal::Copy(op_, src, value_.dynamic);
StoreAtomic();
InvokeCallback();
@@ -341,7 +346,7 @@ bool FlagImpl::SetFromString(absl::string_view value, FlagSettingMode set_mode,
if (!modified_) {
// Need to set both default value *and* current, in this case
- Copy(op_, default_src_.dynamic_value, value_.dynamic);
+ flags_internal::Copy(op_, default_src_.dynamic_value, value_.dynamic);
StoreAtomic();
InvokeCallback();
}
@@ -359,7 +364,7 @@ void FlagImpl::CheckDefaultValueParsingRoundtrip() const {
auto dst = MakeInitValue();
std::string error;
- if (!flags_internal::Parse(marshalling_op_, v, dst.get(), &error)) {
+ if (!flags_internal::Parse(op_, v, dst.get(), &error)) {
ABSL_INTERNAL_LOG(
FATAL,
absl::StrCat("Flag ", Name(), " (from ", Filename(),
@@ -376,8 +381,7 @@ bool FlagImpl::ValidateInputValue(absl::string_view value) const {
auto obj = MakeInitValue();
std::string ignored_error;
- return flags_internal::Parse(marshalling_op_, value, obj.get(),
- &ignored_error);
+ return flags_internal::Parse(op_, value, obj.get(), &ignored_error);
}
} // namespace flags_internal
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index b426ccb..1c2f15d 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -43,6 +43,94 @@ template <typename T>
class Flag;
///////////////////////////////////////////////////////////////////////////////
+// Type-specific operations, eg., parsing, copying, etc. are provided
+// by function specific to that type with a signature matching FlagOpFn.
+
+enum FlagOp {
+ kDelete,
+ kClone,
+ kCopy,
+ kCopyConstruct,
+ kSizeof,
+ kStaticTypeId,
+ kParse,
+ kUnparse,
+};
+using FlagOpFn = void* (*)(FlagOp, const void*, void*, void*);
+
+// The per-type function
+template <typename T>
+void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) {
+ switch (op) {
+ case flags_internal::kDelete:
+ delete static_cast<const T*>(v1);
+ return nullptr;
+ case flags_internal::kClone:
+ return new T(*static_cast<const T*>(v1));
+ case flags_internal::kCopy:
+ *static_cast<T*>(v2) = *static_cast<const T*>(v1);
+ return nullptr;
+ case flags_internal::kCopyConstruct:
+ new (v2) T(*static_cast<const T*>(v1));
+ return nullptr;
+ case flags_internal::kSizeof:
+ return reinterpret_cast<void*>(sizeof(T));
+ case flags_internal::kStaticTypeId:
+ return reinterpret_cast<void*>(&FlagStaticTypeIdGen<T>);
+ case flags_internal::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 flags_internal::kUnparse:
+ *static_cast<std::string*>(v2) =
+ absl::UnparseFlag<T>(*static_cast<const T*>(v1));
+ return nullptr;
+ default:
+ return nullptr;
+ }
+}
+
+// Functions that invoke flag-type-specific operations.
+inline void Delete(FlagOpFn op, const void* obj) {
+ op(flags_internal::kDelete, obj, nullptr, nullptr);
+}
+inline void* Clone(FlagOpFn op, const void* obj) {
+ return op(flags_internal::kClone, obj, nullptr, nullptr);
+}
+inline void Copy(FlagOpFn op, const void* src, void* dst) {
+ op(flags_internal::kCopy, src, dst, nullptr);
+}
+inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) {
+ op(flags_internal::kCopyConstruct, src, dst, nullptr);
+}
+inline bool Parse(FlagOpFn op, absl::string_view text, void* dst,
+ std::string* error) {
+ return op(flags_internal::kParse, &text, dst, error) != nullptr;
+}
+inline std::string Unparse(FlagOpFn op, const void* val) {
+ std::string result;
+ op(flags_internal::kUnparse, val, &result, nullptr);
+ return result;
+}
+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(flags_internal::kSizeof, nullptr, nullptr, nullptr)));
+}
+inline FlagStaticTypeId StaticTypeId(FlagOpFn op) {
+ return reinterpret_cast<FlagStaticTypeId>(
+ op(flags_internal::kStaticTypeId, nullptr, nullptr, nullptr));
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Persistent state of the flag data.
template <typename T>
@@ -273,12 +361,10 @@ struct DynValueDeleter {
class FlagImpl {
public:
constexpr FlagImpl(const char* name, const char* filename, FlagOpFn op,
- FlagMarshallingOpFn marshalling_op, FlagHelpArg help,
- FlagDfltGenFunc default_value_gen)
+ FlagHelpArg help, FlagDfltGenFunc default_value_gen)
: name_(name),
filename_(filename),
op_(op),
- marshalling_op_(marshalling_op),
help_(help.source),
help_source_kind_(static_cast<uint8_t>(help.kind)),
def_kind_(static_cast<uint8_t>(FlagDefaultKind::kGenFunc)),
@@ -306,7 +392,7 @@ class FlagImpl {
template <typename T, typename std::enable_if<
!IsAtomicFlagTypeTrait<T>::value, int>::type = 0>
void Get(T* dst) const {
- AssertValidType(&flags_internal::FlagOps<T>);
+ AssertValidType(&flags_internal::FlagStaticTypeIdGen<T>);
Read(dst);
}
// Overload for `GetFlag()` for types that support lock-free reads.
@@ -317,7 +403,7 @@ class FlagImpl {
// slowing down flag value access due to type validation. That's why
// this validation is hidden behind !NDEBUG
#ifndef NDEBUG
- AssertValidType(&flags_internal::FlagOps<T>);
+ AssertValidType(&flags_internal::FlagStaticTypeIdGen<T>);
#endif
using U = flags_internal::BestAtomicType<T>;
typename U::type r = value_.atomics.template load<T>();
@@ -329,7 +415,7 @@ class FlagImpl {
}
template <typename T>
void Set(const T& src) {
- AssertValidType(&flags_internal::FlagOps<T>);
+ AssertValidType(&flags_internal::FlagStaticTypeIdGen<T>);
Write(&src);
}
@@ -388,7 +474,7 @@ class FlagImpl {
// int. To do that we pass the "assumed" type id (which is deduced from type
// int) as an argument `op`, which is in turn is validated against the type id
// stored in flag object by flag definition statement.
- void AssertValidType(const flags_internal::FlagOpFn op) const;
+ void AssertValidType(FlagStaticTypeId type_id) const;
// Immutable flag's state.
@@ -396,10 +482,8 @@ class FlagImpl {
const char* const name_;
// The file name where ABSL_FLAG resides.
const char* const filename_;
- // Type-specific handler.
+ // Type-specific operations "vtable".
const FlagOpFn op_;
- // Marshalling ops handler.
- const FlagMarshallingOpFn marshalling_op_;
// Help message literal or function to generate it.
const FlagHelpMsg help_;
// Indicates if help message was supplied as literal or generator func.
@@ -456,12 +540,9 @@ class FlagImpl {
template <typename T>
class Flag final : public flags_internal::CommandLineFlag {
public:
- constexpr Flag(const char* name, const char* filename,
- const FlagMarshallingOpFn marshalling_op,
- const FlagHelpArg help,
+ constexpr Flag(const char* name, const char* filename, const FlagHelpArg help,
const FlagDfltGenFunc default_value_gen)
- : impl_(name, filename, &FlagOps<T>, marshalling_op, help,
- default_value_gen) {}
+ : impl_(name, filename, &FlagOps<T>, help, default_value_gen) {}
T Get() const {
// See implementation notes in CommandLineFlag::Get().
@@ -520,7 +601,7 @@ class Flag final : public flags_internal::CommandLineFlag {
friend class FlagState<T>;
void Read(void* dst) const override { impl_.Read(dst); }
- FlagOpFn TypeId() const override { return &FlagOps<T>; }
+ FlagStaticTypeId TypeId() const override { return &FlagStaticTypeIdGen<T>; }
// Flag's data
FlagImpl impl_;
diff --git a/absl/flags/internal/registry.cc b/absl/flags/internal/registry.cc
index 2ef16e8..e434a85 100644
--- a/absl/flags/internal/registry.cc
+++ b/absl/flags/internal/registry.cc
@@ -284,14 +284,14 @@ namespace {
class RetiredFlagObj final : public flags_internal::CommandLineFlag {
public:
- constexpr RetiredFlagObj(const char* name, FlagOpFn ops)
- : name_(name), op_(ops) {}
+ constexpr RetiredFlagObj(const char* name, FlagStaticTypeId type_id)
+ : name_(name), type_id_(type_id) {}
private:
absl::string_view Name() const override { return name_; }
std::string Filename() const override { return "RETIRED"; }
absl::string_view Typename() const override { return ""; }
- flags_internal::FlagOpFn TypeId() const override { return op_; }
+ FlagStaticTypeId TypeId() const override { return type_id_; }
std::string Help() const override { return ""; }
bool IsRetired() const override { return true; }
bool IsModified() const override { return false; }
@@ -317,7 +317,7 @@ class RetiredFlagObj final : public flags_internal::CommandLineFlag {
// Data members
const char* const name_;
- const FlagOpFn op_;
+ const FlagStaticTypeId type_id_;
};
void DestroyRetiredFlag(flags_internal::CommandLineFlag* flag) {
@@ -327,8 +327,8 @@ void DestroyRetiredFlag(flags_internal::CommandLineFlag* flag) {
} // namespace
-bool Retire(const char* name, FlagOpFn ops) {
- auto* flag = new flags_internal::RetiredFlagObj(name, ops);
+bool Retire(const char* name, FlagStaticTypeId type_id) {
+ auto* flag = new flags_internal::RetiredFlagObj(name, type_id);
FlagRegistry::GlobalRegistry()->RegisterFlag(flag);
return true;
}
diff --git a/absl/flags/internal/registry.h b/absl/flags/internal/registry.h
index 99cb685..69ff889 100644
--- a/absl/flags/internal/registry.h
+++ b/absl/flags/internal/registry.h
@@ -79,12 +79,12 @@ bool RegisterCommandLineFlag(CommandLineFlag*);
//
// Retire flag with name "name" and type indicated by ops.
-bool Retire(const char* name, FlagOpFn ops);
+bool Retire(const char* name, FlagStaticTypeId type_id);
// Registered a retired flag with name 'flag_name' and type 'T'.
template <typename T>
inline bool RetiredFlag(const char* flag_name) {
- return flags_internal::Retire(flag_name, flags_internal::FlagOps<T>);
+ return flags_internal::Retire(flag_name, &FlagStaticTypeIdGen<T>);
}
// If the flag is retired, returns true and indicates in |*type_is_bool|