1 /* Flyweight class.
2 *
3 * Copyright 2006-2014 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
init()180 static bool init(){return core::init();}
181
182 class initializer
183 {
184 public:
initializer()185 initializer():b(init()){}
186 private:
187 bool b;
188 };
189
190 /* construct/copy/destroy */
191
flyweight()192 flyweight():h(core::insert()){}
193
194 #define BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY(args) \
195 :h(core::insert(BOOST_FLYWEIGHT_FORWARD(args))){}
196
BOOST_FLYWEIGHT_PERFECT_FWD_WITH_ARGS(explicit flyweight,BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY)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
flyweight(const flyweight & x)212 flyweight(const flyweight& x):h(x.h){}
flyweight(flyweight & x)213 flyweight(flyweight& x):h(x.h){}
214
215 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
flyweight(const flyweight && x)216 flyweight(const flyweight&& x):h(x.h){}
flyweight(flyweight && x)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
operator =(std::initializer_list<V> list)224 operator=(std::initializer_list<V> list)
225 {
226 return operator=(flyweight(list));
227 }
228 #endif
229
operator =(const flyweight & x)230 flyweight& operator=(const flyweight& x){h=x.h;return *this;}
operator =(const value_type & x)231 flyweight& operator=(const value_type& x){return operator=(flyweight(x));}
232
233 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
operator =(value_type && x)234 flyweight& operator=(value_type&& x)
235 {
236 return operator=(flyweight(std::move(x)));
237 }
238 #endif
239
240 /* convertibility to underlying type */
241
get_key() const242 const key_type& get_key()const{return core::key(h);}
get() const243 const value_type& get()const{return core::value(h);}
operator const value_type&() const244 operator const value_type&()const{return get();}
245
246 /* exact type equality */
247
operator ==(const flyweight & x,const flyweight & y)248 friend bool operator==(const flyweight& x,const flyweight& y)
249 {
250 return &x.get()==&y.get();
251 }
252
253 /* modifiers */
254
swap(flyweight & x)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 >
operator ==(const flyweight<T1,BOOST_FLYWEIGHT_TEMPL_ARGS (1)> & x,const flyweight<T2,BOOST_FLYWEIGHT_TEMPL_ARGS (2)> & y)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 >
operator <(const flyweight<T1,BOOST_FLYWEIGHT_TEMPL_ARGS (1)> & x,const flyweight<T2,BOOST_FLYWEIGHT_TEMPL_ARGS (2)> & y)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 >
operator ==(const flyweight<T1,BOOST_FLYWEIGHT_TEMPL_ARGS (1)> & x,const T2 & y)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 >
operator ==(const T1 & x,const flyweight<T2,BOOST_FLYWEIGHT_TEMPL_ARGS (2)> & y)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 >
operator <(const flyweight<T1,BOOST_FLYWEIGHT_TEMPL_ARGS (1)> & x,const T2 & y)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 >
operator <(const T1 & x,const flyweight<T2,BOOST_FLYWEIGHT_TEMPL_ARGS (2)> & y)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(_)>
swap(flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS (_)> & x,flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS (_)> & y)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 >
BOOST_TEMPLATED_STREAM(istream,ElemType,Traits)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 struct hash<boost::flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)> >
449 {
450 typedef std::size_t result_type;
451 typedef boost::flyweight<
452 T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)> argument_type;
453
operator ()std::hash454 result_type operator()(const argument_type& x)const
455 {
456 typedef typename argument_type::value_type value_type;
457
458 std::hash<const value_type*> h;
459 return h(&x.get());
460 }
461 };
462
463 } /* namespace std */
464 #endif /* !defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) */
465
466 namespace boost{
467 #if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
468 namespace flyweights{
469 #endif
470
471 template<typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_)>
hash_value(const flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS (_)> & x)472 std::size_t hash_value(const flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)>& x)
473 {
474 typedef typename flyweight<
475 T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)
476 >::value_type value_type;
477
478 boost::hash<const value_type*> h;
479 return h(&x.get());
480 }
481
482 #if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
483 } /* namespace flyweights */
484 #endif
485 } /* namespace boost */
486 #endif /* !defined(BOOST_FLYWEIGHT_DISABLE_HASH_SUPPORT) */
487
488 #undef BOOST_FLYWEIGHT_COMPLETE_COMP_OPS
489 #undef BOOST_FLYWEIGHT_TEMPL_ARGS
490 #undef BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS
491
492 #if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400))
493 #pragma warning(pop)
494 #endif
495
496 #endif
497