/usr/include/shevek/crefptr.hh is in libshevek-dev 1.4-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | /* crefptr - cyclic-protected reference counting smart pointers.
* Copyright 2009 Bas Wijnen <wijnen@debian.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SHEVEK_CREFPTR_HH
#define SHEVEK_CREFPTR_HH
#include <list>
#include <iostream>
#include "error.hh"
namespace shevek
{
// Structure of the refptr:
// The object with the data derives from crefbase. This cannot be copied.
// Pointers to it are of type crefptr <_T>, where _T is the deriving class.
// crefbase contains a list of _ptrdata with pointers to the object.
// _ptrdata contains the target object, the pointer which references it and the owner of the reference.
// crefptr contains (through _ptr) a list iterator, pointing to its _ptrdata.
// crefptr->_data->_ref is always crefptr, and object->_refs[]->target is always object.
/// Circular-dependancy-protected reference-counting object base class.
/** Objects which derive from this class are reference-counted in a way that detects dependency loops and destroys the entire loop when it is no longer externally referenced.
* For this, it is important that objects which contain pointers register them appropriately.
*/
class crefbase
{
class _ptr;
class _ptrptr;
class _objptr;
template <typename _T> friend class crefptr;
// Internal pointers to crefptrs.
class _ptrptr
{
_ptr *_data;
public:
_ptr &operator* () { return *_data; }
_ptr *operator-> () { return _data; }
_ptrptr (_ptr *p) { _data = p; }
};
// Internal pointers to crefbase objects.
class _objptr
{
crefbase *_data;
public:
_objptr (crefbase *d) { _data = d; }
crefbase &operator* () { return *_data; }
crefbase *operator-> () const { return _data; }
};
// This struct is used internally for storing back references to a pointer.
struct _ptrdata
{
_objptr target; // Link to self, so _ptr only needs to store an iterator.
_ptrptr ref; // The referencing pointer.
_objptr owner; // The owner of ref.
_ptrdata (_objptr t, _ptrptr r, _objptr o) : target (t), ref (r), owner (o) {}
};
// Base class for crefptr.
class _ptr
{
friend class crefbase;
template <typename _T> friend class crefptr;
std::list <_ptrdata>::iterator _data;
_objptr _target () const { return _data->target; }
_objptr &_owner () const { return _data->owner; }
// The reference counting machinery.
protected:
inline _ptr (_objptr owner, _objptr target);
inline ~_ptr ();
public:
inline _ptr (_ptr const &that);
inline _ptr &operator= (_ptr const &that);
inline void reset ();
inline void set_owner (crefbase *owner);
};
// Object to which null-pointers point. This is needed to store their owners. This object is never deleted because init_done () is never called.
static crefbase no_target;
// This is set at creation; the object cannot be destroyed until it is reset using init_done ().
int _init;
// List of pointers referencing this object, with their owner.
// This costs more memory than storing the data in _ptr, but _ptr must be as small as possible,
// because it is passed around and thus copied a lot.
std::list <_ptrdata> _refs;
// Use _refs.
void _check ();
bool _checking;
void _add (_ptrptr p, _objptr owner);
void _remove (_ptrptr p);
// Can't copy refcounted objects.
crefbase &operator= (crefbase const &that); // NI
crefbase (crefbase const &that); // NI
static int dbg_tag;
#ifdef DEBUG_CREFBASE
std::list <crefbase *>::iterator dbg_iterator;
static std::list <crefbase *> dbg_check;
#endif
protected:
/// Constructor, which is called when an object is created.
crefbase () : _init (0), _checking (false)
{
#ifdef DEBUG_CREFBASE
dbg_check.push_back (this);
dbg_iterator = --dbg_check.end ();
#endif
}
/// Virtual destructor, which does nothing except allowing derived class to have a virtual destructor.
virtual ~crefbase ()
{
if (this == &no_target)
return;
if (!_refs.empty ())
shevek_error ("reference list is not empty");
#ifdef DEBUG_CREFBASE
dbg_check.erase (dbg_iterator);
#endif
if (_init == 0)
shevek_error ("removing object before init_done was called");
if (_init != 1)
std::cerr << "Removing object " << this << " which is tagged " << _init << '\n';
}
public:
/// Set the default tag for when init_done is called.
/** If the tag is not set to 1, a message will be printed to standard error on destruction.
* The previous tag is returned.
* If tag is set to 0, the old value is not changed.
* The initial default value is 1.
*/
static int set_default_tag (int tag)
{
int old = dbg_tag;
if (tag)
dbg_tag = tag;
return old;
}
/// After calling this, the object is destroyed without references.
/** On creation, an object does not have any references. To prevent immediate destruction, it is first in an initialisation phase.
* During that phase, it will not be destroyed, even if it has no references.
* This function should be called immeiately after creating the object (normally through crefptr::init):
* shevek::crefptr <foo> bar = foo::create ().init ();
* If code is not given or 0, the default tag (set with set_default_tag) will be used.
*/
void init_done (int code = 0)
{
if (!code)
code = dbg_tag;
if (this == &no_target)
shevek_error ("calling init_done on no_target");
if (_init)
shevek_error ("calling init_done more than once");
_init = code;
if (code != 1)
std::cerr << "Tagging object " << this << " with code " << code << '\n';
_check ();
}
/// Check if all objects have called init_done.
/** When debugging is enabled, this function checks for all objects if they have called init_done.
* When debugging is not enabled, no list of objects is kept, and this check does nothing.
*/
static void check (bool fatal = true)
{
#ifdef DEBUG_CREFBASE
unsigned count = 0;
for (std::list <crefbase *>::iterator i = dbg_check.begin (); i != dbg_check.end (); ++i)
{
if (*i == &no_target)
continue;
if (!(*i)->_init)
{
shevek_warning (shevek::ostring ("init_done not called before check for %08x", (unsigned)*i));
++count;
}
else if ((*i)->_init != 1)
std::cerr << "Check: object " << *i << ", tagged " << (*i)->_init << " still lives (" << (*i)->_refs.size () << " references)\n";
}
std::cerr << "checked " << dbg_check.size () << " items\n";
if (count && fatal)
{
shevek_error ("check failed");
throw "check failed";
}
#endif
}
};
/// Keep a pointer to an object derived from crefbase.
template <typename _T> class crefptr : public crefbase::_ptr
{
public:
/// Create a new pointer. If this pointer is stored inside a crefbase-derived object, make sure to set the owner.
crefptr (crefbase *target = NULL, crefbase *owner = NULL) : _ptr (owner, target) {}
/// Dereference the pointer.
_T &operator* () const { if (_target ().operator-> () == &crefbase::no_target) shevek_error ("dereferencing NULL crefptr"); return reinterpret_cast <_T &> (*_target ()); }
/// Dereference the pointer.
_T *operator-> () const { if (_target ().operator-> () == &crefbase::no_target) return NULL; return reinterpret_cast <_T *> (_target ().operator-> ()); }
/// Test if two pointers refer to the same object.
bool operator== (crefptr <_T> const &that) const { return _target ().operator-> () == that._target ().operator-> (); }
/// Test if two pointers don't refer to the same object.
bool operator!= (crefptr <_T> const &that) const { return _target ().operator-> () != that._target ().operator-> (); }
/// Create a new pointer from this one, up- or downcast. Normally, this is used to fill a new crefptr.
template <typename _R> _R *cast_dynamic () const { return dynamic_cast <_R *> (_target ().operator-> ()); }
/// Implicit pointer conversion.
operator _T * () const { _T *ret = reinterpret_cast <_T *> (_target ().operator-> ()); if (ret == &crefbase::no_target) return NULL; return ret; }
/// Allow the pointer to be destroyed. See crefbase::init_done for details.
crefptr <_T> init (int code = 0)
{
_target ()->init_done (code);
return *this;
}
};
crefbase::_ptr::_ptr (_objptr owner, _objptr target)
{
if (target.operator-> () == NULL)
target = &crefbase::no_target;
target->_add (this, owner);
}
crefbase::_ptr::~_ptr ()
{
_target ()->_remove (this);
}
// Using the copy constructor is a problem, because the owner is not given.
// So it really shouldn't be used, but it's unacceptable to forbid passing
// crefptrs as function arguments. So we assume that the copy constructor
// will not be used in other places, and set the owner to NULL.
crefbase::_ptr::_ptr (_ptr const &that)
{
_objptr target = that._target ();
target->_add (this, NULL);
}
crefbase::_ptr &crefbase::_ptr::operator= (_ptr const &that)
{
_objptr target = that._target ();
if (target.operator-> () == _target ().operator-> ())
return *this;
_objptr owner = _owner ();
_target ()->_remove (this);
target->_add (this, owner);
return *this;
}
void crefbase::_ptr::reset ()
{
if (_target ().operator-> () == &crefbase::no_target)
return;
_objptr owner = _owner ();
_target ()->_remove (this);
crefbase::no_target._add (this, owner);
}
void crefbase::_ptr::set_owner (crefbase *owner)
{
_owner () = owner;
_target ()->_check ();
}
}
#endif
|