Lunchbox
1.4.0
|
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