00001
00002
00003
00004
00005
00006
00007
00008
00009 #ifndef GIL_DYNAMICIMAGE_VARIANT_HPP
00010 #define GIL_DYNAMICIMAGE_VARIANT_HPP
00011
00020
00021 #include "../../core/gil_config.hpp"
00022 #include <cassert>
00023 #include <stdexcept>
00024 #include <boost/bind.hpp>
00025
00026 #include <boost/mpl/transform.hpp>
00027 #include <boost/mpl/size.hpp>
00028 #include <boost/mpl/sizeof.hpp>
00029 #include <boost/mpl/max.hpp>
00030 #include <boost/mpl/at.hpp>
00031 #include <boost/mpl/fold.hpp>
00032
00033 ADOBE_GIL_NAMESPACE_BEGIN
00034
00035 template <typename TYPES, typename T> struct type_to_index;
00036 namespace detail {
00037 template <typename OP, typename T> struct reduce;
00038 struct destructor_op;
00039 template <typename T, typename BITS> void copy_construct_in_place(const T& t, BITS& bits);
00040 template <typename BITS> struct copy_construct_in_place_fn;
00041 }
00076 template <typename TYPES>
00077 class variant {
00078
00079 static const std::size_t MAX_SIZE = boost::mpl::fold<TYPES, boost::mpl::size_t<0>, boost::mpl::max<boost::mpl::_1, boost::mpl::sizeof_<boost::mpl::_2> > >::type::value;
00080 static const std::size_t NUM_TYPES = boost::mpl::size<TYPES>::value;
00081 public:
00082 typedef TYPES types_t;
00083
00084 typedef struct { char data[MAX_SIZE]; } base_t;
00085
00086
00087 variant() : _index(0) { new(&_bits) typename boost::mpl::at_c<TYPES,0>::type(); }
00088 virtual ~variant() { apply_operation(*this, detail::destructor_op()); }
00089
00090
00091 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); }
00092
00093
00094 template <typename T> explicit variant(T& obj, bool do_swap);
00095
00096 template <typename T> variant& operator=(const T& obj) { variant tmp(obj); swap(*this,tmp); return *this; }
00097 variant& operator=(const variant& v) { variant tmp(v ); swap(*this,tmp); return *this; }
00098
00099 variant(const variant& v) : _index(v._index) { apply_operation(v, detail::copy_construct_in_place_fn<base_t>(_bits)); }
00100 template <typename T> void move_in(T& obj) { variant tmp(obj, true); swap(*this,tmp); }
00101
00102 template <typename TS> friend bool operator==(const variant<TS>& x, const variant<TS>& y);
00103 template <typename TS> friend bool operator!=(const variant<TS>& x, const variant<TS>& y);
00104
00105 template <typename T> static bool has_type() { return type_id<T>()!=NUM_TYPES; }
00106
00107 template <typename T> const T& _dynamic_cast() const{ if (type_id<T>()!=_index) throw std::bad_cast(); return reinterpret_cast<const T&>(_bits); }
00108 template <typename T> T& _dynamic_cast() { if (type_id<T>()!=_index) throw std::bad_cast(); return reinterpret_cast< T&>(_bits); }
00109
00110 private:
00111 template <typename T> static std::size_t type_id() { return type_to_index<TYPES,T>::value; }
00112
00113 template <typename CS> friend void swap(variant<CS>& x, variant<CS>& y);
00114 template <typename TYPES2, typename UNARY_OP> friend typename UNARY_OP::result_type apply_operation(variant<TYPES2>& var, UNARY_OP op);
00115 template <typename TYPES2, typename UNARY_OP> friend typename UNARY_OP::result_type apply_operation(const variant<TYPES2>& var, UNARY_OP op);
00116 template <typename TYPES1, typename TYPES2, typename BINARY_OP> friend typename BINARY_OP::result_type apply_operation(const variant<TYPES1>& arg1, const variant<TYPES2>& arg2, BINARY_OP op);
00117
00118 base_t _bits;
00119 std::size_t _index;
00120 };
00121
00122 namespace detail {
00123 struct destructor_op {
00124 typedef void result_type;
00125 template <typename T> result_type operator()(const T& t) const { t.~T(); }
00126 };
00127
00128 template <typename T, typename BITS>
00129 void copy_construct_in_place(const T& t, BITS& bits) {
00130 T& b=reinterpret_cast<T&>(bits);
00131 new(&b)T(t);
00132 }
00133
00134 template <typename BITS>
00135 struct copy_construct_in_place_fn {
00136 typedef void result_type;
00137 BITS& _dst;
00138 copy_construct_in_place_fn(BITS& dst) : _dst(dst) {}
00139
00140 template <typename T> void operator()(const T& src) const { copy_construct_in_place(src,_dst); }
00141 };
00142
00143 template <typename BITS>
00144 struct equal_to_fn {
00145 const BITS& _dst;
00146 equal_to_fn(const BITS& dst) : _dst(dst) {}
00147
00148 typedef bool result_type;
00149 template <typename T> result_type operator()(const T& x) const {
00150 return x==reinterpret_cast<const T&>(_dst);
00151 }
00152 };
00153 }
00154
00155
00156 template <typename TYPES>
00157 template <typename T> variant<TYPES>::variant(T& obj, bool do_swap) {
00158 _index=type_id<T>();
00159 if (_index==NUM_TYPES) throw std::bad_cast();
00160
00161 if (do_swap) {
00162 new(&_bits) T();
00163 swap(obj, reinterpret_cast<T&>(_bits));
00164 } else
00165 detail::copy_construct_in_place(const_cast<const T&>(obj), _bits);
00166 }
00167
00168 template <typename TYPES>
00169 void swap(variant<TYPES>& x, variant<TYPES>& y) {
00170 std::swap(x._bits,y._bits);
00171 std::swap(x._index, y._index);
00172 }
00173
00174 template <typename TYPES>
00175 inline bool operator==(const variant<TYPES>& x, const variant<TYPES>& y) {
00176 return x._index==y._index && apply_operation(x,detail::equal_to_fn<typename variant<TYPES>::base_t>(y._bits));
00177 }
00178
00179 template <typename C>
00180 inline bool operator!=(const variant<C>& x, const variant<C>& y) {
00181 return !(x==y);
00182 }
00183
00184 ADOBE_GIL_NAMESPACE_END
00185
00186 #endif