Blender  V3.3
BLI_any.hh
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #pragma once
4 
15 #include <algorithm>
16 #include <cstring>
17 #include <utility>
18 
19 #include "BLI_memory_utils.hh"
20 
21 namespace blender {
22 
23 namespace detail {
24 
29 template<typename ExtraInfo> struct AnyTypeInfo {
30  /* The pointers are allowed to be null, which means that the implementation is trivial. */
31  void (*copy_construct)(void *dst, const void *src);
32  void (*move_construct)(void *dst, void *src);
33  void (*destruct)(void *src);
34  const void *(*get)(const void *src);
35  ExtraInfo extra_info;
36 };
37 
41 template<typename ExtraInfo, typename T>
43  is_trivially_copy_constructible_extended_v<T> ?
44  nullptr :
45  +[](void *dst, const void *src) { new (dst) T(*(const T *)src); },
46  is_trivially_move_constructible_extended_v<T> ?
47  nullptr :
48  +[](void *dst, void *src) { new (dst) T(std::move(*(T *)src)); },
49  is_trivially_destructible_extended_v<T> ? nullptr :
50  +[](void *src) { std::destroy_at(((T *)src)); },
51  nullptr,
52  ExtraInfo::template get<T>()};
53 
58 template<typename T> using Ptr = std::unique_ptr<T>;
59 template<typename ExtraInfo, typename T>
61  [](void *dst, const void *src) { new (dst) Ptr<T>(new T(**(const Ptr<T> *)src)); },
62  [](void *dst, void *src) { new (dst) Ptr<T>(new T(std::move(**(Ptr<T> *)src))); },
63  [](void *src) { std::destroy_at((Ptr<T> *)src); },
64  [](const void *src) -> const void * { return &**(const Ptr<T> *)src; },
65  ExtraInfo::template get<T>()};
66 
70 struct NoExtraInfo {
71  template<typename T> static constexpr NoExtraInfo get()
72  {
73  return {};
74  }
75 };
76 
77 } // namespace detail
78 
79 template<
85  typename ExtraInfo = void,
90  size_t InlineBufferCapacity = 8,
95  size_t Alignment = 8>
96 class Any {
97  private:
98  /* Makes it possible to use void in the template parameters. */
99  using RealExtraInfo =
100  std::conditional_t<std::is_void_v<ExtraInfo>, detail::NoExtraInfo, ExtraInfo>;
102  static constexpr size_t RealInlineBufferCapacity = std::max(InlineBufferCapacity,
103  sizeof(std::unique_ptr<int>));
104 
110 
115  const Info *info_ = nullptr;
116 
117  public:
119  template<typename T> static constexpr inline bool is_allowed_v = std::is_copy_constructible_v<T>;
120 
125  template<typename T>
126  static constexpr inline bool is_inline_v = std::is_nothrow_move_constructible_v<T> &&
127  sizeof(T) <= InlineBufferCapacity &&
128  alignof(T) <= Alignment;
129 
134  template<typename T>
135  static constexpr inline bool is_same_any_v = std::is_same_v<std::decay_t<T>, Any>;
136 
137  private:
138  template<typename T> const Info &get_info() const
139  {
140  using DecayT = std::decay_t<T>;
141  static_assert(is_allowed_v<DecayT>);
142  if constexpr (is_inline_v<DecayT>) {
143  return detail::template info_for_inline<RealExtraInfo, DecayT>;
144  }
145  else {
146  return detail::template info_for_unique_ptr<RealExtraInfo, DecayT>;
147  }
148  }
149 
150  public:
151  Any() = default;
152 
153  Any(const Any &other) : info_(other.info_)
154  {
155  if (info_ != nullptr) {
156  if (info_->copy_construct != nullptr) {
157  info_->copy_construct(&buffer_, &other.buffer_);
158  }
159  else {
160  memcpy(&buffer_, &other.buffer_, RealInlineBufferCapacity);
161  }
162  }
163  }
164 
169  Any(Any &&other) noexcept : info_(other.info_)
170  {
171  if (info_ != nullptr) {
172  if (info_->move_construct != nullptr) {
173  info_->move_construct(&buffer_, &other.buffer_);
174  }
175  else {
176  memcpy(&buffer_, &other.buffer_, RealInlineBufferCapacity);
177  }
178  }
179  }
180 
185  template<typename T, typename... Args> explicit Any(std::in_place_type_t<T>, Args &&...args)
186  {
187  this->emplace_on_empty<T>(std::forward<Args>(args)...);
188  }
189 
193  template<typename T, BLI_ENABLE_IF((!is_same_any_v<T>))>
194  Any(T &&value) : Any(std::in_place_type<T>, std::forward<T>(value))
195  {
196  }
197 
199  {
200  if (info_ != nullptr) {
201  if (info_->destruct != nullptr) {
202  info_->destruct(&buffer_);
203  }
204  }
205  }
206 
210  Any &operator=(const Any &other)
211  {
212  if (this == &other) {
213  return *this;
214  }
215  this->~Any();
216  new (this) Any(other);
217  return *this;
218  }
219 
221  template<typename T> Any &operator=(T &&other)
222  {
223  if constexpr (is_same_any_v<T>) {
224  if (this == &other) {
225  return *this;
226  }
227  }
228  this->~Any();
229  new (this) Any(std::forward<T>(other));
230  return *this;
231  }
232 
234  void reset()
235  {
236  if (info_ != nullptr) {
237  if (info_->destruct != nullptr) {
238  info_->destruct(&buffer_);
239  }
240  }
241  info_ = nullptr;
242  }
243 
244  operator bool() const
245  {
246  return this->has_value();
247  }
248 
249  bool has_value() const
250  {
251  return info_ != nullptr;
252  }
253 
254  template<typename T, typename... Args> std::decay_t<T> &emplace(Args &&...args)
255  {
256  this->~Any();
257  new (this) Any(std::in_place_type<T>, std::forward<Args>(args)...);
258  return this->get<T>();
259  }
260 
261  template<typename T, typename... Args> std::decay_t<T> &emplace_on_empty(Args &&...args)
262  {
263  BLI_assert(!this->has_value());
264  using DecayT = std::decay_t<T>;
265  static_assert(is_allowed_v<DecayT>);
266  info_ = &this->template get_info<DecayT>();
267  if constexpr (is_inline_v<DecayT>) {
268  /* Construct the value directly in the inline buffer. */
269  DecayT *stored_value = new (&buffer_) DecayT(std::forward<Args>(args)...);
270  return *stored_value;
271  }
272  else {
273  /* Construct the value in a new allocation and store a #std::unique_ptr to it in the inline
274  * buffer. */
275  std::unique_ptr<DecayT> *stored_value = new (&buffer_)
276  std::unique_ptr<DecayT>(new DecayT(std::forward<Args>(args)...));
277  return **stored_value;
278  }
279  }
280 
282  template<typename T> bool is() const
283  {
284  return info_ == &this->template get_info<T>();
285  }
286 
288  void *get()
289  {
290  BLI_assert(info_ != nullptr);
291  if (info_->get != nullptr) {
292  return const_cast<void *>(info_->get(&buffer_));
293  }
294  return &buffer_;
295  }
296 
298  const void *get() const
299  {
300  BLI_assert(info_ != nullptr);
301  if (info_->get != nullptr) {
302  return info_->get(&buffer_);
303  }
304  return &buffer_;
305  }
306 
311  template<typename T> std::decay_t<T> &get()
312  {
313  BLI_assert(this->is<T>());
314  return *static_cast<std::decay_t<T> *>(this->get());
315  }
316 
321  template<typename T> const std::decay_t<T> &get() const
322  {
323  BLI_assert(this->is<T>());
324  return *static_cast<const std::decay_t<T> *>(this->get());
325  }
326 
330  const RealExtraInfo &extra_info() const
331  {
332  BLI_assert(info_ != nullptr);
333  return info_->extra_info;
334  }
335 };
336 
337 } // namespace blender
#define BLI_assert(a)
Definition: BLI_assert.h:46
const std::decay_t< T > & get() const
Definition: BLI_any.hh:321
static constexpr bool is_same_any_v
Definition: BLI_any.hh:135
Any(std::in_place_type_t< T >, Args &&...args)
Definition: BLI_any.hh:185
std::decay_t< T > & emplace_on_empty(Args &&...args)
Definition: BLI_any.hh:261
Any(const Any &other)
Definition: BLI_any.hh:153
static constexpr bool is_inline_v
Definition: BLI_any.hh:126
bool has_value() const
Definition: BLI_any.hh:249
void reset()
Definition: BLI_any.hh:234
bool is() const
Definition: BLI_any.hh:282
Any(Any &&other) noexcept
Definition: BLI_any.hh:169
Any(T &&value)
Definition: BLI_any.hh:194
std::decay_t< T > & emplace(Args &&...args)
Definition: BLI_any.hh:254
Any & operator=(const Any &other)
Definition: BLI_any.hh:210
static constexpr bool is_allowed_v
Definition: BLI_any.hh:119
const RealExtraInfo & extra_info() const
Definition: BLI_any.hh:330
std::decay_t< T > & get()
Definition: BLI_any.hh:311
const void * get() const
Definition: BLI_any.hh:298
void * get()
Definition: BLI_any.hh:288
Any()=default
Any & operator=(T &&other)
Definition: BLI_any.hh:221
SyclQueue void void * src
SyclQueue void void size_t num_bytes void
#define T
static constexpr AnyTypeInfo< ExtraInfo > info_for_inline
Definition: BLI_any.hh:42
static constexpr AnyTypeInfo< ExtraInfo > info_for_unique_ptr
Definition: BLI_any.hh:60
std::unique_ptr< T > Ptr
Definition: BLI_any.hh:58
void(* move_construct)(void *dst, void *src)
Definition: BLI_any.hh:32
void(* destruct)(void *src)
Definition: BLI_any.hh:33
const void *(* get)(const void *src)
Definition: BLI_any.hh:34
void(* copy_construct)(void *dst, const void *src)
Definition: BLI_any.hh:31
static constexpr NoExtraInfo get()
Definition: BLI_any.hh:71
float max