mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-18 01:14:38 +00:00
TESTS: add a unit test for one_among_mask()
This one produces random numbers and verifies that the output is correct. It can also take arguments to test individual values.
This commit is contained in:
parent
c7a8a3c7bd
commit
798d6fc0a7
105
tests/unit/test-1-among.c
Normal file
105
tests/unit/test-1-among.c
Normal file
@ -0,0 +1,105 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static inline unsigned long statistical_prng()
|
||||
{
|
||||
static unsigned long statistical_prng_state = 2463534242U;
|
||||
unsigned long x = statistical_prng_state;
|
||||
|
||||
if (sizeof(long) <= 4) {
|
||||
x ^= x << 13;
|
||||
x ^= x >> 17;
|
||||
x ^= x << 5;
|
||||
} else {
|
||||
x ^= x << 13;
|
||||
x ^= x >> 7;
|
||||
x ^= x << 17;
|
||||
}
|
||||
return statistical_prng_state = x;
|
||||
}
|
||||
|
||||
/* returns the position of one bit set in <v>, starting at position <bit>, and
|
||||
* searching in other halves if not found. This is intended to be used to
|
||||
* report the position of one bit set among several based on a counter or a
|
||||
* random generator while preserving a relatively good distribution so that
|
||||
* values made of holes in the middle do not see one of the bits around the
|
||||
* hole being returned much more often than the other one. It can be seen as a
|
||||
* disturbed ffsl() where the initial search starts at bit <bit>. The look up
|
||||
* is performed in O(logN) time for N bit words, yielding a bit among 64 in
|
||||
* about 16 cycles. Passing value 0 for <v> makes no sense and -1 is returned
|
||||
* in this case.
|
||||
*/
|
||||
int one_among(unsigned long v, int bit)
|
||||
{
|
||||
/* note, these masks may be produced by ~0UL/((1UL<<scale)+1) but
|
||||
* that's more expensive.
|
||||
*/
|
||||
static const unsigned long halves[] = {
|
||||
(unsigned long)0x5555555555555555ULL,
|
||||
(unsigned long)0x3333333333333333ULL,
|
||||
(unsigned long)0x0F0F0F0F0F0F0F0FULL,
|
||||
(unsigned long)0x00FF00FF00FF00FFULL,
|
||||
(unsigned long)0x0000FFFF0000FFFFULL,
|
||||
(unsigned long)0x00000000FFFFFFFFULL
|
||||
};
|
||||
unsigned long halfword = ~0UL;
|
||||
int scope = 0;
|
||||
int mirror;
|
||||
int scale;
|
||||
|
||||
if (!v)
|
||||
return -1;
|
||||
|
||||
/* we check if the exact bit is set or if it's present in a mirror
|
||||
* position based on the current scale we're checking, in which case
|
||||
* it's returned with its current (or mirrored) value. Otherwise we'll
|
||||
* make sure there's at least one bit in the half we're in, and will
|
||||
* scale down to a smaller scope and try again, until we find the
|
||||
* closest bit.
|
||||
*/
|
||||
for (scale = (sizeof(long) > 4) ? 5 : 4; scale >= 0; scale--) {
|
||||
halfword >>= (1UL << scale);
|
||||
scope |= (1UL << scale);
|
||||
mirror = bit ^ (1UL << scale);
|
||||
if (v & ((1UL << bit) | (1UL << mirror)))
|
||||
return (v & (1UL << bit)) ? bit : mirror;
|
||||
|
||||
if (!((v >> (bit & scope)) & halves[scale] & halfword))
|
||||
bit = mirror;
|
||||
}
|
||||
return bit;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
unsigned long mask;
|
||||
int bit;
|
||||
|
||||
if (argc < 2) {
|
||||
unsigned long long tests = 0;
|
||||
int ret;
|
||||
|
||||
while (1) {
|
||||
mask = statistical_prng(); // note: cannot be zero
|
||||
bit = statistical_prng() % (sizeof(long) * 8);
|
||||
ret = one_among(mask, bit);
|
||||
if (ret < 0 || !((mask >> ret) & 1))
|
||||
printf("###ERR### mask=%#lx bit=%d ret=%d\n", mask, bit, ret);
|
||||
if (!(tests & 0xffffff))
|
||||
printf("count=%Ld mask=%lx bit=%d ret=%d\n", tests, mask, bit, ret);
|
||||
tests++;
|
||||
}
|
||||
}
|
||||
|
||||
mask = atol(argv[1]);
|
||||
|
||||
if (argc < 3) {
|
||||
for (bit = 0; bit < 8*sizeof(long); bit++)
|
||||
printf("v %#x bit %d best %d\n", mask, bit, one_among(mask, bit));
|
||||
} else {
|
||||
bit = atoi(argv[2]);
|
||||
printf("v %#x bit %d best %d\n", mask, bit, one_among(mask, bit));
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user