density
C++11 library for paged memory management, function queues, heterogeneous queues and lifo memory management
runtime_type.h
1 
2 // Copyright Giuseppe Campana (giu.campana@gmail.com) 2016-2018.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
7 #pragma once
9 #include <density/detail/runtime_type_internals.h>
10 #include <functional> // for std::hash
11 #include <limits>
12 #include <stdexcept>
13 #include <tuple>
14 #include <type_traits>
15 #include <typeinfo>
16 #include <utility>
17 
18 namespace density
19 {
46  template <typename... FEATURES> struct feature_list;
47  template <> struct feature_list<> /* an empty feature_list gives an empty tuple */
48  {
49  using tuple_type = std::tuple<>;
50  };
51  template <typename FIRST_FEATURE, typename... OTHER_FEATURES>
52  struct feature_list<FIRST_FEATURE, OTHER_FEATURES...> /* the generic case, to
53  handle types satisfying [TypeFeature](TypeFeature_requirements.html) */
54  {
55  static_assert(
56  !std::is_void<FIRST_FEATURE>::value, "[cv-qualified] void does not satisfy TypeFeature");
57 
58  static_assert(
59  std::is_literal_type<FIRST_FEATURE>::value, "a TypeFeature must be a literal type");
60 
61  using tuple_type = detail::Tuple_Merge_t<
62 
63  // add FIRST_FEATURE to the tuple
64  std::tuple<FIRST_FEATURE>,
65 
66  /* use recursively feature_list to add the other features, but removes
67  FIRST_FEATURE from the result */
68  detail::
69  Tuple_Remove_t<typename feature_list<OTHER_FEATURES...>::tuple_type, FIRST_FEATURE>>;
70  };
71  template <typename... GROUPED_FEATURES, typename... OTHER_FEATURES>
72  struct feature_list<feature_list<GROUPED_FEATURES...>, OTHER_FEATURES...> /* handle
73  nesting of feature_list's */
74  {
75  using tuple_type = detail::Tuple_Merge_t<
76 
77  // add to the tuple GROUPED_FEATURES (the nested features)
78  typename feature_list<GROUPED_FEATURES...>::tuple_type,
79 
80  // add to the tuple the remaining features with the features already in GROUPED_FEATURES removed
81  detail::Tuple_Diff_t<
82  typename feature_list<OTHER_FEATURES...>::tuple_type,
83  typename feature_list<GROUPED_FEATURES...>::tuple_type>
84 
85  >;
86  };
87  template <typename... OTHER_FEATURES>
88  struct feature_list<f_none, OTHER_FEATURES...> /* strip f_none from the feature list*/
89  {
90  using tuple_type = typename feature_list<OTHER_FEATURES...>::tuple_type;
91  };
92 
100  struct f_none
101  {
102  };
103 
105  class f_size
106  {
107  public:
109  template <typename TARGET_TYPE> constexpr static f_size make() noexcept
110  {
111  // constraining the size of types allows to reduce the runtime checks to detect pointer arithmetic overflow
112  static_assert(
113  sizeof(TARGET_TYPE) < (std::numeric_limits<uintptr_t>::max)() / 4,
114  "Type with size >= 1/4 of the address space are not supported");
115 
116  return f_size{sizeof(TARGET_TYPE)};
117  }
118 
120  DENSITY_NODISCARD constexpr size_t operator()() const noexcept { return m_size; }
121 
122  private:
123  constexpr f_size(size_t i_size) noexcept : m_size(i_size) {}
124  size_t const m_size;
125  };
126 
129  {
130  public:
132  template <typename TARGET_TYPE> constexpr static f_alignment make() noexcept
133  {
134  // constraining the alignment of types allows to reduce the runtime checks to detect pointer arithmetic overflow
135  static_assert(
136  alignof(TARGET_TYPE) < (std::numeric_limits<uintptr_t>::max)() / 4,
137  "Type with alignment >= 1/4 of the address space are not supported");
138 
139  return f_alignment{alignof(TARGET_TYPE)};
140  }
141 
143  DENSITY_NODISCARD constexpr size_t operator()() const noexcept { return m_alignment; }
144 
145  private:
146  constexpr f_alignment(size_t i_alignment) noexcept : m_alignment(i_alignment) {}
147  size_t const m_alignment;
148  };
149 
154  {
155  public:
157  template <typename TARGET_TYPE> constexpr static f_default_construct make() noexcept
158  {
159  return f_default_construct{&invoke<TARGET_TYPE>};
160  }
161 
166  void operator()(void * i_dest) const { (*m_function)(i_dest); }
167 
168  private:
169  using Function = void (*)(void * i_dest);
170  Function const m_function;
171  constexpr f_default_construct(Function i_function) : m_function(i_function) {}
172  template <typename TARGET_TYPE> static void invoke(void * i_dest)
173  {
174  DENSITY_ASSUME(i_dest != nullptr);
175  new (i_dest) TARGET_TYPE();
176  }
177  };
178 
182  {
183  public:
185  template <typename TARGET_TYPE> constexpr static f_copy_construct make() noexcept
186  {
187  return f_copy_construct{&invoke<TARGET_TYPE>};
188  }
189 
197  void operator()(void * i_dest, const void * i_source) const
198  {
199  (*m_function)(i_dest, i_source);
200  }
201 
202  private:
203  using Function = void (*)(void * i_dest, const void * i_source);
204  Function const m_function;
205  constexpr f_copy_construct(Function i_function) : m_function(i_function) {}
206  template <typename TARGET_TYPE> static void invoke(void * i_dest, const void * i_source)
207  {
208  DENSITY_ASSUME(i_dest != nullptr);
209  DENSITY_ASSUME(i_source != nullptr);
210  const TARGET_TYPE & source = *static_cast<const TARGET_TYPE *>(i_source);
211  new (i_dest) TARGET_TYPE(source);
212  }
213  };
214 
218  {
219  public:
221  template <typename TARGET_TYPE> constexpr static f_move_construct make() noexcept
222  {
223  return f_move_construct{&invoke<TARGET_TYPE>};
224  }
225 
233  void operator()(void * i_dest, void * i_source) const { (*m_function)(i_dest, i_source); }
234 
235  private:
236  using Function = void (*)(void * i_dest, void * i_source);
237  Function const m_function;
238  constexpr f_move_construct(Function i_function) : m_function(i_function) {}
239  template <typename TARGET_TYPE> static void invoke(void * i_dest, void * i_source)
240  {
241  DENSITY_ASSUME(i_dest != nullptr);
242  DENSITY_ASSUME(i_source != nullptr);
243  TARGET_TYPE & source = *static_cast<TARGET_TYPE *>(i_source);
244  new (i_dest) TARGET_TYPE(std::move(source));
245  }
246  };
247 
251  {
252  public:
254  template <typename TARGET_TYPE> constexpr static f_copy_assign make() noexcept
255  {
256  return f_copy_assign{&invoke<TARGET_TYPE>};
257  }
258 
266  void operator()(void * i_dest, const void * i_source) const
267  {
268  (*m_function)(i_dest, i_source);
269  }
270 
271  private:
272  using Function = void (*)(void * i_dest, const void * i_source);
273  Function const m_function;
274  constexpr f_copy_assign(Function i_function) : m_function(i_function) {}
275  template <typename TARGET_TYPE> static void invoke(void * i_dest, const void * i_source)
276  {
277  DENSITY_ASSERT(i_dest != nullptr);
278  DENSITY_ASSERT(i_source != nullptr);
279  const TARGET_TYPE & source = *static_cast<const TARGET_TYPE *>(i_source);
280  TARGET_TYPE & dest = *static_cast<TARGET_TYPE *>(i_dest);
281  dest = source;
282  }
283  };
284 
288  {
289  public:
291  template <typename TARGET_TYPE> constexpr static f_move_assign make() noexcept
292  {
293  return f_move_assign{&invoke<TARGET_TYPE>};
294  }
295 
303  void operator()(void * i_dest, void * i_source) const { (*m_function)(i_dest, i_source); }
304 
305  private:
306  using Function = void (*)(void * i_dest, void * i_source);
307  Function const m_function;
308  constexpr f_move_assign(Function i_function) : m_function(i_function) {}
309  template <typename TARGET_TYPE> static void invoke(void * i_dest, void * i_source)
310  {
311  DENSITY_ASSERT(i_dest != nullptr);
312  DENSITY_ASSERT(i_source != nullptr);
313  const TARGET_TYPE & source = *static_cast<TARGET_TYPE *>(i_source);
314  TARGET_TYPE & dest = *static_cast<TARGET_TYPE *>(i_dest);
315  dest = std::move(source);
316  }
317  };
318 
321  class f_destroy
322  {
323  public:
325  template <typename TARGET_TYPE> constexpr static f_destroy make() noexcept
326  {
327  return f_destroy{&invoke<TARGET_TYPE>};
328  }
329 
335  void operator()(void * i_object) const noexcept { return (*m_function)(i_object); }
336 
337  private:
338  using Function = void (*)(void * i_dest) DENSITY_CPP17_NOEXCEPT;
339  Function const m_function;
340  constexpr f_destroy(Function i_function) : m_function(i_function) {}
341  template <typename TARGET_TYPE> static void invoke(void * i_object) noexcept
342  {
343  DENSITY_ASSUME(i_object != nullptr);
344  TARGET_TYPE * obj = static_cast<TARGET_TYPE *>(i_object);
345  static_assert(
346  noexcept(obj->TARGET_TYPE::~TARGET_TYPE()),
347  "TARGET_TYPE must be nothrow destructible");
348  obj->TARGET_TYPE::~TARGET_TYPE();
349  }
350  };
351 
354  class f_equal
355  {
356  public:
358  template <typename TARGET_TYPE> constexpr static f_equal make() noexcept
359  {
360  return f_equal{&invoke<TARGET_TYPE>};
361  }
362 
370  bool operator()(void const * i_first, void const * i_second) const noexcept
371  {
372  return (*m_function)(i_first, i_second);
373  }
374 
375  private:
376  using Function = bool (*)(void const * i_first, void const * i_second)
377  DENSITY_CPP17_NOEXCEPT;
378  Function const m_function;
379  constexpr f_equal(Function i_function) : m_function(i_function) {}
380  template <typename TARGET_TYPE>
381  static bool invoke(void const * i_first, void const * i_second) noexcept
382  {
383  DENSITY_ASSUME(i_first != nullptr);
384  DENSITY_ASSUME(i_second != nullptr);
385  auto const & first = *static_cast<TARGET_TYPE const *>(i_first);
386  auto const & second = *static_cast<TARGET_TYPE const *>(i_second);
387  bool const result = first == second;
388  return result;
389  }
390  };
391 
394  class f_less
395  {
396  public:
398  template <typename TARGET_TYPE> constexpr static f_less make() noexcept
399  {
400  return f_less{&invoke<TARGET_TYPE>};
401  }
402 
410  bool operator()(void const * i_first, void const * i_second) const
411  {
412  return (*m_function)(i_first, i_second);
413  }
414 
415  private:
416  using Function = bool (*)(void const * i_first, void const * i_second)
417  DENSITY_CPP17_NOEXCEPT;
418  Function const m_function;
419  constexpr f_less(Function i_function) : m_function(i_function) {}
420  template <typename TARGET_TYPE>
421  static bool invoke(void const * i_first, void const * i_second) noexcept
422  {
423  DENSITY_ASSUME(i_first != nullptr);
424  DENSITY_ASSUME(i_second != nullptr);
425  auto const & first = *static_cast<TARGET_TYPE const *>(i_first);
426  auto const & second = *static_cast<TARGET_TYPE const *>(i_second);
427  bool const result = first < second;
428  return result;
429  }
430  };
431 
435  class f_hash
436  {
437  public:
439  template <typename TARGET_TYPE> constexpr static f_hash make() noexcept
440  {
441  return f_hash{&invoke<TARGET_TYPE>};
442  }
443 
448  DENSITY_NODISCARD size_t operator()(const void * i_source) const noexcept
449  {
450  return (*m_function)(i_source);
451  }
452 
453  private:
454  using Function = size_t (*)(const void * i_source) DENSITY_CPP17_NOEXCEPT;
455  Function const m_function;
456  constexpr f_hash(Function i_function) noexcept : m_function(i_function) {}
457  template <typename TARGET_TYPE> static size_t invoke(const void * i_source) noexcept
458  {
459  DENSITY_ASSUME(i_source != nullptr);
460  static_assert(
461  noexcept(std::hash<TARGET_TYPE>()(*static_cast<const TARGET_TYPE *>(i_source))),
462  "Specializations of std::hash must be nothrow constructible and invokable");
463  return std::hash<TARGET_TYPE>()(*static_cast<const TARGET_TYPE *>(i_source));
464  }
465  };
466 
468  class f_rtti
469  {
470  public:
472  template <typename TARGET_TYPE> constexpr static f_rtti make() noexcept
473  {
474  return f_rtti{&invoke<TARGET_TYPE>};
475  }
476 
478  DENSITY_NODISCARD std::type_info const & operator()() const noexcept
479  {
480  return (*m_function)();
481  }
482 
483  private:
484  using Function = std::type_info const & (*)() DENSITY_CPP17_NOEXCEPT;
485  Function const m_function;
486  constexpr f_rtti(Function i_function) noexcept : m_function(i_function) {}
487  template <typename TARGET_TYPE> static const std::type_info & invoke() noexcept
488  {
489  return typeid(TARGET_TYPE);
490  }
491  };
492 
494  using default_type_features =
496 
509  template <typename FEATURE_LIST, typename... TARGET_FEATURES> struct has_features;
510  template <typename FEATURE_LIST>
511  struct has_features<FEATURE_LIST> : std::integral_constant<bool, true>
512  {
513  };
514  template <typename FEATURE_LIST, typename FIRST_FEATURE, typename... OTHER_FEATURES>
515  struct has_features<FEATURE_LIST, FIRST_FEATURE, OTHER_FEATURES...>
516  : std::integral_constant<
517  bool,
518 
519  (detail::Tuple_FindFirst<typename FEATURE_LIST::tuple_type, FIRST_FEATURE>::index <
520  std::tuple_size<typename FEATURE_LIST::tuple_type>::value) &&
521  has_features<FEATURE_LIST, OTHER_FEATURES...>::value
522 
523  >
524  {
525  };
526 
665  template <typename... FEATURES> class runtime_type
666  {
667  public:
669  using feature_list_type = typename std::conditional<
670  (sizeof...(FEATURES) > 0),
671  feature_list<FEATURES...>,
672  default_type_features>::type;
673 
679  using tuple_type = typename feature_list_type::tuple_type;
680 
688  template <typename TARGET_TYPE> constexpr static runtime_type make() noexcept
689  {
690  return runtime_type(
691  &detail::FeatureTable<tuple_type, typename std::decay<TARGET_TYPE>::type>::s_table);
692  }
693 
701  constexpr runtime_type() noexcept = default;
702 
711  template <typename... OTHER_FEATURES>
712  constexpr runtime_type(
713  const runtime_type<OTHER_FEATURES...> & i_source
714 #ifndef DOXYGEN_DOC_GENERATION
715  ,
716  typename std::enable_if<
717  std::is_same<
718  typename runtime_type::tuple_type,
720  int>::type = 0
721 #endif
722  ) noexcept
723  : m_feature_table(i_source.m_feature_table)
724  {
725  }
726 
738  template <typename... OTHER_FEATURES>
739  DENSITY_CPP14_CONSTEXPR
740 #ifndef DOXYGEN_DOC_GENERATION
741  typename std::enable_if<
742  std::is_same<
743  typename runtime_type::tuple_type,
744  typename runtime_type<OTHER_FEATURES...>::tuple_type>::value,
745  runtime_type>::type &
746 #else
747  runtime_type &
748 #endif
749  operator=(const runtime_type<OTHER_FEATURES...> & i_source) noexcept
750  {
751  m_feature_table = i_source.m_feature_table;
752  return *this;
753  }
754 
760  friend void swap(runtime_type & i_first, runtime_type & i_second) noexcept
761  {
762  std::swap(i_first.m_feature_table, i_second.m_feature_table);
763  }
764 
768  constexpr bool empty() const noexcept { return m_feature_table == nullptr; }
769 
776  DENSITY_CPP14_CONSTEXPR void clear() noexcept { m_feature_table = nullptr; }
777 
798  constexpr size_t size() const noexcept { return get_feature<f_size>()(); }
799 
820  constexpr size_t alignment() const noexcept { return get_feature<f_alignment>()(); }
821 
849  void default_construct(void * i_dest) const
850  {
851  DENSITY_ASSERT(!empty());
852  get_feature<f_default_construct>()(i_dest);
853  }
854 
881  void copy_construct(void * i_dest, const void * i_source) const
882  {
883  DENSITY_ASSERT(!empty());
884  get_feature<f_copy_construct>()(i_dest, i_source);
885  }
886 
914  void move_construct(void * i_dest, void * i_source) const
915  {
916  DENSITY_ASSERT(!empty());
917  get_feature<f_move_construct>()(i_dest, i_source);
918  }
919 
942  void destroy(void * i_dest) const noexcept
943  {
944  DENSITY_ASSERT(!empty());
945  get_feature<f_destroy>()(i_dest);
946  }
947 
966  const std::type_info & type_info() const noexcept
967  {
968  DENSITY_ASSERT(!empty());
969  return get_feature<f_rtti>()();
970  }
971 
994  bool are_equal(const void * i_first, const void * i_second) const noexcept
995  {
996  DENSITY_ASSERT(i_first != nullptr && i_second != nullptr && !empty());
997  return get_feature<f_equal>()(i_first, i_second);
998  }
999 
1000  /* Returns the instance of a feature associated to the target type.
1001 
1002  \b Requires:
1003  - If the feature FEATURE is not supported by this specialization a compile
1004  error is reported (this function is not SFINAE-friendly).
1005 
1006  \b Precoditions:
1007  The behavior is undefined if any of these conditions is not satisfied:
1008  - The runtime_type is not empty
1009 
1010  \b Throws: nothing. */
1011  template <typename FEATURE> const FEATURE & get_feature() const noexcept
1012  {
1013  static_assert(has_features<feature_list_type, FEATURE>::value, "feature not found");
1014  return std::get<detail::Tuple_FindFirst<tuple_type, FEATURE>::index>(*m_feature_table);
1015  }
1016 
1020  constexpr bool operator==(const runtime_type & i_other) const noexcept
1021  {
1022  return m_feature_table == i_other.m_feature_table;
1023  }
1024 
1028  constexpr bool operator!=(const runtime_type & i_other) const noexcept
1029  {
1030  return m_feature_table != i_other.m_feature_table;
1031  }
1032 
1039  template <typename TARGET_TYPE> constexpr bool is() const noexcept
1040  {
1041  return m_feature_table ==
1042  &detail::FeatureTable<tuple_type, typename std::decay<TARGET_TYPE>::type>::
1043  s_table;
1044  }
1045 
1046  private:
1047  constexpr runtime_type(const tuple_type * i_feature_table) noexcept
1048  : m_feature_table(i_feature_table)
1049  {
1050  }
1051 
1052  private:
1053 #ifndef DOXYGEN_DOC_GENERATION
1054  template <typename...> friend class runtime_type;
1055  friend struct std::hash<density::runtime_type<FEATURES...>>;
1056 #endif
1057  const tuple_type * m_feature_table = nullptr;
1058  };
1059 } // namespace density
1060 
1061 namespace std
1062 {
1065  template <typename... FEATURES> struct hash<density::runtime_type<FEATURES...>>
1066  {
1067  size_t operator()(const density::runtime_type<FEATURES...> & i_runtime_type) const noexcept
1068  {
1069  return std::hash<const void *>()(i_runtime_type.m_feature_table);
1070  }
1071  };
1072 
1073 } // namespace std
Definition: runtime_type.h:354
DENSITY_NODISCARD constexpr size_t operator()() const noexcept
Definition: runtime_type.h:120
static constexpr f_rtti make() noexcept
Definition: runtime_type.h:472
DENSITY_NODISCARD std::type_info const & operator()() const noexcept
Definition: runtime_type.h:478
Definition: conc_function_queue.h:11
Definition: runtime_type.h:665
static constexpr f_copy_construct make() noexcept
Definition: runtime_type.h:185
DENSITY_NODISCARD size_t operator()(const void *i_source) const noexcept
Definition: runtime_type.h:448
void operator()(void *i_dest, const void *i_source) const
Definition: runtime_type.h:197
static constexpr f_alignment make() noexcept
Definition: runtime_type.h:132
void default_construct(void *i_dest) const
Definition: runtime_type.h:849
Definition: runtime_type.h:1061
static constexpr f_move_assign make() noexcept
Definition: runtime_type.h:291
static constexpr f_default_construct make() noexcept
Definition: runtime_type.h:157
const std::type_info & type_info() const noexcept
Definition: runtime_type.h:966
Definition: runtime_type.h:394
constexpr size_t size() const noexcept
Definition: runtime_type.h:798
static constexpr f_destroy make() noexcept
Definition: runtime_type.h:325
DENSITY_NODISCARD constexpr size_t operator()() const noexcept
Definition: runtime_type.h:143
#define DENSITY_ASSERT(...)
Definition: density_config.h:19
void operator()(void *i_object) const noexcept
Definition: runtime_type.h:335
static constexpr f_copy_assign make() noexcept
Definition: runtime_type.h:254
void move_construct(void *i_dest, void *i_source) const
Definition: runtime_type.h:914
Definition: runtime_type.h:153
Definition: runtime_type.h:181
void operator()(void *i_dest, void *i_source) const
Definition: runtime_type.h:233
friend void swap(runtime_type &i_first, runtime_type &i_second) noexcept
Definition: runtime_type.h:760
Definition: runtime_type.h:128
bool operator()(void const *i_first, void const *i_second) const noexcept
Definition: runtime_type.h:370
void operator()(void *i_dest, void *i_source) const
Definition: runtime_type.h:303
constexpr bool is() const noexcept
Definition: runtime_type.h:1039
bool operator()(void const *i_first, void const *i_second) const
Definition: runtime_type.h:410
static constexpr f_hash make() noexcept
Definition: runtime_type.h:439
DENSITY_CPP14_CONSTEXPR void clear() noexcept
Definition: runtime_type.h:776
static constexpr f_less make() noexcept
Definition: runtime_type.h:398
Definition: runtime_type.h:468
constexpr bool operator!=(const runtime_type &i_other) const noexcept
Definition: runtime_type.h:1028
constexpr bool empty() const noexcept
Definition: runtime_type.h:768
Definition: runtime_type.h:321
void operator()(void *i_dest) const
Definition: runtime_type.h:166
void destroy(void *i_dest) const noexcept
Definition: runtime_type.h:942
static constexpr f_size make() noexcept
Definition: runtime_type.h:109
Definition: runtime_type.h:250
DENSITY_CPP14_CONSTEXPR runtime_type & operator=(const runtime_type< OTHER_FEATURES... > &i_source) noexcept
Definition: runtime_type.h:749
Definition: runtime_type.h:46
bool are_equal(const void *i_first, const void *i_second) const noexcept
Definition: runtime_type.h:994
typename feature_list_type::tuple_type tuple_type
Definition: runtime_type.h:679
Definition: runtime_type.h:217
static constexpr f_move_construct make() noexcept
Definition: runtime_type.h:221
Definition: runtime_type.h:287
Definition: runtime_type.h:435
constexpr runtime_type(const runtime_type< OTHER_FEATURES... > &i_source) noexcept
Definition: runtime_type.h:712
Definition: runtime_type.h:105
Definition: runtime_type.h:509
#define DENSITY_ASSUME(bool_expr,...)
Definition: density_config.h:46
static constexpr f_equal make() noexcept
Definition: runtime_type.h:358
Definition: runtime_type.h:100
constexpr bool operator==(const runtime_type &i_other) const noexcept
Definition: runtime_type.h:1020
void copy_construct(void *i_dest, const void *i_source) const
Definition: runtime_type.h:881
constexpr size_t alignment() const noexcept
Definition: runtime_type.h:820
void operator()(void *i_dest, const void *i_source) const
Definition: runtime_type.h:266