|
// variant.hpp
//
// Copyright (c) 2003 Eugene Gladyshev
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
//*************
// variant cannot have 'const' types
// since we are using data_holder, the alignment should not be an issue...?
#ifndef __ttl_variant__hpp
#define __ttl_variant__hpp
#include "ttl/meta/typelist.hpp"
namespace ttl
{
namespace var
{
struct exception : ttl::exception
{
exception() : ttl::exception("variant error") {}
};
namespace impl
{
template< typename F, typename V >
struct variant_binary_visitor
{
template<typename T1>
struct visitor_functor
{
F& f_;
T1 p1_;
visitor_functor( F& f, T1 p1 ) : f_(f), p1_(p1) {}
template < typename T2 >
void operator()( T2 p2 ) { f_(p1_, p2); }
};
F& f_;
V v_;
variant_binary_visitor( F& f, V v ): f_(f), v_(v) {}
template< typename T >
void operator()( T p )
{
visitor_functor<T> f(f_,p);
apply_visitor(f, v_);
}
};
template< typename F, typename V >
struct visitor_adapter_ref
{
F& f_;
V& v_;
visitor_adapter_ref( F& f, V& v ) : f_(f), v_(v) {}
template< typename T >
void operator()()
{
f_( v_.template get_holder<T>()->d_ );
};
};
}; //impl namespace
template< TTL_TPARAMS_DEF(TTL_MAX_TYPELIST_PARAMS, empty_type) >
struct variant
{
typedef meta::typelist<TTL_ARGS(TTL_MAX_TYPELIST_PARAMS)> list;
typedef variant<TTL_ARGS(TTL_MAX_TYPELIST_PARAMS)> this_t;
protected:
struct copier
{
this_t& r_;
const this_t& l_;
copier( this_t& r, const this_t& l ) : r_(r), l_(l) {}
template<typename T>
void operator()()
{
r_ = l_.template get_holder<T>()->d_;
};
};
struct deleter
{
ttl::impl::data_holder_base *p_;
deleter( ttl::impl::data_holder_base *p ) : p_(p) {}
template<typename T>
void operator()()
{
typedef ttl::impl::data_holder<T> var_type;
static_cast<var_type*>(p_)->~var_type();
}
};
template<int N>
struct storage
{
union
{
ttl::impl::data_holder_base dummy; //hope to satisfy alignment settings
char buf_[N];
};
};
public:
int which_;
ttl::impl::data_holder_base* pnt_;
storage< sizeof(ttl::impl::data_holder<typename list::largest_type>) > stor_;
enum
{
size = sizeof(ttl::impl::data_holder<typename list::largest_type>)
};
variant() : which_(0), pnt_(0)
{
}
template< typename T >
variant( const T& l ) : which_(0), pnt_(0)
{
operator=(l);
}
variant( const this_t& l ) : which_(0), pnt_(0)
{
copier c(*this, l);
meta::type_switch<list> ts;
ts( l.which(), c );
}
virtual ~variant() { destroy(); }
template< typename T >
this_t& operator=( const T& l )
{
destroy();
typedef meta::find_equivalent_type<T, list> found;
which_ = found::index;
pnt_ = new(stor_.buf_) ttl::impl::data_holder<typename found::type>(l);
return *this;
}
this_t& operator=( const this_t& l )
{
if( this == &l ) return *this;
copier c(*this, l);
meta::type_switch<list> ts;
ts( l.which(), c );
return *this;
}
inline size_t get_types() const { return list::length; }
inline int which() const { return which_; }
inline bool is_singular() const { return pnt_ != 0; }
template< typename T >
const ttl::impl::data_holder<T>* get_holder() const
{
return static_cast<const ttl::impl::data_holder<T>*>(pnt_);
}
template< typename T >
ttl::impl::data_holder<T>* get_holder()
{
return static_cast<ttl::impl::data_holder<T>*>(pnt_);
}
protected:
void destroy()
{
if( !pnt_ ) return;
ttl::impl::data_holder_base *p = pnt_;
pnt_ = 0;
deleter d(p);
meta::type_switch<list> ts;
ts(which_, d);
}
};
template< typename T, typename V >
T* get( V* v )
{
typedef meta::find_equivalent_type<T, typename V::list> found;
if( v->which() != found::index ) throw var::exception();
return &(v->template get_holder<typename found::type>()->d_);
}
template< typename T, typename V >
T& get( V& v )
{
typedef meta::find_equivalent_type<T, typename V::list> found;
if( v.which() != found::index ) throw var::exception();
return v.template get_holder<typename found::type>()->d_;
}
template< typename F, typename V >
void apply_visitor( F& f, V& v )
{
if( !v.is_singular() ) return;
meta::type_switch<typename V::list> ts;
impl::visitor_adapter_ref<F, V> va(f, v);
ts(v.which(), va);
}
template< typename F, typename V1, typename V2 >
void apply_visitor( F& f, V1& v1, V2& v2 )
{
impl::variant_binary_visitor<F,V2&> bv(f,v2);
apply_visitor(bv, v1);
}
};
};
#endif //__variant__hpp
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.