Modules | Alphabetical List | Class List | Directories | File List | GIL Home Page # variant.hpp Go to the documentation of this file.
    00001 /*
    00002     Copyright 2005-2007 Adobe Systems Incorporated
    00003
    00004     Use, modification and distribution are subject to the Boost Software License,
    00005     Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
    00006     http://www.boost.org/LICENSE_1_0.txt).
    00007
    00008     See http://opensource.adobe.com/gil for most recent version including documentation.
    00009 */
    00010
    00011 /*************************************************************************************************/
    00012
    00013 #ifndef GIL_DYNAMICIMAGE_VARIANT_HPP
    00014 #define GIL_DYNAMICIMAGE_VARIANT_HPP
    00015
    00024
    00025 #include "../../gil_config.hpp"
    00026 #include "../../utilities.hpp"
    00027 #include <cstddef>
    00028 #include <cassert>
    00029 #include <algorithm>
    00030 #include <typeinfo>
    00031 #include <boost/bind.hpp>
    00032
    00033 #include <boost/mpl/transform.hpp>
    00034 #include <boost/mpl/size.hpp>
    00035 #include <boost/mpl/sizeof.hpp>
    00036 #include <boost/mpl/max.hpp>
    00037 #include <boost/mpl/at.hpp>
    00038 #include <boost/mpl/fold.hpp>
    00039
    00040 namespace boost { namespace gil {
    00041
    00042 namespace detail {
    00043     template <typename Types, typename T> struct type_to_index;
    00044     template <typename Op, typename T> struct reduce;
    00045     struct destructor_op {
    00046         typedef void result_type;
    00047         template <typename T> result_type operator()(const T& t) const { t.~T(); }
    00048     };
    00049     template <typename T, typename Bits> void copy_construct_in_place(const T& t, Bits& bits);
    00050     template <typename Bits> struct copy_construct_in_place_fn;
    00051 }
    00086 template <typename Types>    // models MPL Random Access Container
    00087 class variant {
    00088     // size in bytes of the largest type in Types
    00089     static const std::size_t MAX_SIZE  = mpl::fold<Types, mpl::size_t<0>, mpl::max<mpl::_1, mpl::sizeof_<mpl::_2> > >::type::value;
    00090     static const std::size_t NUM_TYPES = mpl::size<Types>::value;
    00091 public:
    00092     typedef Types                            types_t;
    00093
    00094     typedef struct { char data[MAX_SIZE]; } base_t;    // empty space equal to the size of the largest type in Types
    00095
    00096     // Default constructor - default construct the first type
    00097     variant() : _index(0)    { new(&_bits) typename mpl::at_c<Types,0>::type(); }
    00098     virtual ~variant()        { apply_operation(*this, detail::destructor_op()); }
    00099
    00100     // Throws std::bad_cast if T is not in Types
    00101     template <typename T> explicit variant(const T& obj){ _index=type_id<T>(); if (_index==NUM_TYPES) throw std::bad_cast(); detail::copy_construct_in_place(obj, _bits); }
    00102
    00103     // When doSwap is true, swaps obj with the contents of the variant. obj will contain default-constructed instance after the call
    00104     template <typename T> explicit variant(T& obj, bool do_swap);
    00105
    00106     template <typename T> variant& operator=(const T& obj) { variant tmp(obj); swap(*this,tmp); return *this; }
    00107     variant& operator=(const variant& v)                   { variant tmp(v  ); swap(*this,tmp); return *this; }
    00108
    00109     variant(const variant& v) : _index(v._index)           { apply_operation(v, detail::copy_construct_in_place_fn<base_t>(_bits)); }
    00110     template <typename T> void move_in(T& obj)             { variant tmp(obj, true); swap(*this,tmp); }
    00111
    00112     template <typename TS> friend bool operator==(const variant<TS>& x, const variant<TS>& y);
    00113     template <typename TS> friend bool operator!=(const variant<TS>& x, const variant<TS>& y);
    00114
    00115     template <typename T> static bool has_type()           { return type_id<T>()!=NUM_TYPES; }
    00116
    00117     template <typename T> const T& _dynamic_cast()   const { if (!current_type_is<T>()) throw std::bad_cast(); return *gil_reinterpret_cast_c<const T*>(&_bits); }
    00118     template <typename T>       T& _dynamic_cast()         { if (!current_type_is<T>()) throw std::bad_cast(); return *gil_reinterpret_cast  <      T*>(&_bits); }
    00119
    00120     template <typename T> bool current_type_is()     const { return type_id<T>()==_index; }
    00121
    00122 private:
    00123     template <typename T> static std::size_t type_id()     { return detail::type_to_index<Types,T>::value; }
    00124
    00125     template <typename Cs> friend void swap(variant<Cs>& x, variant<Cs>& y);
    00126     template <typename Types2, typename UnaryOp> friend typename UnaryOp::result_type apply_operation(variant<Types2>& var, UnaryOp op);
    00127     template <typename Types2, typename UnaryOp> friend typename UnaryOp::result_type apply_operation(const variant<Types2>& var, UnaryOp op);
    00128     template <typename Types1, typename Types2, typename BinaryOp> friend typename BinaryOp::result_type apply_operation(const variant<Types1>& arg1, const variant<Types2>& arg2, BinaryOp op);
    00129
    00130     base_t      _bits;
    00131     std::size_t    _index;
    00132 };
    00133
    00134 namespace detail {
    00135
    00136     template <typename T, typename Bits>
    00137     void copy_construct_in_place(const T& t, Bits& bits) {
    00138         T& b=*gil_reinterpret_cast<T*>(&bits);
    00139         new(&b)T(t);     // default-construct
    00140     }
    00141
    00142     template <typename Bits>
    00143     struct copy_construct_in_place_fn {
    00144         typedef void result_type;
    00145         Bits& _dst;
    00146         copy_construct_in_place_fn(Bits& dst) : _dst(dst) {}
    00147
    00148         template <typename T> void operator()(const T& src) const { copy_construct_in_place(src,_dst); }
    00149     };
    00150
    00151     template <typename Bits>
    00152     struct equal_to_fn {
    00153         const Bits& _dst;
    00154         equal_to_fn(const Bits& dst) : _dst(dst) {}
    00155
    00156         typedef bool result_type;
    00157         template <typename T> result_type operator()(const T& x) const {
    00158             return x==*gil_reinterpret_cast_c<const T*>(&_dst);
    00159         }
    00160     };
    00161 }
    00162
    00163 // When doSwap is true, swaps obj with the contents of the variant. obj will contain default-constructed instance after the call
    00164 template <typename Types>
    00165 template <typename T> variant<Types>::variant(T& obj, bool do_swap) {
    00166     _index=type_id<T>();
    00167     if (_index==NUM_TYPES) throw std::bad_cast();
    00168
    00169     if (do_swap) {
    00170         new(&_bits) T();    // default construct
    00171         swap(obj, *gil_reinterpret_cast<T*>(&_bits));
    00172     } else
    00173         detail::copy_construct_in_place(const_cast<const T&>(obj), _bits);
    00174 }
    00175
    00176 template <typename Types>
    00177 void swap(variant<Types>& x, variant<Types>& y) {
    00178     std::swap(x._bits,y._bits);
    00179     std::swap(x._index, y._index);
    00180 }
    00181
    00182 template <typename Types>
    00183 inline bool operator==(const variant<Types>& x, const variant<Types>& y) {
    00184     return x._index==y._index && apply_operation(x,detail::equal_to_fn<typename variant<Types>::base_t>(y._bits));
    00185 }
    00186
    00187 template <typename C>
    00188 inline bool operator!=(const variant<C>& x, const variant<C>& y) {
    00189     return !(x==y);
    00190 }
    00191
    00192 } }  // namespace boost::gil
    00193
    00194 #endif