1 /* Copyright 2006-2008 Joaquin M Lopez Munoz.
2 * Distributed under the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or copy at
4 * http://www.boost.org/LICENSE_1_0.txt)
6 * See http://www.boost.org/libs/flyweight for library home page.
9 #ifndef BOOST_FLYWEIGHT_KEY_VALUE_HPP
10 #define BOOST_FLYWEIGHT_KEY_VALUE_HPP
12 #if defined(_MSC_VER)&&(_MSC_VER>=1200)
16 #include <boost/flyweight/detail/value_tag.hpp>
17 #include <boost/flyweight/key_value_fwd.hpp>
18 #include <boost/mpl/assert.hpp>
19 #include <boost/preprocessor/repetition/enum_params.hpp>
20 #include <boost/type_traits/aligned_storage.hpp>
21 #include <boost/type_traits/alignment_of.hpp>
22 #include <boost/type_traits/is_same.hpp>
25 /* key-value policy: flywewight lookup is based on Key, which also serves
26 * to construct Value only when needed (new factory entry). key_value is
27 * used to avoid the construction of temporary values when such construction
29 * Optionally, KeyFromValue extracts the key from a value, which
30 * is needed in expressions like this:
32 * typedef flyweight<key_value<Key,Value> > fw_t;
35 * fw=v; // no key explicitly given
37 * If no KeyFromValue is provided, this latter expression fails to compile.
46 template<typename Key
,typename Value
,typename KeyFromValue
>
47 struct optimized_key_value
:value_marker
50 typedef Value value_type
;
57 #define BOOST_FLYWEIGHT_PERFECT_FWD_NAME explicit rep_type
58 #define BOOST_FLYWEIGHT_PERFECT_FWD_BODY(n) \
61 new(spc_ptr())key_type(BOOST_PP_ENUM_PARAMS(n,t)); \
63 #include <boost/flyweight/detail/perfect_fwd.hpp>
65 rep_type(const value_type
& x
):value_ptr(&x
){}
67 rep_type(const rep_type
& x
):value_ptr(x
.value_ptr
)
69 if(!x
.value_ptr
)new(key_ptr())key_type(*x
.key_ptr());
74 if(!value_ptr
) key_ptr()->~key_type();
75 else if(value_cted())value_ptr
->~value_type();
78 operator const key_type
&()const
80 if(value_ptr
)return key_from_value(*value_ptr
);
81 else return *key_ptr();
84 operator const value_type
&()const
86 /* This is always called after construct_value() or copy_value(),
87 * so we access spc directly rather than through value_ptr to
88 * save us an indirection.
91 return *static_cast<value_type
*>(spc_ptr());
95 friend struct optimized_key_value
;
97 void* spc_ptr()const{return static_cast<void*>(&spc
);}
98 bool value_cted()const{return value_ptr
==spc_ptr();}
100 key_type
* key_ptr()const
102 return static_cast<key_type
*>(static_cast<void*>(&spc
));
105 static const key_type
& key_from_value(const value_type
& x
)
111 void construct_value()const
114 /* value_ptr must be ==0, oherwise copy_value would have been called */
116 key_type
k(*key_ptr());
117 key_ptr()->~key_type();
118 value_ptr
= /* guarantees key won't be re-dted at ~rep_type if the */
119 static_cast<value_type
*>(spc_ptr())+1; /* next statement throws */
120 value_ptr
=new(spc_ptr())value_type(k
);
124 void copy_value()const
126 if(!value_cted())value_ptr
=new(spc_ptr())value_type(*value_ptr
);
129 mutable typename
boost::aligned_storage
<
130 (sizeof(key_type
)>sizeof(value_type
))?
131 sizeof(key_type
):sizeof(value_type
),
132 (boost::alignment_of
<key_type
>::value
>
133 boost::alignment_of
<value_type
>::value
)?
134 boost::alignment_of
<key_type
>::value
:
135 boost::alignment_of
<value_type
>::value
137 mutable const value_type
* value_ptr
;
140 static void construct_value(const rep_type
& r
)
145 static void copy_value(const rep_type
& r
)
151 template<typename Key
,typename Value
>
152 struct regular_key_value
:value_marker
154 typedef Key key_type
;
155 typedef Value value_type
;
162 #define BOOST_FLYWEIGHT_PERFECT_FWD_NAME explicit rep_type
163 #define BOOST_FLYWEIGHT_PERFECT_FWD_BODY(n) \
164 :key(BOOST_PP_ENUM_PARAMS(n,t)),value_ptr(0){}
165 #include <boost/flyweight/detail/perfect_fwd.hpp>
167 rep_type(const value_type
& x
):key(no_key_from_value_failure()){}
169 rep_type(const rep_type
& x
):key(x
.key
),value_ptr(0){}
173 if(value_ptr
)value_ptr
->~value_type();
176 operator const key_type
&()const{return key
;}
178 operator const value_type
&()const
180 /* This is always called after construct_value(),so we access spc
181 * directly rather than through value_ptr to save us an indirection.
184 return *static_cast<value_type
*>(spc_ptr());
188 friend struct regular_key_value
;
190 void* spc_ptr()const{return static_cast<void*>(&spc
);}
192 struct no_key_from_value_failure
194 BOOST_MPL_ASSERT_MSG(
196 NO_KEY_FROM_VALUE_CONVERSION_PROVIDED
,
197 (key_type
,value_type
));
199 operator const key_type
&()const;
202 void construct_value()const
204 if(!value_ptr
)value_ptr
=new(spc_ptr())value_type(key
);
208 mutable typename
boost::aligned_storage
<
210 boost::alignment_of
<value_type
>::value
212 mutable const value_type
* value_ptr
;
215 static void construct_value(const rep_type
& r
)
220 static void copy_value(const rep_type
&){}
223 } /* namespace flyweights::detail */
225 template<typename Key
,typename Value
,typename KeyFromValue
>
228 is_same
<KeyFromValue
,no_key_from_value
>,
229 detail::regular_key_value
<Key
,Value
>,
230 detail::optimized_key_value
<Key
,Value
,KeyFromValue
>
234 } /* namespace flyweights */
236 } /* namespace boost */