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