c30dcb430c52dea5c29726b49f9dc1cd41e8b77b
[ginac.git] / ginac / ptr.h
1 /** @file ptr.h
2  *
3  *  Reference-counted pointer template. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 #ifndef GINAC_PTR_H
24 #define GINAC_PTR_H
25
26 #include "assertion.h"
27
28 #include <cstddef> // for size_t
29 #include <functional>
30 #include <iosfwd>
31
32 namespace GiNaC {
33
34 /** Base class for reference-counted objects. */
35 class refcounted {
36 public:
37         refcounted() throw() : refcount(0) {}
38
39         unsigned int add_reference() throw() { return ++refcount; }
40         unsigned int remove_reference() throw() { return --refcount; }
41         unsigned int get_refcount() const throw() { return refcount; }
42         void set_refcount(unsigned int r) throw() { refcount = r; }
43
44 private:
45         unsigned int refcount; ///< reference counter
46 };
47
48
49 /** Class of (intrusively) reference-counted pointers that support
50  *  copy-on-write semantics.
51  *
52  *  Requirements for T:
53  *    must support the refcounted interface (usually by being derived
54  *      from refcounted)
55  *    T* T::duplicate() member function (only if makewriteable() is used) */
56 template <class T> class ptr {
57         friend class std::less< ptr<T> >;
58
59         // NB: This implementation of reference counting is not thread-safe.
60         // The reference counter needs to be incremented/decremented atomically,
61         // and makewritable() requires locking.
62
63 public:
64     // no default ctor: a ptr is never unbound
65
66         /** Bind ptr to newly created object, start reference counting. */
67         ptr(T *t) throw() : p(t) { GINAC_ASSERT(p); p->set_refcount(1); }
68
69         /** Bind ptr to existing reference-counted object. */
70         explicit ptr(T &t) throw() : p(&t) { p->add_reference(); }
71
72         ptr(const ptr & other) throw() : p(other.p) { p->add_reference(); }
73
74         ~ptr()
75         {
76                 if (p->remove_reference() == 0)
77                         delete p;
78         }
79
80         ptr &operator=(const ptr & other)
81         {
82                 // NB1: Must first add reference to "other", since other might be *this.
83                 // NB2: Cache other.p, because if "other" is a subexpression of p,
84                 //      deleting p will also invalidate "other".
85                 T *otherp = other.p;
86                 otherp->add_reference();
87                 if (p->remove_reference() == 0)
88                         delete p;
89                 p = otherp;
90                 return *this;
91         }
92
93         T &operator*() const throw() { return *p; }
94         T *operator->() const throw() { return p; }
95
96         friend inline T *get_pointer(const ptr & x) throw() { return x.p; }
97
98         /** Announce your intention to modify the object bound to this ptr.
99          *  This ensures that the object is not shared by any other ptrs. */
100         void makewritable()
101         {
102                 if (p->get_refcount() > 1) {
103                         T *p2 = p->duplicate();
104                         p2->set_refcount(1);
105                         p->remove_reference();
106                         p = p2;
107                 }
108         }
109
110         /** Swap the bound object of this ptr with another ptr. */
111         void swap(ptr & other) throw()
112         {
113                 T *t = p;
114                 p = other.p;
115                 other.p = t;
116         }
117
118         // ptr<>s are always supposed to be bound to a valid object, so we don't
119         // provide support for "if (p)", "if (!p)", "if (p==0)" and "if (p!=0)".
120         // We do, however, provide support for comparing ptr<>s with other ptr<>s
121         // to different (probably derived) types and raw pointers.
122
123         template <class U>
124         bool operator==(const ptr<U> & rhs) const throw() { return p == get_pointer(rhs); }
125
126         template <class U>
127         bool operator!=(const ptr<U> & rhs) const throw() { return p != get_pointer(rhs); }
128
129         template <class U>
130         inline friend bool operator==(const ptr & lhs, const U * rhs) throw() { return lhs.p == rhs; }
131
132         template <class U>
133         inline friend bool operator!=(const ptr & lhs, const U * rhs) throw() { return lhs.p != rhs; }
134
135         template <class U>
136         inline friend bool operator==(const U * lhs, const ptr & rhs) throw() { return lhs == rhs.p; }
137
138         template <class U>
139         inline friend bool operator!=(const U * lhs, const ptr & rhs) throw() { return lhs != rhs.p; }
140
141         inline friend std::ostream & operator<<(std::ostream & os, const ptr<T> & rhs)
142         {
143                 os << rhs.p;
144                 return os;
145         }
146
147 private:
148         T *p;
149 };
150
151 } // namespace GiNaC
152
153
154 namespace std {
155
156 /** Specialization of std::less for ptr<T> to enable ordering of ptr<T>
157  *  objects (e.g. for the use as std::map keys). */
158 template <class T> struct less< GiNaC::ptr<T> >
159  : public binary_function<GiNaC::ptr<T>, GiNaC::ptr<T>, bool> {
160         bool operator()(const GiNaC::ptr<T> &lhs, const GiNaC::ptr<T> &rhs) const
161         {
162                 return less<T*>()(lhs.p, rhs.p);
163         }
164 };
165
166 } // namespace std
167
168 #endif // ndef GINAC_PTR_H