1 /* Copyright 2006-2020 Joaquin M Lopez Munoz.
2  * Distributed under the Boost Software License, Version 1.0.
3  * (See accompanying file LICENSE_1_0.txt or copy at
4  * http://www.boost.org/LICENSE_1_0.txt)
5  *
6  * See http://www.boost.org/libs/flyweight for library home page.
7  */
8 
9 #ifndef BOOST_FLYWEIGHT_DETAIL_FLYWEIGHT_CORE_HPP
10 #define BOOST_FLYWEIGHT_DETAIL_FLYWEIGHT_CORE_HPP
11 
12 #if defined(_MSC_VER)
13 #pragma once
14 #endif
15 
16 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
17 #include <boost/core/no_exceptions_support.hpp>
18 #include <boost/detail/workaround.hpp>
19 #include <boost/flyweight/detail/perfect_fwd.hpp>
20 #include <boost/mpl/apply.hpp>
21 
22 #if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400))
23 #pragma warning(push)
24 #pragma warning(disable:4101)  /* unreferenced local vars */
25 #endif
26 
27 /* flyweight_core provides the inner implementation of flyweight<> by
28  * weaving together a value policy, a flyweight factory, a holder for the
29  * factory,a tracking policy and a locking policy.
30  */
31 
32 namespace boost{
33 
34 namespace flyweights{
35 
36 namespace detail{
37 
38 template<
39   typename ValuePolicy,typename Tag,typename TrackingPolicy,
40   typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier
41 >
42 class flyweight_core;
43 
44 template<
45   typename ValuePolicy,typename Tag,typename TrackingPolicy,
46   typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier
47 >
48 struct flyweight_core_tracking_helper
49 {
50 private:
51   typedef flyweight_core<
52     ValuePolicy,Tag,TrackingPolicy,
53     FactorySpecifier,LockingPolicy,
54     HolderSpecifier
55   >                                   core;
56   typedef typename core::handle_type  handle_type;
57   typedef typename core::entry_type   entry_type;
58 
59 public:
entryboost::flyweights::detail::flyweight_core_tracking_helper60   static const entry_type& entry(const handle_type& h)
61   {
62     return core::entry(h);
63   }
64 
65   template<typename Checker>
eraseboost::flyweights::detail::flyweight_core_tracking_helper66   static void erase(const handle_type& h,Checker chk)
67   {
68     typedef typename core::lock_type lock_type;
69     core::init();
70     lock_type lock(core::mutex());(void)lock;
71     if(chk(h))core::factory().erase(h);
72   }
73 };
74 
75 template<
76   typename ValuePolicy,typename Tag,typename TrackingPolicy,
77   typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier
78 >
79 class flyweight_core
80 {
81 public:
82   typedef typename ValuePolicy::key_type     key_type;
83   typedef typename ValuePolicy::value_type   value_type;
84   typedef typename ValuePolicy::rep_type     rep_type;
85   typedef typename mpl::apply2<
86     typename TrackingPolicy::entry_type,
87     rep_type,
88     key_type
89   >::type                                    entry_type;
90   typedef typename mpl::apply2<
91     FactorySpecifier,
92     entry_type,
93     key_type
94   >::type                                    factory_type;
95   typedef typename factory_type::handle_type base_handle_type;
96   typedef typename mpl::apply2<
97     typename TrackingPolicy::handle_type,
98     base_handle_type,
99     flyweight_core_tracking_helper<
100       ValuePolicy,Tag,TrackingPolicy,
101       FactorySpecifier,LockingPolicy,
102       HolderSpecifier
103     >
104   >::type                                    handle_type;
105   typedef typename LockingPolicy::mutex_type mutex_type;
106   typedef typename LockingPolicy::lock_type  lock_type;
107 
init()108   static bool init()
109   {
110     if(static_initializer)return true;
111     else{
112       holder_arg& a=holder_type::get();
113       static_factory_ptr=&a.factory;
114       static_mutex_ptr=&a.mutex;
115       static_initializer=(static_factory_ptr!=0);
116       return static_initializer;
117     }
118   }
119 
120   /* insert overloads*/
121 
122 #define BOOST_FLYWEIGHT_PERFECT_FWD_INSERT_BODY(args)         \
123 {                                                             \
124   return insert_rep(rep_type(BOOST_FLYWEIGHT_FORWARD(args))); \
125 }
126 
BOOST_FLYWEIGHT_PERFECT_FWD(static handle_type insert,BOOST_FLYWEIGHT_PERFECT_FWD_INSERT_BODY)127   BOOST_FLYWEIGHT_PERFECT_FWD(
128     static handle_type insert,
129     BOOST_FLYWEIGHT_PERFECT_FWD_INSERT_BODY)
130 
131 #undef BOOST_FLYWEIGHT_PERFECT_FWD_INSERT_BODY
132 
133   static handle_type insert(const value_type& x){return insert_value(x);}
insert(value_type & x)134   static handle_type insert(value_type& x){return insert_value(x);}
135 
136 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
insert(const value_type && x)137   static handle_type insert(const value_type&& x){return insert_value(x);}
insert(value_type && x)138   static handle_type insert(value_type&& x){return insert_value(std::move(x));}
139 #endif
140 
entry(const base_handle_type & h)141   static const entry_type& entry(const base_handle_type& h)
142   {
143     return factory().entry(h);
144   }
145 
value(const handle_type & h)146   static const value_type& value(const handle_type& h)
147   {
148     return static_cast<const rep_type&>(entry(h));
149   }
150 
key(const handle_type & h)151   static const key_type& key(const handle_type& h)
152   {
153     return static_cast<const rep_type&>(entry(h));
154   }
155 
factory()156   static factory_type& factory()
157   {
158     return *static_factory_ptr;
159   }
160 
mutex()161   static mutex_type& mutex()
162   {
163     return *static_mutex_ptr;
164   }
165 
166 private:
167   struct                              holder_arg
168   {
169     factory_type factory;
170     mutex_type   mutex;
171   };
172   typedef typename mpl::apply1<
173     HolderSpecifier,
174     holder_arg
175   >::type                             holder_type;
176 
insert_rep(const rep_type & x)177   static handle_type insert_rep(const rep_type& x)
178   {
179     init();
180     entry_type       e(x);
181     lock_type        lock(mutex());(void)lock;
182 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
183     base_handle_type h(factory().insert(std::move(e)));
184 #else
185     base_handle_type h(factory().insert(e));
186 #endif
187 
188     BOOST_TRY{
189       ValuePolicy::construct_value(
190         static_cast<const rep_type&>(entry(h)));
191     }
192     BOOST_CATCH(...){
193       factory().erase(h);
194       BOOST_RETHROW;
195     }
196     BOOST_CATCH_END
197     return static_cast<handle_type>(h);
198   }
199 
insert_value(const value_type & x)200   static handle_type insert_value(const value_type& x)
201   {
202     init();
203     entry_type       e((rep_type(x)));
204     lock_type        lock(mutex());(void)lock;
205 
206 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
207     base_handle_type h(factory().insert(std::move(e)));
208 #else
209     base_handle_type h(factory().insert(e));
210 #endif
211 
212     BOOST_TRY{
213       ValuePolicy::copy_value(
214         static_cast<const rep_type&>(entry(h)));
215     }
216     BOOST_CATCH(...){
217       factory().erase(h);
218       BOOST_RETHROW;
219     }
220     BOOST_CATCH_END
221     return static_cast<handle_type>(h);
222   }
223 
224 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
insert_rep(rep_type && x)225   static handle_type insert_rep(rep_type&& x)
226   {
227     init();
228     entry_type       e(std::move(x));
229     lock_type        lock(mutex());(void)lock;
230     base_handle_type h(factory().insert(std::move(e)));
231 
232     BOOST_TRY{
233       ValuePolicy::construct_value(
234         static_cast<const rep_type&>(entry(h)));
235     }
236     BOOST_CATCH(...){
237       factory().erase(h);
238       BOOST_RETHROW;
239     }
240     BOOST_CATCH_END
241     return static_cast<handle_type>(h);
242   }
243 
insert_value(value_type && x)244   static handle_type insert_value(value_type&& x)
245   {
246     init();
247     entry_type       e(rep_type(std::move(x)));
248     lock_type        lock(mutex());(void)lock;
249     base_handle_type h(factory().insert(std::move(e)));
250     BOOST_TRY{
251       ValuePolicy::move_value(
252         static_cast<const rep_type&>(entry(h)));
253     }
254     BOOST_CATCH(...){
255       factory().erase(h);
256       BOOST_RETHROW;
257     }
258     BOOST_CATCH_END
259     return static_cast<handle_type>(h);
260   }
261 #endif
262 
263   static bool          static_initializer;
264   static factory_type* static_factory_ptr;
265   static mutex_type*   static_mutex_ptr;
266 };
267 
268 template<
269   typename ValuePolicy,typename Tag,typename TrackingPolicy,
270   typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier
271 >
272 bool
273 flyweight_core<
274   ValuePolicy,Tag,TrackingPolicy,
275   FactorySpecifier,LockingPolicy,HolderSpecifier>::static_initializer=
276   flyweight_core<
277       ValuePolicy,Tag,TrackingPolicy,
278       FactorySpecifier,LockingPolicy,HolderSpecifier>::init();
279 
280 template<
281   typename ValuePolicy,typename Tag,typename TrackingPolicy,
282   typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier
283 >
284 typename flyweight_core<
285   ValuePolicy,Tag,TrackingPolicy,
286   FactorySpecifier,LockingPolicy,HolderSpecifier>::factory_type*
287 flyweight_core<
288   ValuePolicy,Tag,TrackingPolicy,
289   FactorySpecifier,LockingPolicy,HolderSpecifier>::static_factory_ptr=0;
290 
291 template<
292   typename ValuePolicy,typename Tag,typename TrackingPolicy,
293   typename FactorySpecifier,typename LockingPolicy,typename HolderSpecifier
294 >
295 typename flyweight_core<
296   ValuePolicy,Tag,TrackingPolicy,
297   FactorySpecifier,LockingPolicy,HolderSpecifier>::mutex_type*
298 flyweight_core<
299   ValuePolicy,Tag,TrackingPolicy,
300   FactorySpecifier,LockingPolicy,HolderSpecifier>::static_mutex_ptr=0;
301 
302 } /* namespace flyweights::detail */
303 
304 } /* namespace flyweights */
305 
306 } /* namespace boost */
307 
308 #if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400))
309 #pragma warning(pop)
310 #endif
311 
312 #endif
313