You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
407 lines
12 KiB
407 lines
12 KiB
/* 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
|
|
|