Chris@101
|
1 /* Copyright 2006-2014 Joaquin M Lopez Munoz.
|
Chris@16
|
2 * Distributed under the Boost Software License, Version 1.0.
|
Chris@16
|
3 * (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
4 * http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
5 *
|
Chris@16
|
6 * See http://www.boost.org/libs/flyweight for library home page.
|
Chris@16
|
7 */
|
Chris@16
|
8
|
Chris@16
|
9 #ifndef BOOST_FLYWEIGHT_KEY_VALUE_HPP
|
Chris@16
|
10 #define BOOST_FLYWEIGHT_KEY_VALUE_HPP
|
Chris@16
|
11
|
Chris@101
|
12 #if defined(_MSC_VER)
|
Chris@16
|
13 #pragma once
|
Chris@16
|
14 #endif
|
Chris@16
|
15
|
Chris@101
|
16 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
Chris@101
|
17 #include <boost/detail/workaround.hpp>
|
Chris@101
|
18 #include <boost/flyweight/detail/perfect_fwd.hpp>
|
Chris@16
|
19 #include <boost/flyweight/detail/value_tag.hpp>
|
Chris@16
|
20 #include <boost/flyweight/key_value_fwd.hpp>
|
Chris@16
|
21 #include <boost/mpl/assert.hpp>
|
Chris@16
|
22 #include <boost/type_traits/aligned_storage.hpp>
|
Chris@16
|
23 #include <boost/type_traits/alignment_of.hpp>
|
Chris@16
|
24 #include <boost/type_traits/is_same.hpp>
|
Chris@16
|
25 #include <new>
|
Chris@16
|
26
|
Chris@16
|
27 /* key-value policy: flywewight lookup is based on Key, which also serves
|
Chris@16
|
28 * to construct Value only when needed (new factory entry). key_value is
|
Chris@16
|
29 * used to avoid the construction of temporary values when such construction
|
Chris@16
|
30 * is expensive.
|
Chris@16
|
31 * Optionally, KeyFromValue extracts the key from a value, which
|
Chris@16
|
32 * is needed in expressions like this:
|
Chris@16
|
33 *
|
Chris@16
|
34 * typedef flyweight<key_value<Key,Value> > fw_t;
|
Chris@16
|
35 * fw_t fw;
|
Chris@16
|
36 * Value v;
|
Chris@16
|
37 * fw=v; // no key explicitly given
|
Chris@16
|
38 *
|
Chris@16
|
39 * If no KeyFromValue is provided, this latter expression fails to compile.
|
Chris@16
|
40 */
|
Chris@16
|
41
|
Chris@16
|
42 namespace boost{
|
Chris@16
|
43
|
Chris@16
|
44 namespace flyweights{
|
Chris@16
|
45
|
Chris@16
|
46 namespace detail{
|
Chris@16
|
47
|
Chris@16
|
48 template<typename Key,typename Value,typename KeyFromValue>
|
Chris@16
|
49 struct optimized_key_value:value_marker
|
Chris@16
|
50 {
|
Chris@16
|
51 typedef Key key_type;
|
Chris@16
|
52 typedef Value value_type;
|
Chris@16
|
53
|
Chris@16
|
54 class rep_type
|
Chris@16
|
55 {
|
Chris@16
|
56 public:
|
Chris@16
|
57 /* template ctors */
|
Chris@16
|
58
|
Chris@101
|
59 #define BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY(args) \
|
Chris@101
|
60 :value_ptr(0) \
|
Chris@101
|
61 { \
|
Chris@101
|
62 new(spc_ptr())key_type(BOOST_FLYWEIGHT_FORWARD(args)); \
|
Chris@16
|
63 }
|
Chris@16
|
64
|
Chris@101
|
65 BOOST_FLYWEIGHT_PERFECT_FWD(
|
Chris@101
|
66 explicit rep_type,
|
Chris@101
|
67 BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY)
|
Chris@101
|
68
|
Chris@101
|
69 #undef BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY
|
Chris@16
|
70
|
Chris@16
|
71 rep_type(const rep_type& x):value_ptr(x.value_ptr)
|
Chris@16
|
72 {
|
Chris@16
|
73 if(!x.value_ptr)new(key_ptr())key_type(*x.key_ptr());
|
Chris@16
|
74 }
|
Chris@16
|
75
|
Chris@101
|
76 rep_type(const value_type& x):value_ptr(&x){}
|
Chris@101
|
77
|
Chris@101
|
78 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
Chris@101
|
79 rep_type(rep_type&& x):value_ptr(x.value_ptr)
|
Chris@101
|
80 {
|
Chris@101
|
81 if(!x.value_ptr)new(key_ptr())key_type(std::move(*x.key_ptr()));
|
Chris@101
|
82 }
|
Chris@101
|
83
|
Chris@101
|
84 rep_type(value_type&& x):value_ptr(&x){}
|
Chris@101
|
85 #endif
|
Chris@101
|
86
|
Chris@16
|
87 ~rep_type()
|
Chris@16
|
88 {
|
Chris@16
|
89 if(!value_ptr) key_ptr()->~key_type();
|
Chris@16
|
90 else if(value_cted())value_ptr->~value_type();
|
Chris@16
|
91 }
|
Chris@16
|
92
|
Chris@16
|
93 operator const key_type&()const
|
Chris@16
|
94 {
|
Chris@16
|
95 if(value_ptr)return key_from_value(*value_ptr);
|
Chris@16
|
96 else return *key_ptr();
|
Chris@16
|
97 }
|
Chris@16
|
98
|
Chris@16
|
99 operator const value_type&()const
|
Chris@16
|
100 {
|
Chris@16
|
101 /* This is always called after construct_value() or copy_value(),
|
Chris@16
|
102 * so we access spc directly rather than through value_ptr to
|
Chris@16
|
103 * save us an indirection.
|
Chris@16
|
104 */
|
Chris@16
|
105
|
Chris@16
|
106 return *static_cast<value_type*>(spc_ptr());
|
Chris@16
|
107 }
|
Chris@16
|
108
|
Chris@16
|
109 private:
|
Chris@16
|
110 friend struct optimized_key_value;
|
Chris@16
|
111
|
Chris@16
|
112 void* spc_ptr()const{return static_cast<void*>(&spc);}
|
Chris@16
|
113 bool value_cted()const{return value_ptr==spc_ptr();}
|
Chris@16
|
114
|
Chris@16
|
115 key_type* key_ptr()const
|
Chris@16
|
116 {
|
Chris@16
|
117 return static_cast<key_type*>(static_cast<void*>(&spc));
|
Chris@16
|
118 }
|
Chris@16
|
119
|
Chris@16
|
120 static const key_type& key_from_value(const value_type& x)
|
Chris@16
|
121 {
|
Chris@16
|
122 KeyFromValue k;
|
Chris@16
|
123 return k(x);
|
Chris@16
|
124 }
|
Chris@16
|
125
|
Chris@16
|
126 void construct_value()const
|
Chris@16
|
127 {
|
Chris@16
|
128 if(!value_cted()){
|
Chris@16
|
129 /* value_ptr must be ==0, oherwise copy_value would have been called */
|
Chris@16
|
130
|
Chris@101
|
131 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
Chris@101
|
132 key_type k(std::move(*key_ptr()));
|
Chris@101
|
133 #else
|
Chris@16
|
134 key_type k(*key_ptr());
|
Chris@101
|
135 #endif
|
Chris@101
|
136
|
Chris@16
|
137 key_ptr()->~key_type();
|
Chris@16
|
138 value_ptr= /* guarantees key won't be re-dted at ~rep_type if the */
|
Chris@16
|
139 static_cast<value_type*>(spc_ptr())+1; /* next statement throws */
|
Chris@16
|
140 value_ptr=new(spc_ptr())value_type(k);
|
Chris@16
|
141 }
|
Chris@16
|
142 }
|
Chris@16
|
143
|
Chris@16
|
144 void copy_value()const
|
Chris@16
|
145 {
|
Chris@16
|
146 if(!value_cted())value_ptr=new(spc_ptr())value_type(*value_ptr);
|
Chris@16
|
147 }
|
Chris@16
|
148
|
Chris@101
|
149 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
Chris@101
|
150 void move_value()const
|
Chris@101
|
151 {
|
Chris@101
|
152 if(!value_cted())value_ptr=
|
Chris@101
|
153 new(spc_ptr())value_type(std::move(const_cast<value_type&>(*value_ptr)));
|
Chris@101
|
154 }
|
Chris@101
|
155 #endif
|
Chris@101
|
156
|
Chris@16
|
157 mutable typename boost::aligned_storage<
|
Chris@16
|
158 (sizeof(key_type)>sizeof(value_type))?
|
Chris@16
|
159 sizeof(key_type):sizeof(value_type),
|
Chris@16
|
160 (boost::alignment_of<key_type>::value >
|
Chris@16
|
161 boost::alignment_of<value_type>::value)?
|
Chris@16
|
162 boost::alignment_of<key_type>::value:
|
Chris@16
|
163 boost::alignment_of<value_type>::value
|
Chris@16
|
164 >::type spc;
|
Chris@16
|
165 mutable const value_type* value_ptr;
|
Chris@16
|
166 };
|
Chris@16
|
167
|
Chris@16
|
168 static void construct_value(const rep_type& r)
|
Chris@16
|
169 {
|
Chris@16
|
170 r.construct_value();
|
Chris@16
|
171 }
|
Chris@16
|
172
|
Chris@16
|
173 static void copy_value(const rep_type& r)
|
Chris@16
|
174 {
|
Chris@16
|
175 r.copy_value();
|
Chris@16
|
176 }
|
Chris@101
|
177
|
Chris@101
|
178 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
Chris@101
|
179 static void move_value(const rep_type& r)
|
Chris@101
|
180 {
|
Chris@101
|
181 r.move_value();
|
Chris@101
|
182 }
|
Chris@101
|
183 #endif
|
Chris@16
|
184 };
|
Chris@16
|
185
|
Chris@16
|
186 template<typename Key,typename Value>
|
Chris@16
|
187 struct regular_key_value:value_marker
|
Chris@16
|
188 {
|
Chris@16
|
189 typedef Key key_type;
|
Chris@16
|
190 typedef Value value_type;
|
Chris@16
|
191
|
Chris@16
|
192 class rep_type
|
Chris@16
|
193 {
|
Chris@16
|
194 public:
|
Chris@16
|
195 /* template ctors */
|
Chris@16
|
196
|
Chris@101
|
197 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)&&\
|
Chris@101
|
198 !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)&&\
|
Chris@101
|
199 BOOST_WORKAROUND(__GNUC__,<=4)&&(__GNUC__<4||__GNUC_MINOR__<=4)
|
Chris@16
|
200
|
Chris@101
|
201 /* GCC 4.4.2 (and probably prior) bug: the default ctor generated by the
|
Chris@101
|
202 * variadic temmplate ctor below fails to value-initialize key.
|
Chris@101
|
203 */
|
Chris@101
|
204
|
Chris@101
|
205 rep_type():key(),value_ptr(0){}
|
Chris@101
|
206 #endif
|
Chris@101
|
207
|
Chris@101
|
208 #define BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY(args) \
|
Chris@101
|
209 :key(BOOST_FLYWEIGHT_FORWARD(args)),value_ptr(0){}
|
Chris@101
|
210
|
Chris@101
|
211 BOOST_FLYWEIGHT_PERFECT_FWD(
|
Chris@101
|
212 explicit rep_type,
|
Chris@101
|
213 BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY)
|
Chris@101
|
214
|
Chris@101
|
215 #undef BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY
|
Chris@101
|
216
|
Chris@101
|
217 rep_type(const rep_type& x):key(x.key),value_ptr(0){}
|
Chris@16
|
218 rep_type(const value_type& x):key(no_key_from_value_failure()){}
|
Chris@16
|
219
|
Chris@101
|
220 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
Chris@101
|
221 rep_type(rep_type&& x):key(std::move(x.key)),value_ptr(0){}
|
Chris@101
|
222 rep_type(value_type&& x):key(no_key_from_value_failure()){}
|
Chris@101
|
223 #endif
|
Chris@16
|
224
|
Chris@16
|
225 ~rep_type()
|
Chris@16
|
226 {
|
Chris@16
|
227 if(value_ptr)value_ptr->~value_type();
|
Chris@16
|
228 }
|
Chris@16
|
229
|
Chris@16
|
230 operator const key_type&()const{return key;}
|
Chris@16
|
231
|
Chris@16
|
232 operator const value_type&()const
|
Chris@16
|
233 {
|
Chris@16
|
234 /* This is always called after construct_value(),so we access spc
|
Chris@16
|
235 * directly rather than through value_ptr to save us an indirection.
|
Chris@16
|
236 */
|
Chris@16
|
237
|
Chris@16
|
238 return *static_cast<value_type*>(spc_ptr());
|
Chris@16
|
239 }
|
Chris@16
|
240
|
Chris@16
|
241 private:
|
Chris@16
|
242 friend struct regular_key_value;
|
Chris@16
|
243
|
Chris@16
|
244 void* spc_ptr()const{return static_cast<void*>(&spc);}
|
Chris@16
|
245
|
Chris@16
|
246 struct no_key_from_value_failure
|
Chris@16
|
247 {
|
Chris@16
|
248 BOOST_MPL_ASSERT_MSG(
|
Chris@16
|
249 false,
|
Chris@16
|
250 NO_KEY_FROM_VALUE_CONVERSION_PROVIDED,
|
Chris@16
|
251 (key_type,value_type));
|
Chris@16
|
252
|
Chris@16
|
253 operator const key_type&()const;
|
Chris@16
|
254 };
|
Chris@16
|
255
|
Chris@16
|
256 void construct_value()const
|
Chris@16
|
257 {
|
Chris@16
|
258 if(!value_ptr)value_ptr=new(spc_ptr())value_type(key);
|
Chris@16
|
259 }
|
Chris@16
|
260
|
Chris@16
|
261 key_type key;
|
Chris@16
|
262 mutable typename boost::aligned_storage<
|
Chris@16
|
263 sizeof(value_type),
|
Chris@16
|
264 boost::alignment_of<value_type>::value
|
Chris@16
|
265 >::type spc;
|
Chris@16
|
266 mutable const value_type* value_ptr;
|
Chris@16
|
267 };
|
Chris@16
|
268
|
Chris@16
|
269 static void construct_value(const rep_type& r)
|
Chris@16
|
270 {
|
Chris@16
|
271 r.construct_value();
|
Chris@16
|
272 }
|
Chris@16
|
273
|
Chris@101
|
274 /* copy_value() and move_value() can't really ever be called, provided to avoid
|
Chris@101
|
275 * compile errors (it is the no_key_from_value_failure compile error we want to
|
Chris@101
|
276 * appear in these cases).
|
Chris@101
|
277 */
|
Chris@101
|
278
|
Chris@16
|
279 static void copy_value(const rep_type&){}
|
Chris@101
|
280
|
Chris@101
|
281 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
Chris@101
|
282 static void move_value(const rep_type&){}
|
Chris@101
|
283 #endif
|
Chris@16
|
284 };
|
Chris@16
|
285
|
Chris@16
|
286 } /* namespace flyweights::detail */
|
Chris@16
|
287
|
Chris@16
|
288 template<typename Key,typename Value,typename KeyFromValue>
|
Chris@16
|
289 struct key_value:
|
Chris@16
|
290 mpl::if_<
|
Chris@16
|
291 is_same<KeyFromValue,no_key_from_value>,
|
Chris@16
|
292 detail::regular_key_value<Key,Value>,
|
Chris@16
|
293 detail::optimized_key_value<Key,Value,KeyFromValue>
|
Chris@16
|
294 >::type
|
Chris@16
|
295 {};
|
Chris@16
|
296
|
Chris@16
|
297 } /* namespace flyweights */
|
Chris@16
|
298
|
Chris@16
|
299 } /* namespace boost */
|
Chris@16
|
300
|
Chris@16
|
301 #endif
|