1 #pragma once
2
3 /// \file AlignedStorage.h
4 /// \brief Base class for utility wrappers (Optional, Variant, ...)
5 /// \author Pavel Sevecek (sevecek at sirrah.troja.mff.cuni.cz)
6 /// \date 2016-2021
7
8 #include "common/Assert.h"
9 #include "common/Traits.h"
10 #ifndef SPH_WIN
11 #include <mm_malloc.h>
12 #else
13 #include <malloc.h>
14 #endif
15
16 NAMESPACE_SPH_BEGIN
17
18 /// \brief Creates a new object of type T on heap, using aligned allocation.
19 template <typename T, typename... TArgs>
alignedNew(TArgs &&...args)20 INLINE T* alignedNew(TArgs&&... args) {
21 constexpr Size size = sizeof(T);
22 constexpr Size alignment = alignof(T);
23 void* ptr = _mm_malloc(size, alignment);
24 SPH_ASSERT(ptr);
25 return new (ptr) T(std::forward<TArgs>(args)...);
26 }
27
28 /// \brief Deletes an object previously allocated using \ref alignedNew.
29 template <typename T>
alignedDelete(T * ptr)30 INLINE void alignedDelete(T* ptr) {
31 if (!ptr) {
32 return;
33 }
34
35 ptr->~T();
36 _mm_free(ptr);
37 ptr = nullptr;
38 }
39
40 template <typename T>
isAligned(const T & value)41 INLINE bool isAligned(const T& value) {
42 return reinterpret_cast<std::size_t>(&value) % alignof(T) == 0;
43 }
44
45 /// \brief Simple block of memory on stack with size and alignment given by template type
46
47 /// AlignedStorage can be used to construct an object on stack while sidestepping default construction.
48 /// Objects can be therefore default-constructed even if the underlying type does not have default
49 /// constructor.
50 /// Stored object can be later constructed by calling \ref emplace method. Note that when constructed,
51 /// it has to be later destroyed by explicitly calling \ref destroy method, this is not done
52 /// automatically! This object does NO checks when the stored value is accessed, or whether it is
53 /// constructed multiple times. This is left to the user.
54
55 // dereferencing type-punned pointer will break strict-aliasing rules
56 #ifndef SPH_WIN
57 #pragma GCC diagnostic push
58 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
59 #endif
60 /// \todo It's weird that GCC issues this warning as we are using __may_alias__ attribute. Perhaps a bug?
61
62 template <typename Type>
63 class AlignedStorage {
64 private:
65 struct SPH_MAY_ALIAS Holder {
66 alignas(Type) char storage[sizeof(Type)];
67 } holder;
68
69 public:
70 AlignedStorage() = default;
71
72 template <typename... TArgs>
emplace(TArgs &&...rest)73 INLINE void emplace(TArgs&&... rest) {
74 new (&holder) Type(std::forward<TArgs>(rest)...);
75 }
76
destroy()77 INLINE void destroy() {
78 get().~Type();
79 }
80
81 /// Implicit conversion to stored type
82 INLINE constexpr operator Type&() noexcept {
83 return get();
84 }
85
86 /// Implicit conversion to stored type, const version
87 INLINE constexpr operator const Type&() const noexcept {
88 return get();
89 }
90
91 /// Return the reference to the stored value.
get()92 INLINE constexpr Type& get() noexcept {
93 return reinterpret_cast<Type&>(holder);
94 }
95
96 /// Returns the reference to the stored value, const version.
get()97 INLINE constexpr const Type& get() const noexcept {
98 return reinterpret_cast<const Type&>(holder);
99 }
100 };
101
102 /// \brief Specialization for l-value references, a simple wrapper of ReferenceWrapper with same interface to
103 /// allow generic usage of AlignedStorage for both values and references.
104 template <typename Type>
105 class AlignedStorage<Type&> {
106 using StorageType = ReferenceWrapper<Type>;
107
108 StorageType storage;
109
110 public:
111 AlignedStorage() = default;
112
113 template <typename T>
emplace(T & ref)114 INLINE void emplace(T& ref) {
115 storage = StorageType(ref);
116 }
117
118 // no need do explicitly destroy reference wrapper
destroy()119 INLINE void destroy() {}
120
121 INLINE constexpr operator Type&() noexcept {
122 return get();
123 }
124
125 /// Implicit conversion to stored type, const version
126 INLINE constexpr operator const Type&() const noexcept {
127 return get();
128 }
129
130 /// Return the reference to the stored value.
get()131 INLINE constexpr Type& get() noexcept {
132 return storage;
133 }
134
135 /// Returns the reference to the stored value, const version.
get()136 INLINE constexpr const Type& get() const noexcept {
137 return storage;
138 }
139 };
140
141 #ifndef SPH_WIN
142 #pragma GCC diagnostic pop
143 #endif
144
145 NAMESPACE_SPH_END
146