summaryrefslogtreecommitdiffstats
path: root/src/gc-anchored.h
blob: 8a7b2d765c45eeddf847aa0baabd239faabc25b2 (plain)
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
// 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 :