]> git.lyx.org Git - lyx.git/blob - boost/boost/smart_ptr.hpp
af7cf9856b85a293a617565f7c6c59a283b1bfae
[lyx.git] / boost / boost / smart_ptr.hpp
1 // Baruch Even  baruch@ev-en.org  2001-02-20
2 //  This version is a modified version for use in LyX
3 //  The modifications are done in order to use it where exceptions are disabled
4 //  Currently it has no "no memory" checks in place, asserts are probably the
5 //  only real way.
6 //  all changed are #ifded'ed by LYX_NO_EXCEPTIONS
7 #define LYX_NO_EXCEPTIONS
8
9 //  Boost smart_ptr.hpp header file  -----------------------------------------//
10
11 //  (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. Permission to copy,
12 //  use, modify, sell and distribute this software is granted provided this
13 //  copyright notice appears in all copies. This software is provided "as is"
14 //  without express or implied warranty, and with no claim as to its
15 //  suitability for any purpose.
16
17 //  See http://www.boost.org for most recent version including documentation.
18
19 //  Revision History
20 //  21 May 01  Require complete type where incomplete type is unsafe.
21 //             (suggested by Vladimir Prus)
22 //  21 May 01  operator= fails if operand transitively owned by *this, as in a
23 //             linked list (report by Ken Johnson, fix by Beman Dawes)
24 //  21 Jan 01  Suppress some useless warnings with MSVC (David Abrahams)
25 //  19 Oct 00  Make shared_ptr ctor from auto_ptr explicit. (Robert Vugts) 
26 //  24 Jul 00  Change throw() to // never throws.  See lib guidelines
27 //             Exception-specification rationale. (Beman Dawes)
28 //  22 Jun 00  Remove #if continuations to fix GCC 2.95.2 problem (Beman Dawes)
29 //   1 Feb 00  Additional shared_ptr BOOST_NO_MEMBER_TEMPLATES workarounds
30 //             (Dave Abrahams)
31 //  31 Dec 99  Condition tightened for no member template friend workaround
32 //             (Dave Abrahams)
33 //  30 Dec 99  Moved BOOST_NMEMBER_TEMPLATES compatibility code to config.hpp
34 //             (Dave Abrahams)
35 //  30 Nov 99  added operator ==, operator !=, and std::swap and std::less
36 //             specializations for shared types (Darin Adler)
37 //  11 Oct 99  replaced op[](int) with op[](std::size_t) (Ed Brey, Valentin
38 //             Bonnard), added shared_ptr workaround for no member template
39 //             friends (Matthew Langston)
40 //  25 Sep 99  added shared_ptr::swap and shared_array::swap (Luis Coelho).
41 //  20 Jul 99  changed name to smart_ptr.hpp, #include <boost/config.hpp>,
42 //             #include <boost/utility.hpp> and use boost::noncopyable
43 //  17 May 99  remove scoped_array and shared_array operator*() as
44 //             unnecessary (Beman Dawes)
45 //  14 May 99  reorder code so no effects when bad_alloc thrown (Abrahams/Dawes)
46 //  13 May 99  remove certain throw() specifiers to avoid generated try/catch
47 //             code cost (Beman Dawes)
48 //  11 May 99  get() added, conversion to T* placed in macro guard (Valentin
49 //             Bonnard, Dave Abrahams, and others argued for elimination
50 //             of the automatic conversion)
51 //  28 Apr 99  #include <memory> fix (Valentin Bonnard)
52 //  28 Apr 99  rename transfer() to share() for clarity (Dave Abrahams)
53 //  28 Apr 99  remove unsafe shared_array template conversions(Valentin Bonnard)
54 //  28 Apr 99  p(r) changed to p(r.px) for clarity (Dave Abrahams)
55 //  21 Apr 99  reset() self assignment fix (Valentin Bonnard)
56 //  21 Apr 99  dispose() provided to improve clarity (Valentin Bonnard)
57 //  27 Apr 99  leak when new throws fixes (Dave Abrahams)
58 //  21 Oct 98  initial Version (Greg Colvin/Beman Dawes)
59
60 #ifndef BOOST_SMART_PTR_HPP
61 #define BOOST_SMART_PTR_HPP
62
63 #include <boost/config.hpp>   // for broken compiler workarounds
64 #include <cstddef>            // for std::size_t
65 #include <memory>             // for std::auto_ptr
66 #include <algorithm>          // for std::swap
67 #include <boost/utility.hpp>  // for boost::noncopyable, checked_delete, checked_array_delete
68 #include <functional>         // for std::less
69 #include <boost/static_assert.hpp> // for BOOST_STATIC_ASSERT
70
71 #ifdef LYX_NO_EXCEPTIONS
72 #include <assert.h>
73 #endif
74
75 #ifdef BOOST_MSVC  // moved here to work around VC++ compiler crash
76 # pragma warning(push)
77 # pragma warning(disable:4284) // return type for 'identifier::operator->' is not a UDT or reference to a UDT. Will produce errors if applied using infix notation
78 #endif
79
80 namespace boost {
81
82 //  scoped_ptr  --------------------------------------------------------------//
83
84 //  scoped_ptr mimics a built-in pointer except that it guarantees deletion
85 //  of the object pointed to, either on destruction of the scoped_ptr or via
86 //  an explicit reset().  scoped_ptr is a simple solution for simple needs;
87 //  see shared_ptr (below) or std::auto_ptr if your needs are more complex.
88
89 template<typename T> class scoped_ptr : noncopyable {
90
91   T* ptr;
92
93  public:
94   typedef T element_type;
95
96   explicit scoped_ptr( T* p=0 ) : ptr(p) {}  // never throws
97   ~scoped_ptr()                 { checked_delete(ptr); }
98   void reset( T* p=0 )          { if ( ptr != p ) { checked_delete(ptr); ptr =
99 p; } }
100   T& operator*() const          { return *ptr; }  // never throws
101 #ifdef BOOST_MSVC
102 # pragma warning(push)
103 # pragma warning(disable:4284) // return type for 'identifier::operator->' is not a UDT or reference to a UDT. Will produce errors if applied using infix notation
104 #endif    
105   T* operator->() const         { return ptr; }  // never throws
106 #ifdef BOOST_MSVC
107 # pragma warning(pop)
108 #endif    
109   T* get() const                { return ptr; }  // never throws
110 #ifdef BOOST_SMART_PTR_CONVERSION
111   // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
112   operator T*() const           { return ptr; }  // never throws 
113 #endif
114   };  // scoped_ptr
115
116 //  scoped_array  ------------------------------------------------------------//
117
118 //  scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to
119 //  is guaranteed, either on destruction of the scoped_array or via an explicit
120 //  reset(). See shared_array or std::vector if your needs are more complex.
121
122 template<typename T> class scoped_array : noncopyable {
123
124   T* ptr;
125
126  public:
127   typedef T element_type;
128
129   explicit scoped_array( T* p=0 ) : ptr(p) {}  // never throws
130   ~scoped_array()                    { delete [] ptr; }
131
132   void reset( T* p=0 )               { if ( ptr != p ) {delete [] ptr; ptr=p;} }
133
134   T* get() const                     { return ptr; }  // never throws
135 #ifdef BOOST_SMART_PTR_CONVERSION
136   // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
137   operator T*() const                { return ptr; }  // never throws
138 #else 
139   T& operator[](std::size_t i) const { return ptr[i]; }  // never throws
140 #endif
141   };  // scoped_array
142
143 //  shared_ptr  --------------------------------------------------------------//
144
145 //  An enhanced relative of scoped_ptr with reference counted copy semantics.
146 //  The object pointed to is deleted when the last shared_ptr pointing to it
147 //  is destroyed or reset.
148
149 template<typename T> class shared_ptr {
150   public:
151    typedef T element_type;
152
153    explicit shared_ptr(T* p =0) : px(p) {
154 #ifndef LYX_NO_EXCEPTIONS
155       try { pn = new long(1); }  // fix: prevent leak if new throws
156       catch (...) { delete p; throw; } 
157 #else
158           pn = new long(1);
159           assert(pn != 0);
160 #endif
161    }
162
163    shared_ptr(const shared_ptr& r) : px(r.px) { ++*(pn = r.pn); }  // never throws
164
165    ~shared_ptr() { dispose(); }
166
167    shared_ptr& operator=(const shared_ptr& r) {
168       share(r.px,r.pn);
169       return *this;
170    }
171
172 #if !defined( BOOST_NO_MEMBER_TEMPLATES )
173    template<typename Y>
174       shared_ptr(const shared_ptr<Y>& r) : px(r.px) {  // never throws 
175          ++*(pn = r.pn); 
176       }
177 #ifndef BOOST_NO_AUTO_PTR
178    template<typename Y>
179       explicit shared_ptr(std::auto_ptr<Y>& r) { 
180          pn = new long(1); // may throw
181          px = r.release(); // fix: moved here to stop leak if new throws
182       }
183 #endif 
184
185    template<typename Y>
186       shared_ptr& operator=(const shared_ptr<Y>& r) { 
187          share(r.px,r.pn);
188          return *this;
189       }
190
191 #ifndef BOOST_NO_AUTO_PTR
192    template<typename Y>
193       shared_ptr& operator=(std::auto_ptr<Y>& r) {
194          // code choice driven by guarantee of "no effect if new throws"
195          if (*pn == 1) { delete px; }
196          else { // allocate new reference counter
197            long * tmp = new long(1); // may throw
198            --*pn; // only decrement once danger of new throwing is past
199            pn = tmp;
200          } // allocate new reference counter
201          px = r.release(); // fix: moved here so doesn't leak if new throws 
202          return *this;
203       }
204 #endif
205 #else
206 #ifndef BOOST_NO_AUTO_PTR
207       explicit shared_ptr(std::auto_ptr<T>& r) { 
208          pn = new long(1); // may throw
209          px = r.release(); // fix: moved here to stop leak if new throws
210       } 
211
212       shared_ptr& operator=(std::auto_ptr<T>& r) {
213          // code choice driven by guarantee of "no effect if new throws"
214          if (*pn == 1) { delete px; }
215          else { // allocate new reference counter
216            long * tmp = new long(1); // may throw
217            --*pn; // only decrement once danger of new throwing is past
218            pn = tmp;
219          } // allocate new reference counter
220          px = r.release(); // fix: moved here so doesn't leak if new throws 
221          return *this;
222       }
223 #endif
224 #endif
225
226    void reset(T* p=0) {
227       if ( px == p ) return;  // fix: self-assignment safe
228       if (--*pn == 0) { delete px; }
229       else { // allocate new reference counter
230 #ifndef LYX_NO_EXCEPTIONS                 
231         try { pn = new long; }  // fix: prevent leak if new throws
232         catch (...) {
233           ++*pn;  // undo effect of --*pn above to meet effects guarantee 
234           delete p;
235           throw;
236         } // catch
237 #else
238                 pn = new long;
239                 assert(pn != 0);
240 #endif
241       } // allocate new reference counter
242       *pn = 1;
243       px = p;
244    } // reset
245
246    T& operator*() const          { return *px; }  // never throws
247 #ifdef BOOST_MSVC
248 # pragma warning(push)
249 # pragma warning(disable:4284) // return type for 'identifier::operator->' is not a UDT or reference to a UDT. Will produce errors if applied using infix notation
250 #endif    
251    T* operator->() const         { return px; }  // never throws
252 #ifdef BOOST_MSVC
253 # pragma warning(pop)
254 #endif    
255    T* get() const                { return px; }  // never throws
256  #ifdef BOOST_SMART_PTR_CONVERSION
257    // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
258    operator T*() const           { return px; }  // never throws 
259  #endif
260
261    long use_count() const        { return *pn; }  // never throws
262    bool unique() const           { return *pn == 1; }  // never throws
263
264    void swap(shared_ptr<T>& other)  // never throws
265      { std::swap(px,other.px); std::swap(pn,other.pn); }
266
267 // Tasteless as this may seem, making all members public allows member templates
268 // to work in the absence of member template friends. (Matthew Langston)
269 // Don't split this line into two; that causes problems for some GCC 2.95.2 builds
270 #if defined(BOOST_NO_MEMBER_TEMPLATES) || !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS )
271    private:
272 #endif
273
274    T*     px;     // contained pointer
275    long*  pn;     // ptr to reference counter
276
277 // Don't split this line into two; that causes problems for some GCC 2.95.2 builds
278 #if !defined( BOOST_NO_MEMBER_TEMPLATES ) && !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS )
279    template<typename Y> friend class shared_ptr;
280 #endif
281
282    void dispose() { if (--*pn == 0) { delete px; delete pn; } }
283
284    void share(T* rpx, long* rpn) {
285       if (pn != rpn) {
286          dispose();
287          px = rpx;
288          ++*(pn = rpn);
289       }
290    } // share
291 };  // shared_ptr
292
293 template<typename T, typename U>
294   inline bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b)
295     { return a.get() == b.get(); }
296
297 template<typename T, typename U>
298   inline bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b)
299     { return a.get() != b.get(); }
300
301 //  shared_array  ------------------------------------------------------------//
302
303 //  shared_array extends shared_ptr to arrays.
304 //  The array pointed to is deleted when the last shared_array pointing to it
305 //  is destroyed or reset.
306
307 template<typename T> class shared_array {
308   public:
309    typedef T element_type;
310
311    explicit shared_array(T* p =0) : px(p) {
312 #ifndef LYX_NO_EXCEPTIONS
313       try { pn = new long(1); }  // fix: prevent leak if new throws
314       catch (...) { delete [] p; throw; } 
315 #else
316           pn = new long(1);
317           assert(pn != 0);
318 #endif
319    }
320
321    shared_array(const shared_array& r) : px(r.px)  // never throws
322       { ++*(pn = r.pn); }
323
324    ~shared_array() { dispose(); }
325
326    shared_array& operator=(const shared_array& r) {
327       if (pn != r.pn) {
328          dispose();
329          px = r.px;
330          ++*(pn = r.pn);
331       }
332       return *this;
333    } // operator=
334
335    void reset(T* p=0) {
336       if ( px == p ) return;  // fix: self-assignment safe
337       if (--*pn == 0) { delete [] px; }
338       else { // allocate new reference counter
339 #ifndef LYX_NO_EXCEPTIONS
340         try { pn = new long; }  // fix: prevent leak if new throws
341         catch (...) {
342           ++*pn;  // undo effect of --*pn above to meet effects guarantee 
343           delete [] p;
344           throw;
345         } // catch
346 #else
347                 pn = new long;
348                 assert(pn != 0);
349 #endif
350       } // allocate new reference counter
351       *pn = 1;
352       px = p;
353    } // reset
354
355    T* get() const                     { return px; }  // never throws
356  #ifdef BOOST_SMART_PTR_CONVERSION
357    // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
358    operator T*() const                { return px; }  // never throws
359  #else 
360    T& operator[](std::size_t i) const { return px[i]; }  // never throws
361  #endif
362
363    long use_count() const             { return *pn; }  // never throws
364    bool unique() const                { return *pn == 1; }  // never throws
365
366    void swap(shared_array<T>& other)  // never throws
367      { std::swap(px,other.px); std::swap(pn,other.pn); }
368
369   private:
370
371    T*     px;     // contained pointer
372    long*  pn;     // ptr to reference counter
373
374    void dispose() { if (--*pn == 0) { delete [] px; delete pn; } }
375
376 };  // shared_array
377
378 template<typename T>
379   inline bool operator==(const shared_array<T>& a, const shared_array<T>& b)
380     { return a.get() == b.get(); }
381
382 template<typename T>
383   inline bool operator!=(const shared_array<T>& a, const shared_array<T>& b)
384     { return a.get() != b.get(); }
385
386 } // namespace boost
387
388 //  specializations for things in namespace std  -----------------------------//
389
390 #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
391
392 namespace std {
393
394 // Specialize std::swap to use the fast, non-throwing swap that's provided
395 // as a member function instead of using the default algorithm which creates
396 // a temporary and uses assignment.
397
398 template<typename T>
399   inline void swap(boost::shared_ptr<T>& a, boost::shared_ptr<T>& b)
400     { a.swap(b); }
401
402 template<typename T>
403   inline void swap(boost::shared_array<T>& a, boost::shared_array<T>& b)
404     { a.swap(b); }
405
406 // Specialize std::less so we can use shared pointers and arrays as keys in
407 // associative collections.
408
409 // It's still a controversial question whether this is better than supplying
410 // a full range of comparison operators (<, >, <=, >=).
411
412 template<typename T>
413   struct less< boost::shared_ptr<T> >
414     : binary_function<boost::shared_ptr<T>, boost::shared_ptr<T>, bool>
415   {
416     bool operator()(const boost::shared_ptr<T>& a,
417         const boost::shared_ptr<T>& b) const
418       { return less<T*>()(a.get(),b.get()); }
419   };
420
421 template<typename T>
422   struct less< boost::shared_array<T> >
423     : binary_function<boost::shared_array<T>, boost::shared_array<T>, bool>
424   {
425     bool operator()(const boost::shared_array<T>& a,
426         const boost::shared_array<T>& b) const
427       { return less<T*>()(a.get(),b.get()); }
428   };
429
430 } // namespace std
431
432 #endif  // ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
433
434 #endif  // BOOST_SMART_PTR_HPP
435
436