| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- //
- // typecast.h
- // reflection
- //
- // Created by Sam Jaffe on 7/4/22.
- // Copyright © 2022 Sam Jaffe. All rights reserved.
- //
- #pragma once
- #include <functional>
- #include <typeindex>
- #include <unordered_map>
- #include <utility>
- #if defined __has_include
- #if __has_include(<magic_enum.hpp>)
- #include <magic_enum.hpp>
- #endif
- #endif
- #include "reflection/forward.h"
- #include "reflection/object.h"
- namespace reflection {
- template <typename T> class TypeCast {
- public:
- static bool has_cast(Object const & obj) { return get_.count(obj.type()); }
- static T get(Object const & obj) { return get_.at(obj.type())(obj); }
- static void set(Object & obj, T const & value) {
- set_.at(obj.type())(obj, value);
- }
- operator bool() const { return true; }
- template <typename I, typename O, typename S>
- TypeCast & bind(T (*to)(I), O (*from)(S)) {
- bind_impl(to, from);
- TypeCast<std::decay_t<I>>().template bind_impl(from, to);
- return *this;
- }
- template <typename V> TypeCast & bind() {
- #if defined NEARGYE_MAGIC_ENUM_HPP
- if constexpr (std::is_same_v<V, std::string> && std::is_enum_v<T>) {
- bind<V const &, V, T>([](V const &str) -> T { return *magic_enum::enum_cast<T>(str); },
- [](T val) { return std::string(magic_enum::enum_name(val)); });
- } else
- #endif
- if constexpr (!std::is_same_v<V, T>) {
- bind_impl<V>();
- TypeCast<V>().template bind_impl<T>();
- }
- return *this;
- }
- template <typename V1, typename V2, typename... Vs> TypeCast & bind() {
- return bind<V1>().template bind<V2, Vs...>();
- }
- private:
- template <typename I, typename O, typename S>
- void bind_impl(T (*to)(I), O (*from)(S)) {
- static_assert(std::is_same_v<std::decay_t<S>, T>,
- "this types must be compatible");
- static_assert(std::is_same_v<std::decay_t<I>, std::decay_t<I>>,
- "cast types must be compatible");
- using V = std::decay_t<I>;
- get_.emplace(typeid(V),
- [to](auto & obj) { return to(static_cast<V const &>(obj)); });
- set_.emplace(typeid(V), [from](auto & obj, T const & val) {
- static_cast<V &>(obj) = from(val);
- });
- }
- template <typename V> void bind_impl() {
- get_.emplace(typeid(V), [](auto & obj) {
- return static_cast<T>(static_cast<V const &>(obj));
- });
- set_.emplace(typeid(V), [](auto & obj, T val) {
- static_cast<V &>(obj) = static_cast<V>(val);
- });
- }
- private:
- template <typename S> friend class TypeCast;
- static TypeMap<std::function<T(Object const &)>> get_;
- static TypeMap<std::function<void(Object &, T const &)>> set_;
- };
- template <typename T>
- TypeMap<std::function<T(Object const &)>> TypeCast<T>::get_;
- template <typename T>
- TypeMap<std::function<void(Object &, T const &)>> TypeCast<T>::set_;
- }
- #if defined REFLECTION_TYPE_CAST_IMPLEMENTATION
- namespace reflection {
- INSTANTIATE_REFLECTION_TYPECAST(bool);
- INSTANTIATE_REFLECTION_TYPECAST(int16_t);
- INSTANTIATE_REFLECTION_TYPECAST(int32_t);
- INSTANTIATE_REFLECTION_TYPECAST(int64_t);
- INSTANTIATE_REFLECTION_TYPECAST(uint16_t);
- INSTANTIATE_REFLECTION_TYPECAST(uint32_t);
- INSTANTIATE_REFLECTION_TYPECAST(uint64_t);
- INSTANTIATE_REFLECTION_TYPECAST(float);
- INSTANTIATE_REFLECTION_TYPECAST(double);
- INSTANTIATE_REFLECTION_TYPECAST(long double);
- INSTANTIATE_REFLECTION_TYPECAST(std::string, "string");
- // Bind boolean types to all integer types
- REFLECTION_TYPE_CAST(bool)
- .bind<int16_t, int32_t, int64_t>()
- .bind<uint16_t, uint32_t, uint64_t>();
- // Bind all integer types (wider than 1byte) to each other.
- REFLECTION_TYPE_CAST(int32_t)
- .bind<int16_t, int32_t, int64_t>()
- .bind<uint16_t, uint32_t, uint64_t>()
- .bind<float, double, long double>();
- REFLECTION_TYPE_CAST(uint32_t)
- .bind<int16_t, int32_t, int64_t>()
- .bind<uint16_t, uint32_t, uint64_t>()
- .bind<float, double, long double>();
- REFLECTION_TYPE_CAST(int16_t)
- .bind<int16_t, int32_t, int64_t>()
- .bind<uint16_t, uint32_t, uint64_t>()
- .bind<float, double, long double>();
- REFLECTION_TYPE_CAST(uint16_t)
- .bind<int16_t, int32_t, int64_t>()
- .bind<uint16_t, uint32_t, uint64_t>()
- .bind<float, double, long double>();
- REFLECTION_TYPE_CAST(int64_t)
- .bind<int16_t, int32_t, int64_t>()
- .bind<uint16_t, uint32_t, uint64_t>()
- .bind<float, double, long double>();
- REFLECTION_TYPE_CAST(uint64_t)
- .bind<int16_t, int32_t, int64_t>()
- .bind<uint16_t, uint32_t, uint64_t>()
- .bind<float, double, long double>();
- // Mututally bind all floating point numbers
- REFLECTION_TYPE_CAST(float).bind<float, double, long double>();
- REFLECTION_TYPE_CAST(double).bind<float, double, long double>();
- REFLECTION_TYPE_CAST(long double).bind<float, double, long double>();
- }
- #endif
|