diff options
Diffstat (limited to 'src/gc-anchored.h')
-rw-r--r-- | src/gc-anchored.h | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/src/gc-anchored.h b/src/gc-anchored.h new file mode 100644 index 0000000..8a7b2d7 --- /dev/null +++ b/src/gc-anchored.h @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Authors: + * MenTaLguY <mental@rydia.net> + * * Copyright (C) 2004 MenTaLguY + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#ifndef SEEN_INKSCAPE_GC_ANCHORED_H +#define SEEN_INKSCAPE_GC_ANCHORED_H + +#include "inkgc/gc-managed.h" + +namespace Inkscape { + +namespace GC { + +/** + * A base class for anchored objects. + * + * Objects are managed by our mark-and-sweep collector, but are anchored + * against garbage collection so long as their reference count is nonzero. + * + * Object and member destructors will not be called on destruction + * unless a subclass also inherits from Inkscape::GC::Finalized. + * + * New instances of anchored objects should be created using the C++ new + * operator. Under normal circumstances they should not be created on + * the stack. + * + * A newly created anchored object begins with a refcount of one, and + * will not be collected unless the refcount is zero. + * + * NOTE: If you create an object yourself, it is already anchored for + * you. You do not need to anchor it a second time. + * + * Note that a cycle involving an anchored object (with nonzero refcount) + * cannot be collected. To avoid this, don't increment refcounts for + * pointers between two GC-managed objects. + * + * @see Inkscape::GC::Managed + * @see Inkscape::GC::Finalized + * @see Inkscape::GC::anchor + * @see Inkscape::GC::release + */ + +class Anchored { +public: + void anchor() const; + void release() const; + + // for debugging + unsigned _anchored_refcount() const { + return ( _anchor ? _anchor->refcount : 0 ); + } + + Anchored(Anchored const &) = delete; // no copy + void operator=(Anchored const &) = delete; // no assign + +protected: + Anchored() : _anchor(nullptr) { anchor(); } // initial refcount of one + virtual ~Anchored() = default; + +private: + struct Anchor : public Managed<SCANNED, MANUAL> { + Anchor() : refcount(0),base(nullptr) {} + Anchor(Anchored const *obj) : refcount(0) { + base = Core::base(const_cast<Anchored *>(obj)); + } + int refcount; + void *base; + }; + + mutable Anchor *_anchor; + + Anchor *_new_anchor() const; + void _free_anchor(Anchor *anchor) const; +}; + +/** + * @brief Increments the reference count of a anchored object. + * + * This function template generates functions which take + * a reference to a anchored object of a given type, increment + * that object's reference count, and return a reference to the + * object of the same type as the function's parameter. + * + * @param m a reference to a anchored object + * + * @return the reference to the object + */ +template <typename R> +static R &anchor(R &r) { + static_cast<Anchored const &>(const_cast<R const &>(r)).anchor(); + return r; +} + +/** + * @brief Increments the reference count of a anchored object. + * + * This function template generates functions which take + * a pointer to a anchored object of a given type, increment + * that object's reference count, and return a pointer to the + * object of the same type as the function's parameter. + * + * @param m a pointer to anchored object + * + * @return the pointer to the object + */ +template <typename R> +static R *anchor(R *r) { + static_cast<Anchored const *>(const_cast<R const *>(r))->anchor(); + return r; +} + +/** + * @brief Decrements the reference count of a anchored object. + * + * This function template generates functions which take + * a reference to a anchored object of a given type, increment + * that object's reference count, and return a reference to the + * object of the same type as the function's parameter. + * + * The return value is safe to use since the object, even if + * its refcount has reached zero, will not actually be collected + * until there are no references to it in local variables or + * parameters. + * + * @param m a reference to a anchored object + * + * @return the reference to the object + */ +template <typename R> +static R &release(R &r) { + static_cast<Anchored const &>(const_cast<R const &>(r)).release(); + return r; +} + +/** + * @brief Decrements the reference count of a anchored object. + * + * This function template generates functions which take + * a pointer to a anchored object of a given type, increment + * that object's reference count, and return a pointer to the + * object of the same type as the function's parameter. + * + * The return value is safe to use since the object, even if + * its refcount has reached zero, will not actually be collected + * until there are no references to it in local variables or + * parameters. + * + * @param m a pointer to a anchored object + * + * @return the pointer to the object + */ +template <typename R> +static R *release(R *r) { + static_cast<Anchored const *>(const_cast<R const *>(r))->release(); + return r; +} + +} + +} + +#endif +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : |