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