// SPDX-License-Identifier: GPL-2.0-or-later /* * Authors: * MenTaLguY * * 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 { Anchor() : refcount(0),base(nullptr) {} Anchor(Anchored const *obj) : refcount(0) { base = Core::base(const_cast(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 static R &anchor(R &r) { static_cast(const_cast(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 static R *anchor(R *r) { static_cast(const_cast(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 static R &release(R &r) { static_cast(const_cast(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 static R *release(R *r) { static_cast(const_cast(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 :