typecast.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. //
  2. // typecast.h
  3. // reflection
  4. //
  5. // Created by Sam Jaffe on 7/4/22.
  6. // Copyright © 2022 Sam Jaffe. All rights reserved.
  7. //
  8. #pragma once
  9. #include <functional>
  10. #include <typeindex>
  11. #include <unordered_map>
  12. #include <utility>
  13. #include "reflection/forward.h"
  14. #include "reflection/object.h"
  15. namespace reflection {
  16. template <typename T> class TypeCast {
  17. public:
  18. static bool has_cast(Object const & obj) { return get_.count(obj.type()); }
  19. static T get(Object const & obj) { return get_.at(obj.type())(obj); }
  20. static void set(Object & obj, T const & value) {
  21. set_.at(obj.type())(obj, value);
  22. }
  23. operator bool() const { return true; }
  24. template <typename I, typename O, typename S>
  25. TypeCast & bind(T (*to)(I), O (*from)(S)) {
  26. return bind(std::function(to), std::function(from));
  27. }
  28. template <typename I, typename O, typename S>
  29. TypeCast & bind(std::function<T(I)> to, std::function<O(S)> from) {
  30. bind_impl(to, from);
  31. TypeCast<std::decay_t<I>>().template bind_impl(from, to);
  32. return *this;
  33. }
  34. template <typename V> TypeCast & bind() {
  35. if constexpr (!std::is_same_v<V, T>) {
  36. bind_impl<V>();
  37. TypeCast<V>().template bind_impl<T>();
  38. }
  39. return *this;
  40. }
  41. template <typename V1, typename V2, typename... Vs> TypeCast & bind() {
  42. return bind<V1>().template bind<V2, Vs...>();
  43. }
  44. private:
  45. template <typename I, typename O, typename S>
  46. void bind_impl(std::function<T(I)> to, std::function<O(S)> from) {
  47. static_assert(std::is_same_v<std::decay_t<S>, T>,
  48. "this types must be compatible");
  49. static_assert(std::is_same_v<std::decay_t<I>, std::decay_t<I>>,
  50. "cast types must be compatible");
  51. using V = std::decay_t<I>;
  52. get_.emplace(typeid(V),
  53. [to](auto & obj) { return to(static_cast<V const &>(obj)); });
  54. set_.emplace(typeid(V), [from](auto & obj, T const & val) {
  55. static_cast<V &>(obj) = from(val);
  56. });
  57. }
  58. template <typename V> void bind_impl() {
  59. get_.emplace(typeid(V), [](auto & obj) {
  60. return static_cast<T>(static_cast<V const &>(obj));
  61. });
  62. set_.emplace(typeid(V), [](auto & obj, T val) {
  63. static_cast<V &>(obj) = static_cast<V>(val);
  64. });
  65. }
  66. private:
  67. template <typename S> friend class TypeCast;
  68. static TypeMap<std::function<T(Object const &)>> get_;
  69. static TypeMap<std::function<void(Object &, T const &)>> set_;
  70. };
  71. template <typename T>
  72. TypeMap<std::function<T(Object const &)>> TypeCast<T>::get_;
  73. template <typename T>
  74. TypeMap<std::function<void(Object &, T const &)>> TypeCast<T>::set_;
  75. }
  76. #if defined REFLECTION_TYPE_CAST_IMPLEMENTATION
  77. namespace reflection {
  78. INSTANTIATE_REFLECTION_TYPECAST(bool);
  79. INSTANTIATE_REFLECTION_TYPECAST(int16_t);
  80. INSTANTIATE_REFLECTION_TYPECAST(int32_t);
  81. INSTANTIATE_REFLECTION_TYPECAST(int64_t);
  82. INSTANTIATE_REFLECTION_TYPECAST(uint16_t);
  83. INSTANTIATE_REFLECTION_TYPECAST(uint32_t);
  84. INSTANTIATE_REFLECTION_TYPECAST(uint64_t);
  85. INSTANTIATE_REFLECTION_TYPECAST(float);
  86. INSTANTIATE_REFLECTION_TYPECAST(double);
  87. INSTANTIATE_REFLECTION_TYPECAST(long double);
  88. INSTANTIATE_REFLECTION_TYPECAST(std::string);
  89. // Bind boolean types to all integer types
  90. REFLECTION_TYPE_CAST(bool)
  91. .bind<int16_t, int32_t, int64_t>()
  92. .bind<uint16_t, uint32_t, uint64_t>();
  93. // Bind all integer types (wider than 1byte) to each other.
  94. REFLECTION_TYPE_CAST(int32_t)
  95. .bind<int16_t, int32_t, int64_t>()
  96. .bind<uint16_t, uint32_t, uint64_t>();
  97. REFLECTION_TYPE_CAST(uint32_t)
  98. .bind<int16_t, int32_t, int64_t>()
  99. .bind<uint16_t, uint32_t, uint64_t>();
  100. REFLECTION_TYPE_CAST(int16_t)
  101. .bind<int16_t, int32_t, int64_t>()
  102. .bind<uint16_t, uint32_t, uint64_t>();
  103. REFLECTION_TYPE_CAST(uint16_t)
  104. .bind<int16_t, int32_t, int64_t>()
  105. .bind<uint16_t, uint32_t, uint64_t>();
  106. REFLECTION_TYPE_CAST(int64_t)
  107. .bind<int16_t, int32_t, int64_t>()
  108. .bind<uint16_t, uint32_t, uint64_t>();
  109. REFLECTION_TYPE_CAST(uint64_t)
  110. .bind<int16_t, int32_t, int64_t>()
  111. .bind<uint16_t, uint32_t, uint64_t>();
  112. // Mututally bind all floating point numbers
  113. REFLECTION_TYPE_CAST(float).bind<float, double, long double>();
  114. REFLECTION_TYPE_CAST(double).bind<float, double, long double>();
  115. REFLECTION_TYPE_CAST(long double).bind<float, double, long double>();
  116. }
  117. #endif