libpsynth 0.2.1
/home/raskolnikov/dev/psynth/trunk/src/psynth/sound/variant.hpp
Go to the documentation of this file.
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 */