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