ChaiScript / ChaiScript
1
// This file is distributed under the BSD License.
2
// See "license.txt" for details.
3
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
4
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
5
// http://www.chaiscript.com
6

7
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
8
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
9

10

11
#ifndef CHAISCRIPT_BOXED_CAST_HPP_
12
#define CHAISCRIPT_BOXED_CAST_HPP_
13

14
#include "../chaiscript_defines.hpp"
15
#include "bad_boxed_cast.hpp"
16
#include "boxed_cast_helper.hpp"
17
#include "boxed_value.hpp"
18
#include "type_conversions.hpp"
19
#include "type_info.hpp"
20

21
namespace chaiscript {
22
class Type_Conversions;
23
namespace detail {
24
namespace exception {
25
class bad_any_cast;
26
}  // namespace exception
27
}  // namespace detail
28
}  // namespace chaiscript
29

30
namespace chaiscript 
31
{
32
 
33
  /// \brief Function for extracting a value stored in a Boxed_Value object
34
  /// \tparam Type The type to extract from the Boxed_Value
35
  /// \param[in] bv The Boxed_Value to extract a typed value from
36
  /// \returns Type equivalent to the requested type 
37
  /// \throws exception::bad_boxed_cast If the requested conversion is not possible
38
  /// 
39
  /// boxed_cast will attempt to make conversions between value, &, *, std::shared_ptr, std::reference_wrapper,
40
  /// and std::function (const and non-const) where possible. boxed_cast is used internally during function
41
  /// dispatch. This means that all of these conversions will be attempted automatically for you during
42
  /// ChaiScript function calls.
43
  ///
44
  /// \li non-const values can be extracted as const or non-const
45
  /// \li const values can be extracted only as const
46
  /// \li Boxed_Value constructed from pointer or std::reference_wrapper can be extracted as reference,
47
  ///     pointer or value types
48
  /// \li Boxed_Value constructed from std::shared_ptr or value types can be extracted as reference,
49
  ///     pointer, value, or std::shared_ptr types
50
  ///
51
  /// Conversions to std::function objects are attempted as well
52
  ///
53
  /// Example:
54
  /// \code
55
  /// // All of the following should succeed
56
  /// chaiscript::Boxed_Value bv(1);
57
  /// std::shared_ptr<int> spi = chaiscript::boxed_cast<std::shared_ptr<int> >(bv);
58
  /// int i = chaiscript::boxed_cast<int>(bv);
59
  /// int *ip = chaiscript::boxed_cast<int *>(bv);
60
  /// int &ir = chaiscript::boxed_cast<int &>(bv);
61
  /// std::shared_ptr<const int> cspi = chaiscript::boxed_cast<std::shared_ptr<const int> >(bv);
62
  /// const int ci = chaiscript::boxed_cast<const int>(bv);
63
  /// const int *cip = chaiscript::boxed_cast<const int *>(bv);
64
  /// const int &cir = chaiscript::boxed_cast<const int &>(bv);
65
  /// \endcode
66
  ///
67
  /// std::function conversion example
68
  /// \code
69
  /// chaiscript::ChaiScript chai;
70
  /// Boxed_Value bv = chai.eval("`+`"); // Get the functor for the + operator which is built in 
71
  /// std::function<int (int, int)> f = chaiscript::boxed_cast<std::function<int (int, int)> >(bv);
72
  /// int i = f(2,3);
73
  /// assert(i == 5);
74
  /// \endcode
75
  template<typename Type>
76
  decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr)
77
  {
78
    if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) {
79
      try {
80
        return(detail::Cast_Helper<Type>::cast(bv, t_conversions));
81 1
      } catch (const chaiscript::detail::exception::bad_any_cast &) {
82
      }
83
    }
84

85

86
    if (t_conversions && (*t_conversions)->convertable_type<Type>())
87
    {
88
      try {
89
        // We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
90
        // either way, we are not responsible if it doesn't work
91
        return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions));
92 1
      } catch (...) {
93
        try {
94
          // try going the other way
95 1
          return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), t_conversions));
96 0
        } catch (const chaiscript::detail::exception::bad_any_cast &) {
97 0
          throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
98
        }
99
      }
100
    } else {
101
      // If it's not convertable, just throw the error, don't waste the time on the 
102
      // attempted dynamic_cast
103
      throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
104
    }
105

106
  }
107

108
}
109

110

111

112
#endif
113

Read our documentation on viewing source code .

Loading