about summary refs log tree commit diff
path: root/absl/flags/internal
diff options
context:
space:
mode:
Diffstat (limited to 'absl/flags/internal')
-rw-r--r--absl/flags/internal/flag.cc73
-rw-r--r--absl/flags/internal/flag.h103
2 files changed, 91 insertions, 85 deletions
diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc
index f3c424ad83d8..089567f7ae50 100644
--- a/absl/flags/internal/flag.cc
+++ b/absl/flags/internal/flag.cc
@@ -92,9 +92,9 @@ class FlagState : public flags_internal::FlagStateInterface {
         counter_(counter) {}
 
   ~FlagState() override {
-    if (flag_impl_->ValueStorageKind() != FlagValueStorageKind::kHeapAllocated)
+    if (flag_impl_->ValueStorageKind() != FlagValueStorageKind::kAlignedBuffer)
       return;
-    flags_internal::Delete(flag_impl_->op_, value_.dynamic);
+    flags_internal::Delete(flag_impl_->op_, value_.heap_allocated);
   }
 
  private:
@@ -112,11 +112,11 @@ class FlagState : public flags_internal::FlagStateInterface {
   // Flag and saved flag data.
   FlagImpl* flag_impl_;
   union SavedValue {
-    explicit SavedValue(void* v) : dynamic(v) {}
+    explicit SavedValue(void* v) : heap_allocated(v) {}
     explicit SavedValue(int64_t v) : one_word(v) {}
     explicit SavedValue(flags_internal::AlignedTwoWords v) : two_words(v) {}
 
-    void* dynamic;
+    void* heap_allocated;
     int64_t one_word;
     flags_internal::AlignedTwoWords two_words;
   } value_;
@@ -128,25 +128,33 @@ class FlagState : public flags_internal::FlagStateInterface {
 ///////////////////////////////////////////////////////////////////////////////
 // Flag implementation, which does not depend on flag value type.
 
+DynValueDeleter::DynValueDeleter(FlagOpFn op_arg) : op(op_arg) {}
+
+void DynValueDeleter::operator()(void* ptr) const {
+  if (op == nullptr) return;
+
+  Delete(op, ptr);
+}
+
 void FlagImpl::Init() {
   new (&data_guard_) absl::Mutex;
 
   // At this point the default_value_ always points to gen_func.
-  std::unique_ptr<void, DynValueDeleter> init_value(
-      (*default_value_.gen_func)(), DynValueDeleter{op_});
   switch (ValueStorageKind()) {
-    case FlagValueStorageKind::kHeapAllocated:
-      HeapAllocatedValue() = init_value.release();
+    case FlagValueStorageKind::kAlignedBuffer:
+      (*default_value_.gen_func)(AlignedBufferValue());
       break;
     case FlagValueStorageKind::kOneWordAtomic: {
-      int64_t atomic_value;
-      std::memcpy(&atomic_value, init_value.get(), Sizeof(op_));
-      OneWordValue().store(atomic_value, std::memory_order_release);
+      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);
       break;
     }
     case FlagValueStorageKind::kTwoWordsAtomic: {
-      AlignedTwoWords atomic_value{0, 0};
-      std::memcpy(&atomic_value, init_value.get(), Sizeof(op_));
+      alignas(AlignedTwoWords) std::array<char, sizeof(AlignedTwoWords)> buf{};
+      (*default_value_.gen_func)(buf.data());
+      auto atomic_value = absl::bit_cast<AlignedTwoWords>(buf);
       TwoWordsValue().store(atomic_value, std::memory_order_release);
       break;
     }
@@ -191,15 +199,16 @@ std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const {
   if (DefaultKind() == FlagDefaultKind::kDynamicValue) {
     res = flags_internal::Clone(op_, default_value_.dynamic_value);
   } else {
-    res = (*default_value_.gen_func)();
+    res = flags_internal::Alloc(op_);
+    (*default_value_.gen_func)(res);
   }
   return {res, DynValueDeleter{op_}};
 }
 
 void FlagImpl::StoreValue(const void* src) {
   switch (ValueStorageKind()) {
-    case FlagValueStorageKind::kHeapAllocated:
-      Copy(op_, src, HeapAllocatedValue());
+    case FlagValueStorageKind::kAlignedBuffer:
+      Copy(op_, src, AlignedBufferValue());
       break;
     case FlagValueStorageKind::kOneWordAtomic: {
       int64_t one_word_val = 0;
@@ -257,9 +266,9 @@ std::string FlagImpl::DefaultValue() const {
 std::string FlagImpl::CurrentValue() const {
   auto* guard = DataGuard();  // Make sure flag initialized
   switch (ValueStorageKind()) {
-    case FlagValueStorageKind::kHeapAllocated: {
+    case FlagValueStorageKind::kAlignedBuffer: {
       absl::MutexLock l(guard);
-      return flags_internal::Unparse(op_, HeapAllocatedValue());
+      return flags_internal::Unparse(op_, AlignedBufferValue());
     }
     case FlagValueStorageKind::kOneWordAtomic: {
       const auto one_word_val =
@@ -318,9 +327,9 @@ std::unique_ptr<FlagStateInterface> FlagImpl::SaveState() {
   bool modified = modified_;
   bool on_command_line = on_command_line_;
   switch (ValueStorageKind()) {
-    case FlagValueStorageKind::kHeapAllocated: {
+    case FlagValueStorageKind::kAlignedBuffer: {
       return absl::make_unique<FlagState>(
-          this, flags_internal::Clone(op_, HeapAllocatedValue()), modified,
+          this, flags_internal::Clone(op_, AlignedBufferValue()), modified,
           on_command_line, counter_);
     }
     case FlagValueStorageKind::kOneWordAtomic: {
@@ -345,8 +354,8 @@ bool FlagImpl::RestoreState(const FlagState& flag_state) {
   }
 
   switch (ValueStorageKind()) {
-    case FlagValueStorageKind::kHeapAllocated:
-      StoreValue(flag_state.value_.dynamic);
+    case FlagValueStorageKind::kAlignedBuffer:
+      StoreValue(flag_state.value_.heap_allocated);
       break;
     case FlagValueStorageKind::kOneWordAtomic:
       StoreValue(&flag_state.value_.one_word);
@@ -363,25 +372,27 @@ bool FlagImpl::RestoreState(const FlagState& flag_state) {
 }
 
 template <typename StorageT>
-typename StorageT::value_type& FlagImpl::OffsetValue() const {
+StorageT* FlagImpl::OffsetValue() const {
   char* p = reinterpret_cast<char*>(const_cast<FlagImpl*>(this));
   // The offset is deduced via Flag value type specific op_.
   size_t offset = flags_internal::ValueOffset(op_);
 
-  return reinterpret_cast<StorageT*>(p + offset)->value;
+  return reinterpret_cast<StorageT*>(p + offset);
 }
 
-void*& FlagImpl::HeapAllocatedValue() const {
-  assert(ValueStorageKind() == FlagValueStorageKind::kHeapAllocated);
-  return OffsetValue<FlagHeapAllocatedValue>();
+void* FlagImpl::AlignedBufferValue() const {
+  assert(ValueStorageKind() == FlagValueStorageKind::kAlignedBuffer);
+  return OffsetValue<void>();
 }
+
 std::atomic<int64_t>& FlagImpl::OneWordValue() const {
   assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic);
-  return OffsetValue<FlagOneWordValue>();
+  return OffsetValue<FlagOneWordValue>()->value;
 }
+
 std::atomic<AlignedTwoWords>& FlagImpl::TwoWordsValue() const {
   assert(ValueStorageKind() == FlagValueStorageKind::kTwoWordsAtomic);
-  return OffsetValue<FlagTwoWordsValue>();
+  return OffsetValue<FlagTwoWordsValue>()->value;
 }
 
 // Attempts to parse supplied `value` string using parsing routine in the `flag`
@@ -406,9 +417,9 @@ std::unique_ptr<void, DynValueDeleter> FlagImpl::TryParse(
 void FlagImpl::Read(void* dst) const {
   auto* guard = DataGuard();  // Make sure flag initialized
   switch (ValueStorageKind()) {
-    case FlagValueStorageKind::kHeapAllocated: {
+    case FlagValueStorageKind::kAlignedBuffer: {
       absl::MutexLock l(guard);
-      flags_internal::CopyConstruct(op_, HeapAllocatedValue(), dst);
+      flags_internal::CopyConstruct(op_, AlignedBufferValue(), dst);
       break;
     }
     case FlagValueStorageKind::kOneWordAtomic: {
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index ae42dedcd633..2ae3dce3d13d 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -46,8 +46,8 @@ namespace flags_internal {
 // by function specific to that type with a signature matching FlagOpFn.
 
 enum class FlagOp {
+  kAlloc,
   kDelete,
-  kClone,
   kCopy,
   kCopyConstruct,
   kSizeof,
@@ -63,13 +63,13 @@ using FlagOpFn = void* (*)(FlagOp, const void*, void*, void*);
 template <typename T>
 void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3);
 
-// Deletes memory interpreting obj as flag value type pointer.
-inline void Delete(FlagOpFn op, const void* obj) {
-  op(FlagOp::kDelete, obj, nullptr, nullptr);
+// Allocate aligned memory for a flag value.
+inline void* Alloc(FlagOpFn op) {
+  return op(FlagOp::kAlloc, nullptr, nullptr, nullptr);
 }
-// Makes a copy of flag value pointed by obj.
-inline void* Clone(FlagOpFn op, const void* obj) {
-  return op(FlagOp::kClone, obj, nullptr, nullptr);
+// Deletes memory interpreting obj as flag value type pointer.
+inline void Delete(FlagOpFn op, void* obj) {
+  op(FlagOp::kDelete, nullptr, obj, nullptr);
 }
 // Copies src to dst interpreting as flag value type pointers.
 inline void Copy(FlagOpFn op, const void* src, void* dst) {
@@ -80,6 +80,12 @@ inline void Copy(FlagOpFn op, const void* src, void* dst) {
 inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) {
   op(FlagOp::kCopyConstruct, src, dst, nullptr);
 }
+// Makes a copy of flag value pointed by obj.
+inline void* Clone(FlagOpFn op, const void* obj) {
+  void* res = flags_internal::Alloc(op);
+  flags_internal::CopyConstruct(op, obj, res);
+  return res;
+}
 // Returns true if parsing of input text is successfull.
 inline bool Parse(FlagOpFn op, absl::string_view text, void* dst,
                   std::string* error) {
@@ -195,7 +201,7 @@ constexpr FlagHelpArg HelpArg(char) {
 
 // Signature for the function generating the initial flag value (usually
 // based on default value supplied in flag's definition)
-using FlagDfltGenFunc = void* (*)();
+using FlagDfltGenFunc = void (*)(void*);
 
 union FlagDefaultSrc {
   constexpr explicit FlagDefaultSrc(FlagDfltGenFunc gen_func_arg)
@@ -253,46 +259,36 @@ using FlagUseTwoWordsStorage =
 #endif
 
 template <typename T>
-using FlagUseHeapStorage =
+using FlagUseBufferStorage =
     std::integral_constant<bool, !FlagUseOneWordStorage<T>::value &&
                                      !FlagUseTwoWordsStorage<T>::value>;
 
 enum class FlagValueStorageKind : uint8_t {
-  kHeapAllocated = 0,
+  kAlignedBuffer = 0,
   kOneWordAtomic = 1,
   kTwoWordsAtomic = 2
 };
 
 template <typename T>
 static constexpr FlagValueStorageKind StorageKind() {
-  return FlagUseHeapStorage<T>::value
-             ? FlagValueStorageKind::kHeapAllocated
+  return FlagUseBufferStorage<T>::value
+             ? FlagValueStorageKind::kAlignedBuffer
              : FlagUseOneWordStorage<T>::value
                    ? FlagValueStorageKind::kOneWordAtomic
-                   : FlagUseTwoWordsStorage<T>::value
-                         ? FlagValueStorageKind::kTwoWordsAtomic
-                         : FlagValueStorageKind::kHeapAllocated;
+                   : FlagValueStorageKind::kTwoWordsAtomic;
 }
 
-struct FlagHeapAllocatedValue {
-  using value_type = void*;
-
-  value_type value;
-};
-
 struct FlagOneWordValue {
-  using value_type = std::atomic<int64_t>;
   constexpr FlagOneWordValue() : value(UninitializedFlagValue()) {}
 
-  value_type value;
+  std::atomic<int64_t> value;
 };
 
 struct FlagTwoWordsValue {
-  using value_type = std::atomic<AlignedTwoWords>;
   constexpr FlagTwoWordsValue()
       : value(AlignedTwoWords{UninitializedFlagValue(), 0}) {}
 
-  value_type value;
+  std::atomic<AlignedTwoWords> value;
 };
 
 template <typename T,
@@ -300,9 +296,10 @@ template <typename T,
 struct FlagValue;
 
 template <typename T>
-struct FlagValue<T, FlagValueStorageKind::kHeapAllocated>
-    : FlagHeapAllocatedValue {
+struct FlagValue<T, FlagValueStorageKind::kAlignedBuffer> {
   bool Get(T*) const { return false; }
+
+  alignas(T) char value[sizeof(T)];
 };
 
 template <typename T>
@@ -347,10 +344,8 @@ struct FlagCallback {
 // The class encapsulates the Flag's data and access to it.
 
 struct DynValueDeleter {
-  explicit DynValueDeleter(FlagOpFn op_arg = nullptr) : op(op_arg) {}
-  void operator()(void* ptr) const {
-    if (op != nullptr) flags_internal::Delete(op, ptr);
-  }
+  explicit DynValueDeleter(FlagOpFn op_arg = nullptr);
+  void operator()(void* ptr) const;
 
   FlagOpFn op;
 };
@@ -416,10 +411,10 @@ class FlagImpl final : public flags_internal::CommandLineFlag {
   // it is only used inside the three routines below, which are defined in
   // flag.cc, we can define it in that file as well.
   template <typename StorageT>
-  typename StorageT::value_type& OffsetValue() const;
-  // This is an accessor for a value stored in heap allocated storage.
-  // Returns a mutable reference to a pointer to allow vlaue mutation.
-  void*& HeapAllocatedValue() const;
+  StorageT* OffsetValue() const;
+  // This is an accessor for a value stored in an aligned buffer storage.
+  // Returns a mutable pointer to the start of a buffer.
+  void* AlignedBufferValue() const;
   // This is an accessor for a value stored as one word atomic. Returns a
   // mutable reference to an atomic value.
   std::atomic<int64_t>& OneWordValue() const;
@@ -492,17 +487,8 @@ class FlagImpl final : public flags_internal::CommandLineFlag {
   // Kind of storage this flag is using for the flag's value.
   const uint8_t value_storage_kind_ : 2;
 
-  // ------------------------------------------------------------------------
-  // The bytes containing the const bitfields must not be shared with bytes
-  // containing the mutable bitfields.
-  // ------------------------------------------------------------------------
-
-  // Unique tag for absl::call_once call to initialize this flag.
-  //
-  // The placement of this variable between the immutable and mutable bitfields
-  // is important as prevents them from occupying the same byte. If you remove
-  // this variable, make sure to maintain this property.
-  absl::once_flag init_control_;
+  uint8_t : 0;  // The bytes containing the const bitfields must not be
+                // shared with bytes containing the mutable bitfields.
 
   // Mutable flag's state (guarded by `data_guard_`).
 
@@ -514,6 +500,9 @@ class FlagImpl final : public flags_internal::CommandLineFlag {
   // Has this flag been specified on command line.
   bool on_command_line_ : 1 ABSL_GUARDED_BY(*DataGuard());
 
+  // Unique tag for absl::call_once call to initialize this flag.
+  absl::once_flag init_control_;
+
   // Mutation counter
   int64_t counter_ ABSL_GUARDED_BY(*DataGuard());
   // Optional flag's callback and absl::Mutex to guard the invocations.
@@ -600,11 +589,17 @@ class Flag {
 template <typename T>
 void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) {
   switch (op) {
-    case FlagOp::kDelete:
-      delete static_cast<const T*>(v1);
+    case FlagOp::kAlloc: {
+      std::allocator<T> alloc;
+      return std::allocator_traits<std::allocator<T>>::allocate(alloc, 1);
+    }
+    case FlagOp::kDelete: {
+      T* p = static_cast<T*>(v2);
+      p->~T();
+      std::allocator<T> alloc;
+      std::allocator_traits<std::allocator<T>>::deallocate(alloc, p, 1);
       return nullptr;
-    case FlagOp::kClone:
-      return new T(*static_cast<const T*>(v1));
+    }
     case FlagOp::kCopy:
       *static_cast<T*>(v2) = *static_cast<const T*>(v1);
       return nullptr;
@@ -675,13 +670,13 @@ class FlagRegistrar {
 struct EmptyBraces {};
 
 template <typename T>
-T* MakeFromDefaultValue(T t) {
-  return new T(std::move(t));
+void MakeFromDefaultValue(void* dst, T t) {
+  new (dst) T(std::move(t));
 }
 
 template <typename T>
-T* MakeFromDefaultValue(EmptyBraces) {
-  return new T{};
+void MakeFromDefaultValue(void* dst, EmptyBraces) {
+  new (dst) T{};
 }
 
 }  // namespace flags_internal