mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-18 15:01:41 +00:00
Use set_bits_t for holding set elements.
set_bits_t is now 64 bits for x86_64 machines (in linux, anyway). This gave qfvis a huge speed boost: from ~815s to ~720s. Also, expose some of the set internals so custom set operators can be created.
This commit is contained in:
parent
195bdcb92f
commit
27bb337a60
3 changed files with 72 additions and 58 deletions
|
@ -31,15 +31,32 @@
|
|||
#ifndef __QF_set_h
|
||||
#define __QF_set_h
|
||||
|
||||
#include "QF/qtypes.h"
|
||||
|
||||
/** \defgroup set Set handling
|
||||
\ingroup utils
|
||||
*/
|
||||
//@{
|
||||
|
||||
#define DEFMAP_SIZE ((32 - sizeof (struct set_s *) \
|
||||
- sizeof (unsigned *) \
|
||||
- sizeof (int) - sizeof (unsigned))\
|
||||
/ sizeof (unsigned))
|
||||
//FIXME other archs
|
||||
#ifdef __x86_64__
|
||||
typedef uint64_t set_bits_t;
|
||||
#else
|
||||
typedef uint32_t set_bits_t;
|
||||
#endif
|
||||
|
||||
#define SET_DEFMAP_SIZE ((32 - sizeof (struct set_s *) \
|
||||
- sizeof (set_bits_t *) \
|
||||
- sizeof (int) - sizeof (unsigned))\
|
||||
/ sizeof (set_bits_t))
|
||||
#define SET_BITS (sizeof (set_bits_t) * 8)
|
||||
//NOTE: x is the element number, so size is x + 1
|
||||
#define SET_SIZE(x) (((x) + SET_BITS) & ~(SET_BITS - 1))
|
||||
#define SET_WORDS(s) ((s)->size / SET_BITS)
|
||||
#define SET_ZERO ((set_bits_t) 0)
|
||||
#define SET_ONE ((set_bits_t) 1)
|
||||
#define SET_TEST_MEMBER(s, x) \
|
||||
((s)->map[(x) / SET_BITS] & (SET_ONE << ((x) % SET_BITS)))
|
||||
|
||||
/** Represent a set using a bitmap.
|
||||
|
||||
|
@ -50,10 +67,10 @@
|
|||
*/
|
||||
typedef struct set_s {
|
||||
struct set_s *next; ///< private. for ALLOC
|
||||
unsigned *map; ///< bitmap of set members
|
||||
set_bits_t *map; ///< bitmap of set members
|
||||
int inverted; ///< if true, 0 indicates membership
|
||||
unsigned size; ///< number of representable members
|
||||
unsigned defmap[DEFMAP_SIZE];///< backing store for small sets
|
||||
set_bits_t defmap[SET_DEFMAP_SIZE];///< backing store for small sets
|
||||
} set_t;
|
||||
|
||||
/** Represent the state of a scan through a set.
|
||||
|
|
|
@ -45,8 +45,6 @@
|
|||
#include "QF/mathlib.h"
|
||||
#include "QF/set.h"
|
||||
|
||||
#define BITS (sizeof (((set_t *) 0)->map[0]) * 8)
|
||||
|
||||
set_t *sets_freelist;
|
||||
set_iter_t *set_iters_freelist;
|
||||
|
||||
|
@ -92,16 +90,16 @@ set_delete (set_t *set)
|
|||
static void
|
||||
set_expand (set_t *set, unsigned x)
|
||||
{
|
||||
unsigned *map = set->map;
|
||||
set_bits_t *map = set->map;
|
||||
size_t size;
|
||||
|
||||
if (x <= set->size)
|
||||
return;
|
||||
|
||||
size = (x + BITS) & ~(BITS - 1);
|
||||
size = SET_SIZE (x);
|
||||
set->map = malloc (size / 8);
|
||||
memcpy (set->map, map, set->size / 8);
|
||||
memset (set->map + set->size / BITS, 0, (size - set->size) / 8);
|
||||
memset (set->map + SET_WORDS (set), 0, (size - set->size) / 8);
|
||||
set->size = size;
|
||||
if (map != set->defmap)
|
||||
free (map);
|
||||
|
@ -123,7 +121,7 @@ _set_add (set_t *set, unsigned x)
|
|||
{
|
||||
if (x >= set->size)
|
||||
set_expand (set, x + 1);
|
||||
set->map[x / BITS] |= 1 << (x % BITS);
|
||||
set->map[x / SET_BITS] |= SET_ONE << (x % SET_BITS);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -131,7 +129,7 @@ _set_remove (set_t *set, unsigned x)
|
|||
{
|
||||
if (x >= set->size)
|
||||
return;
|
||||
set->map[x / BITS] &= ~(1 << (x % BITS));
|
||||
set->map[x / SET_BITS] &= ~(SET_ONE << (x % SET_BITS));
|
||||
}
|
||||
|
||||
set_t *
|
||||
|
@ -169,7 +167,7 @@ _set_union (set_t *dst, const set_t *src)
|
|||
|
||||
size = max (dst->size, src->size);
|
||||
set_expand (dst, size);
|
||||
for (i = 0; i < src->size / BITS; i++)
|
||||
for (i = 0; i < SET_WORDS (src); i++)
|
||||
dst->map[i] |= src->map[i];
|
||||
return dst;
|
||||
}
|
||||
|
@ -182,9 +180,9 @@ _set_intersection (set_t *dst, const set_t *src)
|
|||
|
||||
size = max (dst->size, src->size);
|
||||
set_expand (dst, size);
|
||||
for (i = 0; i < src->size / BITS; i++)
|
||||
for (i = 0; i < SET_WORDS (src); i++)
|
||||
dst->map[i] &= src->map[i];
|
||||
for ( ; i < dst->size / BITS; i++)
|
||||
for ( ; i < SET_WORDS (dst); i++)
|
||||
dst->map[i] = 0;
|
||||
return dst;
|
||||
}
|
||||
|
@ -197,7 +195,7 @@ _set_difference (set_t *dst, const set_t *src)
|
|||
|
||||
size = max (dst->size, src->size);
|
||||
set_expand (dst, size);
|
||||
for (i = 0; i < src->size / BITS; i++)
|
||||
for (i = 0; i < SET_WORDS (src); i++)
|
||||
dst->map[i] &= ~src->map[i];
|
||||
return dst;
|
||||
}
|
||||
|
@ -210,7 +208,7 @@ _set_reverse_difference (set_t *dst, const set_t *src)
|
|||
|
||||
size = max (dst->size, src->size);
|
||||
set_expand (dst, size);
|
||||
for (i = 0; i < src->size / BITS; i++)
|
||||
for (i = 0; i < SET_WORDS (src); i++)
|
||||
dst->map[i] = ~dst->map[i] & src->map[i];
|
||||
return dst;
|
||||
}
|
||||
|
@ -286,9 +284,9 @@ set_assign (set_t *dst, const set_t *src)
|
|||
size = max (dst->size, src->size);
|
||||
set_expand (dst, size);
|
||||
dst->inverted = src->inverted;
|
||||
for (i = 0; i < src->size / BITS; i++)
|
||||
for (i = 0; i < SET_WORDS (src); i++)
|
||||
dst->map[i] = src->map[i];
|
||||
for ( ; i < dst->size / BITS; i++)
|
||||
for ( ; i < SET_WORDS (dst); i++)
|
||||
dst->map[i] = 0;
|
||||
return dst;
|
||||
}
|
||||
|
@ -299,7 +297,7 @@ set_empty (set_t *set)
|
|||
unsigned i;
|
||||
|
||||
set->inverted = 0;
|
||||
for (i = 0; i < set->size / BITS; i++)
|
||||
for (i = 0; i < SET_WORDS (set); i++)
|
||||
set->map[i] = 0;
|
||||
return set;
|
||||
}
|
||||
|
@ -310,7 +308,7 @@ set_everything (set_t *set)
|
|||
unsigned i;
|
||||
|
||||
set->inverted = 1;
|
||||
for (i = 0; i < set->size / BITS; i++)
|
||||
for (i = 0; i < SET_WORDS (set); i++)
|
||||
set->map[i] = 0;
|
||||
return set;
|
||||
}
|
||||
|
@ -320,7 +318,7 @@ _set_is_empty (const set_t *set)
|
|||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < set->size / BITS; i++)
|
||||
for (i = 0; i < SET_WORDS (set); i++)
|
||||
if (set->map[i])
|
||||
return 0;
|
||||
return 1;
|
||||
|
@ -346,21 +344,21 @@ static int
|
|||
set_test_n_n (const set_t *s1, const set_t *s2)
|
||||
{
|
||||
unsigned i, end;
|
||||
unsigned intersection = 0;
|
||||
unsigned difference = 0;
|
||||
set_bits_t intersection = 0;
|
||||
set_bits_t difference = 0;
|
||||
|
||||
end = min (s1->size, s2->size) / BITS;
|
||||
end = min (s1->size, s2->size) / SET_BITS;
|
||||
for (i = 0; i < end; i++) {
|
||||
unsigned m1 = s1->map[i];
|
||||
unsigned m2 = s2->map[i];
|
||||
set_bits_t m1 = s1->map[i];
|
||||
set_bits_t m2 = s2->map[i];
|
||||
|
||||
intersection |= m1 & m2;
|
||||
difference |= m1 ^ m2;
|
||||
}
|
||||
for ( ; i < s1->size / BITS; i++) {
|
||||
for ( ; i < SET_WORDS (s1); i++) {
|
||||
difference |= s1->map[i];
|
||||
}
|
||||
for ( ; i < s2->size / BITS; i++) {
|
||||
for ( ; i < SET_WORDS (s2); i++) {
|
||||
difference |= s2->map[i];
|
||||
}
|
||||
return (difference != 0) | ((intersection != 0) << 1);
|
||||
|
@ -370,22 +368,22 @@ static int
|
|||
set_test_n_i (const set_t *s1, const set_t *s2)
|
||||
{
|
||||
unsigned i, end;
|
||||
unsigned intersection = 0;
|
||||
unsigned difference = 0;
|
||||
set_bits_t intersection = 0;
|
||||
set_bits_t difference = 0;
|
||||
|
||||
end = min (s1->size, s2->size) / BITS;
|
||||
end = min (s1->size, s2->size) / SET_BITS;
|
||||
for (i = 0; i < end; i++) {
|
||||
unsigned m1 = s1->map[i];
|
||||
unsigned m2 = ~s2->map[i];
|
||||
set_bits_t m1 = s1->map[i];
|
||||
set_bits_t m2 = ~s2->map[i];
|
||||
|
||||
intersection |= m1 & m2;
|
||||
difference |= m1 ^ m2;
|
||||
}
|
||||
for ( ; i < s1->size / BITS; i++) {
|
||||
for ( ; i < SET_WORDS (s1); i++) {
|
||||
intersection |= s1->map[i];
|
||||
difference |= ~s1->map[i];
|
||||
}
|
||||
for ( ; i < s2->size / BITS; i++) {
|
||||
for ( ; i < SET_WORDS (s2); i++) {
|
||||
difference |= ~s2->map[i];
|
||||
}
|
||||
return (difference != 0) | ((intersection != 0) << 1);
|
||||
|
@ -395,21 +393,21 @@ static int
|
|||
set_test_i_n (const set_t *s1, const set_t *s2)
|
||||
{
|
||||
unsigned i, end;
|
||||
unsigned intersection = 0;
|
||||
unsigned difference = 0;
|
||||
set_bits_t intersection = 0;
|
||||
set_bits_t difference = 0;
|
||||
|
||||
end = min (s1->size, s2->size) / BITS;
|
||||
end = min (s1->size, s2->size) / SET_BITS;
|
||||
for (i = 0; i < end; i++) {
|
||||
unsigned m1 = ~s1->map[i];
|
||||
unsigned m2 = s2->map[i];
|
||||
set_bits_t m1 = ~s1->map[i];
|
||||
set_bits_t m2 = s2->map[i];
|
||||
|
||||
intersection |= m1 & m2;
|
||||
difference |= m1 ^ m2;
|
||||
}
|
||||
for ( ; i < s1->size / BITS; i++) {
|
||||
for ( ; i < SET_WORDS (s1); i++) {
|
||||
difference |= ~s1->map[i];
|
||||
}
|
||||
for ( ; i < s2->size / BITS; i++) {
|
||||
for ( ; i < SET_WORDS (s2); i++) {
|
||||
intersection |= s2->map[i];
|
||||
difference |= ~s2->map[i];
|
||||
}
|
||||
|
@ -420,21 +418,21 @@ static int
|
|||
set_test_i_i (const set_t *s1, const set_t *s2)
|
||||
{
|
||||
unsigned i, end;
|
||||
unsigned intersection = 0;
|
||||
unsigned difference = 0;
|
||||
set_bits_t intersection = 0;
|
||||
set_bits_t difference = 0;
|
||||
|
||||
end = min (s1->size, s2->size) / BITS;
|
||||
end = min (s1->size, s2->size) / SET_BITS;
|
||||
for (i = 0; i < end; i++) {
|
||||
unsigned m1 = ~s1->map[i];
|
||||
unsigned m2 = ~s2->map[i];
|
||||
set_bits_t m1 = ~s1->map[i];
|
||||
set_bits_t m2 = ~s2->map[i];
|
||||
|
||||
intersection |= m1 & m2;
|
||||
difference |= m1 ^ m2;
|
||||
}
|
||||
for ( ; i < s1->size / BITS; i++) {
|
||||
for ( ; i < SET_WORDS (s1); i++) {
|
||||
difference |= ~s1->map[i];
|
||||
}
|
||||
for ( ; i < s2->size / BITS; i++) {
|
||||
for ( ; i < SET_WORDS (s2); i++) {
|
||||
intersection |= s2->map[i];
|
||||
difference |= ~s2->map[i];
|
||||
}
|
||||
|
@ -478,13 +476,13 @@ set_is_subset (const set_t *set, const set_t *sub)
|
|||
{
|
||||
unsigned i, end;
|
||||
|
||||
end = min (set->size, sub->size) / BITS;
|
||||
end = min (set->size, sub->size) / SET_BITS;
|
||||
if (set->inverted && sub->inverted) {
|
||||
for (i = 0; i < end; i++) {
|
||||
if (~sub->map[i] & set->map[i])
|
||||
return 0;
|
||||
}
|
||||
for ( ; i < set->size / BITS; i++)
|
||||
for ( ; i < SET_WORDS (set); i++)
|
||||
if (set->map[i])
|
||||
return 0;
|
||||
} else if (set->inverted) {
|
||||
|
@ -500,7 +498,7 @@ set_is_subset (const set_t *set, const set_t *sub)
|
|||
if (sub->map[i] & ~set->map[i])
|
||||
return 0;
|
||||
}
|
||||
for ( ; i < sub->size / BITS; i++)
|
||||
for ( ; i < SET_WORDS (sub); i++)
|
||||
if (sub->map[i])
|
||||
return 0;
|
||||
}
|
||||
|
@ -512,7 +510,7 @@ _set_is_member (const set_t *set, unsigned x)
|
|||
{
|
||||
if (x >= set->size)
|
||||
return 0;
|
||||
return (set->map[x / BITS] & (1 << (x % BITS))) != 0;
|
||||
return (set->map[x / SET_BITS] & (SET_ONE << (x % SET_BITS))) != 0;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
|
||||
#include "QF/set.h"
|
||||
|
||||
#define SIZE (DEFMAP_SIZE * sizeof (unsigned) * 8)
|
||||
#define BITS (sizeof (((set_t *) 0)->map[0]) * 8)
|
||||
#define SIZE (SET_DEFMAP_SIZE * sizeof (set_bits_t) * 8)
|
||||
|
||||
typedef set_t *(*setup_func) (void);
|
||||
typedef set_t *(*op_func) (set_t *s1, const set_t *s2);
|
||||
|
@ -121,7 +120,7 @@ struct {
|
|||
{make_everything, 0, 0, check_size, SIZE, "{...}"},
|
||||
{make_empty_invert, 0, 0, check_size, SIZE, "{...}"},
|
||||
{make_everything_invert, 0, 0, check_size, SIZE, "{}"},
|
||||
{make_SIZE, 0, 0, check_size, SIZE + BITS, "{64}"},
|
||||
{make_SIZE, 0, 0, check_size, SIZE + SET_BITS, "{64}"},
|
||||
{make_0_to_SIZEm1, 0, 0, check_size, SIZE,
|
||||
"{0 1 2 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"
|
||||
|
|
Loading…
Reference in a new issue