/* Flyweight class. | |
* | |
* Copyright 2006-2009 Joaquin M Lopez Munoz. | |
* Distributed under the Boost Software License, Version 1.0. | |
* (See accompanying file LICENSE_1_0.txt or copy at | |
* http://www.boost.org/LICENSE_1_0.txt) | |
* | |
* See http://www.boost.org/libs/flyweight for library home page. | |
*/ | |
#ifndef BOOST_FLYWEIGHT_FLYWEIGHT_HPP | |
#define BOOST_FLYWEIGHT_FLYWEIGHT_HPP | |
#if defined(_MSC_VER)&&(_MSC_VER>=1200) | |
#pragma once | |
#endif | |
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ | |
#include <algorithm> | |
#include <boost/detail/workaround.hpp> | |
#include <boost/flyweight/detail/default_value_policy.hpp> | |
#include <boost/flyweight/detail/flyweight_core.hpp> | |
#include <boost/flyweight/factory_tag.hpp> | |
#include <boost/flyweight/flyweight_fwd.hpp> | |
#include <boost/flyweight/locking_tag.hpp> | |
#include <boost/flyweight/simple_locking_fwd.hpp> | |
#include <boost/flyweight/static_holder_fwd.hpp> | |
#include <boost/flyweight/hashed_factory_fwd.hpp> | |
#include <boost/flyweight/holder_tag.hpp> | |
#include <boost/flyweight/refcounted_fwd.hpp> | |
#include <boost/flyweight/tag.hpp> | |
#include <boost/flyweight/tracking_tag.hpp> | |
#include <boost/mpl/assert.hpp> | |
#include <boost/mpl/if.hpp> | |
#include <boost/mpl/not.hpp> | |
#include <boost/mpl/or.hpp> | |
#include <boost/parameter/binding.hpp> | |
#include <boost/preprocessor/repetition/enum_params.hpp> | |
#include <boost/type_traits/is_same.hpp> | |
#include <boost/utility/swap.hpp> | |
#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400)) | |
#pragma warning(push) | |
#pragma warning(disable:4521) /* multiple copy ctors */ | |
#endif | |
namespace boost{ | |
namespace flyweights{ | |
namespace detail{ | |
/* Used for the detection of unmatched template args in a | |
* flyweight instantiation. | |
*/ | |
struct unmatched_arg; | |
/* Boost.Parameter structures for use in flyweight. | |
* NB: these types are derived from instead of typedef'd to force their | |
* instantiation, which solves http://bugs.sun.com/view_bug.do?bug_id=6782987 | |
* as found out by Simon Atanasyan. | |
*/ | |
struct flyweight_signature: | |
parameter::parameters< | |
parameter::optional< | |
parameter::deduced<tag<> >, | |
detail::is_tag<boost::mpl::_> | |
>, | |
parameter::optional< | |
parameter::deduced<tracking<> >, | |
is_tracking<boost::mpl::_> | |
>, | |
parameter::optional< | |
parameter::deduced<factory<> >, | |
is_factory<boost::mpl::_> | |
>, | |
parameter::optional< | |
parameter::deduced<locking<> >, | |
is_locking<boost::mpl::_> | |
>, | |
parameter::optional< | |
parameter::deduced<holder<> >, | |
is_holder<boost::mpl::_> | |
> | |
> | |
{}; | |
struct flyweight_unmatched_signature: | |
parameter::parameters< | |
parameter::optional< | |
parameter::deduced< | |
detail::unmatched_arg | |
>, | |
mpl::not_< | |
mpl::or_< | |
detail::is_tag<boost::mpl::_>, | |
is_tracking<boost::mpl::_>, | |
is_factory<boost::mpl::_>, | |
is_locking<boost::mpl::_>, | |
is_holder<boost::mpl::_> | |
> | |
> | |
> | |
> | |
{}; | |
} /* namespace flyweights::detail */ | |
template< | |
typename T, | |
typename Arg1,typename Arg2,typename Arg3,typename Arg4,typename Arg5 | |
> | |
class flyweight | |
{ | |
private: | |
typedef typename mpl::if_< | |
detail::is_value<T>, | |
T, | |
detail::default_value_policy<T> | |
>::type value_policy; | |
typedef typename detail:: | |
flyweight_signature::bind< | |
Arg1,Arg2,Arg3,Arg4,Arg5 | |
>::type args; | |
typedef typename parameter::binding< | |
args,tag<>,mpl::na | |
>::type tag_type; | |
typedef typename parameter::binding< | |
args,tracking<>,refcounted | |
>::type tracking_policy; | |
typedef typename parameter::binding< | |
args,factory<>,hashed_factory<> | |
>::type factory_specifier; | |
typedef typename parameter::binding< | |
args,locking<>,simple_locking | |
>::type locking_policy; | |
typedef typename parameter::binding< | |
args,holder<>,static_holder | |
>::type holder_specifier; | |
typedef typename detail:: | |
flyweight_unmatched_signature::bind< | |
Arg1,Arg2,Arg3,Arg4,Arg5 | |
>::type unmatched_args; | |
typedef typename parameter::binding< | |
unmatched_args,detail::unmatched_arg, | |
detail::unmatched_arg | |
>::type unmatched_arg_detected; | |
/* You have passed a type in the specification of a flyweight type that | |
* could not be interpreted as a valid argument. | |
*/ | |
BOOST_MPL_ASSERT_MSG( | |
(is_same<unmatched_arg_detected,detail::unmatched_arg>::value), | |
INVALID_ARGUMENT_TO_FLYWEIGHT, | |
(flyweight)); | |
typedef detail::flyweight_core< | |
value_policy,tag_type,tracking_policy, | |
factory_specifier,locking_policy, | |
holder_specifier | |
> core; | |
typedef typename core::handle_type handle_type; | |
public: | |
typedef typename value_policy::key_type key_type; | |
typedef typename value_policy::value_type value_type; | |
/* static data initialization */ | |
static bool init(){return core::init();} | |
class initializer | |
{ | |
public: | |
initializer():b(init()){} | |
private: | |
bool b; | |
}; | |
/* construct/copy/destroy */ | |
flyweight():h(core::insert(key_type())){} | |
flyweight(const flyweight& x):h(x.h){} | |
flyweight(flyweight& x):h(x.h){} | |
/* template ctors */ | |
#define BOOST_FLYWEIGHT_PERFECT_FWD_NAME explicit flyweight | |
#define BOOST_FLYWEIGHT_PERFECT_FWD_BODY(n) \ | |
:h(core::insert(BOOST_PP_ENUM_PARAMS(n,t))){} | |
#include <boost/flyweight/detail/perfect_fwd.hpp> | |
flyweight& operator=(const flyweight& x){h=x.h;return *this;} | |
flyweight& operator=(const value_type& x){return operator=(flyweight(x));} | |
/* convertibility to underlying type */ | |
const key_type& get_key()const{return core::key(h);} | |
const value_type& get()const{return core::value(h);} | |
operator const value_type&()const{return get();} | |
/* exact type equality */ | |
friend bool operator==(const flyweight& x,const flyweight& y) | |
{ | |
return &x.get()==&y.get(); | |
} | |
/* modifiers */ | |
void swap(flyweight& x){boost::swap(h,x.h);} | |
private: | |
handle_type h; | |
}; | |
#define BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(n) \ | |
typename Arg##n##1,typename Arg##n##2,typename Arg##n##3, \ | |
typename Arg##n##4,typename Arg##n##5 | |
#define BOOST_FLYWEIGHT_TEMPL_ARGS(n) \ | |
Arg##n##1,Arg##n##2,Arg##n##3,Arg##n##4,Arg##n##5 | |
/* Comparison. Unlike exact type comparison defined above, intertype | |
* comparison just forwards to the underlying objects. | |
*/ | |
template< | |
typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1), | |
typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2) | |
> | |
bool operator==( | |
const flyweight<T1,BOOST_FLYWEIGHT_TEMPL_ARGS(1)>& x, | |
const flyweight<T2,BOOST_FLYWEIGHT_TEMPL_ARGS(2)>& y) | |
{ | |
return x.get()==y.get(); | |
} | |
template< | |
typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1), | |
typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2) | |
> | |
bool operator<( | |
const flyweight<T1,BOOST_FLYWEIGHT_TEMPL_ARGS(1)>& x, | |
const flyweight<T2,BOOST_FLYWEIGHT_TEMPL_ARGS(2)>& y) | |
{ | |
return x.get()<y.get(); | |
} | |
#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) | |
template< | |
typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1), | |
typename T2 | |
> | |
bool operator==( | |
const flyweight<T1,BOOST_FLYWEIGHT_TEMPL_ARGS(1)>& x,const T2& y) | |
{ | |
return x.get()==y; | |
} | |
template< | |
typename T1, | |
typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2) | |
> | |
bool operator==( | |
const T1& x,const flyweight<T2,BOOST_FLYWEIGHT_TEMPL_ARGS(2)>& y) | |
{ | |
return x==y.get(); | |
} | |
template< | |
typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1), | |
typename T2 | |
> | |
bool operator<( | |
const flyweight<T1,BOOST_FLYWEIGHT_TEMPL_ARGS(1)>& x,const T2& y) | |
{ | |
return x.get()<y; | |
} | |
template< | |
typename T1, | |
typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2) | |
> | |
bool operator<( | |
const T1& x,const flyweight<T2,BOOST_FLYWEIGHT_TEMPL_ARGS(2)>& y) | |
{ | |
return x<y.get(); | |
} | |
#endif /* !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) */ | |
/* rest of comparison operators */ | |
#define BOOST_FLYWEIGHT_COMPLETE_COMP_OPS(t,a1,a2) \ | |
template<t> \ | |
inline bool operator!=(const a1& x,const a2& y) \ | |
{ \ | |
return !(x==y); \ | |
} \ | |
\ | |
template<t> \ | |
inline bool operator>(const a1& x,const a2& y) \ | |
{ \ | |
return y<x; \ | |
} \ | |
\ | |
template<t> \ | |
inline bool operator>=(const a1& x,const a2& y) \ | |
{ \ | |
return !(x<y); \ | |
} \ | |
\ | |
template<t> \ | |
inline bool operator<=(const a1& x,const a2& y) \ | |
{ \ | |
return !(y<x); \ | |
} | |
BOOST_FLYWEIGHT_COMPLETE_COMP_OPS( | |
typename T1 BOOST_PP_COMMA() | |
BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1) BOOST_PP_COMMA() | |
typename T2 BOOST_PP_COMMA() | |
BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2), | |
flyweight< | |
T1 BOOST_PP_COMMA() BOOST_FLYWEIGHT_TEMPL_ARGS(1) | |
>, | |
flyweight< | |
T2 BOOST_PP_COMMA() BOOST_FLYWEIGHT_TEMPL_ARGS(2) | |
>) | |
#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) | |
BOOST_FLYWEIGHT_COMPLETE_COMP_OPS( | |
typename T1 BOOST_PP_COMMA() | |
BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1) BOOST_PP_COMMA() | |
typename T2, | |
flyweight< | |
T1 BOOST_PP_COMMA() BOOST_FLYWEIGHT_TEMPL_ARGS(1) | |
>, | |
T2) | |
BOOST_FLYWEIGHT_COMPLETE_COMP_OPS( | |
typename T1 BOOST_PP_COMMA() | |
typename T2 BOOST_PP_COMMA() | |
BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2), | |
T1, | |
flyweight< | |
T2 BOOST_PP_COMMA() BOOST_FLYWEIGHT_TEMPL_ARGS(2) | |
>) | |
#endif /* !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) */ | |
/* specialized algorithms */ | |
template<typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_)> | |
void swap( | |
flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)>& x, | |
flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)>& y) | |
{ | |
x.swap(y); | |
} | |
template< | |
BOOST_TEMPLATED_STREAM_ARGS(ElemType,Traits) | |
BOOST_TEMPLATED_STREAM_COMMA | |
typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_) | |
> | |
BOOST_TEMPLATED_STREAM(ostream,ElemType,Traits)& operator<<( | |
BOOST_TEMPLATED_STREAM(ostream,ElemType,Traits)& out, | |
const flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)>& x) | |
{ | |
return out<<x.get(); | |
} | |
template< | |
BOOST_TEMPLATED_STREAM_ARGS(ElemType,Traits) | |
BOOST_TEMPLATED_STREAM_COMMA | |
typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_) | |
> | |
BOOST_TEMPLATED_STREAM(istream,ElemType,Traits)& operator>>( | |
BOOST_TEMPLATED_STREAM(istream,ElemType,Traits)& in, | |
flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)>& x) | |
{ | |
typedef typename flyweight< | |
T,BOOST_FLYWEIGHT_TEMPL_ARGS(_) | |
>::value_type value_type; | |
/* value_type need not be default ctble but must be copy ctble */ | |
value_type t(x.get()); | |
in>>t; | |
x=t; | |
return in; | |
} | |
} /* namespace flyweights */ | |
} /* namespace boost */ | |
#undef BOOST_FLYWEIGHT_COMPLETE_COMP_OPS | |
#undef BOOST_FLYWEIGHT_TEMPL_ARGS | |
#undef BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS | |
#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400)) | |
#pragma warning(pop) | |
#endif | |
#endif |