Expression Templates Library (ETL)
allocator.hpp
Go to the documentation of this file.
1 //=======================================================================
2 // Copyright (c) 2014-2023 Baptiste Wicht
3 // Distributed under the terms of the MIT License.
4 // (See accompanying file LICENSE or copy at
5 // http://opensource.org/licenses/MIT)
6 //=======================================================================
7 
13 #pragma once
14 
15 namespace etl {
16 /*
17  * GCC mangling of vector types (__m128, __m256, ...) is terribly
18  * broken. To avoid this, the chosen solution is to use special
19  * functions for allocations of these types
20  */
21 
26 template <size_t T>
27 struct mangling_faker {};
28 
33 template <typename T>
34 concept is_mangle_able = std::same_as<std::decay_t<T>, float> || std::same_as<std::decay_t<T>, double>
35  || cpp::specialization_of<std::complex, T> || cpp::specialization_of<etl::complex, T>;
36 
41 template <size_t A>
48  template <typename T, size_t S = sizeof(T)>
49  static T* allocate(size_t size, mangling_faker<S> /*unused*/ = mangling_faker<S>()) {
50  auto required_bytes = sizeof(T) * size;
51  auto offset = (A - 1) + sizeof(uintptr_t);
52  auto orig = malloc(required_bytes + offset);
53 
54  if (!orig) {
55  return nullptr;
56  }
57 
58  auto aligned = reinterpret_cast<void**>((reinterpret_cast<size_t>(orig) + offset) & ~(A - 1));
59  aligned[-1] = orig;
60  return reinterpret_cast<T*>(aligned);
61  }
62 
67  template <typename T, size_t S = sizeof(T)>
68  static void release(T* ptr, mangling_faker<S> /*unused*/ = mangling_faker<S>()) {
69  //Note the const_cast is only to allow compilation
70  free((reinterpret_cast<void**>(const_cast<std::remove_const_t<T>*>(ptr)))[-1]);
71  }
72 };
73 
79 template <typename T, size_t S = sizeof(T)>
80 auto allocate(size_t size, mangling_faker<S> /*unused*/ = mangling_faker<S>()) {
81  static_assert(is_mangle_able<T>, "allocate does not work with vector types");
82  return std::make_unique<T[]>(size);
83 }
84 
90 template <typename T, size_t S = sizeof(T)>
91 T* aligned_allocate(size_t size, mangling_faker<S> /*unused*/ = mangling_faker<S>()) {
92  return aligned_allocator<32>::allocate<T>(size);
93 }
94 
99 template <typename T, size_t S = sizeof(T)>
101  return aligned_allocator<32>::release<T>(ptr);
102 }
103 
107 template <typename T, size_t S = sizeof(T)>
108 struct aligned_ptr {
109  T* ptr;
110 
114  explicit aligned_ptr(T* ptr) : ptr(ptr) {}
115 
116  aligned_ptr(const aligned_ptr& rhs) = delete;
117  aligned_ptr& operator=(const aligned_ptr& rhs) = delete;
118 
123  aligned_ptr(aligned_ptr&& rhs) noexcept : ptr(rhs.ptr) {
124  rhs.ptr = nullptr;
125  }
126 
132  aligned_ptr& operator=(aligned_ptr&& rhs) noexcept {
133  if (this != &rhs) {
134  ptr = rhs.ptr;
135  rhs.ptr = nullptr;
136  }
137 
138  return *this;
139  }
140 
144  inline T& operator[](size_t i) {
145  return ptr[i];
146  }
147 
151  inline const T& operator[](size_t i) const {
152  return ptr[i];
153  }
154 
159  if (ptr) {
160  aligned_release(ptr);
161  }
162  }
163 
167  T* get() {
168  return ptr;
169  }
170 };
171 
177 template <typename T, size_t S = sizeof(T)>
179  return aligned_ptr<T>{aligned_allocate<T>(size)};
180 }
181 
182 } //end of namespace etl
T & operator[](size_t i)
Returns a reference to the element at psition i.
Definition: allocator.hpp:144
aligned_ptr(T *ptr)
Build an aligned_ptr managing the given pointer.
Definition: allocator.hpp:114
aligned_ptr(aligned_ptr &&rhs) noexcept
Move construct an aligned_ptr.
Definition: allocator.hpp:123
void aligned_release(T *ptr, mangling_faker< S >=mangling_faker< S >())
Release some aligned memory.
Definition: allocator.hpp:100
static void release(T *ptr, mangling_faker< S >=mangling_faker< S >())
Release the memory.
Definition: allocator.hpp:68
Root namespace for the ETL library.
Definition: adapter.hpp:15
constexpr bool aligned
Alignment flag to aligned expressions.
Definition: std.hpp:46
const T & operator[](size_t i) const
Returns a reference to the element at psition i.
Definition: allocator.hpp:151
Allocated for aligned memory.
Definition: allocator.hpp:42
T * ptr
The raw pointer.
Definition: allocator.hpp:109
Use of this type in the parameter with the size of a vector type fakes mangling.
Definition: allocator.hpp:27
aligned_ptr & operator=(aligned_ptr &&rhs) noexcept
Move assign an aligned_ptr.
Definition: allocator.hpp:132
T * aligned_allocate(size_t size, mangling_faker< S >=mangling_faker< S >())
Allocate an aligned rray of the given size for the given type.
Definition: allocator.hpp:91
~aligned_ptr()
Destruct the aligned_ptr and release the aligned memory.
Definition: allocator.hpp:158
aligned_ptr< T > aligned_allocate_auto(size_t size, mangling_faker< S >=mangling_faker< S >())
Allocate an aligned rray of the given size for the given type.
Definition: allocator.hpp:178
static T * allocate(size_t size, mangling_faker< S >=mangling_faker< S >())
Allocate a block of memory of size elements.
Definition: allocator.hpp:49
RAII wrapper for allocated aligned memory.
Definition: allocator.hpp:108
auto allocate(size_t size, mangling_faker< S >=mangling_faker< S >())
Allocate an array of the given size for the given type.
Definition: allocator.hpp:80
concept is_mangle_able
Test if the given type can be mangled correctly.
Definition: allocator.hpp:34