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