When g_hash_table_resize() gets called, we clear out tombstones and grow
the table at the same time if needed. However, the threshold was set too
low, so we'd grow if the load was greater than .5 after subtracting
tombstones. Increase this threshold to ~.75.
When resizing, we were keeping both the old and new hash, key and value
arrays around while we reinserted entries, resulting in a peak memory
overhead of 50%. Using a temporary bookkeeping array with one bit per
entry we can now grow and shrink the main arrays using realloc() and an
eviction scheme, reducing the overhead to .625% (assuming 64-bit keys and
values). Tests show the CPU overhead is negligible.
If int is smaller than void * on our arch, we start out with
int-sized keys and values and resize to pointer-sized entries as
needed. This saves a good amount of memory when the HT is being
used with e.g. GUINT_TO_POINTER().
Even if we're using a prime modulo for the initial probe, our table is
power-of-two-sized, meaning we can set the mask simply by subtracting one
from the size.
Sequential integers would be densely packed in the table, leaving the
high-index buckets unused and causing abnormally long probes for many
operations. This was especially noticeable with failed lookups and
when "aging" the table by repeatedly inserting and removing integers
from a narrow range using g_direct_hash() as the hashing function.
The solution is to multiply the hash by a small prime before applying
the modulo. The compiler optimizes this to a few left shifts and adds, so
the constant overhead is small, and the entries will be spread out,
yielding a lower average probe count.
If the given key is not found, clear the orig_key and value arguments to
NULL as well as returning FALSE. Then the caller can unconditionally
check them.
This makes the behaviour of g_hash_table_lookup_extended() consistent
with g_hash_table_steal_extended().
Signed-off-by: Philip Withnall <withnall@endlessm.com>
People do (and should) use g_str_equal() for string comparisons outside
of hash tables, because it’s easier to read than
`strcmp (str1, str2) == 0`. That should not be discouraged.
However, we should still be careful to point out that g_str_equal() is
not NULL-safe, and g_strcmp0() is.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
This is a combination of g_hash_table_lookup_extended() and
g_hash_table_steal(), so that users can combine the two to reduce code
and eliminate a pointless second hash table lookup by
g_hash_table_steal().
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=795302
The return value of the g_hash_table_add(), g_hash_table_insert(), and
g_hash_table_replace() functions was changed from void to gboolean in
GLib 2.40, but it was not mentioned in the API reference or the release
notes.
https://bugzilla.gnome.org/show_bug.cgi?id=793300
gtk-doc doesn’t support them any more since it was ported to Markdown,
so they end up appearing in the generated documentation, which isn’t
great.
Mostly, they were used to split up things invisibly, which we can do in
other ways.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Reviewed-by: nobody
All glib/*.{c,h} files have been processed, as well as gtester-report.
12 of those files are not licensed under LGPL:
gbsearcharray.h
gconstructor.h
glibintl.h
gmirroringtable.h
gscripttable.h
gtranslit-data.h
gunibreak.h
gunichartables.h
gunicomp.h
gunidecomp.h
valgrind.h
win_iconv.c
Some of them are generated files, some are licensed under a BSD-style
license and win_iconv.c is in the public domain.
Sub-directories inside glib/:
deprecated/: processed in a previous commit
glib-mirroring-tab/: already LGPLv2.1+
gnulib/: not modified, the code is copied from gnulib
libcharset/: a copy
pcre/: a copy
tests/: processed in a previous commit
https://bugzilla.gnome.org/show_bug.cgi?id=776504
There are a few places where commit 18a33f72 replaced valid (nullable)
(optional) annotations with just (optional). That has a different
meaning.
(nullable) (optional) can only be applied to gpointer* parameters, and
means that both the gpointer* and returned gpointer can be NULL. i.e.
The caller can pass in NULL to ignore the return value; and the returned
value can be NULL.
(optional) can be applied to anything* parameters, and means that the
anything* can be NULL. i.e. The caller can pass in NULL to ignore the
return value. The return value cannot be NULL.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
If we have an input parameter (or return value) we need to use (nullable).
However, if it is an (inout) or (out) parameter, (optional) is sufficient.
It looks like (nullable) could be used for everything according to the
Annotation documentation, but (optional) is more specific.
Add various (nullable) and (optional) annotations which were missing
from a variety of functions. Also port a couple of existing (allow-none)
annotations in the same files to use (nullable) and (optional) as
appropriate instead.
Secondly, add various (not nullable) annotations as needed by the new
default in gobject-introspection of marking gpointers as (nullable). See
https://bugzilla.gnome.org/show_bug.cgi?id=729660.
This includes adding some stub documentation comments for the
assertion macro error functions, which weren’t previously documented.
The new comments are purely to allow for annotations, and hence are
marked as (skip) to prevent the symbols appearing in the GIR file.
https://bugzilla.gnome.org/show_bug.cgi?id=719966
We should not advise people to cast the result of
g_hash_table_get_keys_as_array() to a type that looks suitable for use
with g_strfreev(). Advise to use (const gchar **) instead.
With this patch it is fine to call g_hash_table_lookup and
g_hash_table_remove from destroy notification functions. Before
this could lead to an infinitie loop if g_hash_table_remove_all
was used.
https://bugzilla.gnome.org/show_bug.cgi?id=695082
Since we are no longer using sgml mode, using /* */ to
escape block comments inside examples does not work anymore.
Switch to using line comments with //
GHashTable remains a set for as long as all of the keys are exactly
equal (in pointer value) to all of the values. We check this by
comparing keys to values when we do inserts.
Unfortunately, when doing g_hash_table_insert() when a key is already in
the table, the old key pointer value is kept, but the new value pointer
is used. Now we have a situation where a key pointer is unequal to a
value pointer, but we were not treating this case properly.
Fix that.
https://bugzilla.gnome.org/show_bug.cgi?id=692815
When G_DISABLE_ASSERT is not defined, g_hash_table_foreach and
g_hash_table_find dereferences the hash table argument before
checking if it's NULL. This causes a crash when one of this function
is mistakenly called with a NULL argument instead of returning
with a warning through g_return_if_fail.