summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: a4208bf)
raw | patch | inline | side by side (parent: a4208bf)
author | Sebastian Harl <sh@tokkee.org> | |
Mon, 20 Oct 2014 06:03:13 +0000 (08:03 +0200) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Mon, 20 Oct 2014 06:03:13 +0000 (08:03 +0200) |
An array may contain elements of one type and it's stored in compact raw form
(as in: not an array of union values but an array of the actual values).
'copy', 'free', and 'concat' operations are currently supported but limited to
integer, decimal, or string element types. ENOTSUP is returned for any other
operations.
(as in: not an array of union values but an array of the actual values).
'copy', 'free', and 'concat' operations are currently supported but limited to
integer, decimal, or string element types. ENOTSUP is returned for any other
operations.
src/core/data.c | patch | blob | history | |
src/include/core/data.h | 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 c1e99a8cab82ed742b76a8d8165fe44ceb999269..0e40474edaabab45e98b9dc30d31b2b244de33d9 100644 (file)
--- a/src/core/data.c
+++ b/src/core/data.c
* private helper functions
*/
+/* this function supports in-place copies */
+static int
+copy_array_values(sdb_data_t *dst, const sdb_data_t *src, size_t elem_size)
+{
+ int type = src->type & 0xff;
+
+ if ((type == SDB_TYPE_INTEGER) || (type == SDB_TYPE_DECIMAL)) {
+ if (dst != src)
+ memcpy(dst->data.array.values, src->data.array.values,
+ src->data.array.length * elem_size);
+ }
+ else if (type == SDB_TYPE_STRING) {
+ char **s = src->data.array.values;
+ char **d = dst->data.array.values;
+ size_t i;
+
+ for (i = 0; i < src->data.array.length; ++i) {
+ d[i] = strdup(s[i]);
+ if (! d[i])
+ return -1;
+ }
+ }
+ else {
+ /* TODO */
+ errno = ENOTSUP;
+ return -1;
+ }
+ return 0;
+} /* copy_array_values */
+
+static void
+free_array_values(sdb_data_t *datum)
+{
+ int type = datum->type & 0xff;
+
+ if (type == SDB_TYPE_STRING) {
+ char **v = datum->data.array.values;
+ size_t i;
+
+ for (i = 0; i < datum->data.array.length; ++i) {
+ if (v[i])
+ free(v[i]);
+ v[i] = NULL;
+ }
+ }
+} /* free_array_values */
+
/* Calculate the linear function 'd1 + n * d2'. */
static int
data_lin(const sdb_data_t *d1, int n, const sdb_data_t *d2, sdb_data_t *res)
unsigned char *s1, *s2;
size_t len1, len2;
+ /* TODO: support array plus element */
if (d1->type != d2->type)
return -1;
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;
if (res->type == SDB_TYPE_STRING) {
res->data.string = (char *)new;
}
- else {
+ else if (res->type == SDB_TYPE_BINARY) {
res->data.binary.datum = new;
res->data.binary.length = len1 + len2;
}
+ else if (d1->type & SDB_TYPE_ARRAY) {
+ res->data.array.values = new;
+ res->data.array.length = len1 + len2;
+ 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 */
+ free(new);
+ res->data.array.values = NULL;
+ res->data.array.length = 0;
+ return -1;
+ }
+ }
return 0;
} /* data_concat */
else
memset(&tmp.data.re.regex, 0, sizeof(tmp.data.re.regex));
}
+ else if (src->type & SDB_TYPE_ARRAY) {
+ if (src->data.array.values) {
+ size_t elem_size = sdb_data_sizeof(src->type & 0xff);
+ tmp.data.array.values = calloc(src->data.array.length, elem_size);
+ if (! tmp.data.array.values)
+ return -1;
+ if (copy_array_values(&tmp, src, elem_size)) {
+ sdb_data_free_datum(&tmp);
+ return -1;
+ }
+ }
+ }
sdb_data_free_datum(dst);
*dst = tmp;
datum->data.re.raw = NULL;
memset(&datum->data.re.regex, 0, sizeof(datum->data.re.regex));
}
+ else if (datum->type & SDB_TYPE_ARRAY) {
+ free_array_values(datum);
+ if (datum->data.array.values)
+ free(datum->data.array.values);
+ datum->data.array.values = NULL;
+ datum->data.array.length = 0;
+ }
} /* sdb_data_free_datum */
int
CMP_NULL(d1->data.re.raw, d2->data.re.raw);
return strcmp(d1->data.re.raw, d2->data.re.raw);
}
+ else if (d1->type & SDB_TYPE_ARRAY) {
+ /* TODO */
+ errno = ENOTSUP;
+ return -1;
+ }
return -1;
} /* sdb_data_cmp */
char d1_str[sdb_data_strlen(d1) + 1];
char d2_str[sdb_data_strlen(d2) + 1];
+ if ((d1->type & SDB_TYPE_ARRAY) || (d2->type & SDB_TYPE_ARRAY)) {
+ /* TODO */
+ errno = ENOTSUP;
+ return -1;
+ }
+
if (sdb_data_isnull(d1))
d1 = NULL;
if (sdb_data_isnull(d2))
return 1;
if ((datum->type == SDB_TYPE_REGEX) && (! datum->data.re.raw))
return 1;
+ if ((datum->type & SDB_TYPE_ARRAY) && (! datum->data.array.values))
+ return 1;
return 0;
} /* sdb_data_isnull */
/* "/.../" */
return strlen(datum->data.re.raw) + 4;
}
+ else if (datum->type & SDB_TYPE_ARRAY) {
+ /* TODO */
+ errno = ENOTSUP;
+ return 0;
+ }
return 0;
} /* sdb_data_strlen */
data = tmp;
}
}
+ else if (datum->type & SDB_TYPE_ARRAY) {
+ /* TODO */
+ errno = ENOTSUP;
+ return -1;
+ }
if (data) {
if (quoted == SDB_UNQUOTED)
sdb_data_free_datum(&tmp);
}
}
+ else if (type & SDB_TYPE_ARRAY) {
+ /* TODO */
+ errno = ENOTSUP;
+ return -1;
+ }
else {
errno = EINVAL;
return -1;
index c8c7482e796f4438aeafdb8eebe4588223636e7b..cfdf48db8ea7d63fd1c2ef718901706bd10ca2e0 100644 (file)
--- a/src/include/core/data.h
+++ b/src/include/core/data.h
SDB_TYPE_DATETIME,
SDB_TYPE_BINARY,
SDB_TYPE_REGEX, /* extended, case-insensitive POSIX regex */
+
+ /* flags: */
+ SDB_TYPE_ARRAY = 1 << 8,
};
#define SDB_TYPE_TO_STRING(t) \
: ((t) == SDB_TYPE_BINARY) ? "BINARY" \
: ((t) == SDB_TYPE_REGEX) ? "REGEX" : "UNKNOWN")
+union sdb_datum;
+typedef union sdb_datum sdb_datum_t;
+
+union sdb_datum {
+ int64_t integer; /* SDB_TYPE_INTEGER */
+ double decimal; /* SDB_TYPE_DECIMAL */
+ char *string; /* SDB_TYPE_STRING */
+ sdb_time_t datetime; /* SDB_TYPE_DATETIME */
+ struct {
+ size_t length;
+ unsigned char *datum;
+ } binary; /* SDB_TYPE_BINARY */
+ struct {
+ char *raw;
+ regex_t regex;
+ } re; /* SDB_TYPE_REGEX */
+
+ struct {
+ size_t length;
+ void *values;
+ } array;
+};
+
/*
* sdb_data_t:
- * A datum retrieved from an arbitrary data source.
+ * An arbitrary value of a specified type.
*/
typedef struct {
- int type;
- union {
- int64_t integer; /* SDB_TYPE_INTEGER */
- double decimal; /* SDB_TYPE_DECIMAL */
- char *string; /* SDB_TYPE_STRING */
- sdb_time_t datetime; /* SDB_TYPE_DATETIME */
- struct {
- size_t length;
- unsigned char *datum;
- } binary; /* SDB_TYPE_BINARY */
- struct {
- char *raw;
- regex_t regex;
- } re; /* SDB_TYPE_REGEX */
- } data;
+ int type; /* type of the datum */
+ sdb_datum_t data;
} sdb_data_t;
#define SDB_DATA_INIT { SDB_TYPE_NULL, { .integer = 0 } }
index 702afa487a0fa9aa7fbc31090f7d133f770ffe20..c33382386e8c99e60ac08c69af95cd6cba0486e5 100644 (file)
--- a/t/unit/core/data_test.c
+++ b/t/unit/core/data_test.c
sdb_data_t d1, d2;
int check;
+ int int_values[] = { 47, 11, 23 };
+ char *string_values[] = { "foo", "bar", "qux" "baz" };
+ size_t i;
+
d2.type = SDB_TYPE_INTEGER;
d2.data.integer = 4711;
memset(&d1, 0, sizeof(d1));
fail_unless(d1.type == d2.type,
"sdb_data_copy() didn't copy type; got: %i; expected: %i",
d1.type, d2.type);
+
+ d2.type = SDB_TYPE_ARRAY | SDB_TYPE_INTEGER;
+ d2.data.array.length = SDB_STATIC_ARRAY_LEN(int_values);
+ d2.data.array.values = int_values;
+ check = sdb_data_copy(&d1, &d2);
+ fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
+ fail_unless(d1.type == d2.type,
+ "sdb_data_copy() didn't copy type; got: %i; expected: %i",
+ d1.type, d2.type);
+ fail_unless(d1.data.array.values != d2.data.array.values,
+ "sdb_data_copy() didn't copy values: got: %p; expected: %p",
+ d1.data.array.values, d2.data.array.values);
+ for (i = 0; i < SDB_STATIC_ARRAY_LEN(int_values); ++i) {
+ int *i1 = d1.data.array.values;
+ int *i2 = d2.data.array.values;
+ fail_unless(i1[i] == i2[i],
+ "sdb_data_copy() modified integer value %d: "
+ "got: %d; expected: %d", i, i1[i], i2[i]);
+ }
+ sdb_data_free_datum(&d1);
+
+ d2.type = SDB_TYPE_ARRAY | SDB_TYPE_STRING;
+ d2.data.array.length = SDB_STATIC_ARRAY_LEN(string_values);
+ d2.data.array.values = string_values;
+ check = sdb_data_copy(&d1, &d2);
+ fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
+ fail_unless(d1.type == d2.type,
+ "sdb_data_copy() didn't copy type; got: %i; expected: %i",
+ d1.type, d2.type);
+ fail_unless(d1.data.array.values != d2.data.array.values,
+ "sdb_data_copy() didn't copy values: got: %p; expected: %p",
+ d1.data.array.values, d2.data.array.values);
+ for (i = 0; i < SDB_STATIC_ARRAY_LEN(string_values); ++i) {
+ char **s1 = d1.data.array.values;
+ char **s2 = d2.data.array.values;
+ fail_unless(s1[i] != s2[i],
+ "sdb_data_copy() didn't copy string value %d", i);
+ fail_unless(!strcmp(s1[i], s2[i]),
+ "sdb_data_copy() modified string value %d: "
+ "got: %s; expected: %s", i, s1[i], s2[i]);
+ }
+ sdb_data_free_datum(&d1);
}
END_TEST