10 #ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ 11 #define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ 19 #include <type_traits> 22 #include "../chaiscript_threading.hpp" 23 #include "../utility/static_string.hpp" 24 #include "bad_boxed_cast.hpp" 25 #include "boxed_cast_helper.hpp" 26 #include "boxed_value.hpp" 27 #include "type_info.hpp" 87 const Type_Info &
to()
const noexcept {
return m_to; }
90 virtual bool bidir()
const noexcept {
return true; }
96 : m_to(std::move(t_to))
97 , m_from(std::move(t_from)) {
105 template<
typename From,
typename To>
109 if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>())) {
110 if (t_from.is_pointer()) {
112 if (t_from.is_const()) {
115 = std::static_pointer_cast<const To>(
detail::Cast_Helper<std::shared_ptr<const From>>::cast(t_from,
nullptr))) {
118 throw std::bad_cast();
123 if (
auto data = std::static_pointer_cast<To>(
detail::Cast_Helper<std::shared_ptr<From>>::cast(t_from,
nullptr))) {
126 throw std::bad_cast();
132 if (t_from.is_const()) {
134 const To &data =
static_cast<const To &
>(d);
138 To &data =
static_cast<To &
>(d);
148 template<
typename From,
typename To>
152 if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>())) {
153 if (t_from.is_pointer()) {
155 if (t_from.is_const()) {
158 = std::dynamic_pointer_cast<const To>(
detail::Cast_Helper<std::shared_ptr<const From>>::cast(t_from,
nullptr))) {
161 throw std::bad_cast();
166 if (
auto data = std::dynamic_pointer_cast<To>(
detail::Cast_Helper<std::shared_ptr<From>>::cast(t_from,
nullptr))) {
169 #ifdef CHAISCRIPT_LIBCPP 170 if (std::string(
typeid(To).name()).find(
"Assignable_Proxy_Function") != std::string::npos) {
173 if (std::string(
typeid(*from).name()).find(
"Assignable_Proxy_Function_Impl") != std::string::npos) {
174 return std::static_pointer_cast<To>(
from);
178 throw std::bad_cast();
184 if (t_from.is_const()) {
186 const To &data =
dynamic_cast<const To &
>(d);
190 To &data =
dynamic_cast<To &
>(d);
200 template<
typename Base,
typename Derived>
212 template<
typename Base,
typename Derived>
222 "Unable to cast down inheritance hierarchy with non-polymorphic types");
225 bool bidir()
const noexcept
override {
return false; }
230 template<
typename Callable>
235 , m_func(std::move(t_func)) {
244 return m_func(t_from);
247 bool bidir()
const noexcept
override {
return false; }
257 bool enabled =
false;
258 std::vector<Boxed_Value> saves;
262 bool operator()(
const std::type_info *t_lhs,
const std::type_info *t_rhs)
const noexcept {
263 return *t_lhs != *t_rhs && t_lhs->before(*t_rhs);
270 , m_convertableTypes()
280 const std::set<const std::type_info *, Less_Than> &thread_cache()
const {
281 auto &cache = *m_thread_cache;
282 if (cache.size() != m_num_types) {
283 chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
284 cache = m_convertableTypes;
290 void add_conversion(
const std::shared_ptr<detail::Type_Conversion_Base> &conversion) {
291 chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
292 if (find_bidir(conversion->to(), conversion->from()) != m_conversions.end()) {
295 m_conversions.insert(conversion);
296 m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()});
297 m_num_types = m_convertableTypes.size();
301 bool convertable_type()
const noexcept {
302 const auto type = user_type<T>().bare_type_info();
303 return thread_cache().count(type) != 0;
306 template<
typename To,
typename From>
307 bool converts()
const noexcept {
308 return converts(user_type<To>(), user_type<From>());
312 const auto &types = thread_cache();
313 if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0) {
314 return has_conversion(to, from);
320 template<
typename To>
322 return boxed_type_conversion(user_type<To>(), t_saves, from);
325 template<
typename From>
327 return boxed_type_down_conversion(user_type<From>(), t_saves, to);
332 Boxed_Value ret = get_conversion(to, from.get_type_info())->convert(from);
333 if (t_saves.enabled) {
334 t_saves.saves.push_back(ret);
337 }
catch (
const std::out_of_range &) {
339 }
catch (
const std::bad_cast &) {
346 Boxed_Value ret = get_conversion(to.get_type_info(),
from)->convert_down(to);
347 if (t_saves.enabled) {
348 t_saves.saves.push_back(ret);
351 }
catch (
const std::out_of_range &) {
353 }
catch (
const std::bad_cast &) {
358 static void enable_conversion_saves(
Conversion_Saves &t_saves,
bool t_val) { t_saves.enabled = t_val; }
361 std::vector<Boxed_Value> ret;
362 std::swap(ret, t_saves.saves);
367 chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
368 return find_bidir(to, from) != m_conversions.end();
371 std::shared_ptr<detail::Type_Conversion_Base> get_conversion(
const Type_Info &to,
const Type_Info &from)
const {
372 chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
374 const auto itr = find(to, from);
376 if (itr != m_conversions.end()) {
379 throw std::out_of_range(std::string(
"No such conversion exists from ") + from.bare_name() +
" to " + to.bare_name());
383 Conversion_Saves &conversion_saves()
const noexcept {
return *m_conversion_saves; }
386 std::set<std::shared_ptr<detail::Type_Conversion_Base>>::const_iterator find_bidir(
const Type_Info &to,
const Type_Info &from)
const {
387 return std::find_if(m_conversions.begin(),
389 [&
to, &
from](
const std::shared_ptr<detail::Type_Conversion_Base> &conversion) ->
bool {
390 return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from))
391 || (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from));
395 std::set<std::shared_ptr<detail::Type_Conversion_Base>>::const_iterator find(
const Type_Info &to,
const Type_Info &from)
const {
396 return std::find_if(m_conversions.begin(),
398 [&
to, &
from](
const std::shared_ptr<detail::Type_Conversion_Base> &conversion) {
399 return conversion->to().bare_equal(to) && conversion->from().bare_equal(from);
403 std::set<std::shared_ptr<detail::Type_Conversion_Base>> get_conversions()
const {
404 chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
406 return m_conversions;
409 mutable chaiscript::detail::threading::shared_mutex m_mutex;
410 std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions;
411 std::set<const std::type_info *, Less_Than> m_convertableTypes;
412 std::atomic_size_t m_num_types;
420 : m_conversions(t_conversions)
424 const Type_Conversions *operator->()
const noexcept {
return &m_conversions.get(); }
426 const Type_Conversions *
get()
const noexcept {
return &m_conversions.get(); }
431 std::reference_wrapper<const Type_Conversions> m_conversions;
432 std::reference_wrapper<Type_Conversions::Conversion_Saves> m_saves;
435 using Type_Conversion = std::shared_ptr<chaiscript::detail::Type_Conversion_Base>;
458 template<
typename Base,
typename Derived>
462 static_assert(std::is_base_of<Base, Derived>::value,
"Classes are not related by inheritance");
464 if constexpr (std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value) {
465 return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Dynamic_Conversion_Impl<Base, Derived>>();
467 return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Static_Conversion_Impl<Base, Derived>>();
471 template<
typename Callable>
472 Type_Conversion type_conversion(
const Type_Info &t_from,
const Type_Info &t_to,
const Callable &t_func) {
473 return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func);
476 template<
typename From,
typename To,
typename Callable>
477 Type_Conversion type_conversion(
const Callable &t_function) {
483 return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(),
488 template<
typename From,
typename To>
489 Type_Conversion type_conversion() {
490 static_assert(std::is_convertible<From, To>::value,
"Types are not automatically convertible");
496 return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(),
501 template<
typename To>
502 Type_Conversion vector_conversion() {
507 vec.reserve(from_vec.size());
515 return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(),
520 template<
typename To>
521 Type_Conversion map_conversion() {
523 const std::map<std::string, Boxed_Value> &from_map
527 for (
const std::pair<const std::string, Boxed_Value> &p : from_map) {
534 return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(
535 user_type<std::map<std::string, Boxed_Value>>(), user_type<To>(), func);
Definition: type_conversions.hpp:82
Compile time deduced information about a type.
Definition: type_info.hpp:27
Type_Conversion base_class()
Used to register a to / parent class relationship with ChaiScript.
Definition: type_conversions.hpp:459
Definition: type_conversions.hpp:417
Namespace chaiscript contains every API call that the average user will be concerned with...
Error thrown when there's a problem with type conversion.
Definition: type_conversions.hpp:32
Definition: type_conversions.hpp:261
Definition: type_conversions.hpp:201
Definition: type_conversions.hpp:149
A wrapper for holding any valid C++ type.
Definition: boxed_value.hpp:24
Definition: type_conversions.hpp:213
Thrown in the event that a Boxed_Value cannot be cast to the desired type.
Definition: bad_boxed_cast.hpp:31
Type_Info from
Type_Info contained in the Boxed_Value.
Definition: bad_boxed_cast.hpp:55
Definition: type_conversions.hpp:231
Typesafe thread specific storage.
Definition: chaiscript_threading.hpp:59
Definition: static_string.hpp:11
Definition: type_conversions.hpp:42
const char * what() const noexcept override
Description of what error occurred.
Definition: bad_boxed_cast.hpp:53
Definition: type_conversions.hpp:106
Definition: type_conversions.hpp:256
Boxed_Value convert(const Boxed_Value &t_from) const override
Definition: type_conversions.hpp:242
const std::type_info * to
std::type_info of the desired (but failed) result type
Definition: bad_boxed_cast.hpp:56
Definition: type_conversions.hpp:254
The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner.
Definition: boxed_cast_helper.hpp:251
Definition: type_conversions.hpp:61