Code

data: Added sdb_data_array_get().
authorSebastian Harl <sh@tokkee.org>
Sat, 8 Nov 2014 16:00:05 +0000 (17:00 +0100)
committerSebastian Harl <sh@tokkee.org>
Sat, 8 Nov 2014 16:00:05 +0000 (17:00 +0100)
This function retrieves an array element, returning an "alias" to its value.

src/core/data.c
src/include/core/data.h
t/unit/core/data_test.c

index 8754f8868a11471fe1e359cee75ac0d52b87721d..a6cd092265a274a3f1c5b316d3f9ddffe30a0f81 100644 (file)
@@ -650,6 +650,43 @@ sdb_data_inarray(const sdb_data_t *value, const sdb_data_t *array)
        return 0;
 } /* sdb_data_inarray */
 
+int
+sdb_data_array_get(const sdb_data_t *array, size_t i, sdb_data_t *value)
+{
+       sdb_data_t tmp = SDB_DATA_INIT;
+       int type;
+
+       if ((! array) || (! (array->type & SDB_TYPE_ARRAY)))
+               return -1;
+       if (i >= array->data.array.length)
+               return -1;
+
+       type = array->type & 0xff;
+       if (type == SDB_TYPE_INTEGER) {
+               int64_t *v = array->data.array.values;
+               tmp.data.integer = v[i];
+       }
+       else if (type == SDB_TYPE_DECIMAL) {
+               double *v = array->data.array.values;
+               tmp.data.decimal = v[i];
+       }
+       else if (type == SDB_TYPE_STRING) {
+               char **v = array->data.array.values;
+               tmp.data.string = v[i];
+       }
+       else {
+               /* TODO */
+               errno = ENOTSUP;
+               return -1;
+       }
+
+       if (value) {
+               *value = tmp;
+               value->type = type;
+       }
+       return 0;
+} /* sdb_data_array_get */
+
 int
 sdb_data_parse_op(const char *op)
 {
index cf4e27eca022ba6f61282c7c90653ecc908e8b38..c03c0c1b6210b730dc0790693f642d45b4012886 100644 (file)
@@ -173,6 +173,20 @@ sdb_data_isnull(const sdb_data_t *datum);
 _Bool
 sdb_data_inarray(const sdb_data_t *value, const sdb_data_t *array);
 
+/*
+ * sdb_data_array_get:
+ * Get the i-th value stored in the specified array and store an alias in
+ * 'value'. Storing an alias means that the value points to the actual array
+ * element. Do *not* free the value after using it (i.e., don't use
+ * sdb_data_free_datum).
+ *
+ * Returns:
+ *  - 0 on success
+ *  - a negative value else
+ */
+int
+sdb_data_array_get(const sdb_data_t *array, size_t i, sdb_data_t *value);
+
 /*
  * Operators supported by sdb_data_eval_expr.
  */
index a647e020bb7e63b8b34d3d95c6eee81201c00474..704ebdd48b43ae58cf38b62c8d18fb4c0e1b781c 100644 (file)
@@ -794,6 +794,81 @@ START_TEST(test_inarray)
 }
 END_TEST
 
+START_TEST(test_array_get)
+{
+       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 array;
+               size_t i;
+               sdb_data_t expected;
+       } golden_data[] = {
+               { int_array, 0, { SDB_TYPE_INTEGER, { .integer = 47 } } },
+               { int_array, 1, { SDB_TYPE_INTEGER, { .integer = 11 } } },
+               { int_array, 2, { SDB_TYPE_INTEGER, { .integer = 64 } } },
+               { int_array, 3, { -1, { .integer = 0 } } },
+               { dec_array, 0, { SDB_TYPE_DECIMAL, { .decimal = 12.3 } } },
+               { dec_array, 1, { SDB_TYPE_DECIMAL, { .decimal = 47.11 } } },
+               { dec_array, 2, { SDB_TYPE_DECIMAL, { .decimal = 64.0 } } },
+               { dec_array, 3, { -1, { .integer = 0 } } },
+               { string_array, 0, { SDB_TYPE_STRING, { .string = "foo" } } },
+               { string_array, 1, { SDB_TYPE_STRING, { .string = "bar" } } },
+               { string_array, 2, { SDB_TYPE_STRING, { .string = "qux" } } },
+               { string_array, 3, { SDB_TYPE_STRING, { .string = "baz" } } },
+               { string_array, 4, { -1, { .integer = 0 } } },
+               { { SDB_TYPE_INTEGER, { .integer = 666 } }, 0, { -1, { .integer = 0 } } },
+               { { SDB_TYPE_INTEGER, { .integer = 666 } }, 1, { -1, { .integer = 0 } } },
+       };
+
+       size_t i;
+
+       for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
+               char a_str[1024] = "", v_str[1024] = "", exp_str[1024] = "";
+               sdb_data_t value = SDB_DATA_INIT;
+               int check;
+
+               sdb_data_format(&golden_data[i].array,
+                               a_str, sizeof(a_str), SDB_UNQUOTED);
+               sdb_data_format(&golden_data[i].expected,
+                               exp_str, sizeof(exp_str), SDB_UNQUOTED);
+
+               check = sdb_data_array_get(&golden_data[i].array,
+                               golden_data[i].i, &value);
+
+               sdb_data_format(&value, v_str, sizeof(v_str), SDB_UNQUOTED);
+
+               if (golden_data[i].expected.type < 0) {
+                       fail_unless(check < 0,
+                                       "sdb_data_array_get(%s, %zu) = %d (%s); expected: <0",
+                                       a_str, golden_data[i].i, check, v_str);
+                       continue;
+               }
+
+               fail_unless(check == 0,
+                               "sdb_data_array_get(%s, %zu) = %d; expected: 0",
+                               a_str, golden_data[i].i, check);
+               fail_unless(! sdb_data_cmp(&value, &golden_data[i].expected),
+                               "sdb_data_array_get(%s, %zu) -> '%s'; expected: '%s'",
+                               a_str, golden_data[i].i, v_str, exp_str);
+       }
+}
+END_TEST
+
 START_TEST(test_parse_op)
 {
        struct {
@@ -1670,6 +1745,7 @@ core_data_suite(void)
        tcase_add_test(tc, test_cmp);
        tcase_add_test(tc, test_strcmp);
        tcase_add_test(tc, test_inarray);
+       tcase_add_test(tc, test_array_get);
        tcase_add_test(tc, test_parse_op);
        tcase_add_test(tc, test_expr_eval);
        tcase_add_test(tc, test_format);