mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-18 15:01:41 +00:00
Re-write the set testing code.
Getting everything right with an enum proved to be too difficult if not impossible. Also use better tests for equivalence and intersection. Many more tests have been added. All pass :)
This commit is contained in:
parent
94e804d786
commit
061e2be5d4
3 changed files with 95 additions and 67 deletions
|
@ -229,6 +229,8 @@ int set_is_everything (const set_t *set);
|
|||
\param s1 The first set to test.
|
||||
\param s2 The second set to test.
|
||||
\return 1 if \a s2 is disjoint from \a s1, 0 if not.
|
||||
|
||||
\note The emtpy set is disjoint with itself.
|
||||
*/
|
||||
int set_is_disjoint (const set_t *s1, const set_t *s2);
|
||||
|
||||
|
@ -238,7 +240,7 @@ int set_is_disjoint (const set_t *s1, const set_t *s2);
|
|||
\param s2 The second set to test.
|
||||
\return 1 if \a s2 intersects \a s1, 0 if not.
|
||||
|
||||
\note Equivalent sets are treated as not intersecting.
|
||||
\note Equivalent non-empty sets are treated as intersecting.
|
||||
*/
|
||||
int set_is_intersecting (const set_t *s1, const set_t *s2);
|
||||
|
||||
|
|
118
libs/util/set.c
118
libs/util/set.c
|
@ -331,18 +331,12 @@ set_is_everything (const set_t *set)
|
|||
return _set_is_empty (set);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
set_equiv,
|
||||
set_intersecting,
|
||||
set_disjoint,
|
||||
} set_test_e;
|
||||
|
||||
static int
|
||||
set_test_intersect_n_n (const set_t *s1, const set_t *s2)
|
||||
set_test_n_n (const set_t *s1, const set_t *s2)
|
||||
{
|
||||
unsigned i, end;
|
||||
unsigned intersection = 0;
|
||||
set_test_e rval = set_equiv;
|
||||
unsigned difference = 0;
|
||||
|
||||
end = min (s1->size, s2->size) / BITS;
|
||||
for (i = 0; i < end; i++) {
|
||||
|
@ -350,20 +344,23 @@ set_test_intersect_n_n (const set_t *s1, const set_t *s2)
|
|||
unsigned m2 = s2->map[i];
|
||||
|
||||
intersection |= m1 & m2;
|
||||
if (m1 != m2)
|
||||
rval = set_intersecting;
|
||||
difference |= m1 ^ m2;
|
||||
}
|
||||
if (rval == set_intersecting && !intersection)
|
||||
rval = set_disjoint;
|
||||
return rval;
|
||||
for ( ; i < s1->size / BITS; i++) {
|
||||
difference |= s1->map[i];
|
||||
}
|
||||
for ( ; i < s2->size / BITS; i++) {
|
||||
difference |= s2->map[i];
|
||||
}
|
||||
return (difference != 0) | ((intersection != 0) << 1);
|
||||
}
|
||||
|
||||
static int
|
||||
set_test_intersect_n_i (const set_t *s1, const set_t *s2)
|
||||
set_test_n_i (const set_t *s1, const set_t *s2)
|
||||
{
|
||||
unsigned i, end;
|
||||
unsigned intersection = 0;
|
||||
set_test_e rval = set_equiv;
|
||||
unsigned difference = 0;
|
||||
|
||||
end = min (s1->size, s2->size) / BITS;
|
||||
for (i = 0; i < end; i++) {
|
||||
|
@ -371,20 +368,24 @@ set_test_intersect_n_i (const set_t *s1, const set_t *s2)
|
|||
unsigned m2 = ~s2->map[i];
|
||||
|
||||
intersection |= m1 & m2;
|
||||
if (m1 != m2)
|
||||
rval = set_intersecting;
|
||||
difference |= m1 ^ m2;
|
||||
}
|
||||
if (rval == set_intersecting && !intersection)
|
||||
rval = set_disjoint;
|
||||
return rval;
|
||||
for ( ; i < s1->size / BITS; i++) {
|
||||
intersection |= s1->map[i];
|
||||
difference |= ~s1->map[i];
|
||||
}
|
||||
for ( ; i < s2->size / BITS; i++) {
|
||||
difference |= ~s2->map[i];
|
||||
}
|
||||
return (difference != 0) | ((intersection != 0) << 1);
|
||||
}
|
||||
|
||||
static int
|
||||
set_test_intersect_i_n (const set_t *s1, const set_t *s2)
|
||||
set_test_i_n (const set_t *s1, const set_t *s2)
|
||||
{
|
||||
unsigned i, end;
|
||||
unsigned intersection = 0;
|
||||
set_test_e rval = set_equiv;
|
||||
unsigned difference = 0;
|
||||
|
||||
end = min (s1->size, s2->size) / BITS;
|
||||
for (i = 0; i < end; i++) {
|
||||
|
@ -392,20 +393,24 @@ set_test_intersect_i_n (const set_t *s1, const set_t *s2)
|
|||
unsigned m2 = s2->map[i];
|
||||
|
||||
intersection |= m1 & m2;
|
||||
if (m1 != m2)
|
||||
rval = set_intersecting;
|
||||
difference |= m1 ^ m2;
|
||||
}
|
||||
if (rval == set_intersecting && !intersection)
|
||||
rval = set_disjoint;
|
||||
return rval;
|
||||
for ( ; i < s1->size / BITS; i++) {
|
||||
difference |= ~s1->map[i];
|
||||
}
|
||||
for ( ; i < s2->size / BITS; i++) {
|
||||
intersection |= s2->map[i];
|
||||
difference |= ~s2->map[i];
|
||||
}
|
||||
return (difference != 0) | ((intersection != 0) << 1);
|
||||
}
|
||||
|
||||
static int
|
||||
set_test_intersect_i_i (const set_t *s1, const set_t *s2)
|
||||
set_test_i_i (const set_t *s1, const set_t *s2)
|
||||
{
|
||||
unsigned i, end;
|
||||
unsigned intersection = 0;
|
||||
set_test_e rval = set_equiv;
|
||||
unsigned difference = 0;
|
||||
|
||||
end = min (s1->size, s2->size) / BITS;
|
||||
for (i = 0; i < end; i++) {
|
||||
|
@ -413,61 +418,48 @@ set_test_intersect_i_i (const set_t *s1, const set_t *s2)
|
|||
unsigned m2 = ~s2->map[i];
|
||||
|
||||
intersection |= m1 & m2;
|
||||
if (m1 != m2)
|
||||
rval = set_intersecting;
|
||||
difference |= m1 ^ m2;
|
||||
}
|
||||
return rval;
|
||||
for ( ; i < s1->size / BITS; i++) {
|
||||
difference |= ~s1->map[i];
|
||||
}
|
||||
for ( ; i < s2->size / BITS; i++) {
|
||||
intersection |= s2->map[i];
|
||||
difference |= ~s2->map[i];
|
||||
}
|
||||
intersection |= ~0; // two inverted sets can never be disjoint
|
||||
return (difference != 0) | ((intersection != 0) << 1);
|
||||
}
|
||||
|
||||
static int
|
||||
set_test (const set_t *s1, const set_t *s2)
|
||||
{
|
||||
unsigned i, end;
|
||||
set_test_e rval = set_equiv;
|
||||
set_test_e ext = set_disjoint;
|
||||
|
||||
if (s1->inverted && s2->inverted) {
|
||||
rval = set_test_intersect_i_i (s1, s2);
|
||||
ext = set_intersecting;
|
||||
} else if (s2->inverted) {
|
||||
rval = set_test_intersect_n_i (s1, s2);
|
||||
if (rval == set_equiv)
|
||||
rval = set_disjoint;
|
||||
} else if (s1->inverted) {
|
||||
rval = set_test_intersect_i_n (s1, s2);
|
||||
if (rval == set_equiv)
|
||||
rval = set_disjoint;
|
||||
} else {
|
||||
rval = set_test_intersect_n_n (s1, s2);
|
||||
}
|
||||
if (rval == set_equiv) {
|
||||
end = min (s1->size, s2->size) / BITS;
|
||||
for (i = end; i < s1->size / BITS; i++)
|
||||
if (s1->map[i])
|
||||
return ext;
|
||||
for (i = end; i < s2->size / BITS; i++)
|
||||
if (s2->map[i])
|
||||
return ext;
|
||||
}
|
||||
return rval;
|
||||
if (s1->inverted && s2->inverted)
|
||||
return set_test_i_i (s1, s2);
|
||||
else if (s2->inverted)
|
||||
return set_test_n_i (s1, s2);
|
||||
else if (s1->inverted)
|
||||
return set_test_i_n (s1, s2);
|
||||
else
|
||||
return set_test_n_n (s1, s2);
|
||||
}
|
||||
|
||||
int
|
||||
set_is_disjoint (const set_t *s1, const set_t *s2)
|
||||
{
|
||||
return set_test (s1, s2) == set_disjoint;
|
||||
return !(set_test (s1, s2) & 2);
|
||||
}
|
||||
|
||||
int
|
||||
set_is_intersecting (const set_t *s1, const set_t *s2)
|
||||
{
|
||||
return set_test (s1, s2) == set_intersecting;
|
||||
return !!(set_test (s1, s2) & 2);
|
||||
}
|
||||
|
||||
int
|
||||
set_is_equivalent (const set_t *s1, const set_t *s2)
|
||||
{
|
||||
return set_test (s1, s2) == set_equiv;
|
||||
return !(set_test (s1, s2) & 1);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -57,6 +57,14 @@ make_SIZE (void)
|
|||
return set;
|
||||
}
|
||||
|
||||
static set_t *
|
||||
make_not_SIZE (void)
|
||||
{
|
||||
set_t *set = set_new ();
|
||||
set_add (set, SIZE);
|
||||
return set_invert (set);
|
||||
}
|
||||
|
||||
static set_t *
|
||||
make_0_to_SIZEm1 (void)
|
||||
{
|
||||
|
@ -126,10 +134,24 @@ struct {
|
|||
{make_0_to_SIZEm1, make_everything, set_reverse_difference,
|
||||
check_size, SIZE, "64 ..."
|
||||
},
|
||||
{make_everything, make_empty, 0, set_is_subset, 1, 0},
|
||||
{make_empty, make_everything, 0, set_is_subset, 0, 0},
|
||||
{make_everything, make_empty, 0, set_is_subset, 1, 0},
|
||||
{make_everything, make_empty, 0, set_is_equivalent, 0, 0},
|
||||
{make_everything, make_empty, 0, set_is_intersecting, 0, 0},
|
||||
{make_everything, make_empty, 0, set_is_disjoint, 1, 0},
|
||||
{make_empty, make_everything, 0, set_is_subset, 0, 0},
|
||||
{make_empty, make_everything, 0, set_is_equivalent, 0, 0},
|
||||
{make_empty, make_everything, 0, set_is_intersecting, 0, 0},
|
||||
{make_empty, make_everything, 0, set_is_disjoint, 1, 0},
|
||||
{make_everything, make_everything, 0, set_is_subset, 1, 0},
|
||||
{make_everything, make_everything, 0, set_is_equivalent, 1, 0},
|
||||
{make_everything, make_everything, 0, set_is_intersecting, 1, 0},
|
||||
{make_everything, make_everything, 0, set_is_disjoint, 0, 0},
|
||||
{make_empty, make_empty, 0, set_is_subset, 1, 0},
|
||||
{make_empty, make_empty, 0, set_is_equivalent, 1, 0},
|
||||
{make_empty, make_empty, 0, set_is_intersecting, 0, 0},
|
||||
{make_empty, make_empty, 0, set_is_disjoint, 1, 0},
|
||||
{make_5, make_5, 0, set_is_equivalent, 1, 0},
|
||||
{make_5, make_5, 0, set_is_intersecting, 0, 0},
|
||||
{make_5, make_5, 0, set_is_intersecting, 1, 0},
|
||||
{make_5, make_5, 0, set_is_disjoint, 0, 0},
|
||||
{make_5, make_55, 0, set_is_equivalent, 0, 0},
|
||||
{make_5, make_55, 0, set_is_intersecting, 0, 0},
|
||||
|
@ -149,6 +171,18 @@ struct {
|
|||
{make_55, make_5, set_union, set_is_equivalent, 0, "5 55"},
|
||||
{make_55, make_5, set_union, set_is_intersecting, 1, "5 55"},
|
||||
{make_55, make_5, set_union, set_is_disjoint, 0, "5 55"},
|
||||
{make_not_SIZE, make_everything, 0, set_is_equivalent, 0, 0},
|
||||
{make_not_SIZE, make_everything, 0, set_is_intersecting, 1, 0},
|
||||
{make_not_SIZE, make_everything, 0, set_is_disjoint, 0, 0},
|
||||
{make_SIZE, make_everything, 0, set_is_equivalent, 0, 0},
|
||||
{make_SIZE, make_everything, 0, set_is_intersecting, 1, 0},
|
||||
{make_SIZE, make_everything, 0, set_is_disjoint, 0, 0},
|
||||
{make_not_5, make_everything, 0, set_is_equivalent, 0, 0},
|
||||
{make_not_5, make_everything, 0, set_is_intersecting, 1, 0},
|
||||
{make_not_5, make_everything, 0, set_is_disjoint, 0, 0},
|
||||
{make_5, make_everything, 0, set_is_equivalent, 0, 0},
|
||||
{make_5, make_everything, 0, set_is_intersecting, 1, 0},
|
||||
{make_5, make_everything, 0, set_is_disjoint, 0, 0},
|
||||
};
|
||||
#define num_tests (sizeof (tests) / sizeof (tests[0]))
|
||||
|
||||
|
|
Loading…
Reference in a new issue