|
GiNaC
1.6.2
|
00001 00005 /* 00006 * GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 #ifndef GINAC_PTR_H 00024 #define GINAC_PTR_H 00025 00026 #include "assertion.h" 00027 00028 #include <cstddef> // for size_t 00029 #include <functional> 00030 #include <iosfwd> 00031 00032 namespace GiNaC { 00033 00035 class refcounted { 00036 public: 00037 refcounted() throw() : refcount(0) {} 00038 00039 unsigned int add_reference() throw() { return ++refcount; } 00040 unsigned int remove_reference() throw() { return --refcount; } 00041 unsigned int get_refcount() const throw() { return refcount; } 00042 void set_refcount(unsigned int r) throw() { refcount = r; } 00043 00044 private: 00045 unsigned int refcount; 00046 }; 00047 00048 00056 template <class T> class ptr { 00057 friend class std::less< ptr<T> >; 00058 00059 // NB: This implementation of reference counting is not thread-safe. 00060 // The reference counter needs to be incremented/decremented atomically, 00061 // and makewritable() requires locking. 00062 00063 public: 00064 // no default ctor: a ptr is never unbound 00065 00067 ptr(T *t) throw() : p(t) { GINAC_ASSERT(p); p->set_refcount(1); } 00068 00070 explicit ptr(T &t) throw() : p(&t) { p->add_reference(); } 00071 00072 ptr(const ptr & other) throw() : p(other.p) { p->add_reference(); } 00073 00074 ~ptr() 00075 { 00076 if (p->remove_reference() == 0) 00077 delete p; 00078 } 00079 00080 ptr &operator=(const ptr & other) 00081 { 00082 // NB1: Must first add reference to "other", since other might be *this. 00083 // NB2: Cache other.p, because if "other" is a subexpression of p, 00084 // deleting p will also invalidate "other". 00085 T *otherp = other.p; 00086 otherp->add_reference(); 00087 if (p->remove_reference() == 0) 00088 delete p; 00089 p = otherp; 00090 return *this; 00091 } 00092 00093 T &operator*() const throw() { return *p; } 00094 T *operator->() const throw() { return p; } 00095 00096 friend inline T *get_pointer(const ptr & x) throw() { return x.p; } 00097 00100 void makewritable() 00101 { 00102 if (p->get_refcount() > 1) { 00103 T *p2 = p->duplicate(); 00104 p2->set_refcount(1); 00105 p->remove_reference(); 00106 p = p2; 00107 } 00108 } 00109 00111 void swap(ptr & other) throw() 00112 { 00113 T *t = p; 00114 p = other.p; 00115 other.p = t; 00116 } 00117 00118 // ptr<>s are always supposed to be bound to a valid object, so we don't 00119 // provide support for "if (p)", "if (!p)", "if (p==0)" and "if (p!=0)". 00120 // We do, however, provide support for comparing ptr<>s with other ptr<>s 00121 // to different (probably derived) types and raw pointers. 00122 00123 template <class U> 00124 bool operator==(const ptr<U> & rhs) const throw() { return p == get_pointer(rhs); } 00125 00126 template <class U> 00127 bool operator!=(const ptr<U> & rhs) const throw() { return p != get_pointer(rhs); } 00128 00129 template <class U> 00130 inline friend bool operator==(const ptr & lhs, const U * rhs) throw() { return lhs.p == rhs; } 00131 00132 template <class U> 00133 inline friend bool operator!=(const ptr & lhs, const U * rhs) throw() { return lhs.p != rhs; } 00134 00135 template <class U> 00136 inline friend bool operator==(const U * lhs, const ptr & rhs) throw() { return lhs == rhs.p; } 00137 00138 template <class U> 00139 inline friend bool operator!=(const U * lhs, const ptr & rhs) throw() { return lhs != rhs.p; } 00140 00141 inline friend std::ostream & operator<<(std::ostream & os, const ptr<T> & rhs) 00142 { 00143 os << rhs.p; 00144 return os; 00145 } 00146 00147 private: 00148 T *p; 00149 }; 00150 00151 } // namespace GiNaC 00152 00153 00154 namespace std { 00155 00158 template <class T> struct less< GiNaC::ptr<T> > 00159 : public binary_function<GiNaC::ptr<T>, GiNaC::ptr<T>, bool> { 00160 bool operator()(const GiNaC::ptr<T> &lhs, const GiNaC::ptr<T> &rhs) const 00161 { 00162 return less<T*>()(lhs.p, rhs.p); 00163 } 00164 }; 00165 00166 } // namespace std 00167 00168 #endif // ndef GINAC_PTR_H