]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | #ifndef BOOST_DETAIL_SHARED_COUNT_132_HPP_INCLUDED |
2 | #define BOOST_DETAIL_SHARED_COUNT_132_HPP_INCLUDED | |
3 | ||
4 | // MS compatible compilers support #pragma once | |
5 | ||
6 | #if defined(_MSC_VER) | |
7 | # pragma once | |
8 | #endif | |
9 | ||
10 | // | |
11 | // detail/shared_count.hpp | |
12 | // | |
13 | // Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. | |
14 | // | |
15 | // Distributed under the Boost Software License, Version 1.0. (See | |
16 | // accompanying file LICENSE_1_0.txt or copy at | |
17 | // http://www.boost.org/LICENSE_1_0.txt) | |
18 | // | |
19 | ||
20 | #include <boost/config.hpp> | |
21 | ||
22 | #if defined(BOOST_SP_USE_STD_ALLOCATOR) && defined(BOOST_SP_USE_QUICK_ALLOCATOR) | |
23 | # error BOOST_SP_USE_STD_ALLOCATOR and BOOST_SP_USE_QUICK_ALLOCATOR are incompatible. | |
24 | #endif | |
25 | ||
26 | #include <boost/checked_delete.hpp> | |
27 | #include <boost/serialization/throw_exception.hpp> | |
28 | #include <boost/detail/lightweight_mutex.hpp> | |
29 | ||
30 | #if defined(BOOST_SP_USE_QUICK_ALLOCATOR) | |
31 | #include <boost/detail/quick_allocator.hpp> | |
32 | #endif | |
33 | ||
34 | #include <memory> // std::auto_ptr, std::allocator | |
35 | #include <functional> // std::less | |
36 | #include <exception> // std::exception | |
37 | #include <new> // std::bad_alloc | |
38 | #include <typeinfo> // std::type_info in get_deleter | |
39 | #include <cstddef> // std::size_t | |
40 | ||
41 | #include <boost/config.hpp> // msvc 6.0 needs this for warning suppression | |
42 | #if defined(BOOST_NO_STDC_NAMESPACE) | |
43 | namespace std{ | |
44 | using ::size_t; | |
45 | } // namespace std | |
46 | #endif | |
47 | ||
48 | namespace boost_132 { | |
49 | ||
50 | // Debug hooks | |
51 | ||
52 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
53 | ||
54 | void sp_scalar_constructor_hook(void * px, std::size_t size, void * pn); | |
55 | void sp_array_constructor_hook(void * px); | |
56 | void sp_scalar_destructor_hook(void * px, std::size_t size, void * pn); | |
57 | void sp_array_destructor_hook(void * px); | |
58 | ||
59 | #endif | |
60 | ||
61 | ||
62 | // The standard library that comes with Borland C++ 5.5.1 | |
63 | // defines std::exception and its members as having C calling | |
64 | // convention (-pc). When the definition of bad_weak_ptr | |
65 | // is compiled with -ps, the compiler issues an error. | |
66 | // Hence, the temporary #pragma option -pc below. The version | |
67 | // check is deliberately conservative. | |
68 | ||
69 | class bad_weak_ptr: public std::exception | |
70 | { | |
71 | public: | |
72 | ||
73 | virtual char const * what() const throw() | |
74 | { | |
75 | return "boost::bad_weak_ptr"; | |
76 | } | |
77 | }; | |
78 | ||
79 | namespace detail{ | |
80 | ||
81 | class sp_counted_base | |
82 | { | |
83 | //private: | |
84 | ||
85 | typedef boost::detail::lightweight_mutex mutex_type; | |
86 | ||
87 | public: | |
88 | ||
89 | sp_counted_base(): use_count_(1), weak_count_(1) | |
90 | { | |
91 | } | |
92 | ||
93 | virtual ~sp_counted_base() // nothrow | |
94 | { | |
95 | } | |
96 | ||
97 | // dispose() is called when use_count_ drops to zero, to release | |
98 | // the resources managed by *this. | |
99 | ||
100 | virtual void dispose() = 0; // nothrow | |
101 | ||
102 | // destruct() is called when weak_count_ drops to zero. | |
103 | ||
104 | virtual void destruct() // nothrow | |
105 | { | |
106 | delete this; | |
107 | } | |
108 | ||
109 | virtual void * get_deleter(std::type_info const & ti) = 0; | |
110 | ||
111 | void add_ref_copy() | |
112 | { | |
113 | #if defined(BOOST_HAS_THREADS) | |
114 | mutex_type::scoped_lock lock(mtx_); | |
115 | #endif | |
116 | ++use_count_; | |
117 | } | |
118 | ||
119 | void add_ref_lock() | |
120 | { | |
121 | #if defined(BOOST_HAS_THREADS) | |
122 | mutex_type::scoped_lock lock(mtx_); | |
123 | #endif | |
124 | if(use_count_ == 0) boost::serialization::throw_exception(bad_weak_ptr()); | |
125 | ++use_count_; | |
126 | } | |
127 | ||
128 | void release() // nothrow | |
129 | { | |
130 | { | |
131 | #if defined(BOOST_HAS_THREADS) | |
132 | mutex_type::scoped_lock lock(mtx_); | |
133 | #endif | |
134 | long new_use_count = --use_count_; | |
135 | ||
136 | if(new_use_count != 0) return; | |
137 | } | |
138 | ||
139 | dispose(); | |
140 | weak_release(); | |
141 | } | |
142 | ||
143 | void weak_add_ref() // nothrow | |
144 | { | |
145 | #if defined(BOOST_HAS_THREADS) | |
146 | mutex_type::scoped_lock lock(mtx_); | |
147 | #endif | |
148 | ++weak_count_; | |
149 | } | |
150 | ||
151 | void weak_release() // nothrow | |
152 | { | |
153 | long new_weak_count; | |
154 | ||
155 | { | |
156 | #if defined(BOOST_HAS_THREADS) | |
157 | mutex_type::scoped_lock lock(mtx_); | |
158 | #endif | |
159 | new_weak_count = --weak_count_; | |
160 | } | |
161 | ||
162 | if(new_weak_count == 0) | |
163 | { | |
164 | destruct(); | |
165 | } | |
166 | } | |
167 | ||
168 | long use_count() const // nothrow | |
169 | { | |
170 | #if defined(BOOST_HAS_THREADS) | |
171 | mutex_type::scoped_lock lock(mtx_); | |
172 | #endif | |
173 | return use_count_; | |
174 | } | |
175 | ||
176 | //private: | |
177 | public: | |
178 | sp_counted_base(sp_counted_base const &); | |
179 | sp_counted_base & operator= (sp_counted_base const &); | |
180 | ||
181 | long use_count_; // #shared | |
182 | long weak_count_; // #weak + (#shared != 0) | |
183 | ||
184 | #if defined(BOOST_HAS_THREADS) || defined(BOOST_LWM_WIN32) | |
185 | mutable mutex_type mtx_; | |
186 | #endif | |
187 | }; | |
188 | ||
189 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
190 | ||
191 | template<class T> void cbi_call_constructor_hook(sp_counted_base * pn, T * px, boost::checked_deleter< T > const &) | |
192 | { | |
193 | boost::sp_scalar_constructor_hook(px, sizeof(T), pn); | |
194 | } | |
195 | ||
196 | template<class T> void cbi_call_constructor_hook(sp_counted_base *, T * px, boost::checked_array_deleter< T > const &) | |
197 | { | |
198 | boost::sp_array_constructor_hook(px); | |
199 | } | |
200 | ||
201 | template<class P, class D> void cbi_call_constructor_hook(sp_counted_base *, P const &, D const &, long) | |
202 | { | |
203 | } | |
204 | ||
205 | template<class T> void cbi_call_destructor_hook(sp_counted_base * pn, T * px, boost::checked_deleter< T > const &) | |
206 | { | |
207 | boost::sp_scalar_destructor_hook(px, sizeof(T), pn); | |
208 | } | |
209 | ||
210 | template<class T> void cbi_call_destructor_hook(sp_counted_base *, T * px, boost::checked_array_deleter< T > const &) | |
211 | { | |
212 | boost::sp_array_destructor_hook(px); | |
213 | } | |
214 | ||
215 | template<class P, class D> void cbi_call_destructor_hook(sp_counted_base *, P const &, D const &, long) | |
216 | { | |
217 | } | |
218 | ||
219 | #endif | |
220 | ||
221 | // | |
222 | // Borland's Codeguard trips up over the -Vx- option here: | |
223 | // | |
224 | #ifdef __CODEGUARD__ | |
225 | # pragma option push -Vx- | |
226 | #endif | |
227 | ||
228 | template<class P, class D> class sp_counted_base_impl: public sp_counted_base | |
229 | { | |
230 | //private: | |
231 | public: | |
232 | P ptr; // copy constructor must not throw | |
233 | D del; // copy constructor must not throw | |
234 | ||
235 | sp_counted_base_impl(sp_counted_base_impl const &); | |
236 | sp_counted_base_impl & operator= (sp_counted_base_impl const &); | |
237 | ||
238 | typedef sp_counted_base_impl<P, D> this_type; | |
239 | ||
240 | public: | |
241 | ||
242 | // pre: initial_use_count <= initial_weak_count, d(p) must not throw | |
243 | ||
244 | sp_counted_base_impl(P p, D d): ptr(p), del(d) | |
245 | { | |
246 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
247 | detail::cbi_call_constructor_hook(this, p, d, 0); | |
248 | #endif | |
249 | } | |
250 | ||
251 | virtual void dispose() // nothrow | |
252 | { | |
253 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
254 | detail::cbi_call_destructor_hook(this, ptr, del, 0); | |
255 | #endif | |
256 | del(ptr); | |
257 | } | |
258 | ||
259 | virtual void * get_deleter(std::type_info const & ti) | |
260 | { | |
261 | return ti == typeid(D)? &del: 0; | |
262 | } | |
263 | ||
264 | #if defined(BOOST_SP_USE_STD_ALLOCATOR) | |
265 | ||
266 | void * operator new(std::size_t) | |
267 | { | |
268 | return std::allocator<this_type>().allocate(1, static_cast<this_type *>(0)); | |
269 | } | |
270 | ||
271 | void operator delete(void * p) | |
272 | { | |
273 | std::allocator<this_type>().deallocate(static_cast<this_type *>(p), 1); | |
274 | } | |
275 | ||
276 | #endif | |
277 | ||
278 | #if defined(BOOST_SP_USE_QUICK_ALLOCATOR) | |
279 | ||
280 | void * operator new(std::size_t) | |
281 | { | |
282 | return boost::detail::quick_allocator<this_type>::alloc(); | |
283 | } | |
284 | ||
285 | void operator delete(void * p) | |
286 | { | |
287 | boost::detail::quick_allocator<this_type>::dealloc(p); | |
288 | } | |
289 | ||
290 | #endif | |
291 | }; | |
292 | ||
293 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
294 | ||
295 | int const shared_count_id = 0x2C35F101; | |
296 | int const weak_count_id = 0x298C38A4; | |
297 | ||
298 | #endif | |
299 | ||
300 | class weak_count; | |
301 | ||
302 | class shared_count | |
303 | { | |
304 | //private: | |
305 | public: | |
306 | sp_counted_base * pi_; | |
307 | ||
308 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
309 | int id_; | |
310 | #endif | |
311 | ||
312 | friend class weak_count; | |
313 | ||
314 | public: | |
315 | ||
316 | shared_count(): pi_(0) // nothrow | |
317 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
318 | , id_(shared_count_id) | |
319 | #endif | |
320 | { | |
321 | } | |
322 | ||
323 | template<class P, class D> shared_count(P p, D d): pi_(0) | |
324 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
325 | , id_(shared_count_id) | |
326 | #endif | |
327 | { | |
328 | #ifndef BOOST_NO_EXCEPTIONS | |
329 | ||
330 | try | |
331 | { | |
332 | pi_ = new sp_counted_base_impl<P, D>(p, d); | |
333 | } | |
334 | catch(...) | |
335 | { | |
336 | d(p); // delete p | |
337 | throw; | |
338 | } | |
339 | ||
340 | #else | |
341 | ||
342 | pi_ = new sp_counted_base_impl<P, D>(p, d); | |
343 | ||
344 | if(pi_ == 0) | |
345 | { | |
346 | d(p); // delete p | |
347 | boost::serialization::throw_exception(std::bad_alloc()); | |
348 | } | |
349 | ||
350 | #endif | |
351 | } | |
352 | ||
353 | #ifndef BOOST_NO_AUTO_PTR | |
354 | ||
355 | // auto_ptr<Y> is special cased to provide the strong guarantee | |
356 | ||
357 | template<class Y> | |
358 | explicit shared_count(std::auto_ptr<Y> & r): pi_( | |
359 | new sp_counted_base_impl< | |
360 | Y *, | |
361 | boost::checked_deleter<Y> | |
362 | >(r.get(), boost::checked_deleter<Y>())) | |
363 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
364 | , id_(shared_count_id) | |
365 | #endif | |
366 | { | |
367 | r.release(); | |
368 | } | |
369 | ||
370 | #endif | |
371 | ||
372 | ~shared_count() // nothrow | |
373 | { | |
374 | if(pi_ != 0) pi_->release(); | |
375 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
376 | id_ = 0; | |
377 | #endif | |
378 | } | |
379 | ||
380 | shared_count(shared_count const & r): pi_(r.pi_) // nothrow | |
381 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
382 | , id_(shared_count_id) | |
383 | #endif | |
384 | { | |
385 | if(pi_ != 0) pi_->add_ref_copy(); | |
386 | } | |
387 | ||
388 | explicit shared_count(weak_count const & r); // throws bad_weak_ptr when r.use_count() == 0 | |
389 | ||
390 | shared_count & operator= (shared_count const & r) // nothrow | |
391 | { | |
392 | sp_counted_base * tmp = r.pi_; | |
393 | ||
394 | if(tmp != pi_) | |
395 | { | |
396 | if(tmp != 0) tmp->add_ref_copy(); | |
397 | if(pi_ != 0) pi_->release(); | |
398 | pi_ = tmp; | |
399 | } | |
400 | ||
401 | return *this; | |
402 | } | |
403 | ||
404 | void swap(shared_count & r) // nothrow | |
405 | { | |
406 | sp_counted_base * tmp = r.pi_; | |
407 | r.pi_ = pi_; | |
408 | pi_ = tmp; | |
409 | } | |
410 | ||
411 | long use_count() const // nothrow | |
412 | { | |
413 | return pi_ != 0? pi_->use_count(): 0; | |
414 | } | |
415 | ||
416 | bool unique() const // nothrow | |
417 | { | |
418 | return use_count() == 1; | |
419 | } | |
420 | ||
421 | friend inline bool operator==(shared_count const & a, shared_count const & b) | |
422 | { | |
423 | return a.pi_ == b.pi_; | |
424 | } | |
425 | ||
426 | friend inline bool operator<(shared_count const & a, shared_count const & b) | |
427 | { | |
428 | return std::less<sp_counted_base *>()(a.pi_, b.pi_); | |
429 | } | |
430 | ||
431 | void * get_deleter(std::type_info const & ti) const | |
432 | { | |
433 | return pi_? pi_->get_deleter(ti): 0; | |
434 | } | |
435 | }; | |
436 | ||
437 | #ifdef __CODEGUARD__ | |
438 | # pragma option pop | |
439 | #endif | |
440 | ||
441 | ||
442 | class weak_count | |
443 | { | |
444 | private: | |
445 | ||
446 | sp_counted_base * pi_; | |
447 | ||
448 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
449 | int id_; | |
450 | #endif | |
451 | ||
452 | friend class shared_count; | |
453 | ||
454 | public: | |
455 | ||
456 | weak_count(): pi_(0) // nothrow | |
457 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
458 | , id_(weak_count_id) | |
459 | #endif | |
460 | { | |
461 | } | |
462 | ||
463 | weak_count(shared_count const & r): pi_(r.pi_) // nothrow | |
464 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
465 | , id_(shared_count_id) | |
466 | #endif | |
467 | { | |
468 | if(pi_ != 0) pi_->weak_add_ref(); | |
469 | } | |
470 | ||
471 | weak_count(weak_count const & r): pi_(r.pi_) // nothrow | |
472 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
473 | , id_(shared_count_id) | |
474 | #endif | |
475 | { | |
476 | if(pi_ != 0) pi_->weak_add_ref(); | |
477 | } | |
478 | ||
479 | ~weak_count() // nothrow | |
480 | { | |
481 | if(pi_ != 0) pi_->weak_release(); | |
482 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
483 | id_ = 0; | |
484 | #endif | |
485 | } | |
486 | ||
487 | weak_count & operator= (shared_count const & r) // nothrow | |
488 | { | |
489 | sp_counted_base * tmp = r.pi_; | |
490 | if(tmp != 0) tmp->weak_add_ref(); | |
491 | if(pi_ != 0) pi_->weak_release(); | |
492 | pi_ = tmp; | |
493 | ||
494 | return *this; | |
495 | } | |
496 | ||
497 | weak_count & operator= (weak_count const & r) // nothrow | |
498 | { | |
499 | sp_counted_base * tmp = r.pi_; | |
500 | if(tmp != 0) tmp->weak_add_ref(); | |
501 | if(pi_ != 0) pi_->weak_release(); | |
502 | pi_ = tmp; | |
503 | ||
504 | return *this; | |
505 | } | |
506 | ||
507 | void swap(weak_count & r) // nothrow | |
508 | { | |
509 | sp_counted_base * tmp = r.pi_; | |
510 | r.pi_ = pi_; | |
511 | pi_ = tmp; | |
512 | } | |
513 | ||
514 | long use_count() const // nothrow | |
515 | { | |
516 | return pi_ != 0? pi_->use_count(): 0; | |
517 | } | |
518 | ||
519 | friend inline bool operator==(weak_count const & a, weak_count const & b) | |
520 | { | |
521 | return a.pi_ == b.pi_; | |
522 | } | |
523 | ||
524 | friend inline bool operator<(weak_count const & a, weak_count const & b) | |
525 | { | |
526 | return std::less<sp_counted_base *>()(a.pi_, b.pi_); | |
527 | } | |
528 | }; | |
529 | ||
530 | inline shared_count::shared_count(weak_count const & r): pi_(r.pi_) | |
531 | #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) | |
532 | , id_(shared_count_id) | |
533 | #endif | |
534 | { | |
535 | if(pi_ != 0) | |
536 | { | |
537 | pi_->add_ref_lock(); | |
538 | } | |
539 | else | |
540 | { | |
541 | boost::serialization::throw_exception(bad_weak_ptr()); | |
542 | } | |
543 | } | |
544 | ||
545 | } // namespace detail | |
546 | ||
547 | } // namespace boost | |
548 | ||
549 | BOOST_SERIALIZATION_ASSUME_ABSTRACT(boost_132::detail::sp_counted_base) | |
550 | ||
551 | #endif // #ifndef BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED |