diff --git a/spa/include/spa/pod/compare.h b/spa/include/spa/pod/compare.h index 88b01fbfb..f41e48116 100644 --- a/spa/include/spa/pod/compare.h +++ b/spa/include/spa/pod/compare.h @@ -31,16 +31,17 @@ static inline int spa_pod_compare_value(uint32_t type, const void *r1, const voi case SPA_TYPE_None: return 0; case SPA_TYPE_Bool: + return SPA_CMP(!!*(int32_t *)r1, !!*(int32_t *)r2); case SPA_TYPE_Id: - return *(uint32_t *) r1 == *(uint32_t *) r2 ? 0 : 1; + return SPA_CMP(*(uint32_t *)r1, *(uint32_t *)r2); case SPA_TYPE_Int: - return *(int32_t *) r1 - *(int32_t *) r2; + return SPA_CMP(*(int32_t *)r1, *(int32_t *)r2); case SPA_TYPE_Long: - return *(int64_t *) r1 - *(int64_t *) r2; + return SPA_CMP(*(int64_t *)r1, *(int64_t *)r2); case SPA_TYPE_Float: - return *(float *) r1 - *(float *) r2; + return SPA_CMP(*(float *)r1, *(float *)r2); case SPA_TYPE_Double: - return *(double *) r1 - *(double *) r2; + return SPA_CMP(*(double *)r1, *(double *)r2); case SPA_TYPE_String: return strcmp((char *)r1, (char *)r2); case SPA_TYPE_Bytes: @@ -60,15 +61,10 @@ static inline int spa_pod_compare_value(uint32_t type, const void *r1, const voi { const struct spa_fraction *f1 = (struct spa_fraction *) r1, *f2 = (struct spa_fraction *) r2; - int64_t n1, n2; - n1 = ((int64_t) f1->num) * f2->denom; - n2 = ((int64_t) f2->num) * f1->denom; - if (n1 < n2) - return -1; - else if (n1 > n2) - return 1; - else - return 0; + uint64_t n1, n2; + n1 = ((uint64_t) f1->num) * f2->denom; + n2 = ((uint64_t) f2->num) * f1->denom; + return SPA_CMP(n1, n2); } default: break; diff --git a/spa/include/spa/utils/defs.h b/spa/include/spa/utils/defs.h index 0dc236451..474073af9 100644 --- a/spa/include/spa/utils/defs.h +++ b/spa/include/spa/utils/defs.h @@ -186,6 +186,16 @@ struct spa_fraction { x; \ }) +/** 3-way comparison. NaN > NaN and NaN > finite numbers */ +#define SPA_CMP(a, b) \ +({ \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + (_a > _b) ? 1 : (_a == _b) ? 0 : (_a < _b) ? -1 \ + : (_a == _a) ? -1 : (_b == _b) ? 1 \ + : 1; \ +}) + /** * Return the address (buffer + offset) as pointer of \a type */ diff --git a/test/test-spa-utils.c b/test/test-spa-utils.c index a3052c97b..2bd5f7645 100644 --- a/test/test-spa-utils.c +++ b/test/test-spa-utils.c @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -150,6 +151,13 @@ PWTEST(utils_macros) pwtest_int_eq(SPA_CLAMP(-1, 1, 16), 1); pwtest_int_eq(SPA_CLAMP(8, 1, 16), 8); + pwtest_int_eq(SPA_CMP(INT64_MAX, INT64_MIN), 1); + pwtest_int_eq(SPA_CMP(INT64_MIN, INT64_MAX), -1); + pwtest_int_eq(SPA_CMP(INT64_MAX, INT64_MAX), 0); + pwtest_int_eq(SPA_CMP(1, nan("")), -1); + pwtest_int_eq(SPA_CMP(nan(""), 1), 1); + pwtest_int_eq(SPA_CMP(nan(""), nan("")), 1); + /* SPA_MEMBER exists for backwards compatibility but should no * longer be used, let's make sure it does what we expect it to */ pwtest_ptr_eq(SPA_MEMBER(ptr, 4, void), SPA_PTROFF(ptr, 4, void));