dtype.c

Dynamic-ish typing library
git clone git://git.finwo.net/lib/dtype.c
Log | Files | Refs | README | LICENSE

commit 6d6bc4e5fda551d544a72e8a157c59ab9d7f9b69
parent ac47eecae739f172adfe92b99744c1f66a680c6f
Author: Yersa Nordman <finwo@pm.me>
Date:   Wed, 15 May 2024 23:22:28 +0200

Added basic testing

Diffstat:
M.gitignore | 2++
Mbenchmark.c | 2++
Dconfig.mk | 1-
Mpackage.ini | 5++++-
Dsrc/dtype.c | 0
Msrc/dtype.h | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtest.c | 53++++++++++++++++++++++++++++++++++++++++++++++++++++-
7 files changed, 138 insertions(+), 3 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -5,3 +5,5 @@ /libdtype.* /benchmark /test +/.cache/ +/compile_commands.json diff --git a/benchmark.c b/benchmark.c @@ -1,3 +1,5 @@ +#include "src/dtype.h" + int main() { return 0; } diff --git a/config.mk b/config.mk @@ -1 +0,0 @@ -SRC+=__DIRNAME/src/dtype.c diff --git a/package.ini b/package.ini @@ -1,5 +1,8 @@ +[dependencies] +finwo/assert=main +tidwall/buf=master + [export] -config.mk=config.mk include/finwo/dtype.h=src/dtype.h [package] diff --git a/src/dtype.c b/src/dtype.c diff --git a/src/dtype.h b/src/dtype.h @@ -0,0 +1,78 @@ +#ifndef __FINWO_DTYPE_H__ +#define __FINWO_DTYPE_H__ + +#include <stdio.h> + +#include <stdlib.h> +#include <string.h> + +#include "tidwall/buf.h" + +enum dtype_typ { + DTYPE_NULL, + DTYPE_STRING, + DTYPE_INTEGER, + DTYPE_DOUBLE, + DTYPE_BUFFER, + DTYPE_UNKNOWN, +}; + +struct dtype_value { + union { + void *val_null; + char *val_string; + int val_integer; + double val_double; + struct buf *val_buffer; + void *val_unknown; + }; + enum dtype_typ type; +}; + +#define dtype_type(x) ((x)->type) + +struct dtype_value * dtype_copy(const struct dtype_value *subject) { + struct dtype_value *output = (struct dtype_value *)calloc(1, sizeof(struct dtype_value)); + memcpy(output, subject, sizeof(struct dtype_value)); + if (dtype_type(output) == DTYPE_STRING) { + output->val_string = strdup(output->val_string); + } else if (dtype_type(subject) == DTYPE_BUFFER) { + output->val_buffer = malloc(sizeof(struct buf)); + memcpy(output->val_buffer, subject->val_buffer, sizeof(struct buf)); + output->val_buffer->data = malloc(output->val_buffer->cap); + memcpy(output->val_buffer->data, subject->val_buffer->data, subject->val_buffer->len); + } + return output; +} + +#define dtype_init_null() dtype_copy(&((const struct dtype_value){ .type = DTYPE_NULL })) +#define dtype_init_string(x) dtype_copy(&((const struct dtype_value){ .type = DTYPE_STRING , .val_string = x })) +#define dtype_init_integer(x) dtype_copy(&((const struct dtype_value){ .type = DTYPE_INTEGER, .val_integer = x })) +#define dtype_init_double(x) dtype_copy(&((const struct dtype_value){ .type = DTYPE_DOUBLE , .val_double = x })) +#define dtype_init_buffer(x) dtype_copy(&((const struct dtype_value){ .type = DTYPE_BUFFER , .val_buffer = x })) +#define dtype_init_unknown(x) dtype_copy(&((const struct dtype_value){ .type = DTYPE_UNKNOWN, .val_unknown = x })) + +#define dtype_buf_append(x,data,len) buf_append(x->val_buffer, data, len) +#define dtype_buf_append_byte(x,c) buf_append_byte(x->val_buffer, c) +#define dtype_buf_clear(x) buf_clear(x->val_buffer) + +#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900) +#define dtype_init(x) _Generic((x), \ + char * : dtype_init_string, \ + int : dtype_init_integer, \ + double : dtype_init_double, \ + void * : dtype_init_unknown, \ + struct buf *: dtype_init_buffer \ + )(x) +#endif + +void dtype_free(struct dtype_value *subject) { + if (dtype_type(subject) == DTYPE_STRING) { + free(subject->val_string); + } else if (dtype_type(subject) == DTYPE_BUFFER) { + buf_clear((struct buf *)subject); + } + free(subject); +} + +#endif // __FINWO_DTYPE_H__ diff --git a/test.c b/test.c @@ -1,3 +1,54 @@ +#include "finwo/assert.h" + +#include "src/dtype.h" + +void test_init() { + struct dtype_value *subject; + char *str = "Hello World"; + void *dat = strdup(str); + size_t datl = strlen(str)+1; + + subject = dtype_init_null(); + ASSERT("init_null returns a valid pointer", subject != NULL ); + ASSERT("init_null returns a null value" , dtype_type(subject) == DTYPE_NULL); + dtype_free(subject); + + subject = dtype_init_string(str); + ASSERT("init_string returns a valid pointer" , subject != NULL ); + ASSERT("init_string returns the correct type" , dtype_type(subject) == DTYPE_STRING); + ASSERT("init_string returns a cloned value" , subject->val_string != dat ); + ASSERT("init_string returns the correct value", !strcmp(str, subject->val_string) ); + dtype_free(subject); + + subject = dtype_init_integer(12); + ASSERT("init_integer returns a valid pointer" , subject != NULL ); + ASSERT("init_integer returns the correct type" , dtype_type(subject) == DTYPE_INTEGER); + ASSERT("init_integer returns the correct value", subject->val_integer == 12 ); + dtype_free(subject); + + subject = dtype_init_double(12); + ASSERT("init_double returns a valid pointer" , subject != NULL ); + ASSERT("init_double returns the correct type" , dtype_type(subject) == DTYPE_DOUBLE); + ASSERT("init_double returns the correct value", subject->val_double == 12 ); + dtype_free(subject); + + subject = dtype_init_buffer((&((struct buf){ .cap = datl, .len = datl, .data = dat })) ); + ASSERT("init_buffer returns a valid pointer" , subject != NULL ); + ASSERT("init_buffer returns the correct type" , dtype_type(subject) == DTYPE_BUFFER ); + ASSERT("init_buffer returns a cloned value" , subject->val_buffer->data != dat ); + ASSERT("init_buffer returns the correct value", !strcmp(str, subject->val_buffer->data)); + dtype_free(subject); + + subject = dtype_init_unknown(dat); + ASSERT("init_unknown returns a valid pointer" , subject != NULL ); + ASSERT("init_unknown returns the correct type" , dtype_type(subject) == DTYPE_UNKNOWN); + ASSERT("init_unknown returns a copied value" , subject->val_unknown == dat ); + dtype_free(subject); + + ASSERT("unknown data is untouched after free", !strcmp(dat, str)); +} + int main() { - return 0; + RUN(test_init); + return TEST_REPORT(); }