Imported Upstream version 2.74.3
[platform/upstream/glib.git] / glib / grefstring.c
1 /* grefstring.c: Reference counted strings
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 /**
22  * SECTION:refstring
23  * @Title: Reference counted strings
24  * @Short_description: Strings with reference counted memory management
25  *
26  * Reference counted strings are normal C strings that have been augmented
27  * with a reference counter to manage their resources. You allocate a new
28  * reference counted string and acquire and release references as needed,
29  * instead of copying the string among callers; when the last reference on
30  * the string is released, the resources allocated for it are freed.
31  *
32  * Typically, reference counted strings can be used when parsing data from
33  * files and storing them into data structures that are passed to various
34  * callers:
35  *
36  * |[<!-- language="C" -->
37  * PersonDetails *
38  * person_details_from_data (const char *data)
39  * {
40  *   // Use g_autoptr() to simplify error cases
41  *   g_autoptr(GRefString) full_name = NULL;
42  *   g_autoptr(GRefString) address =  NULL;
43  *   g_autoptr(GRefString) city = NULL;
44  *   g_autoptr(GRefString) state = NULL;
45  *   g_autoptr(GRefString) zip_code = NULL;
46  *
47  *   // parse_person_details() is defined elsewhere; returns refcounted strings
48  *   if (!parse_person_details (data, &full_name, &address, &city, &state, &zip_code))
49  *     return NULL;
50  *
51  *   if (!validate_zip_code (zip_code))
52  *     return NULL;
53  *
54  *   // add_address_to_cache() and add_full_name_to_cache() are defined
55  *   // elsewhere; they add strings to various caches, using refcounted
56  *   // strings to avoid copying data over and over again
57  *   add_address_to_cache (address, city, state, zip_code);
58  *   add_full_name_to_cache (full_name);
59  *
60  *   // person_details_new() is defined elsewhere; it takes a reference
61  *   // on each string
62  *   PersonDetails *res = person_details_new (full_name,
63  *                                            address,
64  *                                            city,
65  *                                            state,
66  *                                            zip_code);
67  *
68  *   return res;
69  * }
70  * ]|
71  *
72  * In the example above, we have multiple functions taking the same strings
73  * for different uses; with typical C strings, we'd have to copy the strings
74  * every time the life time rules of the data differ from the life time of
75  * the string parsed from the original buffer. With reference counted strings,
76  * each caller can take a reference on the data, and keep it as long as it
77  * needs to own the string.
78  *
79  * Reference counted strings can also be "interned" inside a global table
80  * owned by GLib; while an interned string has at least a reference, creating
81  * a new interned reference counted string with the same contents will return
82  * a reference to the existing string instead of creating a new reference
83  * counted string instance. Once the string loses its last reference, it will
84  * be automatically removed from the global interned strings table.
85  *
86  * Since: 2.58
87  */
88
89 #include "config.h"
90
91 #include "grefstring.h"
92
93 #include "ghash.h"
94 #include "gmessages.h"
95 #include "grcbox.h"
96 #include "gthread.h"
97
98 #include <string.h>
99
100 /* A global table of refcounted strings; the hash table does not own
101  * the strings, just a pointer to them. Strings are interned as long
102  * as they are alive; once their reference count drops to zero, they
103  * are removed from the table
104  */
105 G_LOCK_DEFINE_STATIC (interned_ref_strings);
106 static GHashTable *interned_ref_strings;
107
108 /**
109  * g_ref_string_new:
110  * @str: (not nullable): a NUL-terminated string
111  *
112  * Creates a new reference counted string and copies the contents of @str
113  * into it.
114  *
115  * Returns: (transfer full) (not nullable): the newly created reference counted string
116  *
117  * Since: 2.58
118  */
119 char *
120 g_ref_string_new (const char *str)
121 {
122   char *res;
123   gsize len;
124
125   g_return_val_if_fail (str != NULL, NULL);
126   
127   len = strlen (str);
128   
129   res = (char *) g_atomic_rc_box_dup (sizeof (char) * len + 1, str);
130
131   return res;
132 }
133
134 /**
135  * g_ref_string_new_len:
136  * @str: (not nullable): a string
137  * @len: length of @str to use, or -1 if @str is nul-terminated
138  *
139  * Creates a new reference counted string and copies the contents of @str
140  * into it, up to @len bytes.
141  *
142  * Since this function does not stop at nul bytes, it is the caller's
143  * responsibility to ensure that @str has at least @len addressable bytes.
144  *
145  * Returns: (transfer full) (not nullable): the newly created reference counted string
146  *
147  * Since: 2.58
148  */
149 char *
150 g_ref_string_new_len (const char *str, gssize len)
151 {
152   char *res;
153
154   g_return_val_if_fail (str != NULL, NULL);
155
156   if (len < 0)
157     return g_ref_string_new (str);
158
159   /* allocate then copy as str[len] may not be readable */
160   res = (char *) g_atomic_rc_box_alloc ((gsize) len + 1);
161   memcpy (res, str, len);
162   res[len] = '\0';
163
164   return res;
165 }
166
167 /* interned_str_equal: variant of g_str_equal() that compares
168  * pointers as well as contents; this avoids running strcmp()
169  * on arbitrarily long strings, as it's more likely to have
170  * g_ref_string_new_intern() being called on the same refcounted
171  * string instance, than on a different string with the same
172  * contents
173  */
174 static gboolean
175 interned_str_equal (gconstpointer v1,
176                     gconstpointer v2)
177 {
178   const char *str1 = v1;
179   const char *str2 = v2;
180
181   if (v1 == v2)
182     return TRUE;
183
184   return strcmp (str1, str2) == 0;
185 }
186
187 /**
188  * g_ref_string_new_intern:
189  * @str: (not nullable): a NUL-terminated string
190  *
191  * Creates a new reference counted string and copies the content of @str
192  * into it.
193  *
194  * If you call this function multiple times with the same @str, or with
195  * the same contents of @str, it will return a new reference, instead of
196  * creating a new string.
197  *
198  * Returns: (transfer full) (not nullable): the newly created reference
199  *   counted string, or a new reference to an existing string
200  *
201  * Since: 2.58
202  */
203 char *
204 g_ref_string_new_intern (const char *str)
205 {
206   char *res;
207
208   g_return_val_if_fail (str != NULL, NULL);
209
210   G_LOCK (interned_ref_strings);
211
212   if (G_UNLIKELY (interned_ref_strings == NULL))
213     interned_ref_strings = g_hash_table_new (g_str_hash, interned_str_equal);
214
215   res = g_hash_table_lookup (interned_ref_strings, str);
216   if (res != NULL)
217     {
218       /* We acquire the reference while holding the lock, to
219        * avoid a potential race between releasing the lock on
220        * the hash table and another thread releasing the reference
221        * on the same string
222        */
223       g_atomic_rc_box_acquire (res);
224       G_UNLOCK (interned_ref_strings);
225       return res;
226     }
227
228   res = g_ref_string_new (str);
229   g_hash_table_add (interned_ref_strings, res);
230   G_UNLOCK (interned_ref_strings);
231
232   return res;
233 }
234
235 /**
236  * g_ref_string_acquire:
237  * @str: a reference counted string
238  *
239  * Acquires a reference on a string.
240  *
241  * Returns: the given string, with its reference count increased
242  *
243  * Since: 2.58
244  */
245 char *
246 g_ref_string_acquire (char *str)
247 {
248   g_return_val_if_fail (str != NULL, NULL);
249
250   return g_atomic_rc_box_acquire (str);
251 }
252
253 static void
254 remove_if_interned (gpointer data)
255 {
256   char *str = data;
257
258   G_LOCK (interned_ref_strings);
259
260   if (G_LIKELY (interned_ref_strings != NULL))
261     {
262       g_hash_table_remove (interned_ref_strings, str);
263
264       if (g_hash_table_size (interned_ref_strings) == 0)
265         g_clear_pointer (&interned_ref_strings, g_hash_table_destroy);
266     }
267
268   G_UNLOCK (interned_ref_strings);
269 }
270
271 /**
272  * g_ref_string_release:
273  * @str: a reference counted string
274  *
275  * Releases a reference on a string; if it was the last reference, the
276  * resources allocated by the string are freed as well.
277  *
278  * Since: 2.58
279  */
280 void
281 g_ref_string_release (char *str)
282 {
283   g_return_if_fail (str != NULL);
284
285   g_atomic_rc_box_release_full (str, remove_if_interned);
286 }
287
288 /**
289  * g_ref_string_length:
290  * @str: a reference counted string
291  *
292  * Retrieves the length of @str.
293  *
294  * Returns: the length of the given string, in bytes
295  *
296  * Since: 2.58
297  */
298 gsize
299 g_ref_string_length (char *str)
300 {
301   g_return_val_if_fail (str != NULL, 0);
302
303   return g_atomic_rc_box_get_size (str) - 1;
304 }