Lunchbox  1.4.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 
00031 #include <boost/config.hpp>
00032 #include <boost/type_traits/remove_reference.hpp>
00033 #include <boost/type_traits/is_reference.hpp>
00034 #include <boost/throw_exception.hpp>
00035 #include <boost/static_assert.hpp>
00036 #include <boost/shared_ptr.hpp>
00037 #include <boost/serialization/access.hpp>
00038 #include <boost/serialization/assume_abstract.hpp>
00039 #include <boost/serialization/base_object.hpp>
00040 #include <boost/serialization/shared_ptr.hpp>
00041 
00042 #include <algorithm>
00043 #include <typeinfo>
00044 
00045 // See boost/python/type_id.hpp
00046 // TODO: add BOOST_TYPEID_COMPARE_BY_NAME to config.hpp
00047 # if (defined(__GNUC__) && __GNUC__ >= 3) \
00048  || defined(_AIX) \
00049  || (   defined(__sgi) && defined(__host_mips)) \
00050  || (defined(__hpux) && defined(__HP_aCC)) \
00051  || (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC))
00052 #  define BOOST_AUX_ANY_TYPE_ID_NAME
00053 #  include <cstring>
00054 # endif
00055 
00056 
00057 namespace lunchbox
00058 {
00059 class Any
00060 {
00061 public:
00062     LUNCHBOX_API Any();
00063 
00064     template< typename ValueType >
00065     Any( const ValueType& value )
00066       : content( new holder< ValueType >( value ))
00067     {
00068     }
00069 
00070     LUNCHBOX_API Any( const Any& other );
00071 
00072     LUNCHBOX_API ~Any();
00073 
00074     LUNCHBOX_API Any& swap( Any& rhs );
00075 
00076     template< typename ValueType >
00077     Any& operator=( const ValueType& rhs )
00078     {
00079         Any( rhs ).swap( *this );
00080         return *this;
00081     }
00082 
00083     LUNCHBOX_API Any& operator=( Any rhs );
00084 
00085     LUNCHBOX_API bool empty() const;
00086 
00087     LUNCHBOX_API const std::type_info& type() const;
00088 
00089     LUNCHBOX_API bool operator == ( const Any& rhs ) const;
00090 
00091     bool operator != ( const Any& rhs ) const { return !(*this == rhs); }
00092 
00093 
00094     class placeholder
00095     {
00096     public:
00097         virtual ~placeholder() {}
00098 
00099         virtual bool operator == ( const placeholder& rhs ) const = 0;
00100 
00101         bool operator != ( const placeholder& rhs ) const
00102             { return !(*this == rhs); }
00103 
00104         virtual const std::type_info& type() const = 0;
00105 
00106         virtual placeholder* clone() const = 0;
00107 
00108     private:
00109         friend class boost::serialization::access;
00110         template< class Archive >
00111         void serialize( Archive & ar, const unsigned int version )
00112         {
00113         }
00114     };
00115 
00116     BOOST_SERIALIZATION_ASSUME_ABSTRACT(placeholder)
00117 
00118     template< typename ValueType >
00119     class holder : public placeholder
00120     {
00121     public:
00122         holder()
00123             : held()
00124         {
00125         }
00126 
00127         holder( const ValueType& value )
00128           : held( value )
00129         {
00130         }
00131 
00132         virtual const std::type_info& type() const
00133         {
00134             return typeid(ValueType);
00135         }
00136 
00137         virtual bool operator == ( const placeholder& rhs ) const
00138         {
00139             return held == static_cast< const holder& >( rhs ).held;
00140         }
00141 
00142         virtual placeholder* clone() const
00143         {
00144             return new holder( held );
00145         }
00146 
00147         ValueType held;
00148 
00149     private:
00150         holder& operator=( const holder& );
00151 
00152         friend class boost::serialization::access;
00153         template< class Archive >
00154         void serialize( Archive & ar, const unsigned int version )
00155         {
00156             // serialize base class information
00157             ar & boost::serialization::base_object< placeholder >( *this );
00158             ar & held;
00159         }
00160     };
00161 
00162 private:
00163 
00164     template< typename ValueType >
00165     friend ValueType* any_cast( Any* );
00166 
00167     template< typename ValueType >
00168     friend ValueType* unsafe_any_cast( Any* );
00169 
00170     friend class boost::serialization::access;
00171     template< class Archive >
00172     void serialize( Archive & ar, const unsigned int version )
00173     {
00174         ar & content;
00175     }
00176 
00177     boost::shared_ptr< placeholder > content;
00178 };
00179 
00180 class bad_any_cast : public std::bad_cast
00181 {
00182 public:
00183     LUNCHBOX_API bad_any_cast( const std::string& from, const std::string& to );
00184 
00185     virtual const char * what() const throw() { return data; }
00186 
00187 private:
00188     char data[256];
00189 };
00190 
00191 template< typename ValueType >
00192 ValueType* any_cast( Any* operand )
00193 {
00194     return operand &&
00195 #ifdef BOOST_AUX_ANY_TYPE_ID_NAME
00196         std::strcmp(operand->type().name(), typeid(ValueType).name()) == 0
00197 #else
00198         operand->type() == typeid(ValueType)
00199 #endif
00200         ? &static_cast<Any::holder<ValueType> *>(operand->content.get())->held
00201         : 0;
00202 }
00203 
00204 template< typename ValueType >
00205 inline const ValueType* any_cast( const Any* operand )
00206 {
00207     return any_cast<ValueType>(const_cast<Any *>(operand));
00208 }
00209 
00210 template< typename ValueType >
00211 ValueType any_cast( Any& operand )
00212 {
00213     typedef typename boost::remove_reference< ValueType >::type nonref;
00214 
00215     nonref * result = any_cast<nonref>(&operand);
00216     if(!result)
00217         boost::throw_exception( bad_any_cast( operand.type().name(),
00218                                               typeid( nonref ).name( )));
00219     return *result;
00220 }
00221 
00222 template< typename ValueType >
00223 inline ValueType any_cast( const Any& operand )
00224 {
00225     typedef typename boost::remove_reference< ValueType >::type nonref;
00226 
00227     return any_cast< const nonref& >( const_cast< Any& >( operand ));
00228 }
00229 
00230 // Note: The "unsafe" versions of any_cast are not part of the
00231 // public interface and may be removed at any time. They are
00232 // required where we know what type is stored in the any and can't
00233 // use typeid() comparison, e.g., when our types may travel across
00234 // different shared libraries.
00235 template< typename ValueType >
00236 inline ValueType* unsafe_any_cast( Any* operand )
00237 {
00238     return &static_cast< Any::holder< ValueType >* >( operand->content )->held;
00239 }
00240 
00241 template< typename ValueType >
00242 inline const ValueType* unsafe_any_cast( const Any* operand )
00243 {
00244     return unsafe_any_cast< ValueType >( const_cast< Any* > (operand ));
00245 }
00246 
00247 }
00248 
00249 #endif