Adobe Systems, Inc.

variant.hpp

Go to the documentation of this file.
00001 /*
00002     Copyright 2005-2006 Adobe Systems Incorporated
00003     Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
00004     or a copy at http://opensource.adobe.com/licenses.html)
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>   // models MPL Random Access Container
00077 class variant {
00078     // size in bytes of the largest type in TYPES
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; // empty space equal to the size of the largest type in TYPES
00085 
00086     // Default constructor - default construct the first type
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     // Throws std::bad_cast if T is not in TYPES
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     // When doSwap is true, swaps obj with the contents of the variant. obj will contain default-constructed instance after the call
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);     // default-construct
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 // When doSwap is true, swaps obj with the contents of the variant. obj will contain default-constructed instance after the call
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();    // default construct
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

Copyright © 2006 Adobe Systems Incorporated.

Use of this website signifies your agreement to the Terms of Use and Online Privacy Policy.

Search powered by Google