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:
Bill Currie 2013-03-16 21:26:49 +09:00
parent 195bdcb92f
commit 27bb337a60
3 changed files with 72 additions and 58 deletions

View file

@ -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.

View file

@ -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

View file

@ -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"