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