|
libpsynth 0.2.1
|
00001 00014 /* 00015 * Copyright (C) 2010 Juan Pedro Bolivar Puente 00016 * 00017 * This file is part of Psychosynth. 00018 * 00019 * Psychosynth is free software: you can redistribute it and/or modify 00020 * it under the terms of the GNU General Public License as published by 00021 * the Free Software Foundation, either version 3 of the License, or 00022 * (at your option) any later version. 00023 * 00024 * Psychosynth is distributed in the hope that it will be useful, 00025 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00026 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00027 * GNU General Public License for more details. 00028 * 00029 * You should have received a copy of the GNU General Public License 00030 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00031 * 00032 */ 00033 00034 /* 00035 * Copyright 2005-2007 Adobe Systems Incorporated 00036 * 00037 * Use, modification and distribution are subject to the Boost 00038 * Software License, Version 1.0. (See accompanying file 00039 * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). 00040 */ 00041 00042 #ifndef PSYNTH_SOUND_VARIANT_HPP 00043 #define PSYNTH_SOUND_VARIANT_HPP 00044 00045 #include <psynth/base/compat.hpp> 00046 #include <psynth/sound/util.hpp> 00047 00048 #include <cstddef> 00049 #include <cassert> 00050 #include <algorithm> 00051 #include <typeinfo> 00052 #include <boost/bind.hpp> 00053 00054 #include <boost/mpl/transform.hpp> 00055 #include <boost/mpl/size.hpp> 00056 #include <boost/mpl/sizeof.hpp> 00057 #include <boost/mpl/max.hpp> 00058 #include <boost/mpl/at.hpp> 00059 #include <boost/mpl/fold.hpp> 00060 00061 namespace psynth 00062 { 00063 namespace sound 00064 { 00065 00066 namespace detail 00067 { 00068 00069 template <typename Types, typename T> 00070 struct type_to_index; 00071 00072 template <typename Op, typename T> 00073 struct reduce; 00074 00075 struct destructor_op 00076 { 00077 typedef void result_type; 00078 template <typename T> 00079 result_type operator () (const T& t) const { t.~T(); } 00080 }; 00081 00082 template <typename T, typename Bits> 00083 void copy_construct_in_place (const T& t, Bits& bits); 00084 00085 template <typename Bits> 00086 struct copy_construct_in_place_fn; 00087 00088 } /* namespace detail */ 00089 00143 template <typename Types> // models MPL Random Access Container 00144 class variant 00145 { 00146 // size in bytes of the largest type in Types 00147 static const std::size_t MAX_SIZE = 00148 boost::mpl::fold<Types, boost::mpl::size_t<0>, 00149 boost::mpl::max< 00150 boost::mpl::_1, 00151 boost::mpl::sizeof_<boost::mpl::_2> > >::type::value; 00152 00153 static const std::size_t NUM_TYPES = boost::mpl::size<Types>::value; 00154 00155 public: 00156 typedef Types types_t; 00157 00158 typedef struct { char data [MAX_SIZE]; } base_t; 00159 // empty space equal to the size of the largest type in Types 00160 00161 // Default constructor - default construct the first type 00162 variant () 00163 : _index(0) 00164 { 00165 new (&_bits) typename boost::mpl::at_c<Types, 0>::type (); 00166 } 00167 00168 virtual ~variant () 00169 { 00170 apply_operation (*this, detail::destructor_op()); 00171 } 00172 00173 // Throws std::bad_cast if T is not in Types 00174 template <typename T> 00175 explicit variant (const T& obj) 00176 { 00177 _index = type_id<T>(); 00178 if (_index == NUM_TYPES) 00179 throw std::bad_cast (); 00180 detail::copy_construct_in_place (obj, _bits); 00181 } 00182 00183 // When doSwap is true, swaps obj with the contents of the 00184 // variant. obj will contain default-constructed instance after 00185 // the call 00186 template <typename T> 00187 explicit variant (T& obj, bool do_swap); 00188 00189 template <typename T> 00190 variant& operator= (const T& obj) 00191 { 00192 variant tmp (obj); 00193 swap (*this,tmp); 00194 return *this; 00195 } 00196 00197 variant& operator= (const variant& v) 00198 { 00199 variant tmp (v); 00200 swap (*this, tmp); 00201 return *this; 00202 } 00203 00204 variant (const variant& v) 00205 : _index (v._index) 00206 { 00207 apply_operation (v, detail::copy_construct_in_place_fn<base_t> (_bits)); 00208 } 00209 00210 template <typename T> 00211 void move_in (T& obj) 00212 { 00213 variant tmp (obj, true); 00214 swap (*this, tmp); 00215 } 00216 00217 template <typename TS> 00218 friend bool operator== (const variant<TS>& x, const variant<TS>& y); 00219 00220 template <typename TS> 00221 friend bool operator!= (const variant<TS>& x, const variant<TS>& y); 00222 00223 template <typename T> 00224 static bool has_type () 00225 { return type_id<T> () != NUM_TYPES; } 00226 00227 template <typename T> 00228 const T& do_dynamic_cast() const 00229 { 00230 if (!current_type_is<T>()) 00231 throw std::bad_cast(); 00232 return *psynth_reinterpret_cast_c<const T*> (&_bits); 00233 } 00234 00235 template <typename T> 00236 T& do_dynamic_cast () 00237 { 00238 if (!current_type_is<T>()) 00239 throw std::bad_cast (); 00240 return *psynth_reinterpret_cast <T*>(&_bits); 00241 } 00242 00243 template <typename T> 00244 bool current_type_is () const 00245 { return type_id<T>() == _index; } 00246 00247 base_t bits () const { return _bits; } 00248 std::size_t index () const { return _index; } 00249 00250 private: 00251 template <typename T> 00252 static std::size_t type_id () 00253 { return detail::type_to_index<Types,T>::value; } 00254 00255 template <typename Cs> 00256 friend void swap(variant<Cs>& x, variant<Cs>& y); 00257 00258 template <typename Types2, typename UnaryOp> 00259 friend typename UnaryOp::result_type 00260 apply_operation (variant<Types2>& var, UnaryOp op); 00261 00262 template <typename Types2, typename UnaryOp> 00263 friend typename UnaryOp::result_type 00264 apply_operation (const variant<Types2>& var, UnaryOp op); 00265 00266 template <typename Types1, typename Types2, typename BinaryOp> 00267 friend typename BinaryOp::result_type 00268 apply_operation (const variant<Types1>& arg1, 00269 const variant<Types2>& arg2, BinaryOp op); 00270 00271 base_t _bits; 00272 std::size_t _index; 00273 }; 00274 00275 00276 namespace detail 00277 { 00278 00279 template <typename T, typename Bits> 00280 void copy_construct_in_place(const T& t, Bits& bits) 00281 { 00282 T& b = *psynth_reinterpret_cast<T*>(&bits); 00283 new (&b) T(t); // default-construct 00284 } 00285 00286 template <typename Bits> 00287 struct copy_construct_in_place_fn 00288 { 00289 typedef void result_type; 00290 Bits& _dst; 00291 00292 copy_construct_in_place_fn (Bits& dst) 00293 : _dst(dst) {} 00294 00295 template <typename T> 00296 void operator () (const T& src) const 00297 { copy_construct_in_place(src,_dst); } 00298 }; 00299 00300 template <typename Bits> 00301 struct equal_to_fn 00302 { 00303 const Bits& _dst; 00304 equal_to_fn(const Bits& dst) : _dst(dst) {} 00305 00306 typedef bool result_type; 00307 template <typename T> result_type operator()(const T& x) const 00308 { 00309 return x == *psynth_reinterpret_cast_c<const T*> (&_dst); 00310 } 00311 }; 00312 00313 } /* namespace detail */ 00314 00315 /* 00316 * When doSwap is true, swaps obj with the contents of the 00317 * variant. obj will contain default-constructed instance after the 00318 * call 00319 */ 00320 template <typename Types> 00321 template <typename T> 00322 variant<Types>::variant (T& obj, bool do_swap) 00323 { 00324 _index = type_id<T> (); 00325 if (_index == NUM_TYPES) 00326 throw std::bad_cast (); 00327 00328 if (do_swap) 00329 { 00330 new (&_bits) T(); // default construct 00331 swap (obj, *psynth_reinterpret_cast<T*> (&_bits)); 00332 } 00333 else 00334 detail::copy_construct_in_place (const_cast<const T&>(obj), _bits); 00335 } 00336 00337 template <typename Types> 00338 void swap (variant<Types>& x, variant<Types>& y) 00339 { 00340 std::swap (x._bits, y._bits); 00341 std::swap (x._index, y._index); 00342 } 00343 00344 template <typename Types> 00345 inline bool operator== (const variant<Types>& x, const variant<Types>& y) 00346 { 00347 return 00348 x._index == y._index && 00349 apply_operation ( 00350 x, detail::equal_to_fn<typename variant<Types>::base_t>(y._bits)); 00351 } 00352 00353 template <typename C> 00354 inline bool operator!= (const variant<C>& x, const variant<C>& y) 00355 { 00356 return !(x == y); 00357 } 00358 00359 } /* namespace sound */ 00360 } /* namespace psynth */ 00361 00362 #endif /* PSYNTH_SOUND_VARIANT */
1.7.4