[tint][utils] Add AlignedStorage
Move the 3 copies out to a shared definition.
Change-Id: I98626c03a56aed5602bf19c317eb114a69703a6c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/173980
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/utils/containers/hashmap_base.h b/src/tint/utils/containers/hashmap_base.h
index 2a86e3a..ba78fd0 100644
--- a/src/tint/utils/containers/hashmap_base.h
+++ b/src/tint/utils/containers/hashmap_base.h
@@ -38,6 +38,7 @@
#include "src/tint/utils/ice/ice.h"
#include "src/tint/utils/math/hash.h"
#include "src/tint/utils/math/math.h"
+#include "src/tint/utils/memory/aligned_storage.h"
#include "src/tint/utils/traits/traits.h"
namespace tint {
@@ -418,21 +419,14 @@
protected:
/// Node holds an Entry in a linked list.
struct Node {
- /// A structure that has the same size and alignment as Entry.
- /// Replacement for std::aligned_storage as this is broken on earlier versions of MSVC.
- struct alignas(alignof(ENTRY)) Storage {
- /// Byte array of length sizeof(ENTRY)
- uint8_t data[sizeof(ENTRY)];
- };
-
/// Destructs the entry.
void Destroy() { Entry().~ENTRY(); }
/// @returns the storage reinterpreted as an `Entry&`
- ENTRY& Entry() { return *Bitcast<ENTRY*>(&storage.data[0]); }
+ ENTRY& Entry() { return storage.Get(); }
/// @returns the storage reinterpreted as a `const Entry&`
- const ENTRY& Entry() const { return *Bitcast<const ENTRY*>(&storage.data[0]); }
+ const ENTRY& Entry() const { return storage.Get(); }
/// @returns a reference to the Entry's HashmapKey
const HashmapBase::Key& Key() const { return HashmapBase::Entry::KeyOf(Entry()); }
@@ -450,7 +444,7 @@
/// storage is a buffer that has the same size and alignment as Entry.
/// The storage holds a constructed Entry when linked in the slots, and is destructed when
/// removed from slots.
- Storage storage;
+ AlignedStorage<ENTRY> storage;
/// next is the next Node in the slot, or in the free list.
Node* next;
diff --git a/src/tint/utils/containers/vector.h b/src/tint/utils/containers/vector.h
index c7edd0e..cd806c1 100644
--- a/src/tint/utils/containers/vector.h
+++ b/src/tint/utils/containers/vector.h
@@ -41,6 +41,7 @@
#include "src/tint/utils/ice/ice.h"
#include "src/tint/utils/macros/compiler.h"
#include "src/tint/utils/math/hash.h"
+#include "src/tint/utils/memory/aligned_storage.h"
#include "src/tint/utils/memory/bitcast.h"
#ifndef TINT_VECTOR_MUTATION_CHECKS_ENABLED
@@ -912,26 +913,18 @@
constexpr static bool HasSmallArray = N > 0;
/// A structure that has the same size and alignment as T.
- /// Replacement for std::aligned_storage as this is broken on earlier versions of MSVC.
- struct alignas(alignof(T)) TStorage {
- /// @returns the storage reinterpreted as a T*
- T* Get() { return Bitcast<T*>(&data[0]); }
- /// @returns the storage reinterpreted as a T*
- const T* Get() const { return Bitcast<const T*>(&data[0]); }
- /// Byte array of length sizeof(T)
- uint8_t data[sizeof(T)];
- };
+ using TStorage = AlignedStorage<T>;
/// The internal structure for the vector with a small array.
struct ImplWithSmallArray {
TStorage small_arr[N];
- tint::Slice<T> slice = {small_arr[0].Get(), 0, N};
+ tint::Slice<T> slice = {&small_arr[0].Get(), 0, N};
/// Allocates a new vector of `T` either from #small_arr, or from the heap, then assigns the
/// pointer it to #slice.data, and updates #slice.cap.
void Allocate(size_t new_cap) {
if (new_cap < N) {
- slice.data = small_arr[0].Get();
+ slice.data = &small_arr[0].Get();
slice.cap = N;
} else {
slice.data = Bitcast<T*>(new TStorage[new_cap]);
@@ -941,14 +934,14 @@
/// Frees `data`, if isn't a pointer to #small_arr
void Free(T* data) const {
- if (data != small_arr[0].Get()) {
+ if (data != &small_arr[0].Get()) {
delete[] Bitcast<TStorage*>(data);
}
}
/// Indicates whether the slice structure can be std::move()d.
/// @returns true if #slice.data does not point to #small_arr
- bool CanMove() const { return slice.data != small_arr[0].Get(); }
+ bool CanMove() const { return slice.data != &small_arr[0].Get(); }
};
/// The internal structure for the vector without a small array.
diff --git a/src/tint/utils/memory/BUILD.bazel b/src/tint/utils/memory/BUILD.bazel
index 0bd13c9..6cb1b67 100644
--- a/src/tint/utils/memory/BUILD.bazel
+++ b/src/tint/utils/memory/BUILD.bazel
@@ -42,6 +42,7 @@
"memory.cc",
],
hdrs = [
+ "aligned_storage.h",
"bitcast.h",
"block_allocator.h",
"bump_allocator.h",
diff --git a/src/tint/utils/memory/BUILD.cmake b/src/tint/utils/memory/BUILD.cmake
index 3151d3f..1d69077 100644
--- a/src/tint/utils/memory/BUILD.cmake
+++ b/src/tint/utils/memory/BUILD.cmake
@@ -39,6 +39,7 @@
# Kind: lib
################################################################################
tint_add_target(tint_utils_memory lib
+ utils/memory/aligned_storage.h
utils/memory/bitcast.h
utils/memory/block_allocator.h
utils/memory/bump_allocator.h
diff --git a/src/tint/utils/memory/BUILD.gn b/src/tint/utils/memory/BUILD.gn
index e5b44f2..0ab12e1 100644
--- a/src/tint/utils/memory/BUILD.gn
+++ b/src/tint/utils/memory/BUILD.gn
@@ -44,6 +44,7 @@
libtint_source_set("memory") {
sources = [
+ "aligned_storage.h",
"bitcast.h",
"block_allocator.h",
"bump_allocator.h",
diff --git a/src/tint/utils/memory/aligned_storage.h b/src/tint/utils/memory/aligned_storage.h
new file mode 100644
index 0000000..c532c4f
--- /dev/null
+++ b/src/tint/utils/memory/aligned_storage.h
@@ -0,0 +1,53 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_UTILS_MEMORY_ALIGNED_STORAGE_H_
+#define SRC_TINT_UTILS_MEMORY_ALIGNED_STORAGE_H_
+
+#include <cstddef>
+
+#include "src/tint/utils/memory/bitcast.h"
+
+namespace tint {
+
+/// A structure that has the same size and alignment as Entry.
+/// Replacement for std::aligned_storage as this is broken on earlier versions of MSVC.
+template <typename T>
+struct alignas(alignof(T)) AlignedStorage {
+ /// Byte array of length sizeof(T)
+ std::byte data[sizeof(T)];
+
+ /// @returns a pointer to aligned storage, reinterpreted as T&
+ T& Get() { return *Bitcast<T*>(&data[0]); }
+
+ /// @returns a pointer to aligned storage, reinterpreted as T&
+ const T& Get() const { return *Bitcast<const T*>(&data[0]); }
+};
+
+} // namespace tint
+
+#endif // SRC_TINT_UTILS_MEMORY_ALIGNED_STORAGE_H_
diff --git a/src/tint/utils/rtti/switch.h b/src/tint/utils/rtti/switch.h
index 24173d0..2436f5f 100644
--- a/src/tint/utils/rtti/switch.h
+++ b/src/tint/utils/rtti/switch.h
@@ -33,7 +33,7 @@
#include "src/tint/utils/ice/ice.h"
#include "src/tint/utils/macros/defer.h"
-#include "src/tint/utils/memory/bitcast.h"
+#include "src/tint/utils/memory/aligned_storage.h"
#include "src/tint/utils/rtti/castable.h"
#include "src/tint/utils/rtti/ignore.h"
@@ -300,13 +300,8 @@
}
}
- // Replacement for std::aligned_storage as this is broken on earlier versions of MSVC.
- using ReturnTypeOrU8 = std::conditional_t<kHasReturnType, ReturnType, uint8_t>;
- struct alignas(alignof(ReturnTypeOrU8)) ReturnStorage {
- uint8_t data[sizeof(ReturnTypeOrU8)];
- };
- ReturnStorage return_storage;
- auto* result = tint::Bitcast<ReturnTypeOrU8*>(&return_storage);
+ AlignedStorage<std::conditional_t<kHasReturnType, ReturnType, uint8_t>> return_storage;
+ auto* result = &return_storage.Get();
const tint::TypeInfo& type_info = object->TypeInfo();