OSSIA
Open Scenario System for Interactive Application
pod_vector.hpp
1 #pragma once
2 #include <boost/container/vector.hpp>
3 #include <boost/predef.h>
4 
5 #include <cinttypes>
6 #include <cstddef>
7 #include <cstdlib>
8 #include <type_traits>
9 #include <vector>
10 
11 namespace ossia
12 {
13 #if defined(_MSC_VER) && defined(_DEBUG)
14 template <class T>
15 struct pod_allocator
16 {
17  using value_type = T;
18 
19  template <typename... Args>
20  explicit pod_allocator(Args&&...) noexcept
21  {
22  }
23 
24  pod_allocator() noexcept = default;
25  pod_allocator(const pod_allocator&) noexcept = default;
26  pod_allocator(pod_allocator&&) noexcept = default;
27  pod_allocator& operator=(const pod_allocator&) noexcept = default;
28  pod_allocator& operator=(pod_allocator&&) noexcept = default;
29 
30  static inline T* allocate(std::size_t num) noexcept { return new T[num]; }
31 
32  static inline void deallocate(T* p, std::size_t) noexcept { delete[] p; }
33 
34  friend inline bool
35  operator==(const pod_allocator& lhs, const pod_allocator& rhs) noexcept
36  {
37  return true;
38  }
39  friend inline bool
40  operator!=(const pod_allocator& lhs, const pod_allocator& rhs) noexcept
41  {
42  return false;
43  }
44 };
45 
46 template <class T, std::size_t Align>
47 using aligned_pod_allocator = pod_allocator<T>;
48 
49 #else
50 template <class T>
51 struct pod_allocator
52 {
53  using value_type = T;
54 
55  pod_allocator() noexcept = default;
56  pod_allocator(const pod_allocator&) noexcept = default;
57  pod_allocator(pod_allocator&&) noexcept = default;
58  pod_allocator& operator=(const pod_allocator&) noexcept = default;
59  pod_allocator& operator=(pod_allocator&&) noexcept = default;
60 
61  static inline T* allocate(std::size_t num) noexcept
62  {
63  static_assert(
64  std::is_standard_layout_v<T> && std::is_trivial_v<T>,
65  "can only be used with POD types");
66  static_assert(
67  alignof(T) <= alignof(std::max_align_t),
68  "type must not have specific alignment requirements");
69 
70  return (T*)std::malloc(sizeof(T) * num);
71  }
72 
73  static inline void deallocate(T* p, std::size_t) noexcept { std::free(p); }
74 
75  friend inline bool operator==(pod_allocator lhs, pod_allocator rhs) noexcept
76  {
77  return true;
78  }
79  friend inline bool operator!=(pod_allocator lhs, pod_allocator rhs) noexcept
80  {
81  return false;
82  }
83 };
84 
85 template <class T, std::size_t Align>
86 struct aligned_pod_allocator
87 {
88  template <class U>
89  struct rebind
90  {
91  using other = aligned_pod_allocator<U, Align>;
92  };
93 
94  using value_type = T;
95 
96  aligned_pod_allocator() noexcept = default;
97  aligned_pod_allocator(const aligned_pod_allocator&) noexcept = default;
98  aligned_pod_allocator(aligned_pod_allocator&&) noexcept = default;
99  aligned_pod_allocator& operator=(const aligned_pod_allocator&) noexcept = default;
100  aligned_pod_allocator& operator=(aligned_pod_allocator&&) noexcept = default;
101 
102 #if defined(__linux__) || defined(__unix__) || defined(__unix) || defined(__APPLE__) \
103  || defined(__EMSCRIPTEN__)
104 #define OSSIA_HAS_POSIX_MEMALIGN 1
105 #endif
106 
107  template <typename U>
108  static constexpr bool has_posix_memalign() noexcept
109  {
110 #if defined(__linux__) || defined(__unix__) || defined(__unix) || defined(__APPLE__) \
111  || defined(__EMSCRIPTEN__)
112  return true;
113 #else
114  return false;
115 #endif
116  }
117 
118  static inline T* allocate(std::size_t num) noexcept
119  {
120  static_assert(
121  std::is_standard_layout_v<T> && std::is_trivial_v<T>,
122  "can only be used with POD types");
123  static_assert(
124  alignof(T) <= alignof(std::max_align_t),
125  "type must not have specific alignment requirements");
126 
127  if constexpr(Align != __STDCPP_DEFAULT_NEW_ALIGNMENT__)
128  {
129 #if defined(_WIN32)
130  return static_cast<T*>(::_aligned_malloc(sizeof(T) * num, Align));
131 #else
132  void* p;
133 #if OSSIA_HAS_POSIX_MEMALIGN
134  {
135  posix_memalign(&p, Align, sizeof(T) * num);
136  }
137 #else
138  {
139  static_assert(Align < 128);
140  p = std::malloc(sizeof(T) * num + Align + 1);
141  const auto pb = uintptr_t(p);
142  auto pptr = uintptr_t(p);
143 
144  while((pptr % Align) != 0)
145  {
146  pptr++;
147  }
148  if(pb == pptr)
149  {
150  pptr += Align;
151  }
152  *(unsigned char*)(pptr - 1) = (pptr - pb);
153  p = (void*)pptr;
154  }
155 #endif
156  return static_cast<T*>(p);
157 #endif
158  }
159  else
160  {
161  return (T*)std::malloc(sizeof(T) * num);
162  }
163  }
164 
165  static inline void deallocate(T* p, std::size_t) noexcept
166  {
167 #if defined(_WIN32)
168  if constexpr(Align != __STDCPP_DEFAULT_NEW_ALIGNMENT__)
169  {
170  ::_aligned_free(p);
171  }
172  else
173  {
174  std::free(p);
175  }
176 #else
177 #if OSSIA_HAS_POSIX_MEMALIGN
178  {
179  std::free(p);
180  }
181 #else
182  {
183  auto count = *(((unsigned char*)p) - 1);
184  auto root = ((unsigned char*)p - count);
185  std::free(root);
186  }
187 #endif
188 #endif
189  }
190 
191  friend inline bool
192  operator==(aligned_pod_allocator lhs, aligned_pod_allocator rhs) noexcept
193  {
194  return true;
195  }
196  friend inline bool
197  operator!=(aligned_pod_allocator lhs, aligned_pod_allocator rhs) noexcept
198  {
199  return false;
200  }
201 };
202 #endif
203 
204 template <typename T>
205 struct pod_allocator_avx2 : aligned_pod_allocator<T, 32>
206 {
207  template <class U>
208  struct rebind
209  {
210  using other = pod_allocator_avx2<U>;
211  };
212  using aligned_pod_allocator<T, 32>::aligned_pod_allocator;
213 };
214 
215 template <typename T>
216 using pod_vector = boost::container::vector<T, pod_allocator_avx2<T>>;
217 
218 using int_vector = pod_vector<int>;
219 using float_vector = pod_vector<float>;
220 using double_vector = pod_vector<double>;
221 }
Definition: git_info.h:7