scan-build thinks there can be a `NULL` pointer dereference in `while
((i = N_NODES (node->left)) != pos)`, if `node` is `NULL`.
`node` cannot be `NULL`, though, assuming the `n_nodes` member of each
node in the tree is an accurate count of the number of nodes beneath
that point. It controls the tree descent and avoids trying to descend
beneath a leaf.
A static analyser can’t know this though, so let’s add an assertion to
help.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Helps: #1767
This reverts commit da7a31a052614edd2cc87518585ff371cbb0f204. The renaming of parameters implicitly introduced "closure" annotations in the documentation which are wrong on callbacks.
The user data parameters in callbacks need to be named user_data to
generate correct closure attributes in the introspection data. This
updates parameters missed in GNOME/glib!2633.
Add SPDX license (but not copyright) headers to all files which follow a
certain pattern in their existing non-machine-readable header comment.
This commit was entirely generated using the command:
```
git ls-files glib/*.[ch] | xargs perl -0777 -pi -e 's/\n \*\n \* This library is free software; you can redistribute it and\/or\n \* modify it under the terms of the GNU Lesser General Public/\n \*\n \* SPDX-License-Identifier: LGPL-2.1-or-later\n \*\n \* This library is free software; you can redistribute it and\/or\n \* modify it under the terms of the GNU Lesser General Public/igs'
```
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #1415
../glib/gsequence.c: In function 'g_sequence_move_range':
../glib/gsequence.c:640:24: warning:
'dest_seq' may be used uninitialized in this function [-Wmaybe-uninitialized]
640 | if (dest && dest_seq == src_seq &&
| ~~~~~~~~~^~~~~~~~~~
Previously, priority was not randomly generated and was instead derived
from `GSequenceNode*` pointer value.
As a result, when a `GSequence` was freed and another was created, the
nodes were returned to memory allocator in such order that allocating
them again caused various performance problems in treap.
To my understanding, the problem develops like this :
1) Initially, memory allocator makes some nodes
2) For each node, priority is derived from pointer alone.
Due to the hash function, initially the priorities are reasonably
randomly distributed.
3) `GSequence` moves inserted nodes around to satisfy treap property.
The priority for node must be >= than priorities of its children
4) When `GSequence` is freed, it frees nodes in a new order.
It finds root node and then recursively frees left/right children.
Due to (3), hashes of freed nodes become partially ordered.
Note that this doesn't depend on choice of hash function.
5) Memory allocator will typically add freed chunks to free list.
This means that it will reallocate nodes in same or inverse order.
6) This results in order of hashes being more and more non-random.
7) This order happens to be increasingly anti-optimal.
That is, `GSequence` needs more `node_rotate` to maintain treap.
This also causes the tree to become more and more unbalanced.
The problem becomes worse with each iteration.
The solution is to use additional noise to maintain reasonable
randomness. This prevents "poisoning" the memory allocator.
On top of that, this patch somehow decreases average tree's height,
which is good because it speeds up various operations. I can't quite
explain why the height decreases with new code, probably the properties
of old hash function didn't quite match the needs of treap?
My averaged results for tree height with different sequence lengths:
Items | before| after |
--------+-------+---------------+
2 | 2,69 | 2,67 -00,74% |
4 | 3,71 | 3,80 +02,43% |
8 | 5,30 | 5,34 +00,75% |
16 | 7,45 | 7,22 -03,09% |
32 | 10,05 | 9,38 -06,67% |
64 | 12,97 | 11,72 -09,64% |
128 | 16,01 | 14,20 -11,31% |
256 | 19,11 | 16,77 -12,24% |
512 | 22,03 | 19,39 -11,98% |
1024 | 25,29 | 22,03 -12,89% |
2048 | 28,43 | 24,82 -12,70% |
4096 | 31,11 | 27,52 -11,54% |
8192 | 34,31 | 30,30 -11,69% |
16384 | 37,40 | 32,81 -12,27% |
32768 | 40,40 | 35,84 -11,29% |
65536 | 43,00 | 38,24 -11,07% |
131072 | 45,50 | 40,83 -10,26% |
262144 | 48,40 | 43,00 -11,16% |
524288 | 52,40 | 46,80 -10,69% |
The memory cost of the patch is zero on 64-bit, because the new field
uses the alignment hole between two other fields.
Note: priorities can sometimes have collisions. This is fine, because
treap allows equal priorities, but these will gradually decrease
performance. The hash function that was used previously has just one
collision on 0xbfff7fff in 32-bit space, but such pointer will not
occur because `g_slice_alloc()` always aligns to sizeof(void*).
However, in 64-bit space the old hash function had collisions anyway,
because it only uses lower 32 bits of pointer.
Closes#2468
It was documented at strange places: in g_sequence_search*() and
g_sequence_lookup*(), but how to insert and sort data is not done by
those functions.
So instead, add the information to the class description (since it
involves several functions), and add also the information in
g_sequence_insert_sorted() and g_sequence_insert_sorted_iter() as a kind
of warning when using those functions.
Note that before this commit, it was not explained *why* it is better to
call g_sequence_sort() after doing a lot of unsorted insertions. Now it
is documented as "more efficient" (I think it's the only reason that
makes sense, otherwise why was it documented?).
https://bugzilla.gnome.org/show_bug.cgi?id=792455
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
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.
Instead of finding the GSequence, just walk up
the tree and determine if the iter is the end node.
https://bugzilla.gnome.org/show_bug.cgi?id=749583
Signed-off-by: Garrett Regier <garrettregier@gmail.com>
This function provides an O(1) check to determine if a sequence is empty.
Compare this to the two following alternatives to perform the same check.
O(h): if (0 == g_sequence_get_length (seq))
O(2h): if (g_sequence_get_begin_iter(seq) == g_sequence_get_end_iter(seq))
Where `h' is the height of the tree.
https://bugzilla.gnome.org/show_bug.cgi?id=756316
g_sequence_lookup() only works on sorted sequences, but it's quite easy
to create unsorted sequences. Add a note to the documentation that the
sequence must be sorted in order for g_sequence_lookup() to work.
https://bugzilla.gnome.org/show_bug.cgi?id=670969
2008-01-18 Murray Cumming <murrayc@murrayc.com>
* glib/gfileutils.c:
* glib/gsequence.c:
* glib/gstring.c: Fixed some minor typos in the documentation.
svn path=/trunk/; revision=6332