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