summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 667ae3c)
raw | patch | inline | side by side (parent: 667ae3c)
author | Sebastian Harl <sh@tokkee.org> | |
Mon, 10 Nov 2014 17:40:20 +0000 (18:40 +0100) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Mon, 10 Nov 2014 17:40:20 +0000 (18:40 +0100) |
That is, concatenation may be used to prepend to or append to an array.
src/core/data.c | patch | blob | history | |
t/unit/core/data_test.c | patch | blob | history |
diff --git a/src/core/data.c b/src/core/data.c
index 28d4c36ad66cbd92149ef6bea5a1f97d0e635ca4..27c7aa1452de6aaaeb09f47c5ccd4ea1ee018415 100644 (file)
--- a/src/core/data.c
+++ b/src/core/data.c
data_concat(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res)
{
unsigned char *new;
- unsigned char *s1, *s2;
- size_t len1, len2;
+ const unsigned char *s1, *s2;
+ size_t len1, len2, array1_len = 0, array2_len = 0;
- /* TODO: support array plus element */
- if (d1->type != d2->type)
+ if ((d1->type & 0xff) != (d2->type & 0xff))
return -1;
- if (d1->type == SDB_TYPE_STRING) {
+ if ((d1->type & SDB_TYPE_ARRAY) || (d2->type & SDB_TYPE_ARRAY)) {
+ size_t elem_size = sdb_data_sizeof(d1->type & 0xff);
+ if (d1->type & SDB_TYPE_ARRAY) {
+ s1 = (const unsigned char *)d1->data.array.values;
+ array1_len = d1->data.array.length;
+ }
+ else {
+ /* As per C99, section 6.7.2.1, paragraph 14:
+ * "A pointer to a union object, suitably converted, points to
+ * each of its members" */
+ s1 = (const unsigned char *)&d1->data;
+ array1_len = 1;
+ }
+ if (d2->type & SDB_TYPE_ARRAY) {
+ s2 = (const unsigned char *)d2->data.array.values;
+ array2_len = d2->data.array.length;
+ }
+ else {
+ s2 = (const unsigned char *)&d2->data;
+ array2_len = 1;
+ }
+ len1 = array1_len * elem_size;
+ len2 = array2_len * elem_size;
+ }
+ else if (d1->type == SDB_TYPE_STRING) {
s1 = (unsigned char *)d1->data.string;
s2 = (unsigned char *)d2->data.string;
- len1 = s1 ? strlen((char *)s1) : 0;
- len2 = s2 ? strlen((char *)s2) : 0;
+ len1 = s1 ? strlen((const char *)s1) : 0;
+ len2 = s2 ? strlen((const char *)s2) : 0;
}
else if (d1->type == SDB_TYPE_BINARY) {
s1 = d1->data.binary.datum;
len1 = d1->data.binary.length;
len2 = d2->data.binary.length;
}
- else if (d1->type & SDB_TYPE_ARRAY) {
- size_t elem_size = sdb_data_sizeof(d1->type & 0xff);
- s1 = (unsigned char *)d1->data.array.values;
- s2 = (unsigned char *)d2->data.array.values;
- len1 = d1->data.array.length * elem_size;
- len2 = d2->data.array.length * elem_size;
- }
else
return -1;
memcpy(new + len1, s2, len2);
new[len1 + len2] = '\0';
- res->type = d1->type;
+ /* element types match and if either datum is an array,
+ * the result is an array as well */
+ res->type = d1->type | d2->type;
if (res->type == SDB_TYPE_STRING) {
res->data.string = (char *)new;
}
res->data.binary.datum = new;
res->data.binary.length = len1 + len2;
}
- else if (d1->type & SDB_TYPE_ARRAY) {
+ else if (res->type & SDB_TYPE_ARRAY) {
res->data.array.values = new;
- res->data.array.length = d1->data.array.length + d2->data.array.length;
+ res->data.array.length = array1_len + array2_len;
if (copy_array_values(res, res, sdb_data_sizeof(res->type & 0xff))) {
/* this leaks already copied values but there's not much we can
* do and this should only happen if we're in trouble anyway */
if ((op <= 0) || (SDB_STATIC_ARRAY_LEN(op_matrix) < (size_t)op))
return -1;
- /* arrays only support concat; type has to match */
+ /* arrays only support concat; element type has to match */
if ((type1 & SDB_TYPE_ARRAY) || (type2 & SDB_TYPE_ARRAY)) {
- if ((type1 != type2) || (op != SDB_DATA_CONCAT))
+ if (((type1 & 0xff) != (type2 & 0xff)) || (op != SDB_DATA_CONCAT))
return -1;
- return type1;
+ return type1 | SDB_TYPE_ARRAY;
}
if ((type1 < 0) || (types_num < type1)
|| (type2 < 0) || (types_num < type2))
index 2da33a19833b5d1204aa39ce2834511cb5e13031..2baa6a15876d05ff53b1b98283379cf7d1f50f1a 100644 (file)
--- a/t/unit/core/data_test.c
+++ b/t/unit/core/data_test.c
sdb_data_t err = { -1, { .integer = 0 } };
int64_t int_values[] = { 47, 11, 23 };
+ int64_t expected_int_append[] = { 47, 11, 23, 42 };
+ int64_t expected_int_prepend[] = { 42, 47, 11, 23 };
int64_t expected_int_concat[] = { 47, 11, 23, 47, 11, 23 };
char *string_values[] = { "foo", "bar", "qux" "baz" };
+ char *expected_string_append[] = { "foo", "bar", "qux" "baz", "bay" };
+ char *expected_string_prepend[] = { "bay", "foo", "bar", "qux" "baz" };
char *expected_string_concat[] =
{ "foo", "bar", "qux" "baz", "foo", "bar", "qux" "baz" };
} },
},
},
+ {
+ {
+ SDB_TYPE_ARRAY | SDB_TYPE_INTEGER,
+ { .array = { SDB_STATIC_ARRAY_LEN(int_values), int_values } },
+ },
+ { SDB_TYPE_INTEGER, { .integer = 42 }, },
+ err,
+ err,
+ err,
+ err,
+ err,
+ {
+ SDB_TYPE_ARRAY | SDB_TYPE_INTEGER,
+ { .array = {
+ SDB_STATIC_ARRAY_LEN(expected_int_append),
+ expected_int_append
+ } },
+ },
+ },
+ {
+ { SDB_TYPE_INTEGER, { .integer = 42 }, },
+ {
+ SDB_TYPE_ARRAY | SDB_TYPE_INTEGER,
+ { .array = { SDB_STATIC_ARRAY_LEN(int_values), int_values } },
+ },
+ err,
+ err,
+ err,
+ err,
+ err,
+ {
+ SDB_TYPE_ARRAY | SDB_TYPE_INTEGER,
+ { .array = {
+ SDB_STATIC_ARRAY_LEN(expected_int_prepend),
+ expected_int_prepend
+ } },
+ },
+ },
{
{
SDB_TYPE_ARRAY | SDB_TYPE_STRING,
} },
},
},
+ {
+ {
+ SDB_TYPE_ARRAY | SDB_TYPE_STRING,
+ { .array = { SDB_STATIC_ARRAY_LEN(string_values), string_values } },
+ },
+ { SDB_TYPE_STRING, { .string = "bay" } },
+ err,
+ err,
+ err,
+ err,
+ err,
+ {
+ SDB_TYPE_ARRAY | SDB_TYPE_STRING,
+ { .array = {
+ SDB_STATIC_ARRAY_LEN(expected_string_append),
+ expected_string_append
+ } },
+ },
+ },
+ {
+ { SDB_TYPE_STRING, { .string = "bay" } },
+ {
+ SDB_TYPE_ARRAY | SDB_TYPE_STRING,
+ { .array = { SDB_STATIC_ARRAY_LEN(string_values), string_values } },
+ },
+ err,
+ err,
+ err,
+ err,
+ err,
+ {
+ SDB_TYPE_ARRAY | SDB_TYPE_STRING,
+ { .array = {
+ SDB_STATIC_ARRAY_LEN(expected_string_prepend),
+ expected_string_prepend
+ } },
+ },
+ },
{
{ SDB_TYPE_NULL, { .integer = 0 } },
{ SDB_TYPE_NULL, { .integer = 0 } },