Line data Source code
1 :
2 : /* Copyright (c) 2012, Daniel Nachbaur <daniel.nachbaur@gmail.com>
3 : *
4 : * This library is free software; you can redistribute it and/or modify it under
5 : * the terms of the GNU Lesser General Public License version 3.0 as published
6 : * by the Free Software Foundation.
7 : *
8 : * This library is distributed in the hope that it will be useful, but WITHOUT
9 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
11 : * details.
12 : *
13 : * You should have received a copy of the GNU Lesser General Public License
14 : * along with this library; if not, write to the Free Software Foundation, Inc.,
15 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 : */
17 :
18 : // Based on boost/any.hpp
19 : // Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.
20 : //
21 : // Distributed under the Boost Software License, Version 1.0. (See
22 : // accompanying file LICENSE_1_0.txt or copy at
23 : // http://www.boost.org/LICENSE_1_0.txt)
24 :
25 : #ifndef LUNCHBOX_ANY_H
26 : #define LUNCHBOX_ANY_H
27 :
28 : #include <lunchbox/api.h>
29 : #include <lunchbox/debug.h>
30 :
31 : #include <boost/shared_ptr.hpp>
32 : #include <boost/type_traits/remove_reference.hpp>
33 :
34 : // Don't reorder below!
35 : #include <boost/serialization/access.hpp>
36 : #include <boost/serialization/assume_abstract.hpp>
37 : #include <boost/serialization/base_object.hpp>
38 : #include <boost/serialization/extended_type_info.hpp>
39 : #include <boost/serialization/shared_ptr.hpp>
40 : #include <boost/serialization/singleton.hpp>
41 : #include <boost/serialization/type_info_implementation.hpp>
42 :
43 : // See boost/python/type_id.hpp
44 : // TODO: add BOOST_TYPEID_COMPARE_BY_NAME to config.hpp
45 : #if (defined(__GNUC__) && __GNUC__ >= 3) || defined(_AIX) || \
46 : (defined(__sgi) && defined(__host_mips)) || \
47 : (defined(__hpux) && defined(__HP_aCC)) || \
48 : (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC))
49 : #define BOOST_AUX_ANY_TYPE_ID_NAME
50 : #include <cstring>
51 : #endif
52 :
53 : namespace lunchbox
54 : {
55 : /**
56 : * A class which can hold instances of any type.
57 : *
58 : * This class is based on boost.any with the extension to support serialization
59 : * if the ValueType supports boost.serialization.
60 : *
61 : * Example: @include tests/any.cpp
62 : */
63 : class Any
64 : {
65 : public:
66 : /** @name Construction/Destruction */
67 : //@{
68 : /** Construct a new, empty Any. @version 1.5.0 */
69 : LUNCHBOX_API Any();
70 :
71 : /** Construct a new Any with the given value. @version 1.5.0 */
72 : // cppcheck-suppress noExplicitConstructor
73 : template <typename ValueType>
74 18 : Any(const ValueType& value)
75 18 : : content(new holder<ValueType>(value))
76 : {
77 18 : }
78 :
79 : /** Copy-construct a new Any with copying content of other. @version 1.5.0*/
80 : LUNCHBOX_API Any(const Any& other);
81 :
82 : /** Destruct this Any. @version 1.5.0 */
83 : LUNCHBOX_API ~Any();
84 : //@}
85 :
86 : /** @name Modifiers */
87 : //@{
88 : /** Exchange the content of this and rhs. @version 1.5.0 */
89 : LUNCHBOX_API Any& swap(Any& rhs);
90 :
91 : /** Assign a new value to this Any. @version 1.5.0 */
92 : template <typename ValueType>
93 4 : Any& operator=(const ValueType& rhs)
94 : {
95 4 : Any(rhs).swap(*this);
96 4 : return *this;
97 : }
98 :
99 : /** Exchange the content of this and rhs. @version 1.5.0 */
100 : LUNCHBOX_API Any& operator=(Any rhs);
101 : //@}
102 :
103 : /** @name Queries */
104 : //@{
105 : /** @return true if this Any is not holding a value. @version 1.5.0 */
106 : LUNCHBOX_API bool empty() const;
107 :
108 : /**
109 : * @return the typeid of the contained value if non-empty, otherwise
110 : * typeid(void).
111 : * @version 1.5.0
112 : */
113 : LUNCHBOX_API const std::type_info& type() const;
114 :
115 : /**
116 : * @return true if this and rhs are empty or if their values are equal.
117 : * @version 1.5.0
118 : */
119 : LUNCHBOX_API bool operator==(const Any& rhs) const;
120 :
121 : /**
122 : * @return true if the value from this and rhs are not equal.
123 : * @version 1.5.0
124 : */
125 1 : bool operator!=(const Any& rhs) const { return !(*this == rhs); }
126 : //@}
127 :
128 : /** @cond IGNORE */
129 61 : class placeholder
130 : {
131 : public:
132 61 : virtual ~placeholder() {}
133 : virtual bool operator==(const placeholder& rhs) const = 0;
134 :
135 : bool operator!=(const placeholder& rhs) const
136 : {
137 : return !(*this == rhs);
138 : }
139 :
140 : virtual const std::type_info& type() const = 0;
141 :
142 : virtual placeholder* clone() const = 0;
143 :
144 : private:
145 : friend class boost::serialization::access;
146 : template <class Archive>
147 56 : void serialize(Archive&, const unsigned int)
148 : {
149 56 : }
150 : };
151 :
152 : BOOST_SERIALIZATION_ASSUME_ABSTRACT(placeholder)
153 :
154 : template <typename ValueType>
155 122 : class holder : public placeholder
156 : {
157 : public:
158 28 : holder()
159 28 : : held()
160 : {
161 28 : }
162 :
163 33 : explicit holder(const ValueType& value)
164 33 : : held(value)
165 : {
166 33 : }
167 :
168 69 : virtual const std::type_info& type() const { return typeid(ValueType); }
169 30 : virtual bool operator==(const placeholder& rhs) const
170 : {
171 30 : return held == static_cast<const holder&>(rhs).held;
172 : }
173 :
174 15 : virtual placeholder* clone() const { return new holder(held); }
175 : ValueType held;
176 :
177 : private:
178 : holder& operator=(const holder&);
179 :
180 : friend class boost::serialization::access;
181 : template <class Archive>
182 56 : void serialize(Archive& ar, const unsigned int /*version*/)
183 : {
184 : // serialize base class information
185 56 : ar& boost::serialization::base_object<placeholder>(*this);
186 56 : ar& held;
187 56 : }
188 : };
189 : /** @endcond */
190 :
191 : private:
192 : template <typename ValueType>
193 : friend ValueType* any_cast(Any*);
194 :
195 : template <typename ValueType>
196 : friend ValueType* unsafe_any_cast(Any*);
197 :
198 : friend class boost::serialization::access;
199 : template <class Archive>
200 56 : void serialize(Archive& ar, const unsigned int /*version*/)
201 : {
202 56 : ar& content;
203 56 : }
204 :
205 : boost::shared_ptr<placeholder> content;
206 : };
207 :
208 : /** A specialization for exceptions thrown by an unsuccessful any_cast. */
209 5 : class bad_any_cast : public std::bad_cast
210 : {
211 : public:
212 : LUNCHBOX_API bad_any_cast(const std::string& from, const std::string& to);
213 :
214 0 : virtual const char* what() const throw() { return data; }
215 : private:
216 : char data[256];
217 : };
218 :
219 : /**
220 : * Retrieve the value stored in an Any including type checking.
221 : *
222 : * @return the value stored in the given Any, 0 if types are not matching
223 : * @version 1.5.0
224 : */
225 : template <typename ValueType>
226 4 : ValueType* any_cast(Any* operand)
227 : {
228 4 : return operand &&
229 : #ifdef BOOST_AUX_ANY_TYPE_ID_NAME
230 4 : std::strcmp(operand->type().name(),
231 : typeid(ValueType).name()) == 0
232 : #else
233 : operand->type() == typeid(ValueType)
234 : #endif
235 7 : ? &static_cast<Any::holder<ValueType>*>(operand->content.get())
236 : ->held
237 4 : : 0;
238 : }
239 :
240 : /**
241 : * Retrieve the value stored in an Any including type checking.
242 : *
243 : * @return the value stored in the given Any, 0 if types are not matching
244 : * @version 1.5.0
245 : */
246 : template <typename ValueType>
247 : inline const ValueType* any_cast(const Any* operand)
248 : {
249 : return any_cast<ValueType>(const_cast<Any*>(operand));
250 : }
251 :
252 : /**
253 : * Retrieve the value stored in an Any including type checking.
254 : *
255 : * @return the value stored in the given Any
256 : * @throw bad_any_cast if types are not matching
257 : * @version 1.5.0
258 : */
259 : template <typename ValueType>
260 4 : ValueType any_cast(Any& operand)
261 : {
262 : typedef typename boost::remove_reference<ValueType>::type nonref;
263 :
264 4 : nonref* result = any_cast<nonref>(&operand);
265 4 : if (!result)
266 3 : boost::throw_exception(
267 1 : bad_any_cast(demangleTypeID(operand.type().name()),
268 : demangleTypeID(typeid(nonref).name())));
269 3 : return *result;
270 : }
271 :
272 : /**
273 : * Retrieve the value stored in an Any including type checking.
274 : *
275 : * @return the value stored in the given Any
276 : * @throw bad_any_cast if types are not matching
277 : * @version 1.5.0
278 : */
279 : template <typename ValueType>
280 : inline ValueType any_cast(const Any& operand)
281 : {
282 : typedef typename boost::remove_reference<ValueType>::type nonref;
283 :
284 : return any_cast<const nonref&>(const_cast<Any&>(operand));
285 : }
286 :
287 : /**
288 : * Retrieve the value stored in an Any without type checking.
289 : *
290 : * @return the value stored in the given Any
291 : * @version 1.5.0
292 : */
293 : template <typename ValueType>
294 : inline ValueType* unsafe_any_cast(Any* operand)
295 : {
296 : return &static_cast<Any::holder<ValueType>*>(operand->content.get())->held;
297 : }
298 :
299 : /**
300 : * Retrieve the value stored in an Any without type checking.
301 : *
302 : * @return the value stored in the given Any
303 : * @version 1.5.0
304 : */
305 : template <typename ValueType>
306 : inline const ValueType* unsafe_any_cast(const Any* operand)
307 : {
308 : return unsafe_any_cast<ValueType>(const_cast<Any*>(operand));
309 : }
310 :
311 : /**
312 : * Retrieve the value stored in an Any without type checking.
313 : *
314 : * @return the value stored in the given Any
315 : * @version 1.5.0
316 : */
317 : template <typename ValueType>
318 : ValueType unsafe_any_cast(Any& operand)
319 : {
320 : typedef typename boost::remove_reference<ValueType>::type nonref;
321 : return *unsafe_any_cast<nonref>(&operand);
322 : }
323 :
324 : /**
325 : * Retrieve the value stored in an Any without type checking.
326 : *
327 : * @return the value stored in the given Any
328 : * @version 1.5.0
329 : */
330 : template <typename ValueType>
331 : ValueType unsafe_any_cast(const Any& operand)
332 : {
333 : typedef typename boost::remove_reference<ValueType>::type nonref;
334 : return unsafe_any_cast<const nonref&>(const_cast<Any&>(operand));
335 : }
336 : }
337 :
338 : #endif
|