diff options
Diffstat (limited to 'libmisc')
-rw-r--r-- | libmisc/include/libmisc/macro.h | 62 | ||||
-rw-r--r-- | libmisc/include/libmisc/rand.h | 7 | ||||
-rw-r--r-- | libmisc/map.c | 2 | ||||
-rw-r--r-- | libmisc/tests/test_obj_nest.c | 12 | ||||
-rw-r--r-- | libmisc/tests/test_rand.c | 6 |
5 files changed, 75 insertions, 14 deletions
diff --git a/libmisc/include/libmisc/macro.h b/libmisc/include/libmisc/macro.h index 1712f7d..43a00f6 100644 --- a/libmisc/include/libmisc/macro.h +++ b/libmisc/include/libmisc/macro.h @@ -120,11 +120,63 @@ #define LM_BIT_XOR(a, b) ((typeof(a))(((a)^(b)) + static_assert_as_expr(__builtin_types_compatible_p(typeof(a), typeof(b))))) #define LM_BIT_FLIP(a) ((typeof(a))(~(a))) -#define LM_CEILDIV(n, d) ( ((n)+(d)-1) / (d) ) /** Return ceil(n/d) */ -#define LM_ROUND_UP(n, d) ( LM_CEILDIV(n, d) * (d) ) /** Return `n` rounded up to the nearest multiple of `d` */ -#define LM_ROUND_DOWN(n, d) ( ((n)/(d)) * (d) ) /** Return `n` rounded down to the nearest multiple of `d` */ -#define LM_NEXT_POWER_OF_2(x) ( (x) ? 1ULL<<((sizeof(unsigned long long)*8)-__builtin_clzll(x)) : 1) /** Return the lowest power of 2 that is > x */ -#define LM_FLOORLOG2(x) ((sizeof(unsigned long long)*8)-__builtin_clzll(x)-1) /** Return floor(log_2(x) */ +#define LM_CEILDIV(n, d) ( ((n)+(d)-1) / (d) ) /** Return ceil(n/d) */ +#define LM_ROUND_UP(n, d) ( LM_CEILDIV(n, d) * (d) ) /** Return `n` rounded up to the nearest multiple of `d` */ +#define LM_ROUND_DOWN(n, d) ( ((n)/(d)) * (d) ) /** Return `n` rounded down to the nearest multiple of `d` */ +#define LM_NEXT_POWER_OF_2(x) ( (x) ? 1ULL<<((sizeof(unsigned long long)*8)-(unsigned)__builtin_clzll(x)) : 1) /** Return the lowest power of 2 that is > x */ +#define LM_FLOORLOG2(x) ((sizeof(unsigned long long)*8)-(unsigned)__builtin_clzll(x)-1) /** Return floor(log_2(x) */ + +#define _LM_PROP_SIGNED(TYP) _Generic((TYP)0, \ + unsigned char : 0, \ + unsigned short : 0, \ + unsigned : 0, \ + unsigned long : 0, \ + unsigned long long : 0, \ + signed char : 1, \ + short : 1, \ + int : 1, \ + long : 1, \ + long long : 1) +#define _LM_PROP_MIN(TYP) _Generic((TYP)0, \ + unsigned char : 0, \ + unsigned short : 0, \ + unsigned : 0, \ + unsigned long : 0, \ + unsigned long long : 0, \ + signed char : SCHAR_MIN, \ + short : SHRT_MIN, \ + int : INT_MIN, \ + long : LONG_MIN, \ + long long : LLONG_MIN) +#define _LM_PROP_MAX(TYP) _Generic((TYP)0, \ + unsigned char : UCHAR_MAX, \ + unsigned short : USHRT_MAX, \ + unsigned : UINT_MAX, \ + unsigned long : ULONG_MAX, \ + unsigned long long : ULLONG_MAX, \ + signed char : SCHAR_MAX, \ + short : SHRT_MAX, \ + int : INT_MAX, \ + long : LONG_MAX, \ + long long : LLONG_MAX) + +#define LM_SAFEDOWNCAST(TYP, x) ({ \ + typeof(x) _x = (x); \ + /* Assert that it's a downcast (that this macro is being used \ + * correctly). We're a little forgiving (<= instead of <) to allow \ + * this to be used for types that are different relative sizes on \ + * different architectures. */ \ + static_assert(sizeof((TYP)0) <= sizeof(_x) || \ + _LM_PROP_SIGNED(TYP) != _LM_PROP_SIGNED(typeof(_x))); \ + /* Assert that x is within the new bounds. */ \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \ + assert(_LM_PROP_MIN(TYP) <= _x && _x <= _LM_PROP_MAX(TYP)); \ + _Pragma("GCC diagnostic pop") \ + (TYP)_x; \ +}) + +LM_BITFLIP(TYP, x) ({ TYP _x = x; (TYP)~_x; }) /* strings */ diff --git a/libmisc/include/libmisc/rand.h b/libmisc/include/libmisc/rand.h index 784e580..b54dee0 100644 --- a/libmisc/include/libmisc/rand.h +++ b/libmisc/include/libmisc/rand.h @@ -17,13 +17,13 @@ * Return a psuedo-random number in the half-open interval [0,cnt). * `cnt` must not be greater than 1<<63. */ -static inline uint64_t rand_uint63n(uint64_t cnt) { +static inline uint64_t _rand_uint63n(uint64_t cnt) { assert(cnt != 0 && ((cnt-1) & 0x8000000000000000) == 0); if (cnt <= LM_BIT(uint64_t, 31)) { uint32_t fair_cnt = LM_ROUND_DOWN(LM_BIT(uint32_t, 31), cnt); uint32_t rnd; do { - rnd = random(); + rnd = LM_UPCAST(uint32_t, random()); } while (rnd >= fair_cnt); return rnd % cnt; } else if (cnt <= LM_BIT(uint64_t, 62)) { @@ -37,11 +37,12 @@ static inline uint64_t rand_uint63n(uint64_t cnt) { uint64_t fair_cnt = LM_ROUND_DOWN(LM_BIT(uint64_t, 63), cnt); uint64_t rnd; do { - rnd = (LM_UPCAST(uint64_t, random()) << 62) | (LM_UPCAST(uint64_t, random()) << 31) | LM_UPCAST(random(); + rnd = (LM_UPCAST(uint64_t, random()) << 62) | (LM_UPCAST(uint64_t, random()) << 31) | LM_UPCAST(uint64_t, random()); } while (rnd >= fair_cnt); return rnd % cnt; } assert_notreached("cnt is out of bounds"); } +#define rand_uint63n(cnt) ((typeof(cnt))_rand_uint63n(cnt)) #endif /* _LIBMISC_RAND_H_ */ diff --git a/libmisc/map.c b/libmisc/map.c index d703966..f354f07 100644 --- a/libmisc/map.c +++ b/libmisc/map.c @@ -211,7 +211,7 @@ bool _map_iter_next(struct _map_iter *state) { struct _map_kv_list_node *old_kv = state->kv; state->kv = old_kv->rear; - old_kv->val.flags &= ~FLAG_ITER; + old_kv->val.flags &= flip8(FLAG_ITER); if (old_kv->val.flags & FLAG_DEL) { dlist_remove(&state->m->buckets[state->i], old_kv); free(old_kv); diff --git a/libmisc/tests/test_obj_nest.c b/libmisc/tests/test_obj_nest.c index bb9d6de..be303f2 100644 --- a/libmisc/tests/test_obj_nest.c +++ b/libmisc/tests/test_obj_nest.c @@ -5,6 +5,10 @@ */ #include <string.h> /* for memcpy() */ +#include <limits.h> /* for SSIZE_MAX, not set by newlib */ +#ifndef SSIZE_MAX +#define SSIZE_MAX (SIZE_MAX >> 1) +#endif #include <libmisc/obj.h> @@ -45,8 +49,10 @@ static ssize_t myclass_read(struct myclass *self, void *buf, size_t count) { test_assert(self); if (count > self->len) count = self->len; + if (count > SSIZE_MAX) + count = SSIZE_MAX; memcpy(buf, self->buf, count); - return count; + return (ssize_t)count; } static ssize_t myclass_write(struct myclass *self, void *buf, size_t count) { @@ -55,9 +61,11 @@ static ssize_t myclass_write(struct myclass *self, void *buf, size_t count) { return -1; if (count > sizeof(self->buf)) count = sizeof(self->buf); + if (count > SSIZE_MAX) + count = SSIZE_MAX; memcpy(self->buf, buf, count); self->len = count; - return count; + return (ssize_t)count; } /* main test body *************************************************************/ diff --git a/libmisc/tests/test_rand.c b/libmisc/tests/test_rand.c index 02f4c1c..b98dacf 100644 --- a/libmisc/tests/test_rand.c +++ b/libmisc/tests/test_rand.c @@ -53,14 +53,14 @@ static void test_n(uint64_t cnt) { bool seen[MAX_SEE_ALL] = {0}; for (int i = 0; i < ROUNDS; i++) { uint64_t val = rand_uint63n(cnt); - sum += val; + sum += (double)val; test_assert(val < cnt); if (cnt < MAX_SEE_ALL) seen[val] = true; } if (cnt > 1) { - test_assert(sum/ROUNDS > 0.45*(cnt-1)); - test_assert(sum/ROUNDS < 0.55*(cnt-1)); + test_assert(sum/ROUNDS > 0.45*(double)(cnt-1)); + test_assert(sum/ROUNDS < 0.55*(double)(cnt-1)); } if (cnt < MAX_SEE_ALL) { for (uint64_t i = 0; i < cnt; i++) |