From 8ffb3f64fb58144c9d74ca384d57580459a15a03 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Fri, 12 Apr 2024 09:23:43 -0600 Subject: [PATCH 1/9] build: bump to v0.5.0 Signed-off-by: Eduardo Silva --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7613e5b..f6a3556 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # C Floppy Version set(CFL_VERSION_MAJOR 0) -set(CFL_VERSION_MINOR 4) +set(CFL_VERSION_MINOR 5) set(CFL_VERSION_PATCH 0) set(CFL_VERSION_STR "${CFL_VERSION_MAJOR}.${CFL_VERSION_MINOR}.${CFL_VERSION_PATCH}") From 69e9918633e6d1d53109cb9a8a58387af090cc6f Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Fri, 12 Apr 2024 09:25:19 -0600 Subject: [PATCH 2/9] variant: new internal flag to mark referenced strings or bytes When creating variants as strings or bytes, upon creation the bytes for those data types are allocated in a new memory buffer, it's a copy of what the caller passed as a reference. There are cases where due to performance and optimization reasons the caller might want to keep a reference to the original buffer rather than a full copy. This patch adds a new flag called 'referenced' that can be used by the new API changes coming in the new series of patches. Signed-off-by: Eduardo Silva --- include/cfl/cfl_variant.h | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/include/cfl/cfl_variant.h b/include/cfl/cfl_variant.h index e7135c9..2a9a6cf 100644 --- a/include/cfl/cfl_variant.h +++ b/include/cfl/cfl_variant.h @@ -24,16 +24,16 @@ #include #include -#define CFL_VARIANT_STRING 1 -#define CFL_VARIANT_BOOL 2 -#define CFL_VARIANT_INT 3 +#define CFL_VARIANT_BOOL 1 +#define CFL_VARIANT_INT 2 +#define CFL_VARIANT_UINT 3 #define CFL_VARIANT_DOUBLE 4 -#define CFL_VARIANT_ARRAY 5 -#define CFL_VARIANT_KVLIST 6 -#define CFL_VARIANT_BYTES 7 -#define CFL_VARIANT_REFERENCE 8 -#define CFL_VARIANT_UINT 9 -#define CFL_VARIANT_NULL 10 +#define CFL_VARIANT_NULL 5 +#define CFL_VARIANT_REFERENCE 6 +#define CFL_VARIANT_STRING 7 +#define CFL_VARIANT_BYTES 8 +#define CFL_VARIANT_ARRAY 9 +#define CFL_VARIANT_KVLIST 10 struct cfl_array; struct cfl_kvlist; @@ -42,6 +42,18 @@ struct cfl_variant { int type; size_t size; + /* + * indicate if 'data' is being referenced for 'as_string' and 'as_bytes': + * + * CFL_TRUE: data is being referenced + * CFL_FALSE: data is owned by the variant + * + * Referenced data uses less memory, when the variant is not referenced we use + * a copy of the original data. + */ + uint8_t referenced; + + /* the data */ union { cfl_sds_t as_string; cfl_sds_t as_bytes; @@ -57,8 +69,8 @@ struct cfl_variant { int cfl_variant_print(FILE *fp, struct cfl_variant *val); struct cfl_variant *cfl_variant_create_from_string(char *value); -struct cfl_variant *cfl_variant_create_from_string_s(char *value, size_t value_length); -struct cfl_variant *cfl_variant_create_from_bytes(char *value, size_t length); +struct cfl_variant *cfl_variant_create_from_string_s(char *value, size_t value_length, int referenced); +struct cfl_variant *cfl_variant_create_from_bytes(char *value, size_t length, int referenced); struct cfl_variant *cfl_variant_create_from_bool(int value); struct cfl_variant *cfl_variant_create_from_int64(int64_t value); struct cfl_variant *cfl_variant_create_from_uint64(uint64_t value); From 7b15202354b6e119655713aa932a0687efc6a62c Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Fri, 12 Apr 2024 09:44:16 -0600 Subject: [PATCH 3/9] variant: refactor string and bytes handling API The following patch does prototype changes for functions that create variants of string and byte types, as well it adds two new functions to set the size/lengths of the buffers. The new prototypes are as follows: - struct cfl_variant *cfl_variant_create_from_string_s(char *value, size_t value_size, int referenced) - struct cfl_variant *cfl_variant_create_from_bytes(char *value, size_t length, int referenced) the new `referenced` flag marks if the caller desires to keep a reference to the original buffer rather a full copy in a new buffer. Also this patch adds two new functions to set and retrieve the size of such buffers: - void cfl_variant_size_set(struct cfl_variant *var, size_t size); - size_t cfl_variant_size_get(struct cfl_variant *var); Signed-off-by: Eduardo Silva --- include/cfl/cfl_variant.h | 3 +++ src/cfl_variant.c | 48 +++++++++++++++++++++++++++++---------- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/include/cfl/cfl_variant.h b/include/cfl/cfl_variant.h index 2a9a6cf..4f9953a 100644 --- a/include/cfl/cfl_variant.h +++ b/include/cfl/cfl_variant.h @@ -83,4 +83,7 @@ struct cfl_variant *cfl_variant_create(); void cfl_variant_destroy(struct cfl_variant *instance); +void cfl_variant_size_set(struct cfl_variant *var, size_t size); +size_t cfl_variant_size_get(struct cfl_variant *var); + #endif diff --git a/src/cfl_variant.c b/src/cfl_variant.c index 5f6748c..1b688b8 100644 --- a/src/cfl_variant.c +++ b/src/cfl_variant.c @@ -87,47 +87,60 @@ int cfl_variant_print(FILE *fp, struct cfl_variant *val) return ret; } -struct cfl_variant *cfl_variant_create_from_string_s(char *value, size_t value_size) +struct cfl_variant *cfl_variant_create_from_string_s(char *value, size_t value_size, int referenced) { struct cfl_variant *instance; instance = cfl_variant_create(); + if (!instance) { + return NULL; + } + instance->referenced = referenced; - if (instance != NULL) { + if (referenced) { + instance->data.as_string = value; + } + else { instance->data.as_string = cfl_sds_create_len(value, value_size); if (instance->data.as_string == NULL) { free(instance); instance = NULL; } - else { - instance->type = CFL_VARIANT_STRING; - } + } + cfl_variant_size_set(instance, value_size); + instance->type = CFL_VARIANT_STRING; return instance; } struct cfl_variant *cfl_variant_create_from_string(char *value) { - return cfl_variant_create_from_string_s(value, strlen(value)); + return cfl_variant_create_from_string_s(value, strlen(value), CFL_FALSE); } -struct cfl_variant *cfl_variant_create_from_bytes(char *value, size_t length) +struct cfl_variant *cfl_variant_create_from_bytes(char *value, size_t length, int referenced) { struct cfl_variant *instance; instance = cfl_variant_create(); + if (!instance){ + return NULL; + } + instance->referenced = referenced; - if (instance != NULL) { + if (referenced) { + instance->data.as_bytes = value; + } + else { instance->data.as_bytes = cfl_sds_create_len(value, length); if (instance->data.as_bytes == NULL) { free(instance); instance = NULL; } - else { - instance->type = CFL_VARIANT_BYTES; - } } + cfl_variant_size_set(instance, length); + instance->type = CFL_VARIANT_BYTES; return instance; } @@ -244,6 +257,7 @@ struct cfl_variant *cfl_variant_create() cfl_errno(); return NULL; } + instance->size = 0; return instance; } @@ -256,7 +270,7 @@ void cfl_variant_destroy(struct cfl_variant *instance) if (instance->type == CFL_VARIANT_STRING || instance->type == CFL_VARIANT_BYTES) { - if (instance->data.as_string != NULL) { + if (instance->data.as_string != NULL && !instance->referenced) { cfl_sds_destroy(instance->data.as_string); } } @@ -269,3 +283,13 @@ void cfl_variant_destroy(struct cfl_variant *instance) free(instance); } + +void cfl_variant_size_set(struct cfl_variant *var, size_t size) +{ + var->size = size; +} + +size_t cfl_variant_size_get(struct cfl_variant *var) +{ + return var->size; +} From 29e7e343321ae676ac9d983992c8ba074cd09a2e Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Fri, 12 Apr 2024 10:06:55 -0600 Subject: [PATCH 4/9] kvlist: adjust prototype for handling strings and bytes The following patch adjust the code to use the new Variant API prototypes and also changes some specific kvlist functions to reflect the functionality. The following functions have been modified: int cfl_kvlist_insert_bytes(struct cfl_kvlist *list, char *key, char *value, size_t value_length); size_t value_length, int referenced); int cfl_kvlist_insert_bytes_s(struct cfl_kvlist *list, char *key, size_t key_size, char *value, size_t value_length); size_t value_length, int referenced); int cfl_kvlist_insert_string_s(struct cfl_kvlist *list, char *key, size_t key_size, char *value, size_t value_size); char *value, size_t value_size, int referenced); Signed-off-by: Eduardo Silva --- include/cfl/cfl_kvlist.h | 9 ++++-- src/cfl_kvlist.c | 59 +++++++--------------------------------- 2 files changed, 16 insertions(+), 52 deletions(-) diff --git a/include/cfl/cfl_kvlist.h b/include/cfl/cfl_kvlist.h index 6c223de..ab25b16 100644 --- a/include/cfl/cfl_kvlist.h +++ b/include/cfl/cfl_kvlist.h @@ -43,7 +43,8 @@ int cfl_kvlist_insert_string(struct cfl_kvlist *list, int cfl_kvlist_insert_bytes(struct cfl_kvlist *list, char *key, char *value, - size_t value_length); + size_t value_length, + int referenced); int cfl_kvlist_insert_reference(struct cfl_kvlist *list, char *key, void *value); @@ -78,12 +79,14 @@ int cfl_kvlist_print(FILE *fp, struct cfl_kvlist *list); int cfl_kvlist_insert_string_s(struct cfl_kvlist *list, char *key, size_t key_size, - char *value, size_t value_size); + char *value, size_t value_size, + int referenced); int cfl_kvlist_insert_bytes_s(struct cfl_kvlist *list, char *key, size_t key_size, char *value, - size_t value_length); + size_t value_length, + int referenced); int cfl_kvlist_insert_reference_s(struct cfl_kvlist *list, char *key, size_t key_size, diff --git a/src/cfl_kvlist.c b/src/cfl_kvlist.c index ca1bf3b..12c7711 100644 --- a/src/cfl_kvlist.c +++ b/src/cfl_kvlist.c @@ -60,52 +60,15 @@ void cfl_kvlist_destroy(struct cfl_kvlist *list) free(list); } -/* -int cfl_kvlist_insert(struct cfl_kvlist *list, - char *key, void *value, - size_t value_length, - int value_type) -{ - struct cfl_kvpair *pair; - - pair = malloc(sizeof(struct cfl_kvpair)); - - if (pair == NULL) { - cfl_errno(); - - return -1; - } - - pair->key = cfl_sds_create(key); - - if (pair->key == NULL) { - free(pair); - - return -2; - } - - pair->val = cfl_variant_create(value, value_length, value_type); - - if (pair->val == NULL) { - cfl_sds_destroy(pair->key); - free(pair); - - return -3; - } - - cfl_list_add(&pair->_head, &list->list); - - return 0; -} -*/ - int cfl_kvlist_insert_string_s(struct cfl_kvlist *list, - char *key, size_t key_size, char *value, size_t value_size) + char *key, size_t key_size, + char *value, size_t value_size, + int referenced) { struct cfl_variant *value_instance; int result; - value_instance = cfl_variant_create_from_string_s(value, value_size); + value_instance = cfl_variant_create_from_string_s(value, value_size, referenced); if (value_instance == NULL) { return -1; } @@ -123,13 +86,12 @@ int cfl_kvlist_insert_string_s(struct cfl_kvlist *list, int cfl_kvlist_insert_bytes_s(struct cfl_kvlist *list, char *key, size_t key_size, char *value, - size_t length) + size_t length, int referenced) { struct cfl_variant *value_instance; int result; - value_instance = cfl_variant_create_from_bytes(value, length); - + value_instance = cfl_variant_create_from_bytes(value, length, referenced); if (value_instance == NULL) { return -1; } @@ -138,7 +100,6 @@ int cfl_kvlist_insert_bytes_s(struct cfl_kvlist *list, if (result) { cfl_variant_destroy(value_instance); - return -2; } @@ -390,14 +351,14 @@ int cfl_kvlist_insert_string(struct cfl_kvlist *list, key_len = strlen(key); val_len = strlen(value); - return cfl_kvlist_insert_string_s(list, key, key_len, value, val_len); + return cfl_kvlist_insert_string_s(list, key, key_len, value, val_len, CFL_FALSE); } int cfl_kvlist_insert_bytes(struct cfl_kvlist *list, - char *key, char *value, - size_t length) + char *key, char *value, + size_t length, int referenced) { - return cfl_kvlist_insert_bytes_s(list, key, strlen(key), value, length); + return cfl_kvlist_insert_bytes_s(list, key, strlen(key), value, length, referenced); } int cfl_kvlist_insert_reference(struct cfl_kvlist *list, From 670fd6020d3069ed94ac5e18feba505f807b1b88 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Fri, 12 Apr 2024 10:08:04 -0600 Subject: [PATCH 5/9] tests: kvlist: adjust tests to use new API Signed-off-by: Eduardo Silva --- tests/kvlist.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/kvlist.c b/tests/kvlist.c index fce4319..87a5593 100644 --- a/tests/kvlist.c +++ b/tests/kvlist.c @@ -238,7 +238,7 @@ static void insert_bytes() return; } - ret = cfl_kvlist_insert_bytes(list, "key", "value", 5); + ret = cfl_kvlist_insert_bytes(list, "key", "value", 5, CFL_TRUE); if (!TEST_CHECK(ret == 0)) { TEST_MSG("cfl_kvlist_insert_bytes failed"); cfl_kvlist_destroy(list); @@ -629,7 +629,7 @@ static void insert_string_s() return; } - ret = cfl_kvlist_insert_string_s(list, "key!!!!!", 3, "value", 5); + ret = cfl_kvlist_insert_string_s(list, "key!!!!!", 3, "value", 5, CFL_TRUE); if (!TEST_CHECK(ret == 0)) { TEST_MSG("cfl_kvlist_insert_string_s failed"); cfl_kvlist_destroy(list); @@ -671,7 +671,7 @@ static void insert_bytes_s() return; } - ret = cfl_kvlist_insert_bytes_s(list, "key!!!!!", 3, "value", 5); + ret = cfl_kvlist_insert_bytes_s(list, "key!!!!!", 3, "value", 5, CFL_FALSE); if (!TEST_CHECK(ret == 0)) { TEST_MSG("cfl_kvlist_insert_bytes_s failed"); cfl_kvlist_destroy(list); @@ -1065,7 +1065,7 @@ static void test_basics() ret = cfl_kvlist_insert_string(list, "key1", "value1"); TEST_CHECK(ret == 0); - ret = cfl_kvlist_insert_bytes(list, "key2", "value2", 6); + ret = cfl_kvlist_insert_bytes(list, "key2", "value2", 6, CFL_TRUE); TEST_CHECK(ret == 0); ret = cfl_kvlist_insert_reference(list, "key3", (void *) 0xdeadbeef); From 1baf92a76a6273e13eb0f0cf974ade9f3843af7a Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Fri, 12 Apr 2024 10:10:31 -0600 Subject: [PATCH 6/9] tests: variant: adjust API to new prototypes Signed-off-by: Eduardo Silva --- tests/variant.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/variant.c b/tests/variant.c index 0af2841..1824001 100644 --- a/tests/variant.c +++ b/tests/variant.c @@ -449,7 +449,7 @@ static void test_variant_print_string_s() continue; } - val = cfl_variant_create_from_string_s(inputs[i].str, inputs[i].str_size); + val = cfl_variant_create_from_string_s(inputs[i].str, inputs[i].str_size, CFL_TRUE); if (!TEST_CHECK(val != NULL)) { TEST_MSG("%d: cfl_variant_create_from_string failed", i); fclose(fp); @@ -487,7 +487,7 @@ static void test_variant_print_bytes() exit(1); } - val = cfl_variant_create_from_bytes(input, 4); + val = cfl_variant_create_from_bytes(input, 4, CFL_FALSE); if (!TEST_CHECK(val != NULL)) { TEST_MSG("cfl_variant_create_from_bytes failed"); fclose(fp); From 494bc260fc36e582f884d6e299c2e7776e624b7e Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Fri, 12 Apr 2024 11:15:16 -0600 Subject: [PATCH 7/9] tests: add new 'array' unit tests Signed-off-by: Eduardo Silva --- tests/CMakeLists.txt | 1 + tests/array.c | 371 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 372 insertions(+) create mode 100644 tests/array.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 513facc..13d113c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -3,6 +3,7 @@ include_directories(lib/acutest) set(UNIT_TESTS_FILES kv.c kvlist.c + array.c sds.c hash.c list.c diff --git a/tests/array.c b/tests/array.c new file mode 100644 index 0000000..dfb5195 --- /dev/null +++ b/tests/array.c @@ -0,0 +1,371 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CFL + * === + * Copyright (C) 2022-2024 The CFL Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include "cfl_tests_internal.h" + +static void create() +{ + struct cfl_array *arr; + + arr = cfl_array_create(0); + TEST_CHECK(arr != NULL); + cfl_array_destroy(arr); + + arr = cfl_array_create(100); + TEST_CHECK(arr != NULL); + cfl_array_destroy(arr); +} + +static void resizable() +{ + int ret; + struct cfl_array *arr; + + arr = cfl_array_create(0); + TEST_CHECK(arr != NULL); + + /* try to insert an element, it should fail size the array size (capacity) is zero) */ + ret = cfl_array_append_string(arr, "test"); + TEST_CHECK(ret != 0); + + /* make it resizable */ + ret = cfl_array_resizable(arr, CFL_TRUE); + TEST_CHECK(ret == 0); + + /* try to insert again, it should work */ + ret = cfl_array_append_string(arr, "test"); + TEST_CHECK(ret == 0); + + /* make it not resizable */ + ret = cfl_array_resizable(arr, CFL_FALSE); + TEST_CHECK(ret == 0); + + /* + * in the previous step, the array is not longer resizable, but by default + * it should have allocated 2 slots, the first one must work and the second must fail + */ + ret = cfl_array_append_string(arr, "must work"); + TEST_CHECK(ret == 0); + + ret = cfl_array_append_string(arr, "must fail"); + TEST_CHECK(ret != 0); + + cfl_array_destroy(arr); +} + +static void append_string() +{ + int ret; + struct cfl_array *arr; + + arr = cfl_array_create(1); + TEST_CHECK(arr != NULL); + + ret = cfl_array_append_string(arr, "test"); + TEST_CHECK(ret == 0); + + cfl_array_destroy(arr); +} + +static void append_string_s() +{ + int ret; + struct cfl_array *arr; + + arr = cfl_array_create(1); + TEST_CHECK(arr != NULL); + + ret = cfl_array_append_string_s(arr, "test", 4, CFL_FALSE); + TEST_CHECK(ret == 0); + + cfl_array_destroy(arr); +} + +static void append_string_s_ref() +{ + int ret; + struct cfl_array *arr; + + arr = cfl_array_create(1); + TEST_CHECK(arr != NULL); + + ret = cfl_array_append_string_s(arr, "test", 4, CFL_TRUE); + TEST_CHECK(ret == 0); + + cfl_array_destroy(arr); +} + +static void append_bytes() +{ + int ret; + struct cfl_array *arr; + + arr = cfl_array_create(1); + TEST_CHECK(arr != NULL); + + ret = cfl_array_append_bytes(arr, "test", 4, CFL_FALSE); + TEST_CHECK(ret == 0); + + cfl_array_destroy(arr); +} + +static void append_bytes_ref() +{ + int ret; + struct cfl_array *arr; + + arr = cfl_array_create(1); + TEST_CHECK(arr != NULL); + + ret = cfl_array_append_bytes(arr, "test", 4, CFL_TRUE); + TEST_CHECK(ret == 0); + + cfl_array_destroy(arr); +} + +static void append_reference() +{ + int ret; + struct cfl_array *arr; + struct cfl_variant *v; + + arr = cfl_array_create(1); + TEST_CHECK(arr != NULL); + + v = cfl_variant_create_from_string("test"); + TEST_CHECK(v != NULL); + + ret = cfl_array_append_reference(arr, v); + TEST_CHECK(ret == 0); + + cfl_array_destroy(arr); + + cfl_variant_destroy(v); +} + +static void append_bool() +{ + int ret; + struct cfl_array *arr; + + arr = cfl_array_create(2); + TEST_CHECK(arr != NULL); + + ret = cfl_array_append_bool(arr, CFL_TRUE); + TEST_CHECK(ret == 0); + + ret = cfl_array_append_bool(arr, CFL_FALSE); + TEST_CHECK(ret == 0); + + cfl_array_destroy(arr); +} + +static void append_int64() +{ + int ret; + struct cfl_array *arr; + + arr = cfl_array_create(1); + TEST_CHECK(arr != NULL); + + ret = cfl_array_append_int64(arr, -123); + TEST_CHECK(ret == 0); + + cfl_array_destroy(arr); +} + +static void append_uint64() +{ + int ret; + struct cfl_array *arr; + + arr = cfl_array_create(1); + TEST_CHECK(arr != NULL); + + ret = cfl_array_append_uint64(arr, 123); + TEST_CHECK(ret == 0); + + cfl_array_destroy(arr); +} + +static void append_double() +{ + int ret; + struct cfl_array *arr; + + arr = cfl_array_create(1); + TEST_CHECK(arr != NULL); + + ret = cfl_array_append_double(arr, 123.456); + TEST_CHECK(ret == 0); + + cfl_array_destroy(arr); +} + +static void append_null() +{ + int ret; + struct cfl_array *arr; + + arr = cfl_array_create(1); + TEST_CHECK(arr != NULL); + + ret = cfl_array_append_null(arr); + TEST_CHECK(ret == 0); + + cfl_array_destroy(arr); +} + +static void append_array() +{ + int ret; + struct cfl_array *arr; + struct cfl_array *arr2; + + arr = cfl_array_create(1); + TEST_CHECK(arr != NULL); + + arr2 = cfl_array_create(1); + TEST_CHECK(arr2 != NULL); + + ret = cfl_array_append_string(arr2, "test"); + TEST_CHECK(ret == 0); + + ret = cfl_array_append_array(arr, arr2); + TEST_CHECK(ret == 0); + + cfl_array_destroy(arr); +} + +static void append_new_array() +{ + int ret; + struct cfl_array *arr; + struct cfl_array *arr2; + struct cfl_variant *var; + + arr = cfl_array_create(1); + TEST_CHECK(arr != NULL); + + ret = cfl_array_append_new_array(arr, 1); + TEST_CHECK(ret == 0); + + var = cfl_array_fetch_by_index(arr, 0); + TEST_CHECK(var != NULL); + + arr2 = var->data.as_array; + ret = cfl_array_append_string(arr2, "test"); + TEST_CHECK(ret == 0); + + cfl_array_destroy(arr); +} + +static void append_kvlist() +{ + int ret; + struct cfl_array *arr; + struct cfl_kvlist *kvlist; + + arr = cfl_array_create(1); + TEST_CHECK(arr != NULL); + + kvlist = cfl_kvlist_create(); + TEST_CHECK(kvlist != NULL); + + ret = cfl_kvlist_insert_string(kvlist, "key", "value"); + TEST_CHECK(ret == 0); + + ret = cfl_array_append_kvlist(arr, kvlist); + TEST_CHECK(ret == 0); + + cfl_array_destroy(arr); +} + +static void remove_by_index() +{ + int ret; + struct cfl_array *arr; + struct cfl_variant *var; + + arr = cfl_array_create(1); + TEST_CHECK(arr != NULL); + + ret = cfl_array_append_string(arr, "test"); + TEST_CHECK(ret == 0); + + ret = cfl_array_remove_by_index(arr, 0); + TEST_CHECK(ret == 0); + + var = cfl_array_fetch_by_index(arr, 0); + TEST_CHECK(var == NULL); + + cfl_array_destroy(arr); +} + +static void remove_by_reference() +{ + int ret; + struct cfl_array *arr; + struct cfl_variant *var; + + arr = cfl_array_create(1); + TEST_CHECK(arr != NULL); + + ret = cfl_array_append_string(arr, "test"); + TEST_CHECK(ret == 0); + + var = cfl_array_fetch_by_index(arr, 0); + TEST_CHECK(var != NULL); + + ret = cfl_array_remove_by_reference(arr, var); + TEST_CHECK(ret == 0); + + + var = cfl_array_fetch_by_index(arr, 0); + TEST_CHECK(var == NULL); + + cfl_array_destroy(arr); +} + +TEST_LIST = { + {"create", create}, + {"resizable", resizable}, + {"append_string", append_string}, + {"append_string_s", append_string_s}, + {"append_string_s_ref", append_string_s_ref}, + {"append_bytes", append_bytes}, + {"append_bytes_ref", append_bytes_ref}, + {"append_reference", append_reference}, + {"append_bool", append_bool}, + {"append_int64", append_int64}, + {"append_uint64", append_uint64}, + {"append_double", append_double}, + {"append_null", append_null}, + {"append_array", append_array}, + {"append_new_array", append_new_array}, + {"append_kvlist", append_kvlist}, + {"remove_by_index", remove_by_index}, + {"remove_by_reference", remove_by_reference}, + { 0 } +}; From 71f3c49751244f10ea02349d2f23b87d6b481ebf Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Fri, 12 Apr 2024 11:15:43 -0600 Subject: [PATCH 8/9] array: adjust prototypes for string and bytes handling This patch adjust the following functions to manipulate the new 'referenced' field from variants: int cfl_array_append_string_s(struct cfl_array *array, char *str, size_t str_len, int referenced) int cfl_array_append_bytes(struct cfl_array *array, char *value, size_t length, int referenced) It also adds an extra check for the array size when it's resizable. Signed-off-by: Eduardo Silva --- include/cfl/cfl_array.h | 11 +++++++---- src/cfl_array.c | 43 +++++++++++++++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/include/cfl/cfl_array.h b/include/cfl/cfl_array.h index 590a859..3977df7 100644 --- a/include/cfl/cfl_array.h +++ b/include/cfl/cfl_array.h @@ -43,12 +43,10 @@ static inline struct cfl_variant *cfl_array_fetch_by_index(struct cfl_array *arr return array->entries[position]; } -int cfl_array_resizable(struct cfl_array *array, int v); -int cfl_array_remove_by_index(struct cfl_array *array, size_t position); -int cfl_array_remove_by_reference(struct cfl_array *array, struct cfl_variant *value); int cfl_array_append(struct cfl_array *array, struct cfl_variant *value); int cfl_array_append_string(struct cfl_array *array, char *value); -int cfl_array_append_bytes(struct cfl_array *array, char *value, size_t length); +int cfl_array_append_string_s(struct cfl_array *array, char *str, size_t str_len, int referenced); +int cfl_array_append_bytes(struct cfl_array *array, char *value, size_t length, int referenced); int cfl_array_append_reference(struct cfl_array *array, void *value); int cfl_array_append_bool(struct cfl_array *array, int value); int cfl_array_append_int64(struct cfl_array *array, int64_t value); @@ -58,6 +56,11 @@ int cfl_array_append_null(struct cfl_array *array); int cfl_array_append_array(struct cfl_array *array, struct cfl_array *value); int cfl_array_append_new_array(struct cfl_array *array, size_t size); int cfl_array_append_kvlist(struct cfl_array *array, struct cfl_kvlist *value); + +int cfl_array_resizable(struct cfl_array *array, int v); +int cfl_array_remove_by_index(struct cfl_array *array, size_t position); +int cfl_array_remove_by_reference(struct cfl_array *array, struct cfl_variant *value); + int cfl_array_print(FILE *fp, struct cfl_array *array); #endif diff --git a/src/cfl_array.c b/src/cfl_array.c index b4a5e63..916b053 100644 --- a/src/cfl_array.c +++ b/src/cfl_array.c @@ -129,6 +129,15 @@ int cfl_array_append(struct cfl_array *array, * it controls the input data. */ if (array->resizable) { + + /* + * if the array size is zero (created as an array of 0 slots), + * change the size to 1 so the resize can work properly + */ + if (array->slot_count == 0) { + array->slot_count = 1; + } + /* set new number of slots and total size */ new_slot_count = (array->slot_count * 2); new_size = (new_slot_count * sizeof(void *)); @@ -145,13 +154,17 @@ int cfl_array_append(struct cfl_array *array, return -1; } } - array->entries[array->entry_count++] = value; + /* this is just a double check to make sure the slot is really available */ + if (array->entry_count >= array->slot_count) { + return -1; + } + + array->entries[array->entry_count++] = value; return 0; } -int cfl_array_append_string(struct cfl_array *array, - char *value) +int cfl_array_append_string(struct cfl_array *array, char *value) { struct cfl_variant *value_instance; int result; @@ -165,7 +178,25 @@ int cfl_array_append_string(struct cfl_array *array, result = cfl_array_append(array, value_instance); if (result) { cfl_variant_destroy(value_instance); + return -2; + } + + return 0; +} +int cfl_array_append_string_s(struct cfl_array *array, char *str, size_t str_len, int referenced) +{ + struct cfl_variant *value_instance; + int result; + + value_instance = cfl_variant_create_from_string_s(str, str_len, referenced); + if (value_instance == NULL) { + return -1; + } + + result = cfl_array_append(array, value_instance); + if (result) { + cfl_variant_destroy(value_instance); return -2; } @@ -174,13 +205,13 @@ int cfl_array_append_string(struct cfl_array *array, int cfl_array_append_bytes(struct cfl_array *array, char *value, - size_t length) + size_t length, + int referenced) { struct cfl_variant *value_instance; int result; - value_instance = cfl_variant_create_from_bytes(value, length); - + value_instance = cfl_variant_create_from_bytes(value, length, referenced); if (value_instance == NULL) { return -1; } From 0494143cf744b1903df35f44057104ac1bd195a1 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Fri, 12 Apr 2024 12:18:47 -0600 Subject: [PATCH 9/9] tests: array: for ref test, use the heap Signed-off-by: Eduardo Silva --- tests/array.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/array.c b/tests/array.c index dfb5195..2ec72e1 100644 --- a/tests/array.c +++ b/tests/array.c @@ -105,15 +105,22 @@ static void append_string_s() static void append_string_s_ref() { int ret; + char *buf; struct cfl_array *arr; arr = cfl_array_create(1); TEST_CHECK(arr != NULL); - ret = cfl_array_append_string_s(arr, "test", 4, CFL_TRUE); + buf = malloc(5); + TEST_CHECK(buf != NULL); + memcpy(buf, "test", 4); + buf[4] = '\0'; + + ret = cfl_array_append_string_s(arr, buf, 4, CFL_TRUE); TEST_CHECK(ret == 0); cfl_array_destroy(arr); + free(buf); } static void append_bytes() @@ -133,17 +140,26 @@ static void append_bytes() static void append_bytes_ref() { int ret; + char *buf; struct cfl_array *arr; + buf = malloc(5); + TEST_CHECK(buf != NULL); + memcpy(buf, "test", 4); + buf[4] = '\0'; + arr = cfl_array_create(1); TEST_CHECK(arr != NULL); - ret = cfl_array_append_bytes(arr, "test", 4, CFL_TRUE); + ret = cfl_array_append_bytes(arr, buf, 4, CFL_TRUE); TEST_CHECK(ret == 0); cfl_array_destroy(arr); + + free(buf); } + static void append_reference() { int ret;