Code

data: Let inarray() support <array> IN <array> checks.
authorSebastian Harl <sh@tokkee.org>
Wed, 12 Nov 2014 19:55:10 +0000 (20:55 +0100)
committerSebastian Harl <sh@tokkee.org>
Wed, 12 Nov 2014 19:55:10 +0000 (20:55 +0100)
This check returns true if all elements of the first array are included in the
second array where order does not matter.

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

index 27c7aa1452de6aaaeb09f47c5ccd4ea1ee018415..88c7f8246953d58f1af76a01a04e1919eb96f8c2 100644 (file)
@@ -631,39 +631,58 @@ sdb_data_isnull(const sdb_data_t *datum)
 _Bool
 sdb_data_inarray(const sdb_data_t *value, const sdb_data_t *array)
 {
-       size_t i;
+       const void *values;
+       size_t length, i;
+       int type = value->type & 0xff;
 
        if (sdb_data_isnull(value) || sdb_data_isnull(array))
                return 0;
-       if ((value->type & SDB_TYPE_ARRAY) || (! (array->type & SDB_TYPE_ARRAY)))
+       if (! (array->type & SDB_TYPE_ARRAY))
                return 0;
-       if (value->type != (array->type & 0xff))
+       if ((value->type & 0xff) != (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;
+       if (value->type & SDB_TYPE_ARRAY) {
+               values = value->data.array.values;
+               length = value->data.array.length;
        }
        else {
-               /* TODO */
-               errno = ENOTSUP;
-               return 0;
+               values = &value->data;
+               length = 1;
        }
-       return 0;
+
+       for (i = 0; i < length; ++i) {
+               size_t j;
+
+               if (type == SDB_TYPE_INTEGER) {
+                       int64_t *v = array->data.array.values;
+                       for (j = 0; j < array->data.array.length; ++j)
+                               if (((const int64_t *)values)[i] == v[j])
+                                       break;
+               }
+               else if (type == SDB_TYPE_DECIMAL) {
+                       double *v = array->data.array.values;
+                       for (j = 0; j < array->data.array.length; ++j)
+                               if (((const double *)values)[i] == v[j])
+                                       break;
+               }
+               else if (type == SDB_TYPE_STRING) {
+                       char **v = array->data.array.values;
+                       for (j = 0; j < array->data.array.length; ++j)
+                               if (!strcasecmp(((const char * const*)values)[i], v[j]))
+                                       break;
+               }
+               else {
+                       /* TODO */
+                       errno = ENOTSUP;
+                       return 0;
+               }
+
+               if (j >= array->data.array.length)
+                       /* value not found */
+                       return 0;
+       }
+       return 1;
 } /* sdb_data_inarray */
 
 int
index c03c0c1b6210b730dc0790693f642d45b4012886..997cf9f0a320c616af5074c86f749a03b1dca8b1 100644 (file)
@@ -168,7 +168,10 @@ 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.
+ * to match the type of the value. The value may be another array. In that
+ * case, the element types have to match and the function returns true if all
+ * elements of the first array are included in the second where order does not
+ * matter.
  */
 _Bool
 sdb_data_inarray(const sdb_data_t *value, const sdb_data_t *array);
index 2baa6a15876d05ff53b1b98283379cf7d1f50f1a..956cf3108c0a5d598afcb5eb75e72f938f61c3d8 100644 (file)
@@ -730,21 +730,51 @@ END_TEST
 START_TEST(test_inarray)
 {
        int64_t int_values[] = { 47, 11, 64 };
+       int64_t int_values2[] = { 64, 11 };
+       int64_t int_values3[] = { 47, 11, 42 };
        double dec_values[] = { 12.3, 47.11, 64.0 };
+       double dec_values2[] = { 12.3, 47.11 };
+       double dec_values3[] = { 2.3, 47.11 };
        char *string_values[] = { "foo", "bar", "qux", "baz" };
+       char *string_values2[] = { "qux", "bar" };
+       char *string_values3[] = { "foo", "bar", "qux", "baz", "bay" };
 
        sdb_data_t int_array = {
                SDB_TYPE_ARRAY | SDB_TYPE_INTEGER,
                { .array = { SDB_STATIC_ARRAY_LEN(int_values), int_values } }
        };
+       sdb_data_t int_array2 = {
+               SDB_TYPE_ARRAY | SDB_TYPE_INTEGER,
+               { .array = { SDB_STATIC_ARRAY_LEN(int_values2), int_values2 } }
+       };
+       sdb_data_t int_array3 = {
+               SDB_TYPE_ARRAY | SDB_TYPE_INTEGER,
+               { .array = { SDB_STATIC_ARRAY_LEN(int_values3), int_values3 } }
+       };
        sdb_data_t dec_array = {
                SDB_TYPE_ARRAY | SDB_TYPE_DECIMAL,
                { .array = { SDB_STATIC_ARRAY_LEN(dec_values), dec_values } }
        };
+       sdb_data_t dec_array2 = {
+               SDB_TYPE_ARRAY | SDB_TYPE_DECIMAL,
+               { .array = { SDB_STATIC_ARRAY_LEN(dec_values2), dec_values2 } }
+       };
+       sdb_data_t dec_array3 = {
+               SDB_TYPE_ARRAY | SDB_TYPE_DECIMAL,
+               { .array = { SDB_STATIC_ARRAY_LEN(dec_values3), dec_values3 } }
+       };
        sdb_data_t string_array = {
                SDB_TYPE_ARRAY | SDB_TYPE_STRING,
                { .array = { SDB_STATIC_ARRAY_LEN(string_values), string_values } }
        };
+       sdb_data_t string_array2 = {
+               SDB_TYPE_ARRAY | SDB_TYPE_STRING,
+               { .array = { SDB_STATIC_ARRAY_LEN(string_values2), string_values2 } }
+       };
+       sdb_data_t string_array3 = {
+               SDB_TYPE_ARRAY | SDB_TYPE_STRING,
+               { .array = { SDB_STATIC_ARRAY_LEN(string_values3), string_values3 } }
+       };
 
        struct {
                sdb_data_t value;
@@ -756,8 +786,6 @@ START_TEST(test_inarray)
                { { 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 },
@@ -773,6 +801,22 @@ START_TEST(test_inarray)
                { { SDB_TYPE_STRING,  { .string  = "ba"  } }, string_array, 0 },
                { { SDB_TYPE_STRING,  { .string  = "abc" } }, string_array, 0 },
                { { SDB_TYPE_NULL,    { .integer = 0     } }, string_array, 0 },
+               { int_array, { SDB_TYPE_INTEGER, { .integer = 47 } },       0 },
+               { int_array,     int_array,    1 },
+               { int_array2,    int_array,    1 },
+               { int_array3,    int_array,    0 },
+               { dec_array2,    int_array,    0 },
+               { string_array2, int_array,    0 },
+               { dec_array,     dec_array,    1 },
+               { dec_array2,    dec_array,    1 },
+               { dec_array3,    dec_array,    0 },
+               { int_array2,    dec_array,    0 },
+               { string_array2, dec_array,    0 },
+               { string_array,  string_array, 1 },
+               { string_array2, string_array, 1 },
+               { string_array3, string_array, 0 },
+               { int_array2,    string_array, 0 },
+               { dec_array2,    string_array, 0 },
        };
 
        size_t i;