Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions include/cfl/cfl_array.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ struct cfl_array {
struct cfl_variant **entries;
size_t slot_count;
size_t entry_count;
struct cfl_variant *owner;
struct cfl_array *parent_array;
struct cfl_kvlist *parent_kvlist;
};

struct cfl_array *cfl_array_create(size_t slot_count);
Expand Down Expand Up @@ -62,9 +65,10 @@ static inline size_t cfl_array_size(struct cfl_array *array)
}

/*
* Append APIs take ownership of the value on success. A variant, array, or
* kvlist must have a single owning parent; inserting the same pointer into
* multiple containers is unsupported and can result in double-free.
* Append APIs take ownership of the value on success. A raw array or kvlist
* must have one owning variant at a time. To move an existing kvpair value,
* detach it with cfl_kvpair_take_value() before reinserting it. Do not leave
* the same variant pointer attached to multiple live containers.
*/
int cfl_array_append(struct cfl_array *array, struct cfl_variant *value);
int cfl_array_append_string(struct cfl_array *array, char *value);
Expand Down
11 changes: 11 additions & 0 deletions include/cfl/cfl_container.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,15 @@ int cfl_container_variant_contains_kvlist(struct cfl_variant *variant,
int cfl_container_variant_contains_variant(struct cfl_variant *variant,
struct cfl_variant *target);

int cfl_container_claim_array(struct cfl_array *array,
struct cfl_variant *owner);
int cfl_container_claim_kvlist(struct cfl_kvlist *kvlist,
struct cfl_variant *owner);
int cfl_container_adopt_variant(struct cfl_variant *variant);
int cfl_container_move_variant_to_array(struct cfl_array *array,
struct cfl_variant *variant);
int cfl_container_move_variant_to_kvlist(struct cfl_kvlist *kvlist,
struct cfl_variant *variant);
void cfl_container_release_variant(struct cfl_variant *variant);

#endif
14 changes: 11 additions & 3 deletions include/cfl/cfl_kvlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,30 @@
#include <cfl/cfl_list.h>
#include <cfl/cfl_variant.h>

struct cfl_array;

struct cfl_kvpair {
cfl_sds_t key; /* Key */
struct cfl_variant *val; /* Value */
struct cfl_list _head; /* Link to list cfl_kvlist->list */
};

struct cfl_kvlist {
struct cfl_list list;
struct cfl_list list;
struct cfl_variant *owner;
struct cfl_array *parent_array;
struct cfl_kvlist *parent_kvlist;
};

struct cfl_kvlist *cfl_kvlist_create();
void cfl_kvlist_destroy(struct cfl_kvlist *list);

/*
* Insert APIs take ownership of array, kvlist, and variant values on success.
* A value must have a single owning parent; inserting the same pointer into
* multiple containers is unsupported and can result in double-free.
* A raw array or kvlist must have one owning variant at a time. To move an
* existing kvpair value, detach it with cfl_kvpair_take_value() before
* reinserting it. Do not leave the same variant pointer attached to multiple
* live containers.
*/
int cfl_kvlist_insert_string(struct cfl_kvlist *list,
char *key, char *value);
Expand Down Expand Up @@ -136,6 +143,7 @@ struct cfl_variant *cfl_kvlist_fetch_s(struct cfl_kvlist *list, char *key, size_
int cfl_kvlist_contains(struct cfl_kvlist *kvlist, char *name);
int cfl_kvlist_remove(struct cfl_kvlist *kvlist, char *name);
void cfl_kvpair_destroy(struct cfl_kvpair *pair);
struct cfl_variant *cfl_kvpair_take_value(struct cfl_kvpair *pair);


#endif
1 change: 1 addition & 0 deletions include/cfl/cfl_variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct cfl_variant {
* a copy of the original data.
*/
uint8_t referenced;
uint8_t owned;

/* the data */
union {
Expand Down
49 changes: 49 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
include(CheckCSourceCompiles)

set(src
cfl.c
cfl_log.c
Expand All @@ -14,20 +16,63 @@ set(src
)

set(CFL_ATOMIC_NEEDS_THREADS Off)
set(CFL_ATOMIC_NEEDS_LIBATOMIC Off)
set(CFL_ATOMIC_USES_BUILTINS Off)

set(CFL_ATOMIC_BUILTINS_LINK_SOURCE "
#include <stdint.h>
int main(void) {
uint64_t storage = 0;
uint64_t expected = 0;
uint64_t desired = 1;
__atomic_store_n(&storage, desired, __ATOMIC_SEQ_CST);
(void) __atomic_load_n(&storage, __ATOMIC_SEQ_CST);
(void) __atomic_compare_exchange(&storage, &expected, &desired, 0,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
return 0;
}")

if(MSVC)
set(PLATFORM_SPECIFIC_ATOMIC_MODULE cfl_atomic_msvc.c)
elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
set(PLATFORM_SPECIFIC_ATOMIC_MODULE cfl_atomic_clang.c)
set(CFL_ATOMIC_USES_BUILTINS On)
elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
set(PLATFORM_SPECIFIC_ATOMIC_MODULE cfl_atomic_clang.c)
set(CFL_ATOMIC_USES_BUILTINS On)
elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
set(PLATFORM_SPECIFIC_ATOMIC_MODULE cfl_atomic_gcc.c)
set(CFL_ATOMIC_USES_BUILTINS On)
else()
set(PLATFORM_SPECIFIC_ATOMIC_MODULE cfl_atomic_generic.c)
set(CFL_ATOMIC_NEEDS_THREADS On)
endif()

if(CFL_ATOMIC_USES_BUILTINS)
check_c_source_compiles("${CFL_ATOMIC_BUILTINS_LINK_SOURCE}"
CFL_ATOMIC_BUILTINS_LINK)

if(NOT CFL_ATOMIC_BUILTINS_LINK)
set(CFL_ATOMIC_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}")
set(CMAKE_REQUIRED_LIBRARIES ${CFL_ATOMIC_REQUIRED_LIBRARIES})
list(APPEND CMAKE_REQUIRED_LIBRARIES atomic)

check_c_source_compiles("${CFL_ATOMIC_BUILTINS_LINK_SOURCE}"
CFL_ATOMIC_BUILTINS_LINK_WITH_LIBATOMIC)

set(CMAKE_REQUIRED_LIBRARIES "${CFL_ATOMIC_REQUIRED_LIBRARIES}")

if(CFL_ATOMIC_BUILTINS_LINK_WITH_LIBATOMIC)
set(CFL_ATOMIC_NEEDS_LIBATOMIC On)
elseif(CFL_SYSTEM_WINDOWS)
set(PLATFORM_SPECIFIC_ATOMIC_MODULE cfl_atomic_msvc.c)
else()
set(PLATFORM_SPECIFIC_ATOMIC_MODULE cfl_atomic_generic.c)
set(CFL_ATOMIC_NEEDS_THREADS On)
endif()
endif()
endif()

set(src
${src}
${PLATFORM_SPECIFIC_ATOMIC_MODULE}
Expand All @@ -37,6 +82,10 @@ set(src
add_library(cfl-static STATIC ${src})
target_link_libraries(cfl-static PRIVATE xxhash)

if(CFL_ATOMIC_NEEDS_LIBATOMIC)
target_link_libraries(cfl-static PUBLIC atomic)
endif()

if(CFL_ATOMIC_NEEDS_THREADS)
find_package(Threads REQUIRED)
target_link_libraries(cfl-static PUBLIC Threads::Threads)
Expand Down
42 changes: 13 additions & 29 deletions src/cfl_array.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ struct cfl_array *cfl_array_create(size_t slot_count)

array->entry_count = 0;
array->slot_count = slot_count;
array->owner = NULL;
array->parent_array = NULL;
array->parent_kvlist = NULL;

return array;
}
Expand Down Expand Up @@ -152,27 +155,6 @@ int cfl_array_append(struct cfl_array *array,
return -1;
}

if (cfl_container_array_contains_variant(array, value)) {
return -1;
}

/* Only container-valued variants can participate in container cycles. */
if (value->type == CFL_VARIANT_ARRAY || value->type == CFL_VARIANT_KVLIST) {
if (cfl_container_variant_contains_array(value, array)) {
return -1;
}

if (value->type == CFL_VARIANT_ARRAY &&
cfl_container_array_contains_array(array, value->data.as_array)) {
return -1;
}

if (value->type == CFL_VARIANT_KVLIST &&
cfl_container_array_contains_kvlist(array, value->data.as_kvlist)) {
return -1;
}
}

if (array->entry_count >= array->slot_count) {
/*
* if there is no more space but the caller allowed to resize
Expand Down Expand Up @@ -216,6 +198,10 @@ int cfl_array_append(struct cfl_array *array,
return -1;
}

if (cfl_container_move_variant_to_array(array, value) != 0) {
return -1;
}

array->entries[array->entry_count++] = value;
return 0;
}
Expand Down Expand Up @@ -420,8 +406,7 @@ int cfl_array_append_array(struct cfl_array *array, struct cfl_array *value)
return -1;
}

if (cfl_container_array_contains_array(array, value) ||
cfl_container_array_contains_array(value, array)) {
if (array == value) {
return -1;
}

Expand All @@ -433,6 +418,8 @@ int cfl_array_append_array(struct cfl_array *array, struct cfl_array *value)

result = cfl_array_append(array, value_instance);
if (result) {
cfl_container_release_variant(value_instance);
value_instance->data.as_array = NULL;
cfl_variant_destroy(value_instance);
return -2;
}
Expand All @@ -457,7 +444,7 @@ int cfl_array_append_new_array(struct cfl_array *array, size_t size)
}

result = cfl_array_append_array(array, value);
if (result == -1) {
if (result < 0) {
cfl_array_destroy(value);
}

Expand All @@ -473,18 +460,15 @@ int cfl_array_append_kvlist(struct cfl_array *array, struct cfl_kvlist *value)
return -1;
}

if (cfl_container_array_contains_kvlist(array, value) ||
cfl_container_kvlist_contains_array(value, array)) {
return -1;
}

value_instance = cfl_variant_create_from_kvlist(value);
if (value_instance == NULL) {
return -1;
}
result = cfl_array_append(array, value_instance);

if (result) {
cfl_container_release_variant(value_instance);
value_instance->data.as_kvlist = NULL;
cfl_variant_destroy(value_instance);

return -2;
Expand Down
Loading
Loading