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 
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 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
499