Lunchbox  1.6.0
any.h
00001 
00002 /* Copyright (c) 2012, Daniel Nachbaur <daniel.nachbaur@gmail.com>
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 3.0 as published
00006  * by the Free Software Foundation.
00007  *
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  *
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00016  */
00017 
00018 // Based on boost/any.hpp
00019 // Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.
00020 //
00021 // Distributed under the Boost Software License, Version 1.0. (See
00022 // accompanying file LICENSE_1_0.txt or copy at
00023 // http://www.boost.org/LICENSE_1_0.txt)
00024 
00025 
00026 #ifndef LUNCHBOX_ANY_H
00027 #define LUNCHBOX_ANY_H
00028 
00029 #include <lunchbox/api.h>
00030 #include <lunchbox/debug.h>
00031 
00032 #include <boost/type_traits/remove_reference.hpp>
00033 #include <boost/shared_ptr.hpp>
00034 #include <boost/serialization/access.hpp>
00035 #include <boost/serialization/assume_abstract.hpp>
00036 #include <boost/serialization/base_object.hpp>
00037 #include <boost/serialization/shared_ptr.hpp>
00038 
00039 // See boost/python/type_id.hpp
00040 // TODO: add BOOST_TYPEID_COMPARE_BY_NAME to config.hpp
00041 # if (defined(__GNUC__) && __GNUC__ >= 3) \
00042  || defined(_AIX) \
00043  || (   defined(__sgi) && defined(__host_mips)) \
00044  || (defined(__hpux) && defined(__HP_aCC)) \
00045  || (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC))
00046 #  define BOOST_AUX_ANY_TYPE_ID_NAME
00047 #  include <cstring>
00048 # endif
00049 
00050 
00051 namespace lunchbox
00052 {
00053 
00061 class Any
00062 {
00063 public:
00067     LUNCHBOX_API Any();
00068 
00070     template< typename ValueType >
00071     Any( const ValueType& value )
00072       : content( new holder< ValueType >( value ))
00073     {
00074     }
00075 
00077     LUNCHBOX_API Any( const Any& other );
00078 
00080     LUNCHBOX_API ~Any();
00082 
00086     LUNCHBOX_API Any& swap( Any& rhs );
00087 
00089     template< typename ValueType >
00090     Any& operator=( const ValueType& rhs )
00091     {
00092         Any( rhs ).swap( *this );
00093         return *this;
00094     }
00095 
00097     LUNCHBOX_API Any& operator=( Any rhs );
00099 
00103     LUNCHBOX_API bool empty() const;
00104 
00110     LUNCHBOX_API const std::type_info& type() const;
00111 
00116     LUNCHBOX_API bool operator == ( const Any& rhs ) const;
00117 
00122     bool operator != ( const Any& rhs ) const { return !(*this == rhs); }
00124 
00125 
00127     class placeholder
00128     {
00129     public:
00130         virtual ~placeholder() {}
00131 
00132         virtual bool operator == ( const placeholder& rhs ) const = 0;
00133 
00134         bool operator != ( const placeholder& rhs ) const
00135             { return !(*this == rhs); }
00136 
00137         virtual const std::type_info& type() const = 0;
00138 
00139         virtual placeholder* clone() const = 0;
00140 
00141     private:
00142         friend class boost::serialization::access;
00143         template< class Archive >
00144         void serialize( Archive & ar, const unsigned int version )
00145         {
00146         }
00147     };
00148 
00149     BOOST_SERIALIZATION_ASSUME_ABSTRACT(placeholder)
00150 
00151     
00152     template< typename ValueType >
00153     class holder : public placeholder
00154     {
00155     public:
00156         holder()
00157             : held()
00158         {
00159         }
00160 
00161         holder( const ValueType& value )
00162           : held( value )
00163         {
00164         }
00165 
00166         virtual const std::type_info& type() const
00167         {
00168             return typeid(ValueType);
00169         }
00170 
00171         virtual bool operator == ( const placeholder& rhs ) const
00172         {
00173             return held == static_cast< const holder& >( rhs ).held;
00174         }
00175 
00176         virtual placeholder* clone() const
00177         {
00178             return new holder( held );
00179         }
00180 
00181         ValueType held;
00182 
00183     private:
00184         holder& operator=( const holder& );
00185 
00186         friend class boost::serialization::access;
00187         template< class Archive >
00188         void serialize( Archive & ar, const unsigned int version )
00189         {
00190             // serialize base class information
00191             ar & boost::serialization::base_object< placeholder >( *this );
00192             ar & held;
00193         }
00194     };
00195 
00196 private:
00197     template< typename ValueType >
00198     friend ValueType* any_cast( Any* );
00199 
00200     template< typename ValueType >
00201     friend ValueType* unsafe_any_cast( Any* );
00202 
00203     friend class boost::serialization::access;
00204     template< class Archive >
00205     void serialize( Archive & ar, const unsigned int version )
00206     {
00207         ar & content;
00208     }
00209 
00210     boost::shared_ptr< placeholder > content;
00211 };
00212 
00214 class bad_any_cast : public std::bad_cast
00215 {
00216 public:
00217     LUNCHBOX_API bad_any_cast( const std::string& from, const std::string& to );
00218 
00219     virtual const char* what() const throw() { return data; }
00220 
00221 private:
00222     char data[256];
00223 };
00224 
00231 template< typename ValueType >
00232 ValueType* any_cast( Any* operand )
00233 {
00234     return operand &&
00235 #ifdef BOOST_AUX_ANY_TYPE_ID_NAME
00236         std::strcmp(operand->type().name(), typeid(ValueType).name()) == 0
00237 #else
00238         operand->type() == typeid(ValueType)
00239 #endif
00240         ? &static_cast<Any::holder<ValueType> *>(operand->content.get())->held
00241         : 0;
00242 }
00243 
00250 template< typename ValueType >
00251 inline const ValueType* any_cast( const Any* operand )
00252 {
00253     return any_cast<ValueType>(const_cast<Any *>(operand));
00254 }
00255 
00263 template< typename ValueType >
00264 ValueType any_cast( Any& operand )
00265 {
00266     typedef typename boost::remove_reference< ValueType >::type nonref;
00267 
00268     nonref* result = any_cast< nonref >( &operand );
00269     if( !result )
00270         boost::throw_exception(
00271                       bad_any_cast( demangleTypeID( operand.type().name( )),
00272                                     demangleTypeID( typeid( nonref ).name( ))));
00273     return *result;
00274 }
00275 
00283 template< typename ValueType >
00284 inline ValueType any_cast( const Any& operand )
00285 {
00286     typedef typename boost::remove_reference< ValueType >::type nonref;
00287 
00288     return any_cast< const nonref& >( const_cast< Any& >( operand ));
00289 }
00290 
00297 template< typename ValueType >
00298 inline ValueType* unsafe_any_cast( Any* operand )
00299 {
00300     return &static_cast< Any::holder< ValueType >* >(
00301                              operand->content.get( ))->held;
00302 }
00303 
00310 template< typename ValueType >
00311 inline const ValueType* unsafe_any_cast( const Any* operand )
00312 {
00313     return unsafe_any_cast< ValueType >( const_cast< Any* > ( operand ));
00314 }
00315 
00322 template< typename ValueType >
00323 ValueType unsafe_any_cast( Any& operand )
00324 {
00325     typedef typename boost::remove_reference< ValueType >::type nonref;
00326     return *unsafe_any_cast< nonref >( &operand );
00327 }
00328 
00335 template< typename ValueType >
00336 ValueType unsafe_any_cast( const Any& operand )
00337 {
00338    typedef typename boost::remove_reference< ValueType >::type nonref;
00339    return unsafe_any_cast< const nonref& >( const_cast< Any& >( operand ));
00340 }
00341 
00342 }
00343 
00344 #endif