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