1 /* grefstring.c: Reference counted strings
3 * Copyright 2018 Emmanuele Bassi
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 * @Title: Reference counted strings
22 * @Short_description: Strings with reference counted memory management
24 * Reference counted strings are normal C strings that have been augmented
25 * with a reference counter to manage their resources. You allocate a new
26 * reference counted string and acquire and release references as needed,
27 * instead of copying the string among callers; when the last reference on
28 * the string is released, the resources allocated for it are freed.
30 * Typically, reference counted strings can be used when parsing data from
31 * files and storing them into data structures that are passed to various
34 * |[<!-- language="C" -->
36 * person_details_from_data (const char *data)
38 * // Use g_autoptr() to simplify error cases
39 * g_autoptr(GRefString) full_name = NULL;
40 * g_autoptr(GRefString) address = NULL;
41 * g_autoptr(GRefString) city = NULL;
42 * g_autoptr(GRefString) state = NULL;
43 * g_autoptr(GRefString) zip_code = NULL;
45 * // parse_person_details() is defined elsewhere; returns refcounted strings
46 * if (!parse_person_details (data, &full_name, &address, &city, &state, &zip_code))
49 * if (!validate_zip_code (zip_code))
52 * // add_address_to_cache() and add_full_name_to_cache() are defined
53 * // elsewhere; they add strings to various caches, using refcounted
54 * // strings to avoid copying data over and over again
55 * add_address_to_cache (address, city, state, zip_code);
56 * add_full_name_to_cache (full_name);
58 * // person_details_new() is defined elsewhere; it takes a reference
60 * PersonDetails *res = person_details_new (full_name,
70 * In the example above, we have multiple functions taking the same strings
71 * for different uses; with typical C strings, we'd have to copy the strings
72 * every time the life time rules of the data differ from the life time of
73 * the string parsed from the original buffer. With reference counted strings,
74 * each caller can take a reference on the data, and keep it as long as it
75 * needs to own the string.
77 * Reference counted strings can also be "interned" inside a global table
78 * owned by GLib; while an interned string has at least a reference, creating
79 * a new interned reference counted string with the same contents will return
80 * a reference to the existing string instead of creating a new reference
81 * counted string instance. Once the string loses its last reference, it will
82 * be automatically removed from the global interned strings table.
89 #include "grefstring.h"
92 #include "gmessages.h"
98 /* A global table of refcounted strings; the hash table does not own
99 * the strings, just a pointer to them. Strings are interned as long
100 * as they are alive; once their reference count drops to zero, they
101 * are removed from the table
103 G_LOCK_DEFINE_STATIC (interned_ref_strings
);
104 static GHashTable
*interned_ref_strings
;
108 * @str: (not nullable): a NUL-terminated string
110 * Creates a new reference counted string and copies the contents of @str
113 * Returns: (transfer full) (not nullable): the newly created reference counted string
118 g_ref_string_new (const char *str
)
123 g_return_val_if_fail (str
!= NULL
, NULL
);
127 res
= (char *) g_atomic_rc_box_dup (sizeof (char) * len
+ 1, str
);
134 * g_ref_string_new_len:
135 * @str: (not nullable): a string
136 * @len: length of @str to use, or -1 if @str is nul-terminated
138 * Creates a new reference counted string and copies the contents of @str
139 * into it, up to @len bytes.
141 * Since this function does not stop at nul bytes, it is the caller's
142 * responsibility to ensure that @str has at least @len addressable bytes.
144 * Returns: (transfer full) (not nullable): the newly created reference counted string
149 g_ref_string_new_len (const char *str
, gssize len
)
153 g_return_val_if_fail (str
!= NULL
, NULL
);
156 return g_ref_string_new (str
);
158 /* allocate then copy as str[len] may not be readable */
159 res
= (char *) g_atomic_rc_box_alloc ((gsize
) len
+ 1);
160 memcpy (res
, str
, len
);
166 /* interned_str_equal: variant of g_str_equal() that compares
167 * pointers as well as contents; this avoids running strcmp()
168 * on arbitrarily long strings, as it's more likely to have
169 * g_ref_string_new_intern() being called on the same refcounted
170 * string instance, than on a different string with the same
174 interned_str_equal (gconstpointer v1
,
177 const char *str1
= v1
;
178 const char *str2
= v2
;
183 return strcmp (str1
, str2
) == 0;
187 * g_ref_string_new_intern:
188 * @str: (not nullable): a NUL-terminated string
190 * Creates a new reference counted string and copies the content of @str
193 * If you call this function multiple times with the same @str, or with
194 * the same contents of @str, it will return a new reference, instead of
195 * creating a new string.
197 * Returns: (transfer full) (not nullable): the newly created reference
198 * counted string, or a new reference to an existing string
203 g_ref_string_new_intern (const char *str
)
207 g_return_val_if_fail (str
!= NULL
, NULL
);
209 G_LOCK (interned_ref_strings
);
211 if (G_UNLIKELY (interned_ref_strings
== NULL
))
212 interned_ref_strings
= g_hash_table_new (g_str_hash
, interned_str_equal
);
214 res
= g_hash_table_lookup (interned_ref_strings
, str
);
217 /* We acquire the reference while holding the lock, to
218 * avoid a potential race between releasing the lock on
219 * the hash table and another thread releasing the reference
222 g_atomic_rc_box_acquire (res
);
223 G_UNLOCK (interned_ref_strings
);
227 res
= g_ref_string_new (str
);
228 g_hash_table_add (interned_ref_strings
, res
);
229 G_UNLOCK (interned_ref_strings
);
235 * g_ref_string_acquire:
236 * @str: a reference counted string
238 * Acquires a reference on a string.
240 * Returns: the given string, with its reference count increased
245 g_ref_string_acquire (char *str
)
247 g_return_val_if_fail (str
!= NULL
, NULL
);
249 return g_atomic_rc_box_acquire (str
);
253 remove_if_interned (gpointer data
)
257 G_LOCK (interned_ref_strings
);
259 if (G_LIKELY (interned_ref_strings
!= NULL
))
261 g_hash_table_remove (interned_ref_strings
, str
);
263 if (g_hash_table_size (interned_ref_strings
) == 0)
264 g_clear_pointer (&interned_ref_strings
, g_hash_table_destroy
);
267 G_UNLOCK (interned_ref_strings
);
271 * g_ref_string_release:
272 * @str: a reference counted string
274 * Releases a reference on a string; if it was the last reference, the
275 * resources allocated by the string are freed as well.
280 g_ref_string_release (char *str
)
282 g_return_if_fail (str
!= NULL
);
284 g_atomic_rc_box_release_full (str
, remove_if_interned
);
288 * g_ref_string_length:
289 * @str: a reference counted string
291 * Retrieves the length of @str.
293 * Returns: the length of the given string, in bytes
298 g_ref_string_length (char *str
)
300 g_return_val_if_fail (str
!= NULL
, 0);
302 return g_atomic_rc_box_get_size (str
) - 1;