summaryrefslogtreecommitdiff
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 9b32f467..bc50de54 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) && {