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
55namespace boost{
56
57namespace flyweights{
58
59namespace detail{
60
61/* Used for the detection of unmatched template args in a
62 * flyweight instantiation.
63 */
64
65struct 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
73struct 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
98struct 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
119template<
120 typename T,
121 typename Arg1,typename Arg2,typename Arg3,typename Arg4,typename Arg5
122>
123class flyweight
124{
125private:
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
175public:
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
260private:
261 handle_type h;
262};
263
264#define BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(n) \
265typename Arg##n##1,typename Arg##n##2,typename Arg##n##3, \
266typename Arg##n##4,typename Arg##n##5
267#define BOOST_FLYWEIGHT_TEMPL_ARGS(n) \
268Arg##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
274template<
275 typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1),
276 typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2)
277>
278bool 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
285template<
286 typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1),
287 typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2)
288>
289bool 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)
297template<
298 typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1),
299 typename T2
300>
301bool operator==(
302 const flyweight<T1,BOOST_FLYWEIGHT_TEMPL_ARGS(1)>& x,const T2& y)
303{
304 return x.get()==y;
305}
306
307template<
308 typename T1,
309 typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2)
310>
311bool operator==(
312 const T1& x,const flyweight<T2,BOOST_FLYWEIGHT_TEMPL_ARGS(2)>& y)
313{
314 return x==y.get();
315}
316
317template<
318 typename T1,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(1),
319 typename T2
320>
321bool operator<(
322 const flyweight<T1,BOOST_FLYWEIGHT_TEMPL_ARGS(1)>& x,const T2& y)
323{
324 return x.get()<y;
325}
326
327template<
328 typename T1,
329 typename T2,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(2)
330>
331bool 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) \
341template<t> \
342inline bool operator!=(const a1& x,const a2& y) \
343{ \
344 return !(x==y); \
345} \
346 \
347template<t> \
348inline bool operator>(const a1& x,const a2& y) \
349{ \
350 return y<x; \
351} \
352 \
353template<t> \
354inline bool operator>=(const a1& x,const a2& y) \
355{ \
356 return !(x<y); \
357} \
358 \
359template<t> \
360inline bool operator<=(const a1& x,const a2& y) \
361{ \
362 return !(y<x); \
363}
364
365BOOST_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)
378BOOST_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
387BOOST_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
399template<typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_)>
400void swap(
401 flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)>& x,
402 flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)>& y)
403{
404 x.swap(y);
405}
406
407template<
408 BOOST_TEMPLATED_STREAM_ARGS(ElemType,Traits)
409 BOOST_TEMPLATED_STREAM_COMMA
410 typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_)
411>
412BOOST_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
419template<
420 BOOST_TEMPLATED_STREAM_ARGS(ElemType,Traits)
421 BOOST_TEMPLATED_STREAM_COMMA
422 typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_)
423>
424BOOST_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)
448namespace std{
449
450template<typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_)>
451BOOST_FLYWEIGHT_STD_HASH_STRUCT_KEYWORD
452hash<boost::flyweight<T,BOOST_FLYWEIGHT_TEMPL_ARGS(_)> >
453{
454public:
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
471namespace boost{
472#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
473namespace flyweights{
474#endif
475
476template<typename T,BOOST_FLYWEIGHT_TYPENAME_TEMPL_ARGS(_)>
477std::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

source code of boost/libs/flyweight/include/boost/flyweight/flyweight.hpp