summaryrefslogtreecommitdiff
path: root/libmisc
diff options
context:
space:
mode:
Diffstat (limited to 'libmisc')
-rw-r--r--libmisc/include/libmisc/macro.h62
-rw-r--r--libmisc/include/libmisc/rand.h7
-rw-r--r--libmisc/map.c2
-rw-r--r--libmisc/tests/test_obj_nest.c12
-rw-r--r--libmisc/tests/test_rand.c6
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++)