From: Lennart Poettering Date: Fri, 2 Jun 2023 14:34:32 +0000 (+0200) Subject: test-macro: add ROUND_UP() macro for rounding up to next multiple X-Git-Tag: v254-rc1~300^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=beda8529b9ca72c34bf7896c3bff60039b2c8e4c;p=thirdparty%2Fsystemd.git test-macro: add ROUND_UP() macro for rounding up to next multiple In case of overflow will return -1 cast to the first parameter type. --- diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h index e901e8fb596..1d49765fce9 100644 --- a/src/fundamental/macro-fundamental.h +++ b/src/fundamental/macro-fundamental.h @@ -108,7 +108,6 @@ #define assert_cc(expr) static_assert(expr, #expr) - #define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq)) #define UNIQ __COUNTER__ @@ -253,6 +252,16 @@ (UNIQ_T(X, xq) / UNIQ_T(Y, yq) + !!(UNIQ_T(X, xq) % UNIQ_T(Y, yq))); \ }) +/* Rounds up x to the next multiple of y. Resolves to typeof(x) -1 in case of overflow */ +#define __ROUND_UP(q, x, y) \ + ({ \ + const typeof(y) UNIQ_T(A, q) = (y); \ + const typeof(x) UNIQ_T(B, q) = DIV_ROUND_UP((x), UNIQ_T(A, q)); \ + typeof(x) UNIQ_T(C, q); \ + __builtin_mul_overflow(UNIQ_T(B, q), UNIQ_T(A, q), &UNIQ_T(C, q)) ? (typeof(x)) -1 : UNIQ_T(C, q); \ + }) +#define ROUND_UP(x, y) __ROUND_UP(UNIQ, (x), (y)) + #define CASE_F_1(X) case X: #define CASE_F_2(X, ...) case X: CASE_F_1( __VA_ARGS__) #define CASE_F_3(X, ...) case X: CASE_F_2( __VA_ARGS__) diff --git a/src/test/test-macro.c b/src/test/test-macro.c index 637d6f1a49a..810ebc580e7 100644 --- a/src/test/test-macro.c +++ b/src/test/test-macro.c @@ -818,4 +818,70 @@ TEST(FOREACH_ARRAY) { assert_se(n == 0); } +#define TEST_ROUND_UP_BY_TYPE(type, max_value) \ + ({ \ + type x, y; \ + x = 0, y = 1; \ + assert_se(ROUND_UP(x, y) == 0); \ + x = 0, y = 2; \ + assert_se(ROUND_UP(x, y) == 0); \ + x = 0, y = 3; \ + assert_se(ROUND_UP(x, y) == 0); \ + x = 0, y = 4; \ + assert_se(ROUND_UP(x, y) == 0); \ + x = 1, y = 1; \ + assert_se(ROUND_UP(x, y) == 1); \ + x = 1, y = 2; \ + assert_se(ROUND_UP(x, y) == 2); \ + x = 1, y = 3; \ + assert_se(ROUND_UP(x, y) == 3); \ + x = 1, y = 4; \ + assert_se(ROUND_UP(x, y) == 4); \ + x = 2, y = 1; \ + assert_se(ROUND_UP(x, y) == 2); \ + x = 2, y = 2; \ + assert_se(ROUND_UP(x, y) == 2); \ + x = 2, y = 3; \ + assert_se(ROUND_UP(x, y) == 3); \ + x = 2, y = 4; \ + assert_se(ROUND_UP(x, y) == 4); \ + x = 3, y = 1; \ + assert_se(ROUND_UP(x, y) == 3); \ + x = 3, y = 2; \ + assert_se(ROUND_UP(x, y) == 4); \ + x = 3, y = 3; \ + assert_se(ROUND_UP(x, y) == 3); \ + x = 3, y = 4; \ + assert_se(ROUND_UP(x, y) == 4); \ + x = 4, y = 1; \ + assert_se(ROUND_UP(x, y) == 4); \ + x = 4, y = 2; \ + assert_se(ROUND_UP(x, y) == 4); \ + x = 4, y = 3; \ + assert_se(ROUND_UP(x, y) == 6); \ + x = 4, y = 4; \ + assert_se(ROUND_UP(x, y) == 4); \ + x = max_value, y = 1; \ + assert_se(ROUND_UP(x, y) == max_value); \ + x = max_value, y = 2; \ + assert_se(ROUND_UP(x, y) == max_value); \ + x = max_value, y = 3; \ + assert_se(ROUND_UP(x, y) == max_value); \ + x = max_value, y = 4; \ + assert_se(ROUND_UP(x, y) == max_value); \ + x = max_value-1, y = 1; \ + assert_se(ROUND_UP(x, y) == max_value-1); \ + x = max_value-1, y = 2; \ + assert_se(ROUND_UP(x, y) == max_value-1); \ + x = max_value-1, y = 4; \ + assert_se(ROUND_UP(x, y) == max_value); \ + }) + +TEST(round_up) { + TEST_ROUND_UP_BY_TYPE(uint8_t, UINT8_MAX); + TEST_ROUND_UP_BY_TYPE(uint16_t, UINT16_MAX); + TEST_ROUND_UP_BY_TYPE(uint32_t, UINT32_MAX); + TEST_ROUND_UP_BY_TYPE(uint64_t, UINT64_MAX); +} + DEFINE_TEST_MAIN(LOG_INFO);