mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-03-21 18:01:15 +00:00
[util] Minimize set growth
At the low level, only unions can cause a set to grow. Of course, things get interesting at the higher level when infinite (inverted) sets are mixed in.
This commit is contained in:
parent
37a5b475c0
commit
a01cafe972
3 changed files with 92 additions and 13 deletions
|
@ -162,6 +162,15 @@ void set_delete_r (set_pool_t *set_pool, set_t *set);
|
|||
*/
|
||||
void set_expand (set_t *set, unsigned size);
|
||||
|
||||
/** Shrink the set's backing memory to the minimum required to hold the set.
|
||||
|
||||
This does not affect (nor is affected by) whether the set is an infinite
|
||||
set.
|
||||
|
||||
\param set The set to trim
|
||||
*/
|
||||
void set_trim (set_t *set);
|
||||
|
||||
/** Add an element to a set.
|
||||
|
||||
It is not an error to add an element that is already a member of the set.
|
||||
|
|
|
@ -128,6 +128,30 @@ set_expand (set_t *set, unsigned size)
|
|||
free (map);
|
||||
}
|
||||
|
||||
void
|
||||
set_trim (set_t *set)
|
||||
{
|
||||
if (set->map == set->defmap) {
|
||||
return;
|
||||
}
|
||||
unsigned words = SET_WORDS (set);
|
||||
|
||||
while (words > SET_DEFMAP_SIZE && !set->map[words - 1]) {
|
||||
words--;
|
||||
set->size -= SET_BITS;
|
||||
}
|
||||
if (words > SET_DEFMAP_SIZE) {
|
||||
set_bits_t *map = realloc (set->map, words * sizeof (set_bits_t));
|
||||
if (map && map != set->map) {
|
||||
set->map = map;
|
||||
}
|
||||
} else {
|
||||
memcpy (set->defmap, set->map, sizeof (set->defmap));
|
||||
free (set->map);
|
||||
set->map = set->defmap;
|
||||
}
|
||||
}
|
||||
|
||||
inline set_t *
|
||||
set_new_size_r (set_pool_t *set_pool, unsigned size)
|
||||
{
|
||||
|
@ -204,13 +228,14 @@ _set_union (set_t *dst, const set_t *src)
|
|||
static set_t *
|
||||
_set_intersection (set_t *dst, const set_t *src)
|
||||
{
|
||||
unsigned size;
|
||||
unsigned words;
|
||||
unsigned i;
|
||||
|
||||
size = max (dst->size, src->size);
|
||||
set_expand (dst, size);
|
||||
for (i = 0; i < SET_WORDS (src); i++)
|
||||
words = min (SET_WORDS (dst), SET_WORDS (src));
|
||||
for (i = 0; i < words; i++)
|
||||
dst->map[i] &= src->map[i];
|
||||
// if dst is larger than src, then none of the excess elements in dst
|
||||
// can be in the intersection
|
||||
for ( ; i < SET_WORDS (dst); i++)
|
||||
dst->map[i] = 0;
|
||||
return dst;
|
||||
|
@ -219,26 +244,37 @@ _set_intersection (set_t *dst, const set_t *src)
|
|||
static set_t *
|
||||
_set_difference (set_t *dst, const set_t *src)
|
||||
{
|
||||
unsigned size;
|
||||
unsigned words;
|
||||
unsigned i;
|
||||
|
||||
size = max (dst->size, src->size);
|
||||
set_expand (dst, size);
|
||||
for (i = 0; i < SET_WORDS (src); i++)
|
||||
words = min (SET_WORDS (dst), SET_WORDS (src));
|
||||
for (i = 0; i < words; i++)
|
||||
dst->map[i] &= ~src->map[i];
|
||||
// if src is larger than dst, excess elements in src cannot be in dst thus
|
||||
// there is nothing to remove
|
||||
// if dst is larger than src, there is nothing to remove regardless of what
|
||||
// is in src
|
||||
return dst;
|
||||
}
|
||||
|
||||
static set_t *
|
||||
_set_reverse_difference (set_t *dst, const set_t *src)
|
||||
{
|
||||
unsigned size;
|
||||
unsigned words;
|
||||
unsigned i;
|
||||
|
||||
size = max (dst->size, src->size);
|
||||
set_expand (dst, size);
|
||||
for (i = 0; i < SET_WORDS (src); i++)
|
||||
words = min (SET_WORDS (dst), SET_WORDS (src));
|
||||
set_expand (dst, src->size);
|
||||
for (i = 0; i < words; i++)
|
||||
dst->map[i] = ~dst->map[i] & src->map[i];
|
||||
// if src is larger than dst, then dst cannot remove the excess elements
|
||||
// from src and thus the src elements must be copied
|
||||
for ( ; i < SET_WORDS (src); i++)
|
||||
dst->map[i] = src->map[i];
|
||||
// if dst is larger than src, then the excess elements in dst must be
|
||||
// removed
|
||||
for ( ; i < SET_WORDS (dst); i++)
|
||||
dst->map[i] = 0;
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
|
|
@ -250,7 +250,30 @@ struct {
|
|||
{make_not_1_2, make_0_1, set_union, check_count, 1, "{0 1 3 ...}"},
|
||||
{make_not_1_2, make_0_1, set_intersection, check_count, 1, "{0}"},
|
||||
{make_not_1_2, make_0_1, set_difference, check_count, 3, "{3 ...}"},
|
||||
{make_not_1_2, make_0_1, set_reverse_difference, check_count, 1, "{1}"},
|
||||
{make_not_1_2, make_0_1, set_reverse_difference, check_count, 1, "{1}"},//76
|
||||
{make_SIZE, make_not_1_2, set_union, check_size, SIZE + SET_BITS,
|
||||
"{0 3 ...}"},
|
||||
{make_SIZE, make_not_1_2, set_intersection, check_size, SIZE + SET_BITS,
|
||||
"{64}"},
|
||||
{make_SIZE, make_not_1_2, set_difference, check_size, SIZE + SET_BITS,
|
||||
"{}"},
|
||||
{make_SIZE, make_not_1_2, set_reverse_difference, check_size,
|
||||
SIZE + SET_BITS,
|
||||
"{0 3 4 5 6 7 8 9 10 11 12 13 14 15"
|
||||
" 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31"
|
||||
" 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47"
|
||||
" 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 65 ...}"
|
||||
},//80
|
||||
{make_not_1_2, make_SIZE, set_union, check_size, SIZE, "{0 3 ...}"},
|
||||
{make_not_1_2, make_SIZE, set_intersection, check_size, SIZE + SET_BITS,
|
||||
"{64}"},
|
||||
{make_not_1_2, make_SIZE, set_difference, check_size, SIZE + SET_BITS,
|
||||
"{0 3 4 5 6 7 8 9 10 11 12 13 14 15"
|
||||
" 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31"
|
||||
" 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47"
|
||||
" 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 65 ...}"
|
||||
},
|
||||
{make_not_1_2, make_SIZE, set_reverse_difference, check_size, SIZE, "{}"},
|
||||
};
|
||||
#define num_tests (sizeof (tests) / sizeof (tests[0]))
|
||||
|
||||
|
@ -270,6 +293,8 @@ main (int argc, const char **argv)
|
|||
tests[9].str_expect = tests[5].str_expect;
|
||||
tests[10].str_expect = tests[5].str_expect;
|
||||
tests[11].str_expect = tests[5].str_expect;
|
||||
tests[78].str_expect = tests[5].str_expect;
|
||||
tests[82].str_expect = tests[5].str_expect;
|
||||
|
||||
str = dstring_new ();
|
||||
for (i = 0; i < SIZE; i++) {
|
||||
|
@ -278,6 +303,15 @@ main (int argc, const char **argv)
|
|||
dstring_appendstr (str, "}");
|
||||
tests[6].str_expect = dstring_freeze (str);
|
||||
|
||||
str = dstring_new ();
|
||||
dasprintf (str, "{0");
|
||||
for (i = 3; i < SIZE; i++) {
|
||||
dasprintf (str, " %zd", i);
|
||||
}
|
||||
dasprintf (str, " %zd ...}", SIZE + 1);
|
||||
tests[80].str_expect = dstring_freeze (str);
|
||||
tests[83].str_expect = tests[80].str_expect;
|
||||
|
||||
for (i = 0; i < num_tests; i++) {
|
||||
set_t *s1, *s2 = 0;
|
||||
const char *set_str;
|
||||
|
|
Loading…
Reference in a new issue