[ccan] [PATCH 2/4] order_functions: Scalar comparison functions
David Gibson
david at gibson.dropbear.id.au
Mon Jun 1 20:21:06 AEST 2015
Extend the order_functions module to provide simple, standard, comparison
callbacks for scalar types (i.e. integer and floating point types).
In addition to the usual variants comparing a plain scalar, this also
provides helper macros to construct a suitably typed callback and context
pointer to order structures by a specified scalar field.
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
---
ccan/order_functions/_info | 3 +
ccan/order_functions/order_functions.c | 70 +++++++++++++++++
ccan/order_functions/order_functions.h | 40 ++++++++++
ccan/order_functions/test/run.c | 138 +++++++++++++++++++++++++++++++++
4 files changed, 251 insertions(+)
create mode 100644 ccan/order_functions/order_functions.c
create mode 100644 ccan/order_functions/test/run.c
diff --git a/ccan/order_functions/_info b/ccan/order_functions/_info
index 28fe845..c290d36 100644
--- a/ccan/order_functions/_info
+++ b/ccan/order_functions/_info
@@ -20,9 +20,12 @@ int main(int argc, char *argv[])
if (strcmp(argv[1], "depends") == 0) {
printf("ccan/typesafe_cb\n");
+ printf("ccan/ptrint\n");
return 0;
}
if (strcmp(argv[1], "testdepends") == 0) {
+ printf("ccan/array_size\n");
+ printf("ccan/asort\n");
return 0;
}
diff --git a/ccan/order_functions/order_functions.c b/ccan/order_functions/order_functions.c
new file mode 100644
index 0000000..160b198
--- /dev/null
+++ b/ccan/order_functions/order_functions.c
@@ -0,0 +1,70 @@
+/* CC0 license (public domain) - see LICENSE file for details */
+
+#include <ccan/order_functions/order_functions.h>
+
+#define SCALAR_ORDER(_oname, _type) \
+ int _order_##_oname(const void *a, \
+ const void *b, \
+ void *ctx) \
+ { \
+ ptrdiff_t offset = ptr2int(ctx); \
+ const _type *aa = (const _type *)((char *)a + offset); \
+ const _type *bb = (const _type *)((char *)b + offset); \
+ \
+ if (*aa < *bb) { \
+ return -1; \
+ } else if (*aa > *bb) { \
+ return 1; \
+ } else { \
+ assert(*aa == *bb); \
+ return 0; \
+ } \
+ } \
+ int order_##_oname(const _type *a, \
+ const _type *b, \
+ void *ctx) \
+ { \
+ return _order_##_oname(a, b, int2ptr(0)); \
+ } \
+ int _order_##_oname##_reverse(const void *a, \
+ const void *b, \
+ void *ctx) \
+ { \
+ return -_order_##_oname(a, b, ctx); \
+ } \
+ int order_##_oname##_reverse(const _type *a, \
+ const _type *b, \
+ void *ctx) \
+ { \
+ return _order_##_oname##_reverse(a, b, int2ptr(0)); \
+ } \
+ int order_##_oname##_noctx(const void *a, \
+ const void *b) \
+ { \
+ return _order_##_oname(a, b, int2ptr(0)); \
+ } \
+ int order_##_oname##_reverse_noctx(const void *a, \
+ const void *b) \
+ { \
+ return _order_##_oname##_reverse(a, b, int2ptr(0)); \
+ }
+
+SCALAR_ORDER(s8, int8_t)
+SCALAR_ORDER(s16, int16_t)
+SCALAR_ORDER(s32, int32_t)
+SCALAR_ORDER(s64, int64_t)
+
+SCALAR_ORDER(u8, uint8_t)
+SCALAR_ORDER(u16, uint16_t)
+SCALAR_ORDER(u32, uint32_t)
+SCALAR_ORDER(u64, uint64_t)
+
+SCALAR_ORDER(int, int)
+SCALAR_ORDER(uint, unsigned int)
+SCALAR_ORDER(long, long)
+SCALAR_ORDER(ulong, unsigned long)
+SCALAR_ORDER(size, size_t)
+SCALAR_ORDER(ptrdiff, ptrdiff_t)
+
+SCALAR_ORDER(float, float)
+SCALAR_ORDER(double, double)
diff --git a/ccan/order_functions/order_functions.h b/ccan/order_functions/order_functions.h
index a2beb33..222c76e 100644
--- a/ccan/order_functions/order_functions.h
+++ b/ccan/order_functions/order_functions.h
@@ -6,6 +6,7 @@
#include <assert.h>
#include <ccan/typesafe_cb/typesafe_cb.h>
+#include <ccan/ptrint/ptrint.h>
typedef int (*_total_order_cb)(const void *, const void *, void *);
typedef int (*total_order_noctx_cb)(const void *, const void *);
@@ -30,4 +31,43 @@ struct _total_order {
_ctx ctx; \
} _name
+#define _DECL_ONAME(_oname, _itype) \
+ extern int _order_##_oname(const void *, const void *, void *); \
+ extern int order_##_oname(const _itype *, const _itype *, void *); \
+ extern int order_##_oname##_noctx(const void *, const void *);
+
+#define _DECL_ONAME_BIDIR(_oname, _itype) \
+ _DECL_ONAME(_oname, _itype) \
+ _DECL_ONAME(_oname##_reverse, _itype)
+
+_DECL_ONAME_BIDIR(s8, int8_t)
+_DECL_ONAME_BIDIR(s16, int16_t)
+_DECL_ONAME_BIDIR(s32, int32_t)
+_DECL_ONAME_BIDIR(s64, int64_t)
+
+_DECL_ONAME_BIDIR(u8, uint8_t)
+_DECL_ONAME_BIDIR(u16, uint16_t)
+_DECL_ONAME_BIDIR(u32, uint32_t)
+_DECL_ONAME_BIDIR(u64, uint64_t)
+
+_DECL_ONAME_BIDIR(int, int)
+_DECL_ONAME_BIDIR(uint, unsigned int)
+_DECL_ONAME_BIDIR(long, long)
+_DECL_ONAME_BIDIR(ulong, unsigned long)
+_DECL_ONAME_BIDIR(size, size_t)
+_DECL_ONAME_BIDIR(ptrdiff, ptrdiff_t)
+
+_DECL_ONAME_BIDIR(float, float)
+_DECL_ONAME_BIDIR(double, double)
+
+#undef _DECL_ONAME
+#undef _DECL_ONAME_BIDIR
+
+#define total_order_by_field(_name, _oname, _itype, _field) \
+ total_order(_name, _itype, ptrint_t *) = { \
+ (total_order_cb(, _itype, \
+ ptrint_t *))(_order_##_oname), \
+ int2ptr(offsetof(_itype, _field)), \
+ }
+
#endif /* CCAN_ORDER_FUNCTIONS_H */
diff --git a/ccan/order_functions/test/run.c b/ccan/order_functions/test/run.c
new file mode 100644
index 0000000..a68b3e3
--- /dev/null
+++ b/ccan/order_functions/test/run.c
@@ -0,0 +1,138 @@
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <float.h>
+#include <math.h>
+
+#include <ccan/array_size/array_size.h>
+
+#include <ccan/order_functions/order_functions.h>
+#include <ccan/tap/tap.h>
+
+#include <ccan/asort/asort.h>
+
+#define QSORT_SCALAR(t, oname, ...) \
+ { \
+ t arr0[] = { __VA_ARGS__ }; \
+ const int num = ARRAY_SIZE(arr0); \
+ t arr1[num], arr2[num]; \
+ int i; \
+ \
+ /* Intialize arr1 in reverse order */ \
+ for (i = 0; i < num; i++) \
+ arr1[i] = arr0[num-i-1]; \
+ \
+ memcpy(arr2, arr1, sizeof(arr1)); \
+ qsort(arr2, num, sizeof(t), order_##oname##_noctx); \
+ ok(memcmp(arr2, arr0, sizeof(arr0)) == 0, \
+ "qsort order_%s_noctx", #oname); \
+ \
+ qsort(arr2, num, sizeof(t), order_##oname##_reverse_noctx); \
+ ok(memcmp(arr2, arr1, sizeof(arr1)) == 0, \
+ "qsort order_%s_reverse_noctx", #oname); \
+ }
+
+#define ASORT_SCALAR(t, oname, ...) \
+ { \
+ t arr0[] = { __VA_ARGS__ }; \
+ const int num = ARRAY_SIZE(arr0); \
+ t arr1[num], arr2[num]; \
+ int i; \
+ \
+ /* Intialize arr1 in reverse order */ \
+ for (i = 0; i < num; i++) \
+ arr1[i] = arr0[num-i-1]; \
+ \
+ memcpy(arr2, arr1, sizeof(arr1)); \
+ asort(arr2, num, order_##oname, NULL); \
+ ok(memcmp(arr2, arr0, sizeof(arr0)) == 0, \
+ "asort order_%s", #oname); \
+ \
+ asort(arr2, num, order_##oname##_reverse, NULL); \
+ ok(memcmp(arr2, arr1, sizeof(arr1)) == 0, \
+ "asort order_%s_reverse", #oname); \
+ }
+
+#define ASORT_STRUCT_BY_SCALAR(t, oname, ...) \
+ { \
+ t arrbase[] = { __VA_ARGS__ }; \
+ struct tstruct { \
+ char dummy0[5]; \
+ t val; \
+ long dummy1; \
+ }; \
+ const int num = ARRAY_SIZE(arrbase); \
+ struct tstruct arr0[num], arr1[num], arr2[num]; \
+ int i; \
+ total_order_by_field(order, oname, struct tstruct, val); \
+ total_order_by_field(rorder, oname##_reverse, \
+ struct tstruct, val); \
+ \
+ /* Set up dummy structures */ \
+ memset(arr0, 0, sizeof(arr0)); \
+ for (i = 0; i < num; i++) { \
+ arr0[i].dummy1 = i; \
+ strcpy(arr0[i].dummy0, "abc"); \
+ arr0[i].val = arrbase[i]; \
+ } \
+ \
+ /* Intialize arr1 in reverse order */ \
+ for (i = 0; i < num; i++) \
+ arr1[i] = arr0[num-i-1]; \
+ \
+ memcpy(arr2, arr1, sizeof(arr1)); \
+ asort(arr2, num, order.cb, order.ctx); \
+ ok(memcmp(arr2, arr0, sizeof(arr0)) == 0, \
+ "asort by field %s", #oname); \
+ \
+ asort(arr2, num, rorder.cb, rorder.ctx); \
+ ok(memcmp(arr2, arr1, sizeof(arr1)) == 0, \
+ "asort by field %s_reverse", #oname); \
+ }
+
+#define TEST_SCALAR(t, oname, ...) \
+ { \
+ QSORT_SCALAR(t, oname, __VA_ARGS__); \
+ ASORT_SCALAR(t, oname, __VA_ARGS__); \
+ ASORT_STRUCT_BY_SCALAR(t, oname, __VA_ARGS__); \
+ }
+
+int main(void)
+{
+ /* This is how many tests you plan to run */
+ plan_tests(84);
+
+ TEST_SCALAR(int8_t, s8, -128, -4, 0, 1, 2, 88, 126, 127);
+ TEST_SCALAR(int16_t, s16, -32768, -4, 0, 1, 2, 88, 126, 32767);
+ TEST_SCALAR(int32_t, s32, -2000000000, -4, 0, 1, 2, 88, 126,
+ 2000000000);
+ TEST_SCALAR(int64_t, s64, -999999999999999999LL, -2000000000, -4, 0,
+ 1, 2, 88, 126, 2000000000, 999999999999999999LL);
+
+ TEST_SCALAR(uint8_t, u8, 0, 1, 2, 88, 126, 127, -10, -1);
+ TEST_SCALAR(uint16_t, u16, 0, 1, 2, 88, 126, 32767, -10, -1);
+ TEST_SCALAR(uint32_t, u32, 0, 1, 2, 88, 126, 2000000000, -10, -1);
+ TEST_SCALAR(uint64_t, u64, 0, 1, 2, 88, 126, 2000000000,
+ 999999999999999999LL, -10, -1);
+
+ TEST_SCALAR(int, int, INT_MIN, -10, -1, 0, 1, 10, INT_MAX);
+ TEST_SCALAR(unsigned, uint, 0, 1, 10, INT_MAX, (unsigned)INT_MAX+1,
+ -10, -1);
+
+ TEST_SCALAR(long, long, LONG_MIN, INT_MIN, -10, -1, 0, 1, 10, INT_MAX,
+ LONG_MAX);
+ TEST_SCALAR(unsigned long, ulong, 0, 1, 10, INT_MAX,
+ (unsigned long)INT_MAX+1, LONG_MAX,
+ (unsigned long)LONG_MAX+1, -10, -1);
+
+ TEST_SCALAR(float, float, -INFINITY, -FLT_MAX, -1.0, 0.0, FLT_MIN,
+ 0.1, M_E, M_PI, 5.79, FLT_MAX, INFINITY);
+ TEST_SCALAR(double, double, -INFINITY, -DBL_MAX, -FLT_MAX, -1.0, 0.0,
+ DBL_MIN, FLT_MIN, 0.1, M_E, M_PI, 5.79, FLT_MAX, DBL_MAX,
+ INFINITY);
+
+ /* This exits depending on whether all tests passed */
+ return exit_status();
+}
--
2.4.2
More information about the ccan
mailing list