1/* grefcount.h: Reference counting
2 *
3 * Copyright 2018 Emmanuele Bassi
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __GREFCOUNT_H__
22#define __GREFCOUNT_H__
23
24#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
25#error "Only <glib.h> can be included directly."
26#endif
27
28#include <glib/gatomic.h>
29#include <glib/gtypes.h>
30
31G_BEGIN_DECLS
32
33GLIB_AVAILABLE_IN_2_58
34void g_ref_count_init (grefcount *rc);
35GLIB_AVAILABLE_IN_2_58
36void g_ref_count_inc (grefcount *rc);
37GLIB_AVAILABLE_IN_2_58
38gboolean g_ref_count_dec (grefcount *rc);
39GLIB_AVAILABLE_IN_2_58
40gboolean g_ref_count_compare (grefcount *rc,
41 gint val);
42
43GLIB_AVAILABLE_IN_2_58
44void g_atomic_ref_count_init (gatomicrefcount *arc);
45GLIB_AVAILABLE_IN_2_58
46void g_atomic_ref_count_inc (gatomicrefcount *arc);
47GLIB_AVAILABLE_IN_2_58
48gboolean g_atomic_ref_count_dec (gatomicrefcount *arc);
49GLIB_AVAILABLE_IN_2_58
50gboolean g_atomic_ref_count_compare (gatomicrefcount *arc,
51 gint val);
52
53/**
54 * G_REF_COUNT_INIT:
55 *
56 * Evaluates to the initial reference count for `grefcount`.
57 *
58 * This macro is useful for initializing `grefcount` fields inside
59 * structures, for instance:
60 *
61 * |[<!-- language="C" -->
62 * typedef struct {
63 * grefcount ref_count;
64 * char *name;
65 * char *address;
66 * } Person;
67 *
68 * static const Person default_person = {
69 * .ref_count = G_REF_COUNT_INIT,
70 * .name = "Default name",
71 * .address = "Default address",
72 * };
73 * ]|
74 *
75 * Since: 2.78
76 */
77#define G_REF_COUNT_INIT -1 \
78 GLIB_AVAILABLE_MACRO_IN_2_78
79
80/**
81 * G_ATOMIC_REF_COUNT_INIT:
82 *
83 * Evaluates to the initial reference count for `gatomicrefcount`.
84 *
85 * This macro is useful for initializing `gatomicrefcount` fields inside
86 * structures, for instance:
87 *
88 * |[<!-- language="C" -->
89 * typedef struct {
90 * gatomicrefcount ref_count;
91 * char *name;
92 * char *address;
93 * } Person;
94 *
95 * static const Person default_person = {
96 * .ref_count = G_ATOMIC_REF_COUNT_INIT,
97 * .name = "Default name",
98 * .address = "Default address",
99 * };
100 * ]|
101 *
102 * Since: 2.78
103 */
104#define G_ATOMIC_REF_COUNT_INIT 1 \
105 GLIB_AVAILABLE_MACRO_IN_2_78
106
107/* On GCC we can use __extension__ to inline the API without using
108 * ancillary functions; we only do this when disabling checks, as
109 * it disables warnings when saturating the reference counters
110 */
111#if defined(__GNUC__) && defined(G_DISABLE_CHECKS)
112
113# define g_ref_count_init(rc) \
114 (G_GNUC_EXTENSION ({ \
115 G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
116 (void) (0 ? *(rc) ^ *(rc) : 1); \
117 *(rc) = -1; \
118 }))
119
120# define g_ref_count_inc(rc) \
121 (G_GNUC_EXTENSION ({ \
122 G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
123 (void) (0 ? *(rc) ^ *(rc) : 1); \
124 if (*(rc) == G_MININT) ; else { \
125 *(rc) -= 1; \
126 } \
127 }))
128
129# define g_ref_count_dec(rc) \
130 (G_GNUC_EXTENSION ({ \
131 G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
132 grefcount __rc = *(rc); \
133 __rc += 1; \
134 if (__rc == 0) ; else { \
135 *(rc) = __rc; \
136 } \
137 (gboolean) (__rc == 0); \
138 }))
139
140# define g_ref_count_compare(rc,val) \
141 (G_GNUC_EXTENSION ({ \
142 G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
143 (void) (0 ? *(rc) ^ (val) : 1); \
144 (gboolean) (*(rc) == -(val)); \
145 }))
146
147# define g_atomic_ref_count_init(rc) \
148 (G_GNUC_EXTENSION ({ \
149 G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
150 (void) (0 ? *(rc) ^ *(rc) : 1); \
151 *(rc) = 1; \
152 }))
153
154# define g_atomic_ref_count_inc(rc) \
155 (G_GNUC_EXTENSION ({ \
156 G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
157 (void) (0 ? *(rc) ^ *(rc) : 1); \
158 (void) (g_atomic_int_get (rc) == G_MAXINT ? 0 : g_atomic_int_inc ((rc))); \
159 }))
160
161# define g_atomic_ref_count_dec(rc) \
162 (G_GNUC_EXTENSION ({ \
163 G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
164 (void) (0 ? *(rc) ^ *(rc) : 1); \
165 g_atomic_int_dec_and_test ((rc)); \
166 }))
167
168# define g_atomic_ref_count_compare(rc,val) \
169 (G_GNUC_EXTENSION ({ \
170 G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
171 (void) (0 ? *(rc) ^ (val) : 1); \
172 (gboolean) (g_atomic_int_get (rc) == (val)); \
173 }))
174
175#endif /* __GNUC__ && G_DISABLE_CHECKS */
176
177G_END_DECLS
178
179#endif /* __GREFCOUNT_H__ */
180