EnTT  3.5.0
internal.hpp
1 #ifndef ENTT_META_INTERNAL_HPP
2 #define ENTT_META_INTERNAL_HPP
3 
4 
5 #include <cstddef>
6 #include <functional>
7 #include <iterator>
8 #include <type_traits>
9 #include <utility>
10 #include "../core/attribute.h"
11 #include "../config/config.h"
12 #include "../core/fwd.hpp"
13 #include "../core/type_info.hpp"
14 #include "../core/type_traits.hpp"
15 #include "type_traits.hpp"
16 
17 
18 namespace entt {
19 
20 
21 class meta_any;
22 struct meta_handle;
23 
24 
31 namespace internal {
32 
33 
34 class meta_storage {
35  using storage_type = std::aligned_storage_t<sizeof(void *), alignof(void *)>;
36  using copy_fn_type = void(meta_storage &, const meta_storage &);
37  using steal_fn_type = void(meta_storage &, meta_storage &);
38  using destroy_fn_type = void(meta_storage &);
39 
40  template<typename Type, typename = std::void_t<>>
41  struct type_traits {
42  template<typename... Args>
43  static void instance(meta_storage &buffer, Args &&... args) {
44  buffer.instance = new Type{std::forward<Args>(args)...};
45  new (&buffer.storage) Type *{static_cast<Type *>(buffer.instance)};
46  }
47 
48  static void destroy(meta_storage &buffer) {
49  delete static_cast<Type *>(buffer.instance);
50  }
51 
52  static void copy(meta_storage &to, const meta_storage &from) {
53  to.instance = new Type{*static_cast<const Type *>(from.instance)};
54  new (&to.storage) Type *{static_cast<Type *>(to.instance)};
55  }
56 
57  static void steal(meta_storage &to, meta_storage &from) {
58  new (&to.storage) Type *{static_cast<Type *>(from.instance)};
59  to.instance = from.instance;
60  }
61  };
62 
63  template<typename Type>
64  struct type_traits<Type, std::enable_if_t<sizeof(Type) <= sizeof(void *) && std::is_nothrow_move_constructible_v<Type>>> {
65  template<typename... Args>
66  static void instance(meta_storage &buffer, Args &&... args) {
67  buffer.instance = new (&buffer.storage) Type{std::forward<Args>(args)...};
68  }
69 
70  static void destroy(meta_storage &buffer) {
71  static_cast<Type *>(buffer.instance)->~Type();
72  }
73 
74  static void copy(meta_storage &to, const meta_storage &from) {
75  to.instance = new (&to.storage) Type{*static_cast<const Type *>(from.instance)};
76  }
77 
78  static void steal(meta_storage &to, meta_storage &from) {
79  to.instance = new (&to.storage) Type{std::move(*static_cast<Type *>(from.instance))};
80  destroy(from);
81  }
82  };
83 
84 public:
86  meta_storage() ENTT_NOEXCEPT
87  : storage{},
88  instance{},
89  destroy_fn{},
90  copy_fn{},
91  steal_fn{}
92  {}
93 
94  template<typename Type, typename... Args>
95  explicit meta_storage(std::in_place_type_t<Type>, [[maybe_unused]] Args &&... args)
96  : meta_storage{}
97  {
98  if constexpr(!std::is_void_v<Type>) {
99  type_traits<Type>::instance(*this, std::forward<Args>(args)...);
100  destroy_fn = &type_traits<Type>::destroy;
101  copy_fn = &type_traits<Type>::copy;
102  steal_fn = &type_traits<Type>::steal;
103  }
104  }
105 
106  template<typename Type>
107  meta_storage(std::reference_wrapper<Type> value)
108  : meta_storage{}
109  {
110  instance = &value.get();
111  }
112 
113  template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, meta_storage>>>
114  meta_storage(Type &&value)
115  : meta_storage{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)}
116  {}
117 
118  meta_storage(const meta_storage &other)
119  : meta_storage{}
120  {
121  (other.copy_fn ? other.copy_fn : [](auto &to, const auto &from) { to.instance = from.instance; })(*this, other);
122  destroy_fn = other.destroy_fn;
123  copy_fn = other.copy_fn;
124  steal_fn = other.steal_fn;
125  }
126 
127  meta_storage(meta_storage &&other)
128  : meta_storage{}
129  {
130  swap(*this, other);
131  }
132 
133  ~meta_storage() {
134  if(destroy_fn) {
135  destroy_fn(*this);
136  }
137  }
138 
139  meta_storage & operator=(meta_storage other) {
140  swap(other, *this);
141  return *this;
142  }
143 
144  [[nodiscard]] const void * data() const ENTT_NOEXCEPT {
145  return instance;
146  }
147 
148  [[nodiscard]] void * data() ENTT_NOEXCEPT {
149  return const_cast<void *>(std::as_const(*this).data());
150  }
151 
152  template<typename Type, typename... Args>
153  void emplace(Args &&... args) {
154  *this = meta_storage{std::in_place_type<Type>, std::forward<Args>(args)...};
155  }
156 
157  [[nodiscard]] meta_storage ref() const ENTT_NOEXCEPT {
158  meta_storage other{};
159  other.instance = instance;
160  return other;
161  }
162 
163  [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
164  return !(instance == nullptr);
165  }
166 
167  friend void swap(meta_storage &lhs, meta_storage &rhs) {
168  using std::swap;
169 
170  if(lhs.steal_fn && rhs.steal_fn) {
171  meta_storage buffer{};
172  lhs.steal_fn(buffer, lhs);
173  rhs.steal_fn(lhs, rhs);
174  lhs.steal_fn(rhs, buffer);
175  } else if(lhs.steal_fn) {
176  lhs.steal_fn(rhs, lhs);
177  } else if(rhs.steal_fn) {
178  rhs.steal_fn(lhs, rhs);
179  } else {
180  swap(lhs.instance, rhs.instance);
181  }
182 
183  swap(lhs.destroy_fn, rhs.destroy_fn);
184  swap(lhs.copy_fn, rhs.copy_fn);
185  swap(lhs.steal_fn, rhs.steal_fn);
186  }
187 
188 private:
189  storage_type storage;
190  void *instance;
191  destroy_fn_type *destroy_fn;
192  copy_fn_type *copy_fn;
193  steal_fn_type *steal_fn;
194 };
195 
196 
197 struct meta_type_node;
198 
199 
200 struct meta_prop_node {
201  meta_prop_node * next;
202  meta_any(* const key)();
203  meta_any(* const value)();
204 };
205 
206 
207 struct meta_base_node {
208  meta_type_node * const parent;
209  meta_base_node * next;
210  meta_type_node *(* const type)() ENTT_NOEXCEPT;
211  const void *(* const cast)(const void *) ENTT_NOEXCEPT;
212 };
213 
214 
215 struct meta_conv_node {
216  meta_type_node * const parent;
217  meta_conv_node * next;
218  meta_type_node *(* const type)() ENTT_NOEXCEPT;
219  meta_any(* const conv)(const void *);
220 };
221 
222 
223 struct meta_ctor_node {
224  using size_type = std::size_t;
225  meta_type_node * const parent;
226  meta_ctor_node * next;
227  meta_prop_node * prop;
228  const size_type size;
229  meta_type_node *(* const arg)(size_type) ENTT_NOEXCEPT;
230  meta_any(* const invoke)(meta_any * const);
231 };
232 
233 
234 struct meta_data_node {
235  id_type id;
236  meta_type_node * const parent;
237  meta_data_node * next;
238  meta_prop_node * prop;
239  const bool is_static;
240  meta_type_node *(* const type)() ENTT_NOEXCEPT;
241  bool(* const set)(meta_handle, meta_any);
242  meta_any(* const get)(meta_handle);
243 };
244 
245 
246 struct meta_func_node {
247  using size_type = std::size_t;
248  id_type id;
249  meta_type_node * const parent;
250  meta_func_node * next;
251  meta_prop_node * prop;
252  const size_type size;
253  const bool is_const;
254  const bool is_static;
255  meta_type_node *(* const ret)() ENTT_NOEXCEPT;
256  meta_type_node *(* const arg)(size_type) ENTT_NOEXCEPT;
257  meta_any(* const invoke)(meta_handle, meta_any *);
258 };
259 
260 
261 struct meta_type_node {
262  using size_type = std::size_t;
263  const id_type type_id;
264  id_type id;
265  meta_type_node * next;
266  meta_prop_node * prop;
267  const bool is_void;
268  const bool is_integral;
269  const bool is_floating_point;
270  const bool is_array;
271  const bool is_enum;
272  const bool is_union;
273  const bool is_class;
274  const bool is_pointer;
275  const bool is_function_pointer;
276  const bool is_member_object_pointer;
277  const bool is_member_function_pointer;
278  const bool is_pointer_like;
279  const bool is_sequence_container;
280  const bool is_associative_container;
281  const size_type rank;
282  size_type(* const extent)(size_type);
283  bool(* const compare)(const void *, const void *);
284  meta_type_node *(* const remove_pointer)() ENTT_NOEXCEPT;
285  meta_type_node *(* const remove_extent)() ENTT_NOEXCEPT;
286  meta_base_node *base{nullptr};
287  meta_conv_node *conv{nullptr};
288  meta_ctor_node *ctor{nullptr};
289  meta_data_node *data{nullptr};
290  meta_func_node *func{nullptr};
291  void(* dtor)(void *){nullptr};
292 };
293 
294 
295 template<typename Node>
296 class meta_range {
297  struct range_iterator {
298  using difference_type = std::ptrdiff_t;
299  using value_type = Node;
300  using pointer = value_type *;
301  using reference = value_type &;
302  using iterator_category = std::forward_iterator_tag;
303 
304  range_iterator() ENTT_NOEXCEPT = default;
305 
306  range_iterator(Node *head) ENTT_NOEXCEPT
307  : node{head}
308  {}
309 
310  range_iterator & operator++() ENTT_NOEXCEPT {
311  return node = node->next, *this;
312  }
313 
314  range_iterator operator++(int) ENTT_NOEXCEPT {
315  range_iterator orig = *this;
316  return ++(*this), orig;
317  }
318 
319  [[nodiscard]] bool operator==(const range_iterator &other) const ENTT_NOEXCEPT {
320  return other.node == node;
321  }
322 
323  [[nodiscard]] bool operator!=(const range_iterator &other) const ENTT_NOEXCEPT {
324  return !(*this == other);
325  }
326 
327  [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
328  return node;
329  }
330 
331  [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
332  return *operator->();
333  }
334 
335  private:
336  Node *node{nullptr};
337  };
338 
339 public:
340  using iterator = range_iterator;
341 
342  meta_range() ENTT_NOEXCEPT = default;
343 
344  meta_range(Node *head)
345  : node{head}
346  {}
347 
348  [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
349  return iterator{node};
350  }
351 
352  [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
353  return iterator{};
354  }
355 
356 private:
357  Node *node{nullptr};
358 };
359 
360 
361 template<auto Member, typename Op>
362 auto find_if(const Op &op, const meta_type_node *node)
363 -> std::decay_t<decltype(node->*Member)> {
364  std::decay_t<decltype(node->*Member)> ret = nullptr;
365 
366  for(auto &&curr: meta_range{node->*Member}) {
367  if(op(&curr)) {
368  ret = &curr;
369  break;
370  }
371  }
372 
373  if(!ret) {
374  for(auto &&curr: meta_range{node->base}) {
375  if(ret = find_if<Member>(op, curr.type()); ret) {
376  break;
377  }
378  }
379  }
380 
381  return ret;
382 }
383 
384 
385 template<typename Type>
386 class ENTT_API meta_node {
387  static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Invalid type");
388 
389  [[nodiscard]] static bool compare(const void *lhs, const void *rhs) {
390  if constexpr(!std::is_function_v<Type> && is_equality_comparable_v<Type>) {
391  return *static_cast<const Type *>(lhs) == *static_cast<const Type *>(rhs);
392  } else {
393  return lhs == rhs;
394  }
395  }
396 
397  template<std::size_t... Index>
398  [[nodiscard]] static auto extent(meta_type_node::size_type dim, std::index_sequence<Index...>) {
399  meta_type_node::size_type ext{};
400  ((ext = (dim == Index ? std::extent_v<Type, Index> : ext)), ...);
401  return ext;
402  }
403 
404 public:
405  [[nodiscard]] static meta_type_node * resolve() ENTT_NOEXCEPT {
406  static meta_type_node node{
408  {},
409  nullptr,
410  nullptr,
411  std::is_void_v<Type>,
412  std::is_integral_v<Type>,
413  std::is_floating_point_v<Type>,
414  std::is_array_v<Type>,
415  std::is_enum_v<Type>,
416  std::is_union_v<Type>,
417  std::is_class_v<Type>,
418  std::is_pointer_v<Type>,
419  std::is_pointer_v<Type> && std::is_function_v<std::remove_pointer_t<Type>>,
420  std::is_member_object_pointer_v<Type>,
421  std::is_member_function_pointer_v<Type>,
422  is_meta_pointer_like_v<Type>,
423  has_meta_sequence_container_traits_v<Type>,
424  has_meta_associative_container_traits_v<Type>,
425  std::rank_v<Type>,
426  [](meta_type_node::size_type dim) {
427  return extent(dim, std::make_index_sequence<std::rank_v<Type>>{});
428  },
429  &compare, // workaround for an issue with VS2017
430  &meta_node<std::remove_const_t<std::remove_pointer_t<Type>>>::resolve,
431  &meta_node<std::remove_const_t<std::remove_extent_t<Type>>>::resolve
432  };
433 
434  return &node;
435  }
436 };
437 
438 
439 template<typename... Type>
440 struct meta_info: meta_node<std::remove_cv_t<std::remove_reference_t<Type>>...> {};
441 
442 
443 }
444 
445 
452 }
453 
454 
455 #endif
entt::get
constexpr get_t< Type... > get
Variable template for lists of observed components.
Definition: utility.hpp:40
entt::id_type
std::uint32_t id_type
Alias declaration for type identifiers.
Definition: fwd.hpp:12
entt
EnTT default namespace.
Definition: algorithm.hpp:13
entt::type_info::id
static id_type id() noexcept
Returns the numeric representation of a given type.
Definition: type_info.hpp:114
entt::resolve
meta_type resolve() noexcept
Returns the meta type associated with a given type.
Definition: resolve.hpp:20
entt::invoke
void invoke(basic_registry< Entity > &reg, const Entity entt)
Helper to create a listener that directly invokes a member function.
Definition: helper.hpp:124
entt::operator!=
constexpr bool operator!=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
Definition: hashed_string.hpp:227
entt::operator==
constexpr bool operator==(const Entity entity, null_t other) noexcept
Compares a null object and an entity identifier of any type.
Definition: entity.hpp:184