00001
00002
00003
00004
00005
00006
00007
00008
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 <cassert>
00028 #include <stdexcept>
00029 #include <boost/bind.hpp>
00030
00031 #include <boost/mpl/transform.hpp>
00032 #include <boost/mpl/size.hpp>
00033 #include <boost/mpl/sizeof.hpp>
00034 #include <boost/mpl/max.hpp>
00035 #include <boost/mpl/at.hpp>
00036 #include <boost/mpl/fold.hpp>
00037
00038 namespace boost { namespace gil {
00039
00040 namespace detail {
00041 template <typename Types, typename T> struct type_to_index;
00042 template <typename Op, typename T> struct reduce;
00043 struct destructor_op {
00044 typedef void result_type;
00045 template <typename T> result_type operator()(const T& t) const { t.~T(); }
00046 };
00047 template <typename T, typename Bits> void copy_construct_in_place(const T& t, Bits& bits);
00048 template <typename Bits> struct copy_construct_in_place_fn;
00049 }
00084 template <typename Types>
00085 class variant {
00086
00087 static const std::size_t MAX_SIZE = mpl::fold<Types, mpl::size_t<0>, mpl::max<mpl::_1, mpl::sizeof_<mpl::_2> > >::type::value;
00088 static const std::size_t NUM_TYPES = mpl::size<Types>::value;
00089 public:
00090 typedef Types types_t;
00091
00092 typedef struct { char data[MAX_SIZE]; } base_t;
00093
00094
00095 variant() : _index(0) { new(&_bits) typename mpl::at_c<Types,0>::type(); }
00096 virtual ~variant() { apply_operation(*this, detail::destructor_op()); }
00097
00098
00099 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); }
00100
00101
00102 template <typename T> explicit variant(T& obj, bool do_swap);
00103
00104 template <typename T> variant& operator=(const T& obj) { variant tmp(obj); swap(*this,tmp); return *this; }
00105 variant& operator=(const variant& v) { variant tmp(v ); swap(*this,tmp); return *this; }
00106
00107 variant(const variant& v) : _index(v._index) { apply_operation(v, detail::copy_construct_in_place_fn<base_t>(_bits)); }
00108 template <typename T> void move_in(T& obj) { variant tmp(obj, true); swap(*this,tmp); }
00109
00110 template <typename TS> friend bool operator==(const variant<TS>& x, const variant<TS>& y);
00111 template <typename TS> friend bool operator!=(const variant<TS>& x, const variant<TS>& y);
00112
00113 template <typename T> static bool has_type() { return type_id<T>()!=NUM_TYPES; }
00114
00115 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); }
00116 template <typename T> T& _dynamic_cast() { if (!current_type_is<T>()) throw std::bad_cast(); return *gil_reinterpret_cast < T*>(&_bits); }
00117
00118 template <typename T> bool current_type_is() const { return type_id<T>()==_index; }
00119
00120 private:
00121 template <typename T> static std::size_t type_id() { return detail::type_to_index<Types,T>::value; }
00122
00123 template <typename Cs> friend void swap(variant<Cs>& x, variant<Cs>& y);
00124 template <typename Types2, typename UnaryOp> friend typename UnaryOp::result_type apply_operation(variant<Types2>& var, UnaryOp op);
00125 template <typename Types2, typename UnaryOp> friend typename UnaryOp::result_type apply_operation(const variant<Types2>& var, UnaryOp op);
00126 template <typename Types1, typename Types2, typename BinaryOp> friend typename BinaryOp::result_type apply_operation(const variant<Types1>& arg1, const variant<Types2>& arg2, BinaryOp op);
00127
00128 base_t _bits;
00129 std::size_t _index;
00130 };
00131
00132 namespace detail {
00133
00134 template <typename T, typename Bits>
00135 void copy_construct_in_place(const T& t, Bits& bits) {
00136 T& b=*gil_reinterpret_cast<T*>(&bits);
00137 new(&b)T(t);
00138 }
00139
00140 template <typename Bits>
00141 struct copy_construct_in_place_fn {
00142 typedef void result_type;
00143 Bits& _dst;
00144 copy_construct_in_place_fn(Bits& dst) : _dst(dst) {}
00145
00146 template <typename T> void operator()(const T& src) const { copy_construct_in_place(src,_dst); }
00147 };
00148
00149 template <typename Bits>
00150 struct equal_to_fn {
00151 const Bits& _dst;
00152 equal_to_fn(const Bits& dst) : _dst(dst) {}
00153
00154 typedef bool result_type;
00155 template <typename T> result_type operator()(const T& x) const {
00156 return x==*gil_reinterpret_cast_c<const T*>(&_dst);
00157 }
00158 };
00159 }
00160
00161
00162 template <typename Types>
00163 template <typename T> variant<Types>::variant(T& obj, bool do_swap) {
00164 _index=type_id<T>();
00165 if (_index==NUM_TYPES) throw std::bad_cast();
00166
00167 if (do_swap) {
00168 new(&_bits) T();
00169 swap(obj, *gil_reinterpret_cast<T*>(&_bits));
00170 } else
00171 detail::copy_construct_in_place(const_cast<const T&>(obj), _bits);
00172 }
00173
00174 template <typename Types>
00175 void swap(variant<Types>& x, variant<Types>& y) {
00176 std::swap(x._bits,y._bits);
00177 std::swap(x._index, y._index);
00178 }
00179
00180 template <typename Types>
00181 inline bool operator==(const variant<Types>& x, const variant<Types>& y) {
00182 return x._index==y._index && apply_operation(x,detail::equal_to_fn<typename variant<Types>::base_t>(y._bits));
00183 }
00184
00185 template <typename C>
00186 inline bool operator!=(const variant<C>& x, const variant<C>& y) {
00187 return !(x==y);
00188 }
00189
00190 } }
00191
00192 #endif