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 // and Jason Turner (jason@emptycrate.com) 5 // http://www.chaiscript.com 6 7 #ifndef CHAISCRIPT_ANY_HPP_ 8 #define CHAISCRIPT_ANY_HPP_ 9 10 #include <utility> 11 12 namespace chaiscript { 13 namespace detail { 14 namespace exception 15 { 16 /// \brief Thrown in the event that an Any cannot be cast to the desired type 17 /// 18 /// It is used internally during function dispatch. 19 /// 20 /// \sa chaiscript::detail::Any 21 class bad_any_cast : public std::bad_cast 22 { 23 public: 24 bad_any_cast() = default; 25 26 bad_any_cast(const bad_any_cast &) = default; 27 28 ~bad_any_cast() noexcept override = default; 29 30 /// \brief Description of what error occurred what() const31 const char * what() const noexcept override 32 { 33 return m_what.c_str(); 34 } 35 36 private: 37 std::string m_what = "bad any cast"; 38 }; 39 } 40 41 42 class Any { 43 private: 44 struct Data 45 { Datachaiscript::detail::Any::Data46 explicit Data(const std::type_info &t_type) 47 : m_type(t_type) 48 { 49 } 50 51 Data &operator=(const Data &) = delete; 52 53 virtual ~Data() = default; 54 55 virtual void *data() = 0; 56 typechaiscript::detail::Any::Data57 const std::type_info &type() const 58 { 59 return m_type; 60 } 61 62 virtual std::unique_ptr<Data> clone() const = 0; 63 const std::type_info &m_type; 64 }; 65 66 template<typename T> 67 struct Data_Impl : Data 68 { Data_Implchaiscript::detail::Any::Data_Impl69 explicit Data_Impl(T t_type) 70 : Data(typeid(T)), 71 m_data(std::move(t_type)) 72 { 73 } 74 datachaiscript::detail::Any::Data_Impl75 void *data() override 76 { 77 return &m_data; 78 } 79 clonechaiscript::detail::Any::Data_Impl80 std::unique_ptr<Data> clone() const override 81 { 82 return std::unique_ptr<Data>(new Data_Impl<T>(m_data)); 83 } 84 85 Data_Impl &operator=(const Data_Impl&) = delete; 86 87 T m_data; 88 }; 89 90 std::unique_ptr<Data> m_data; 91 92 public: 93 // construct/copy/destruct 94 Any() = default; 95 Any(Any &&) = default; 96 Any &operator=(Any &&t_any) = default; 97 Any(const Any & t_any)98 Any(const Any &t_any) 99 { 100 if (!t_any.empty()) 101 { 102 m_data = t_any.m_data->clone(); 103 } else { 104 m_data.reset(); 105 } 106 } 107 108 109 template<typename ValueType, 110 typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type> Any(ValueType && t_value)111 explicit Any(ValueType &&t_value) 112 : m_data(std::unique_ptr<Data>(new Data_Impl<typename std::decay<ValueType>::type>(std::forward<ValueType>(t_value)))) 113 { 114 } 115 116 operator =(const Any & t_any)117 Any & operator=(const Any &t_any) 118 { 119 Any copy(t_any); 120 swap(copy); 121 return *this; 122 } 123 124 template<typename ToType> cast() const125 ToType &cast() const 126 { 127 if (m_data && typeid(ToType) == m_data->type()) 128 { 129 return *static_cast<ToType *>(m_data->data()); 130 } else { 131 throw chaiscript::detail::exception::bad_any_cast(); 132 } 133 } 134 135 136 // modifiers swap(Any & t_other)137 Any & swap(Any &t_other) 138 { 139 std::swap(t_other.m_data, m_data); 140 return *this; 141 } 142 143 // queries empty() const144 bool empty() const 145 { 146 return !bool(m_data); 147 } 148 type() const149 const std::type_info & type() const 150 { 151 if (m_data) { 152 return m_data->type(); 153 } else { 154 return typeid(void); 155 } 156 } 157 }; 158 159 } 160 } 161 162 #endif 163 164 165