merging 1.2 branch into main trunk
[ginac.git] / ginac / ptr.h
1 /** @file ptr.h
2  *
3  *  Reference-counted pointer template. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #ifndef __GINAC_PTR_H__
24 #define __GINAC_PTR_H__
25
26 #include <functional>
27 #include <iosfwd>
28
29 #include "assertion.h"
30
31 namespace GiNaC {
32
33 /** Class of (intrusively) reference-counted pointers that support
34  *  copy-on-write semantics.
35  *
36  *  Requirements for T:
37  *    T::refcount member that supports ++refcount, --refcount, refcount = 1,
38  *      refcount == 0 and refcount > 1
39  *    T* T::duplicate() member function (only if makewriteable() is used) */
40 template <class T> class ptr {
41         friend class std::less< ptr<T> >;
42
43         // NB: This implementation of reference counting is not thread-safe.
44         // The reference counter needs to be incremented/decremented atomically,
45         // and makewritable() requires locking.
46
47 public:
48     // no default ctor: a ptr is never unbound
49
50         /** Bind ptr to newly created object, start reference counting. */
51         ptr(T *t) : p(t) { GINAC_ASSERT(p); p->refcount = 1; }
52
53         /** Bind ptr to existing reference-counted object. */
54         explicit ptr(T &t) : p(&t) { ++p->refcount; }
55
56         ptr(const ptr & other) : p(other.p) { ++p->refcount; }
57
58         ~ptr()
59         {
60                 if (--p->refcount == 0)
61                         delete p;
62         }
63
64         ptr &operator=(const ptr & other)
65         {
66                 // NB: must first increment other.p->refcount, since other might be *this.
67                 ++other.p->refcount;
68                 if (--p->refcount == 0)
69                         delete p;
70                 p = other.p;
71                 return *this;
72         }
73
74         T &operator*() const { return *p; }
75         T *operator->() const { return p; }
76
77         friend inline T *get_pointer(const ptr & x) { return x.p; }
78
79         /** Announce your intention to modify the object bound to this ptr.
80          *  This ensures that the object is not shared by any other ptrs. */
81         void makewritable()
82         {
83                 if (p->refcount > 1) {
84                         T *p2 = p->duplicate();
85                         p2->refcount = 1;
86                         --p->refcount;
87                         p = p2;
88                 }
89         }
90
91         /** Swap the bound object of this ptr with another ptr. */
92         void swap(ptr & other)
93         {
94                 T *t = p;
95                 p = other.p;
96                 other.p = t;
97         }
98
99         // ptr<>s are always supposed to be bound to a valid object, so we don't
100         // provide support for "if (p)", "if (!p)", "if (p==0)" and "if (p!=0)".
101         // We do, however, provide support for comparing ptr<>s with other ptr<>s
102         // to different (probably derived) types and raw pointers.
103
104         template <class U>
105         bool operator==(const ptr<U> & rhs) const { return p == get_pointer(rhs); }
106
107         template <class U>
108         bool operator!=(const ptr<U> & rhs) const { return p != get_pointer(rhs); }
109
110         template <class U>
111         inline friend bool operator==(const ptr & lhs, const U * rhs) { return lhs.p == rhs; }
112
113         template <class U>
114         inline friend bool operator!=(const ptr & lhs, const U * rhs) { return lhs.p != rhs; }
115
116         template <class U>
117         inline friend bool operator==(const U * lhs, const ptr & rhs) { return lhs == rhs.p; }
118
119         template <class U>
120         inline friend bool operator!=(const U * lhs, const ptr & rhs) { return lhs != rhs.p; }
121
122         inline friend std::ostream & operator<<(std::ostream & os, const ptr<T> & rhs)
123         {
124                 os << rhs.p;
125         }
126
127 private:
128         T *p;
129 };
130
131 } // namespace GiNaC
132
133 namespace std {
134
135 /** Specialization of std::less for ptr<T> to enable ordering of ptr<T>
136  *  objects (e.g. for the use as std::map keys). */
137 template <class T> struct less< GiNaC::ptr<T> >
138  : public binary_function<GiNaC::ptr<T>, GiNaC::ptr<T>, bool> {
139         bool operator()(const GiNaC::ptr<T> &lhs, const GiNaC::ptr<T> &rhs) const
140         {
141                 return less<T*>()(lhs.p, rhs.p);
142         }
143 };
144
145 } // namespace std
146
147 #endif // ndef __GINAC_UTILS_H__