From 2a5dbbfa0dd7332aa46aeddadccfb9582651a4ed Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Tue, 21 Oct 2014 07:25:37 +0200 Subject: [PATCH] data: Added sdb_data_inarray(). The function determines whether a value is included in an array. --- src/core/data.c | 38 +++++++++++++++++++++++ src/include/core/data.h | 9 ++++++ t/unit/core/data_test.c | 68 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) diff --git a/src/core/data.c b/src/core/data.c index 22d9ba3..1f3aa82 100644 --- a/src/core/data.c +++ b/src/core/data.c @@ -541,6 +541,44 @@ sdb_data_isnull(const sdb_data_t *datum) return 0; } /* sdb_data_isnull */ +_Bool +sdb_data_inarray(const sdb_data_t *value, const sdb_data_t *array) +{ + size_t i; + + if (sdb_data_isnull(value) || sdb_data_isnull(array)) + return 0; + if ((value->type & SDB_TYPE_ARRAY) || (! (array->type & SDB_TYPE_ARRAY))) + return 0; + if (value->type != (array->type & 0xff)) + return 0; + + if (value->type == SDB_TYPE_INTEGER) { + int64_t *v = array->data.array.values; + for (i = 0; i < array->data.array.length; ++i) + if (value->data.integer == v[i]) + return 1; + } + else if (value->type == SDB_TYPE_DECIMAL) { + double *v = array->data.array.values; + for (i = 0; i < array->data.array.length; ++i) + if (value->data.decimal == v[i]) + return 1; + } + else if (value->type == SDB_TYPE_STRING) { + char **v = array->data.array.values; + for (i = 0; i < array->data.array.length; ++i) + if (!strcasecmp(value->data.string, v[i])) + return 1; + } + else { + /* TODO */ + errno = ENOTSUP; + return 0; + } + return 0; +} /* sdb_data_inarray */ + int sdb_data_parse_op(const char *op) { diff --git a/src/include/core/data.h b/src/include/core/data.h index cfdf48d..7ff111c 100644 --- a/src/include/core/data.h +++ b/src/include/core/data.h @@ -157,6 +157,15 @@ sdb_data_strcmp(const sdb_data_t *d1, const sdb_data_t *d2); _Bool sdb_data_isnull(const sdb_data_t *datum); +/* + * sdb_data_inarray: + * Determine whether a datum is included in an array based on the usual + * comparison function of the value's type. The element type of the array has + * to match the type of the value. + */ +_Bool +sdb_data_inarray(const sdb_data_t *value, const sdb_data_t *array); + /* * Operators supported by sdb_data_eval_expr. */ diff --git a/t/unit/core/data_test.c b/t/unit/core/data_test.c index a41a3c2..5c10c59 100644 --- a/t/unit/core/data_test.c +++ b/t/unit/core/data_test.c @@ -727,6 +727,73 @@ START_TEST(test_strcmp) } END_TEST +START_TEST(test_inarray) +{ + int64_t int_values[] = { 47, 11, 64 }; + double dec_values[] = { 12.3, 47.11, 64.0 }; + char *string_values[] = { "foo", "bar", "qux", "baz" }; + + sdb_data_t int_array = { + SDB_TYPE_ARRAY | SDB_TYPE_INTEGER, + { .array = { SDB_STATIC_ARRAY_LEN(int_values), int_values } } + }; + sdb_data_t dec_array = { + SDB_TYPE_ARRAY | SDB_TYPE_DECIMAL, + { .array = { SDB_STATIC_ARRAY_LEN(dec_values), dec_values } } + }; + sdb_data_t string_array = { + SDB_TYPE_ARRAY | SDB_TYPE_STRING, + { .array = { SDB_STATIC_ARRAY_LEN(string_values), string_values } } + }; + + struct { + sdb_data_t value; + sdb_data_t array; + _Bool expected; + } golden_data[] = { + { { SDB_TYPE_INTEGER, { .integer = 47 } }, int_array, 1 }, + { { SDB_TYPE_INTEGER, { .integer = 11 } }, int_array, 1 }, + { { SDB_TYPE_INTEGER, { .integer = 64 } }, int_array, 1 }, + { { SDB_TYPE_INTEGER, { .integer = 65 } }, int_array, 0 }, + { { SDB_TYPE_NULL, { .integer = 0 } }, int_array, 0 }, + { int_array, { SDB_TYPE_INTEGER, { .integer = 47 } }, 0 }, + { int_array, int_array, 0 }, + { { SDB_TYPE_DECIMAL, { .decimal = 12.3 } }, dec_array, 1 }, + { { SDB_TYPE_DECIMAL, { .decimal = 47.11 } }, dec_array, 1 }, + { { SDB_TYPE_DECIMAL, { .decimal = 64.0 } }, dec_array, 1 }, + { { SDB_TYPE_DECIMAL, { .decimal = 60.0 } }, dec_array, 0 }, + { { SDB_TYPE_INTEGER, { .integer = 64 } }, dec_array, 0 }, + { { SDB_TYPE_NULL, { .integer = 0 } }, dec_array, 0 }, + { { SDB_TYPE_STRING, { .string = "Foo" } }, string_array, 1 }, + { { SDB_TYPE_STRING, { .string = "FOO" } }, string_array, 1 }, + { { SDB_TYPE_STRING, { .string = "foo" } }, string_array, 1 }, + { { SDB_TYPE_STRING, { .string = "bar" } }, string_array, 1 }, + { { SDB_TYPE_STRING, { .string = "qux" } }, string_array, 1 }, + { { SDB_TYPE_STRING, { .string = "baz" } }, string_array, 1 }, + { { SDB_TYPE_STRING, { .string = "ba" } }, string_array, 0 }, + { { SDB_TYPE_STRING, { .string = "abc" } }, string_array, 0 }, + { { SDB_TYPE_NULL, { .integer = 0 } }, string_array, 0 }, + }; + + size_t i; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + char v_str[1024] = "", a_str[1024] = ""; + _Bool check; + + sdb_data_format(&golden_data[i].value, + v_str, sizeof(v_str), SDB_UNQUOTED); + sdb_data_format(&golden_data[i].array, + a_str, sizeof(a_str), SDB_UNQUOTED); + + check = sdb_data_inarray(&golden_data[i].value, &golden_data[i].array); + fail_unless(check == golden_data[i].expected, + "sdb_data_inarray(%s, %s) = %d; expected: %d", + v_str, a_str, check, golden_data[i].expected); + } +} +END_TEST + START_TEST(test_parse_op) { struct { @@ -1353,6 +1420,7 @@ core_data_suite(void) tcase_add_test(tc, test_data); tcase_add_test(tc, test_cmp); tcase_add_test(tc, test_strcmp); + tcase_add_test(tc, test_inarray); tcase_add_test(tc, test_parse_op); tcase_add_test(tc, test_expr_eval); tcase_add_test(tc, test_format); -- 2.30.2