sys: util: Add clamp macro
Adds CLAMP macro to complement the current min/max macros, as well as a gcc specific Z_CLAMP macro for single-evaluation expansion. CLAMP combines the functionality of MIN and MAX, eliminating the bug-prone usage of MIN(MAX(value, FLOOR), CEIL) found throughout the codebase in every possible combination. Signed-off-by: Trond Einar Snekvik <Trond.Einar.Snekvik@nordicsemi.no>
This commit is contained in:
parent
1ecdbacc9d
commit
ed1f75da74
3 changed files with 55 additions and 4 deletions
|
@ -178,6 +178,16 @@ extern "C" {
|
||||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @def CLAMP
|
||||||
|
* @brief Clamp a value to a given range.
|
||||||
|
* @note Arguments are evaluated multiple times.
|
||||||
|
*/
|
||||||
|
#ifndef CLAMP
|
||||||
|
/* Use Z_CLAMP for a GCC-only, single evaluation version */
|
||||||
|
#define CLAMP(val, low, high) (((val) <= (low)) ? (low) : MIN(val, high))
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Is @p x a power of two?
|
* @brief Is @p x a power of two?
|
||||||
* @param x value to check
|
* @param x value to check
|
||||||
|
|
|
@ -474,6 +474,21 @@ do { \
|
||||||
_value_a_ < _value_b_ ? _value_a_ : _value_b_; \
|
_value_a_ < _value_b_ ? _value_a_ : _value_b_; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/** @brief Return a value clamped to a given range.
|
||||||
|
*
|
||||||
|
* Macro ensures that expressions are evaluated only once. See @ref Z_MAX for
|
||||||
|
* macro limitations.
|
||||||
|
*/
|
||||||
|
#define Z_CLAMP(val, low, high) ({ \
|
||||||
|
/* random suffix to avoid naming conflict */ \
|
||||||
|
__typeof__(val) _value_val_ = (val); \
|
||||||
|
__typeof__(low) _value_low_ = (low); \
|
||||||
|
__typeof__(high) _value_high_ = (high); \
|
||||||
|
(_value_val_ < _value_low_) ? _value_low_ : \
|
||||||
|
(_value_val_ > _value_high_) ? _value_high_ : \
|
||||||
|
_value_val_; \
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Calculate power of two ceiling for some nonzero value
|
* @brief Calculate power of two ceiling for some nonzero value
|
||||||
*
|
*
|
||||||
|
|
|
@ -203,10 +203,10 @@ static int inc_func(void)
|
||||||
return a++;
|
return a++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test checks if @ref Z_MAX and @ref Z_MIN return correct result and perform
|
/* Test checks if @ref Z_MAX, @ref Z_MIN and @ref Z_CLAMP return correct result
|
||||||
* single evaluation of input arguments.
|
* and perform single evaluation of input arguments.
|
||||||
*/
|
*/
|
||||||
static void test_z_max_z_min(void)
|
static void test_z_max_z_min_z_clamp(void)
|
||||||
{
|
{
|
||||||
zassert_equal(Z_MAX(inc_func(), 0), 1, "Unexpected macro result");
|
zassert_equal(Z_MAX(inc_func(), 0), 1, "Unexpected macro result");
|
||||||
/* Z_MAX should have call inc_func only once */
|
/* Z_MAX should have call inc_func only once */
|
||||||
|
@ -215,6 +215,31 @@ static void test_z_max_z_min(void)
|
||||||
zassert_equal(Z_MIN(inc_func(), 2), 2, "Unexpected macro result");
|
zassert_equal(Z_MIN(inc_func(), 2), 2, "Unexpected macro result");
|
||||||
/* Z_MIN should have call inc_func only once */
|
/* Z_MIN should have call inc_func only once */
|
||||||
zassert_equal(inc_func(), 4, "Unexpected return value");
|
zassert_equal(inc_func(), 4, "Unexpected return value");
|
||||||
|
|
||||||
|
zassert_equal(Z_CLAMP(inc_func(), 1, 3), 3, "Unexpected macro result");
|
||||||
|
/* Z_CLAMP should have call inc_func only once */
|
||||||
|
zassert_equal(inc_func(), 6, "Unexpected return value");
|
||||||
|
|
||||||
|
zassert_equal(Z_CLAMP(inc_func(), 10, 15), 10,
|
||||||
|
"Unexpected macro result");
|
||||||
|
/* Z_CLAMP should have call inc_func only once */
|
||||||
|
zassert_equal(inc_func(), 8, "Unexpected return value");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_CLAMP(void)
|
||||||
|
{
|
||||||
|
zassert_equal(CLAMP(5, 3, 7), 5, "Unexpected clamp result");
|
||||||
|
zassert_equal(CLAMP(3, 3, 7), 3, "Unexpected clamp result");
|
||||||
|
zassert_equal(CLAMP(7, 3, 7), 7, "Unexpected clamp result");
|
||||||
|
zassert_equal(CLAMP(1, 3, 7), 3, "Unexpected clamp result");
|
||||||
|
zassert_equal(CLAMP(8, 3, 7), 7, "Unexpected clamp result");
|
||||||
|
|
||||||
|
zassert_equal(CLAMP(-5, -7, -3), -5, "Unexpected clamp result");
|
||||||
|
zassert_equal(CLAMP(-9, -7, -3), -7, "Unexpected clamp result");
|
||||||
|
zassert_equal(CLAMP(1, -7, -3), -3, "Unexpected clamp result");
|
||||||
|
|
||||||
|
zassert_equal(CLAMP(0xffffffffaULL, 0xffffffff0ULL, 0xfffffffffULL),
|
||||||
|
0xffffffffaULL, "Unexpected clamp result");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_FOR_EACH(void)
|
static void test_FOR_EACH(void)
|
||||||
|
@ -433,7 +458,8 @@ void test_cc(void)
|
||||||
ztest_unit_test(test_IF_ENABLED),
|
ztest_unit_test(test_IF_ENABLED),
|
||||||
ztest_unit_test(test_UTIL_LISTIFY),
|
ztest_unit_test(test_UTIL_LISTIFY),
|
||||||
ztest_unit_test(test_MACRO_MAP_CAT),
|
ztest_unit_test(test_MACRO_MAP_CAT),
|
||||||
ztest_unit_test(test_z_max_z_min),
|
ztest_unit_test(test_z_max_z_min_z_clamp),
|
||||||
|
ztest_unit_test(test_CLAMP),
|
||||||
ztest_unit_test(test_FOR_EACH),
|
ztest_unit_test(test_FOR_EACH),
|
||||||
ztest_unit_test(test_FOR_EACH_NONEMPTY_TERM),
|
ztest_unit_test(test_FOR_EACH_NONEMPTY_TERM),
|
||||||
ztest_unit_test(test_FOR_EACH_FIXED_ARG),
|
ztest_unit_test(test_FOR_EACH_FIXED_ARG),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue