]> git.lyx.org Git - lyx.git/blob - src/support/smart_ptr.h
remove NO_PEXTRA_STUFF
[lyx.git] / src / support / smart_ptr.h
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 LYX_SMART_PTR_H
61 #define LYX_SMART_PTR_H
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 "support/utility.h"  // 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 namespace lyx {
76
77 //  shared_ptr  --------------------------------------------------------------//
78
79 //  An enhanced relative of scoped_ptr with reference counted copy semantics.
80 //  The object pointed to is deleted when the last shared_ptr pointing to it
81 //  is destroyed or reset.
82
83 template<typename T> class shared_c_ptr {
84   public:
85    typedef T element_type;
86
87    explicit shared_c_ptr(T* p =0) : px(p) {
88 #ifndef LYX_NO_EXCEPTIONS
89       try { pn = new long(1); }  // fix: prevent leak if new throws
90       catch (...) { checked_delete(p); throw; }
91 #else
92           pn = new long(1);
93           assert(pn != 0);
94 #endif
95    }
96
97    shared_c_ptr(const shared_c_ptr& r) : px(r.px) { ++*(pn = r.pn); }  // never throws
98
99    ~shared_c_ptr() { dispose(); }
100
101    shared_c_ptr& operator=(const shared_c_ptr& r) {
102       share(r.px,r.pn);
103       return *this;
104    }
105
106 #if !defined(BOOST_NO_MEMBER_TEMPLATES)
107    template<typename Y>
108       shared_c_ptr(const shared_c_ptr<Y>& r) : px(r.px) {  // never throws
109          ++*(pn = r.pn);
110       }
111 #ifndef BOOST_NO_AUTO_PTR
112    template<typename Y>
113       explicit shared_c_ptr(std::auto_ptr<Y>& r) {
114          pn = new long(1); // may throw
115          px = r.release(); // fix: moved here to stop leak if new throws
116       }
117 #endif
118
119    template<typename Y>
120       shared_c_ptr& operator=(const shared_c_ptr<Y>& r) {
121          share(r.px,r.pn);
122          return *this;
123       }
124
125 #ifndef BOOST_NO_AUTO_PTR
126    template<typename Y>
127       shared_c_ptr& operator=(std::auto_ptr<Y>& r) {
128          // code choice driven by guarantee of "no effect if new throws"
129          if (*pn == 1) { checked_delete(px); }
130          else { // allocate new reference counter
131            long * tmp = new long(1); // may throw
132            --*pn; // only decrement once danger of new throwing is past
133            pn = tmp;
134          } // allocate new reference counter
135          px = r.release(); // fix: moved here so doesn't leak if new throws
136          return *this;
137       }
138 #endif
139 #else
140 #ifndef BOOST_NO_AUTO_PTR
141       explicit shared_c_ptr(std::auto_ptr<T>& r) {
142          pn = new long(1); // may throw
143          px = r.release(); // fix: moved here to stop leak if new throws
144       }
145
146       shared_c_ptr& operator=(std::auto_ptr<T>& r) {
147          // code choice driven by guarantee of "no effect if new throws"
148          if (*pn == 1) { checked_delete(px); }
149          else { // allocate new reference counter
150            long * tmp = new long(1); // may throw
151            --*pn; // only decrement once danger of new throwing is past
152            pn = tmp;
153          } // allocate new reference counter
154          px = r.release(); // fix: moved here so doesn't leak if new throws
155          return *this;
156       }
157 #endif
158 #endif
159
160    void reset(T* p=0) {
161       if (px == p) return;  // fix: self-assignment safe
162       if (--*pn == 0) { checked_delete(px); }
163       else { // allocate new reference counter
164 #ifndef LYX_NO_EXCEPTIONS
165         try { pn = new long; }  // fix: prevent leak if new throws
166         catch (...) {
167           ++*pn;  // undo effect of --*pn above to meet effects guarantee
168           checked_delete(p);
169           throw;
170         } // catch
171 #else
172                 pn = new long;
173                 assert(pn != 0);
174 #endif
175       } // allocate new reference counter
176       *pn = 1;
177       px = p;
178    } // reset
179
180    T& operator*() const          { return *px; }  // never throws
181    T* operator->() const         { return px; }  // never throws
182    T* get() const                { return px; }  // never throws
183
184    long use_count() const        { return *pn; }  // never throws
185    bool unique() const           { return *pn == 1; }  // never throws
186
187    void swap(shared_c_ptr<T>& other)  // never throws
188      { std::swap(px,other.px); std::swap(pn,other.pn); }
189
190 // Tasteless as this may seem, making all members public allows member templates
191 // to work in the absence of member template friends. (Matthew Langston)
192 // Don't split this line into two; that causes problems for some GCC 2.95.2 builds
193 #if defined(BOOST_NO_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
194    private:
195 #endif
196
197    T*     px;     // contained pointer
198    long*  pn;     // ptr to reference counter
199
200 // Don't split this line into two; that causes problems for some GCC 2.95.2 builds
201 #if !defined( BOOST_NO_MEMBER_TEMPLATES ) && !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS )
202    template<typename Y> friend class shared_ptr;
203 #endif
204
205    void dispose() { if (--*pn == 0) { checked_delete(px); delete pn; } }
206
207    void share(T* rpx, long* rpn) {
208       if (pn != rpn) { // Q: why not px != rpx? A: fails when both == 0
209          ++*rpn; // done before dispose() in case rpn transitively
210                  // dependent on *this (bug reported by Ken Johnson)
211          dispose();
212          px = rpx;
213          pn = rpn;
214       }
215    } // share
216 };  // shared_ptr
217
218 template<typename T, typename U>
219   inline bool operator==(const shared_c_ptr<T>& a, const shared_c_ptr<U>& b)
220     { return a.get() == b.get(); }
221
222 template<typename T, typename U>
223   inline bool operator!=(const shared_c_ptr<T>& a, const shared_c_ptr<U>& b)
224     { return a.get() != b.get(); }
225
226 } // namespace boost
227
228 //  specializations for things in namespace std  -----------------------------//
229
230 #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
231
232 namespace std {
233
234 // Specialize std::swap to use the fast, non-throwing swap that's provided
235 // as a member function instead of using the default algorithm which creates
236 // a temporary and uses assignment.
237
238 template<typename T>
239   inline void swap(lyx::shared_c_ptr<T>& a, lyx::shared_c_ptr<T>& b)
240     { a.swap(b); }
241
242 // Specialize std::less so we can use shared pointers and arrays as keys in
243 // associative collections.
244
245 // It's still a controversial question whether this is better than supplying
246 // a full range of comparison operators (<, >, <=, >=).
247
248 template<typename T>
249   struct less< lyx::shared_c_ptr<T> >
250     : binary_function<lyx::shared_c_ptr<T>, lyx::shared_c_ptr<T>, bool>
251   {
252     bool operator()(const lyx::shared_c_ptr<T>& a,
253         const lyx::shared_c_ptr<T>& b) const
254       { return less<T*>()(a.get(),b.get()); }
255   };
256
257 } // namespace std
258
259 #endif  // ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
260
261 #endif  // LYX_SMART_PTR_H