]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /* Flyweight class. |
2 | * | |
3 | * Copyright 2006-2015 Joaquin M Lopez Munoz. | |
4 | * Distributed under the Boost Software License, Version 1.0. | |
5 | * (See accompanying file LICENSE_1_0.txt or copy at | |
6 | * http://www.boost.org/LICENSE_1_0.txt) | |
7 | * | |
8 | * See http://www.boost.org/libs/flyweight for library home page. | |
9 | */ | |
10 | ||
11 | #ifndef BOOST_FLYWEIGHT_FLYWEIGHT_HPP | |
12 | #define BOOST_FLYWEIGHT_FLYWEIGHT_HPP | |
13 | ||
14 | #if defined(_MSC_VER) | |
15 | #pragma once | |
16 | #endif | |
17 | ||
18 | #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ | |
19 | #include <algorithm> | |
20 | #include <boost/detail/workaround.hpp> | |
21 | #include <boost/flyweight/detail/default_value_policy.hpp> | |
22 | #include <boost/flyweight/detail/flyweight_core.hpp> | |
23 | #include <boost/flyweight/detail/perfect_fwd.hpp> | |
24 | #include <boost/flyweight/factory_tag.hpp> | |
25 | #include <boost/flyweight/flyweight_fwd.hpp> | |
26 | #include <boost/flyweight/locking_tag.hpp> | |
27 | #include <boost/flyweight/simple_locking_fwd.hpp> | |
28 | #include <boost/flyweight/static_holder_fwd.hpp> | |
29 | #include <boost/flyweight/hashed_factory_fwd.hpp> | |
30 | #include <boost/flyweight/holder_tag.hpp> | |
31 | #include <boost/flyweight/refcounted_fwd.hpp> | |
32 | #include <boost/flyweight/tag.hpp> | |
33 | #include <boost/flyweight/tracking_tag.hpp> | |
34 | #include <boost/mpl/assert.hpp> | |
35 | #include <boost/mpl/if.hpp> | |
36 | #include <boost/mpl/not.hpp> | |
37 | #include <boost/mpl/or.hpp> | |
38 | #include <boost/parameter/binding.hpp> | |
39 | #include <boost/type_traits/is_same.hpp> | |
40 | #include <boost/utility/swap.hpp> | |
41 | ||
42 | #if !defined(BOOST_NO_SFINAE)&&!defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) | |
43 | #include <boost/utility/enable_if.hpp> | |
44 | #include <boost/type_traits/is_convertible.hpp> | |
45 | #include <initializer_list> | |
46 | #endif | |
47 | ||
48 | #if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400)) | |
49 | #pragma warning(push) | |
50 | #pragma warning(disable:4520) /* multiple default ctors */ | |
51 | #pragma warning(disable:4521) /* multiple copy ctors */ | |
52 | #endif | |
53 | ||
54 | namespace boost{ | |
55 | ||
56 | namespace flyweights{ | |
57 | ||
58 | namespace detail{ | |
59 | ||
60 | /* Used for the detection of unmatched template args in a | |
61 | * flyweight instantiation. | |
62 | */ | |
63 | ||
64 | struct unmatched_arg; | |
65 | ||
66 | /* Boost.Parameter structures for use in flyweight. | |
67 | * NB: these types are derived from instead of typedef'd to force their | |
68 | * instantiation, which solves http://bugs.sun.com/view_bug.do?bug_id=6782987 | |
69 | * as found out by Simon Atanasyan. | |
70 | */ | |
71 | ||
72 | struct flyweight_signature: | |
73 | parameter::parameters< | |
74 | parameter::optional< | |
75 | parameter::deduced<tag<> >, | |
76 | detail::is_tag<boost::mpl::_> | |
77 | >, | |
78 | parameter::optional< | |
79 | parameter::deduced<tracking<> >, | |
80 | is_tracking<boost::mpl::_> | |
81 | >, | |
82 | parameter::optional< | |
83 | parameter::deduced<factory<> >, | |
84 | is_factory<boost::mpl::_> | |
85 | >, | |
86 | parameter::optional< | |
87 | parameter::deduced<locking<> >, | |
88 | is_locking<boost::mpl::_> | |
89 | >, | |
90 | parameter::optional< | |
91 | parameter::deduced<holder<> >, | |
92 | is_holder<boost::mpl::_> | |
93 | > | |
94 | > | |
95 | {}; | |
96 | ||
97 | struct flyweight_unmatched_signature: | |
98 | parameter::parameters< | |
99 | parameter::optional< | |
100 | parameter::deduced< | |
101 | detail::unmatched_arg | |
102 | >, | |
103 | mpl::not_< | |
104 | mpl::or_< | |
105 | detail::is_tag<boost::mpl::_>, | |
106 | is_tracking<boost::mpl::_>, | |
107 | is_factory<boost::mpl::_>, | |
108 | is_locking<boost::mpl::_>, | |
109 | is_holder<boost::mpl::_> | |
110 | > | |
111 | > | |
112 | > | |
113 | > | |
114 | {}; | |
115 | ||
116 | } /* namespace flyweights::detail */ | |
117 | ||
118 | template< | |
119 | typename T, | |
120 | typename Arg1,typename Arg2,typename Arg3,typename Arg4,typename Arg5 | |
121 | > | |
122 | class flyweight | |
123 | { | |
124 | private: | |
125 | typedef typename mpl::if_< | |
126 | detail::is_value<T>, | |
127 | T, | |
128 | detail::default_value_policy<T> | |
129 | >::type value_policy; | |
130 | typedef typename detail:: | |
131 | flyweight_signature::bind< | |
132 | Arg1,Arg2,Arg3,Arg4,Arg5 | |
133 | >::type args; | |
134 | typedef typename parameter::binding< | |
135 | args,tag<>,mpl::na | |
136 | >::type tag_type; | |
137 | typedef typename parameter::binding< | |
138 | args,tracking<>,refcounted | |
139 | >::type tracking_policy; | |
140 | typedef typename parameter::binding< | |
141 | args,factory<>,hashed_factory<> | |
142 | >::type factory_specifier; | |
143 | typedef typename parameter::binding< | |
144 | args,locking<>,simple_locking | |
145 | >::type locking_policy; | |
146 | typedef typename parameter::binding< | |
147 | args,holder<>,static_holder | |
148 | >::type holder_specifier; | |
149 | ||
150 | typedef typename detail:: | |
151 | flyweight_unmatched_signature::bind< | |
152 | Arg1,Arg2,Arg3,Arg4,Arg5 | |
153 | >::type unmatched_args; | |
154 | typedef typename parameter::binding< | |
155 | unmatched_args,detail::unmatched_arg, | |
156 | detail::unmatched_arg | |
157 | >::type unmatched_arg_detected; | |
158 | ||
159 | /* You have passed a type in the specification of a flyweight type that | |
160 | * could not be interpreted as a valid argument. | |
161 | */ | |
162 | BOOST_MPL_ASSERT_MSG( | |
163 | (is_same<unmatched_arg_detected,detail::unmatched_arg>::value), | |
164 | INVALID_ARGUMENT_TO_FLYWEIGHT, | |
165 | (flyweight)); | |
166 | ||
167 | typedef detail::flyweight_core< | |
168 | value_policy,tag_type,tracking_policy, | |
169 | factory_specifier,locking_policy, | |
170 | holder_specifier | |
171 | > core; | |
172 | typedef typename core::handle_type handle_type; | |
173 | ||
174 | public: | |
175 | typedef typename value_policy::key_type key_type; | |
176 | typedef typename value_policy::value_type value_type; | |
177 | ||
178 | /* static data initialization */ | |
179 | ||
180 | static bool init(){return core::init();} | |
181 | ||
182 | class initializer | |
183 | { | |
184 | public: | |
185 | initializer():b(init()){} | |
186 | private: | |
187 | bool b; | |
188 | }; | |
189 | ||
190 | /* construct/copy/destroy */ | |
191 | ||
192 | flyweight():h(core::insert()){} | |
193 | ||
194 | #define BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY(args) \ | |
195 | :h(core::insert(BOOST_FLYWEIGHT_FORWARD(args))){} | |
196 | ||
197 | BOOST_FLYWEIGHT_PERFECT_FWD_WITH_ARGS( | |
198 | explicit flyweight, | |
199 | BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY) | |
200 | ||
201 | #undef BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY | |
202 | ||
203 | #if !defined(BOOST_NO_SFINAE)&&!defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) | |
204 | template<typename V> | |
205 | flyweight( | |
206 | std::initializer_list<V> list, | |
207 | typename boost::enable_if< | |
208 | boost::is_convertible<std::initializer_list<V>,key_type> >::type* =0): | |
209 | h(core::insert(list)){} | |
210 | #endif | |
211 | ||
212 | flyweight(const flyweight& x):h(x.h){} | |
213 | flyweight(flyweight& x):h(x.h){} | |
214 | ||
215 | #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) | |
216 | flyweight(const flyweight&& x):h(x.h){} | |
217 | flyweight(flyweight&& x):h(x.h){} | |
218 | #endif | |
219 | ||
220 | #if !defined(BOOST_NO_SFINAE)&&!defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) | |
221 | template<typename V> | |
222 | typename boost::enable_if< | |
223 | boost::is_convertible<std::initializer_list<V>,key_type>,flyweight&>::type | |
224 | operator=(std::initializer_list<V> list) | |
225 | { | |
226 | return operator=(flyweight(list)); | |
227 | } | |
228 | #endif | |
229 | ||
230 | flyweight& operator=(const flyweight& x){h=x.h;return *this;} | |
231 | flyweight& operator=(const value_type& x){return operator=(flyweight(x));} | |
232 | ||
233 | #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) | |
234 | flyweight& operator=(value_type&& x) | |
235 | { | |
236 | return operator=(flyweight(std::move(x))); | |
237 | } | |
238 | #endif | |
239 | ||
240 | /* convertibility to underlying type */ | |
241 | ||
242 | const key_type& get_key()const{return core::key(h);} | |
243 | const value_type& get()const{return core::value(h);} | |
244 | operator const value_type&()const{return get();} | |
245 | ||
246 | /* exact type equality */ | |
247 | ||
248 | friend bool operator==(const flyweight& x,const flyweight& y) | |
249 | { | |
250 | return &x.get()==&y.get(); | |
251 | } | |
252 | ||
253 | /* modifiers */ | |
254 | ||
255 | void swap(flyweight& x){boost::swap(h,x.h);} | |
256 | ||
257 | private: | |
258 | handle_type h; | |
259 | }; | |
260 | ||
261 | #define BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(n) \ | |
262 | typename Arg##n##1,typename Arg##n##2,typename Arg##n##3, \ | |
263 | typename Arg##n##4,typename Arg##n##5 | |
264 | #define BOOST_FLYWEIGHT_TEMPL_ARGS(n) \ | |
265 | Arg##n##1,Arg##n##2,Arg##n##3,Arg##n##4,Arg##n##5 | |
266 | ||
267 | /* Comparison. Unlike exact type comparison defined above, intertype | |
268 | * comparison just forwards to the underlying objects. | |
269 | */ | |
270 | ||
271 | template< | |
272 | typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1), | |
273 | typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2) | |
274 | > | |
275 | bool operator==( | |
276 | const flyweight<T1,BOOST_FLYWEIGHT_TEMPL_ARGS(1)>& x, | |
277 | const flyweight<T2,BOOST_FLYWEIGHT_TEMPL_ARGS(2)>& y) | |
278 | { | |
279 | return x.get()==y.get(); | |
280 | } | |
281 | ||
282 | template< | |
283 | typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1), | |
284 | typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2) | |
285 | > | |
286 | bool operator<( | |
287 | const flyweight<T1,BOOST_FLYWEIGHT_TEMPL_ARGS(1)>& x, | |
288 | const flyweight<T2,BOOST_FLYWEIGHT_TEMPL_ARGS(2)>& y) | |
289 | { | |
290 | return x.get()<y.get(); | |
291 | } | |
292 | ||
293 | #if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) | |
294 | template< | |
295 | typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1), | |
296 | typename T2 | |
297 | > | |
298 | bool operator==( | |
299 | const flyweight<T1,BOOST_FLYWEIGHT_TEMPL_ARGS(1)>& x,const T2& y) | |
300 | { | |
301 | return x.get()==y; | |
302 | } | |
303 | ||
304 | template< | |
305 | typename T1, | |
306 | typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2) | |
307 | > | |
308 | bool operator==( | |
309 | const T1& x,const flyweight<T2,BOOST_FLYWEIGHT_TEMPL_ARGS(2)>& y) | |
310 | { | |
311 | return x==y.get(); | |
312 | } | |
313 | ||
314 | template< | |
315 | typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1), | |
316 | typename T2 | |
317 | > | |
318 | bool operator<( | |
319 | const flyweight<T1,BOOST_FLYWEIGHT_TEMPL_ARGS(1)>& x,const T2& y) | |
320 | { | |
321 | return x.get()<y; | |
322 | } | |
323 | ||
324 | template< | |
325 | typename T1, | |
326 | typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2) | |
327 | > | |
328 | bool operator<( | |
329 | const T1& x,const flyweight<T2,BOOST_FLYWEIGHT_TEMPL_ARGS(2)>& y) | |
330 | { | |
331 | return x<y.get(); | |
332 | } | |
333 | #endif /* !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) */ | |
334 | ||
335 | /* rest of comparison operators */ | |
336 | ||
337 | #define BOOST_FLYWEIGHT_COMPLETE_COMP_OPS(t,a1,a2) \ | |
338 | template<t> \ | |
339 | inline bool operator!=(const a1& x,const a2& y) \ | |
340 | { \ | |
341 | return !(x==y); \ | |
342 | } \ | |
343 | \ | |
344 | template<t> \ | |
345 | inline bool operator>(const a1& x,const a2& y) \ | |
346 | { \ | |
347 | return y<x; \ | |
348 | } \ | |
349 | \ | |
350 | template<t> \ | |
351 | inline bool operator>=(const a1& x,const a2& y) \ | |
352 | { \ | |
353 | return !(x<y); \ | |
354 | } \ | |
355 | \ | |
356 | template<t> \ | |
357 | inline bool operator<=(const a1& x,const a2& y) \ | |
358 | { \ | |
359 | return !(y<x); \ | |
360 | } | |
361 | ||
362 | BOOST_FLYWEIGHT_COMPLETE_COMP_OPS( | |
363 | typename T1 BOOST_PP_COMMA() | |
364 | BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1) BOOST_PP_COMMA() | |
365 | typename T2 BOOST_PP_COMMA() | |
366 | BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2), | |
367 | flyweight< | |
368 | T1 BOOST_PP_COMMA() BOOST_FLYWEIGHT_TEMPL_ARGS(1) | |
369 | >, | |
370 | flyweight< | |
371 | T2 BOOST_PP_COMMA() BOOST_FLYWEIGHT_TEMPL_ARGS(2) | |
372 | >) | |
373 | ||
374 | #if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) | |
375 | BOOST_FLYWEIGHT_COMPLETE_COMP_OPS( | |
376 | typename T1 BOOST_PP_COMMA() | |
377 | BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1) BOOST_PP_COMMA() | |
378 | typename T2, | |
379 | flyweight< | |
380 | T1 BOOST_PP_COMMA() BOOST_FLYWEIGHT_TEMPL_ARGS(1) | |
381 | >, | |
382 | T2) | |
383 | ||
384 | BOOST_FLYWEIGHT_COMPLETE_COMP_OPS( | |
385 | typename T1 BOOST_PP_COMMA() | |
386 | typename T2 BOOST_PP_COMMA() | |
387 | BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2), | |
388 | T1, | |
389 | flyweight< | |
390 | T2 BOOST_PP_COMMA() BOOST_FLYWEIGHT_TEMPL_ARGS(2) | |
391 | >) | |
392 | #endif /* !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) */ | |
393 | ||
394 | /* specialized algorithms */ | |
395 | ||
396 | template<typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_)> | |
397 | void swap( | |
398 | flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)>& x, | |
399 | flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)>& y) | |
400 | { | |
401 | x.swap(y); | |
402 | } | |
403 | ||
404 | template< | |
405 | BOOST_TEMPLATED_STREAM_ARGS(ElemType,Traits) | |
406 | BOOST_TEMPLATED_STREAM_COMMA | |
407 | typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_) | |
408 | > | |
409 | BOOST_TEMPLATED_STREAM(ostream,ElemType,Traits)& operator<<( | |
410 | BOOST_TEMPLATED_STREAM(ostream,ElemType,Traits)& out, | |
411 | const flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)>& x) | |
412 | { | |
413 | return out<<x.get(); | |
414 | } | |
415 | ||
416 | template< | |
417 | BOOST_TEMPLATED_STREAM_ARGS(ElemType,Traits) | |
418 | BOOST_TEMPLATED_STREAM_COMMA | |
419 | typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_) | |
420 | > | |
421 | BOOST_TEMPLATED_STREAM(istream,ElemType,Traits)& operator>>( | |
422 | BOOST_TEMPLATED_STREAM(istream,ElemType,Traits)& in, | |
423 | flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)>& x) | |
424 | { | |
425 | typedef typename flyweight< | |
426 | T,BOOST_FLYWEIGHT_TEMPL_ARGS(_) | |
427 | >::value_type value_type; | |
428 | ||
429 | /* value_type need not be default ctble but must be copy ctble */ | |
430 | value_type t(x.get()); | |
431 | in>>t; | |
432 | x=t; | |
433 | return in; | |
434 | } | |
435 | ||
436 | } /* namespace flyweights */ | |
437 | ||
438 | } /* namespace boost */ | |
439 | ||
440 | #if !defined(BOOST_FLYWEIGHT_DISABLE_HASH_SUPPORT) | |
441 | ||
442 | /* hash support */ | |
443 | ||
444 | #if !defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) | |
445 | namespace std{ | |
446 | ||
447 | template<typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_)> | |
448 | BOOST_FLYWEIGHT_STD_HASH_STRUCT_KEYWORD | |
449 | hash<boost::flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)> > | |
450 | { | |
451 | public: | |
452 | typedef std::size_t result_type; | |
453 | typedef boost::flyweight< | |
454 | T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)> argument_type; | |
455 | ||
456 | result_type operator()(const argument_type& x)const | |
457 | { | |
458 | typedef typename argument_type::value_type value_type; | |
459 | ||
460 | std::hash<const value_type*> h; | |
461 | return h(&x.get()); | |
462 | } | |
463 | }; | |
464 | ||
465 | } /* namespace std */ | |
466 | #endif /* !defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) */ | |
467 | ||
468 | namespace boost{ | |
469 | #if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) | |
470 | namespace flyweights{ | |
471 | #endif | |
472 | ||
473 | template<typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_)> | |
474 | std::size_t hash_value(const flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)>& x) | |
475 | { | |
476 | typedef typename flyweight< | |
477 | T,BOOST_FLYWEIGHT_TEMPL_ARGS(_) | |
478 | >::value_type value_type; | |
479 | ||
480 | boost::hash<const value_type*> h; | |
481 | return h(&x.get()); | |
482 | } | |
483 | ||
484 | #if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) | |
485 | } /* namespace flyweights */ | |
486 | #endif | |
487 | } /* namespace boost */ | |
488 | #endif /* !defined(BOOST_FLYWEIGHT_DISABLE_HASH_SUPPORT) */ | |
489 | ||
490 | #undef BOOST_FLYWEIGHT_COMPLETE_COMP_OPS | |
491 | #undef BOOST_FLYWEIGHT_TEMPL_ARGS | |
492 | #undef BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS | |
493 | ||
494 | #if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400)) | |
495 | #pragma warning(pop) | |
496 | #endif | |
497 | ||
498 | #endif |