boxed_cast.hpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // This file is distributed under the BSD License.
  2. // See "license.txt" for details.
  3. // Copyright 2009-2012, Jonathan Turner ([email protected])
  4. // Copyright 2009-2017, Jason Turner ([email protected])
  5. // http://www.chaiscript.com
  6. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
  7. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
  8. #ifndef CHAISCRIPT_BOXED_CAST_HPP_
  9. #define CHAISCRIPT_BOXED_CAST_HPP_
  10. #include "../chaiscript_defines.hpp"
  11. #include "bad_boxed_cast.hpp"
  12. #include "boxed_cast_helper.hpp"
  13. #include "boxed_value.hpp"
  14. #include "type_conversions.hpp"
  15. #include "type_info.hpp"
  16. namespace chaiscript {
  17. class Type_Conversions;
  18. namespace detail {
  19. namespace exception {
  20. class bad_any_cast;
  21. } // namespace exception
  22. } // namespace detail
  23. } // namespace chaiscript
  24. namespace chaiscript
  25. {
  26. /// \brief Function for extracting a value stored in a Boxed_Value object
  27. /// \tparam Type The type to extract from the Boxed_Value
  28. /// \param[in] bv The Boxed_Value to extract a typed value from
  29. /// \returns Type equivalent to the requested type
  30. /// \throws exception::bad_boxed_cast If the requested conversion is not possible
  31. ///
  32. /// boxed_cast will attempt to make conversions between value, &, *, std::shared_ptr, std::reference_wrapper,
  33. /// and std::function (const and non-const) where possible. boxed_cast is used internally during function
  34. /// dispatch. This means that all of these conversions will be attempted automatically for you during
  35. /// ChaiScript function calls.
  36. ///
  37. /// \li non-const values can be extracted as const or non-const
  38. /// \li const values can be extracted only as const
  39. /// \li Boxed_Value constructed from pointer or std::reference_wrapper can be extracted as reference,
  40. /// pointer or value types
  41. /// \li Boxed_Value constructed from std::shared_ptr or value types can be extracted as reference,
  42. /// pointer, value, or std::shared_ptr types
  43. ///
  44. /// Conversions to std::function objects are attempted as well
  45. ///
  46. /// Example:
  47. /// \code
  48. /// // All of the following should succeed
  49. /// chaiscript::Boxed_Value bv(1);
  50. /// std::shared_ptr<int> spi = chaiscript::boxed_cast<std::shared_ptr<int> >(bv);
  51. /// int i = chaiscript::boxed_cast<int>(bv);
  52. /// int *ip = chaiscript::boxed_cast<int *>(bv);
  53. /// int &ir = chaiscript::boxed_cast<int &>(bv);
  54. /// std::shared_ptr<const int> cspi = chaiscript::boxed_cast<std::shared_ptr<const int> >(bv);
  55. /// const int ci = chaiscript::boxed_cast<const int>(bv);
  56. /// const int *cip = chaiscript::boxed_cast<const int *>(bv);
  57. /// const int &cir = chaiscript::boxed_cast<const int &>(bv);
  58. /// \endcode
  59. ///
  60. /// std::function conversion example
  61. /// \code
  62. /// chaiscript::ChaiScript chai;
  63. /// Boxed_Value bv = chai.eval("`+`"); // Get the functor for the + operator which is built in
  64. /// std::function<int (int, int)> f = chaiscript::boxed_cast<std::function<int (int, int)> >(bv);
  65. /// int i = f(2,3);
  66. /// assert(i == 5);
  67. /// \endcode
  68. template<typename Type>
  69. decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr)
  70. {
  71. if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) {
  72. try {
  73. return(detail::Cast_Helper<Type>::cast(bv, t_conversions));
  74. } catch (const chaiscript::detail::exception::bad_any_cast &) {
  75. }
  76. }
  77. if (t_conversions && (*t_conversions)->convertable_type<Type>())
  78. {
  79. try {
  80. // We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
  81. // either way, we are not responsible if it doesn't work
  82. return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions));
  83. } catch (...) {
  84. try {
  85. // try going the other way
  86. return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), t_conversions));
  87. } catch (const chaiscript::detail::exception::bad_any_cast &) {
  88. throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
  89. }
  90. }
  91. } else {
  92. // If it's not convertable, just throw the error, don't waste the time on the
  93. // attempted dynamic_cast
  94. throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
  95. }
  96. }
  97. }
  98. #endif