From fa6ebe6a84c232041312885567e5ce37600d5dff Mon Sep 17 00:00:00 2001 From: Max Wash Date: Thu, 24 Oct 2024 19:24:54 +0100 Subject: [PATCH] add object module from corelib --- CMakeLists.txt | 2 +- cmake/Templates.cmake | 20 +- core/CMakeLists.txt | 2 +- core/include/blue/core/stringstream.h | 15 +- core/stringstream.c | 90 +- object-test/object-test.c | 50 + object/CMakeLists.txt | 3 + object/array.c | 337 ++++ object/array.h | 15 + object/bitmap.c | 167 ++ object/dict.c | 472 +++++ object/dict.h | 26 + object/hashmap.c | 434 +++++ object/hashmap.h | 25 + object/include/blue/object.h | 0 object/include/blue/object/array.h | 304 +++ object/include/blue/object/bitmap.h | 34 + object/include/blue/object/buffer.h | 33 + object/include/blue/object/dict.h | 69 + object/include/blue/object/hashmap.h | 92 + object/include/blue/object/number.h | 285 +++ object/include/blue/object/object.h | 38 + object/include/blue/object/string.h | 77 + object/include/blue/object/string_formatter.h | 25 + object/include/blue/object/tree.h | 72 + object/include/blue/object/type.h | 51 + object/include/blue/object/uuid.h | 52 + object/number.c | 1681 +++++++++++++++++ object/number.h | 29 + object/object.c | 65 + object/object.h | 6 + object/string.c | 497 +++++ object/string.h | 21 + object/tree.c | 300 +++ object/tree.h | 14 + object/type.c | 29 + object/uuid.c | 187 ++ object/uuid.h | 11 + 38 files changed, 5606 insertions(+), 24 deletions(-) create mode 100644 object-test/object-test.c create mode 100644 object/CMakeLists.txt create mode 100644 object/array.c create mode 100644 object/array.h create mode 100644 object/bitmap.c create mode 100644 object/dict.c create mode 100644 object/dict.h create mode 100644 object/hashmap.c create mode 100644 object/hashmap.h create mode 100644 object/include/blue/object.h create mode 100644 object/include/blue/object/array.h create mode 100644 object/include/blue/object/bitmap.h create mode 100644 object/include/blue/object/buffer.h create mode 100644 object/include/blue/object/dict.h create mode 100644 object/include/blue/object/hashmap.h create mode 100644 object/include/blue/object/number.h create mode 100644 object/include/blue/object/object.h create mode 100644 object/include/blue/object/string.h create mode 100644 object/include/blue/object/string_formatter.h create mode 100644 object/include/blue/object/tree.h create mode 100644 object/include/blue/object/type.h create mode 100644 object/include/blue/object/uuid.h create mode 100644 object/number.c create mode 100644 object/number.h create mode 100644 object/object.c create mode 100644 object/object.h create mode 100644 object/string.c create mode 100644 object/string.h create mode 100644 object/tree.c create mode 100644 object/tree.h create mode 100644 object/type.c create mode 100644 object/uuid.c create mode 100644 object/uuid.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6320208..2ea57b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.25) project(bluelib C) -set(b_modules core) +set(b_modules core object) set(b_system_name ${CMAKE_SYSTEM_NAME}) string(TOLOWER ${b_system_name} b_system_name) diff --git a/cmake/Templates.cmake b/cmake/Templates.cmake index 9d25c17..a5ee956 100644 --- a/cmake/Templates.cmake +++ b/cmake/Templates.cmake @@ -1,4 +1,11 @@ -macro(add_bluelib_module module_name) +function(add_bluelib_module) + set(options) + set(one_value_args NAME) + set(multi_value_args DEPENDENCIES) + cmake_parse_arguments(PARSE_ARGV 0 arg "${options}" "${one_value_args}" "${multi_value_args}") + + set(module_name ${arg_NAME}) + file(GLOB sources *.c *.h) file(GLOB sys_sources sys/${b_system_name}/*.c sys/${b_system_name}/*.h) set(root_header include/blue/${module_name}.h) @@ -16,6 +23,10 @@ macro(add_bluelib_module module_name) target_include_directories(blue-${module_name}-obj PUBLIC include/) target_compile_definitions(blue-${module_name}-obj PUBLIC ${module_preproc_token}) + foreach (dep ${arg_DEPENDENCIES}) + target_link_libraries(blue-${module_name}-obj blue-${dep}-obj) + endforeach (dep) + message(STATUS "Building module ${module_name} (shared)") add_library(blue-${module_name} SHARED $) message(STATUS "Building module ${module_name} (static)") @@ -24,7 +35,12 @@ macro(add_bluelib_module module_name) target_include_directories(blue-${module_name} PUBLIC include/) target_include_directories(blue-${module_name}-s PUBLIC include/) + foreach (dep ${arg_DEPENDENCIES}) + target_link_libraries(blue-${module_name} blue-${dep}) + target_link_libraries(blue-${module_name}-s blue-${dep}-s) + endforeach (dep) + install(TARGETS blue-${module_name} blue-${module_name}-s) install(FILES ${root_header} DESTINATION include/blue) install(FILES ${headers} DESTINATION include/blue/${module_name}) -endmacro(add_bluelib_module) +endfunction(add_bluelib_module) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index e28413d..455014e 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,3 +1,3 @@ include(../cmake/Templates.cmake) -add_bluelib_module(core) +add_bluelib_module(NAME core) diff --git a/core/include/blue/core/stringstream.h b/core/include/blue/core/stringstream.h index 6141598..522493e 100644 --- a/core/include/blue/core/stringstream.h +++ b/core/include/blue/core/stringstream.h @@ -9,21 +9,22 @@ typedef struct b_stringstream { size_t ss_len; size_t ss_max; unsigned char ss_alloc; + int *ss_istack; + int ss_add_indent; + size_t ss_istack_ptr, ss_istack_size; } b_stringstream; extern void b_stringstream_begin(b_stringstream *strv, char *buf, size_t max); extern void b_stringstream_begin_dynamic(b_stringstream *strv); +extern void b_stringstream_push_indent(b_stringstream *strv, int indent); +extern void b_stringstream_pop_indent(b_stringstream *strv); + extern b_status b_stringstream_add(b_stringstream *strv, const char *str); -extern b_status b_stringstream_addf( - b_stringstream *strv, - const char *format, - ...); +extern b_status b_stringstream_addf(b_stringstream *strv, const char *format, ...); extern b_status b_stringstream_addv(b_stringstream *strv, const char **strs); extern b_status b_stringstream_addvl( - b_stringstream *strv, - const char **strs, - size_t count); + b_stringstream *strv, const char **strs, size_t count); extern b_status b_stringstream_add_many(b_stringstream *strv, ...); extern char *b_stringstream_end(b_stringstream *strv); diff --git a/core/stringstream.c b/core/stringstream.c index a368e59..c6052b0 100644 --- a/core/stringstream.c +++ b/core/stringstream.c @@ -20,28 +20,91 @@ void b_stringstream_begin_dynamic(b_stringstream *ss) ss->ss_alloc = 1; } -static b_status ss_builder_push_string(b_stringstream *ss, const char *s, size_t len) +static int current_indent(struct b_stringstream *ss) { - if (ss->ss_len + len >= ss->ss_max && ss->ss_alloc == 1) { - char *new_buf = realloc(ss->ss_buf, ss->ss_len + len + 1); + if (!ss->ss_istack || !ss->ss_istack_size) { + return 0; + } + + return ss->ss_istack[ss->ss_istack_ptr]; +} + +static void __formatter_putchar(struct b_stringstream *ss, char c) +{ + if (ss->ss_len + 1 >= ss->ss_max && ss->ss_alloc == 1) { + char *new_buf = realloc(ss->ss_buf, ss->ss_len + 8); if (!new_buf) { - return B_ERR_NO_MEMORY; + return; } ss->ss_buf = new_buf; - ss->ss_max = ss->ss_len + len + 1; + ss->ss_max = ss->ss_len + 8; } - for (size_t i = 0; i < len; i++) { - if (ss->ss_len < ss->ss_max) { - ss->ss_buf[ss->ss_len++] = s[i]; - ss->ss_buf[ss->ss_len] = 0; + ss->ss_buf[ss->ss_len++] = c; + ss->ss_buf[ss->ss_len] = '\0'; +} + +static void formatter_putchar(struct b_stringstream *f, char c) +{ + if (f->ss_add_indent && c != '\n') { + int indent = current_indent(f); + for (int i = 0; i < indent; i++) { + __formatter_putchar(f, ' '); + __formatter_putchar(f, ' '); } + + f->ss_add_indent = 0; + } + + __formatter_putchar(f, c); + + if (c == '\n') { + f->ss_add_indent = 1; + } +} + +static b_status ss_builder_push_string(b_stringstream *ss, const char *s, size_t len) +{ + for (size_t i = 0; i < len; i++) { + formatter_putchar(ss, s[i]); } return B_SUCCESS; } +void b_stringstream_push_indent(struct b_stringstream *ss, int indent) +{ + if (!ss->ss_istack) { + ss->ss_istack = calloc(4, sizeof(int)); + ss->ss_istack_size = 4; + ss->ss_istack_ptr = 0; + } + + if (ss->ss_istack_ptr + 1 > ss->ss_istack_size) { + int *buf = realloc( + ss->ss_istack, (ss->ss_istack_size + 4) * sizeof(int)); + if (!buf) { + return; + } + + ss->ss_istack = buf; + ss->ss_istack_size += 4; + } + + int cur_indent = ss->ss_istack[ss->ss_istack_ptr]; + ss->ss_istack[++ss->ss_istack_ptr] = cur_indent + indent; +} + +void b_stringstream_pop_indent(b_stringstream *strv) +{ + if (!strv->ss_istack || !strv->ss_istack_size || !strv->ss_istack_ptr) { + return; + } + + strv->ss_istack_ptr--; +} + b_status b_stringstream_add(struct b_stringstream *ss, const char *str) { return ss_builder_push_string(ss, str, strlen(str)); @@ -109,10 +172,11 @@ char *b_stringstream_end(b_stringstream *ss) { char *out = ss->ss_buf; - ss->ss_alloc = 0; - ss->ss_len = 0; - ss->ss_max = 0; - ss->ss_buf = NULL; + if (ss->ss_istack) { + free(ss->ss_istack); + } + + memset(ss, 0x0, sizeof *ss); return out; } diff --git a/object-test/object-test.c b/object-test/object-test.c new file mode 100644 index 0000000..8dec8b8 --- /dev/null +++ b/object-test/object-test.c @@ -0,0 +1,50 @@ +#include +#include + +static void test_string_create(CuTest *tc) +{ + b_string *str = b_string_create(); + + CuAssertPtrNotNull(tc, str); + CuAssertIntEquals(tc, 0, b_string_get_size(str, B_STRLEN_NORMAL)); + CuAssertStrEquals(tc, "", b_string_ptr(str)); + + b_string_release(str); + + str = b_string_create_from_c('A', 8); + + CuAssertPtrNotNull(tc, str); + CuAssertIntEquals(tc, 8, b_string_get_size(str, B_STRLEN_NORMAL)); + CuAssertStrEquals(tc, "AAAAAAAA", b_string_ptr(str)); + + b_string_release(str); + + str = b_string_create_from_cstr("Hello, world!"); + + CuAssertPtrNotNull(tc, str); + CuAssertIntEquals(tc, 13, b_string_get_size(str, B_STRLEN_NORMAL)); + CuAssertStrEquals(tc, "Hello, world!", b_string_ptr(str)); + + b_string_release(str); +} + +static void test_string_length(CuTest *tc) +{ + const char *cstr = "Hello, \033[91;1mworld!"; + b_string *s = b_string_create_from_cstr(cstr); + + CuAssertIntEquals(tc, 13, b_string_get_size(s, B_STRLEN_IGNORE_ESC)); + CuAssertIntEquals(tc, 20, b_string_get_size(s, B_STRLEN_NORMAL)); + + b_string_release(s); +} + +CuSuite *get_all_tests(void) +{ + CuSuite *suite = CuSuiteNew(); + + SUITE_ADD_TEST(suite, test_string_create); + SUITE_ADD_TEST(suite, test_string_length); + + return suite; +} diff --git a/object/CMakeLists.txt b/object/CMakeLists.txt new file mode 100644 index 0000000..905e9c0 --- /dev/null +++ b/object/CMakeLists.txt @@ -0,0 +1,3 @@ +include(../cmake/Templates.cmake) + +add_bluelib_module(NAME object DEPENDENCIES core) diff --git a/object/array.c b/object/array.c new file mode 100644 index 0000000..1fea953 --- /dev/null +++ b/object/array.c @@ -0,0 +1,337 @@ +#include "array.h" + +#include +#include +#include +#include +#include + +static void array_release(struct b_object *obj); + +static struct b_object_type array_type = { + .t_flags = B_OBJECT_FUNDAMENTAL, + .t_id = B_OBJECT_TYPE_ARRAY, + .t_name = "corelib::array", + .t_instance_size = sizeof(struct b_array), + .t_release = array_release, +}; + +struct b_array *b_array_create(void) +{ + struct b_array *array + = (struct b_array *)b_object_type_instantiate(&array_type); + if (!array) { + return NULL; + } + + return array; +} + +struct b_array *b_array_create_with_values( + struct b_object *const *values, size_t nr_values) +{ + struct b_array *array = b_array_create(); + if (!array) { + return NULL; + } + + size_t real_nr_values = 0; + for (size_t i = 0; i < nr_values; i++) { + if (values[i]) { + real_nr_values++; + } + } + + array->ar_len = real_nr_values; + array->ar_cap = real_nr_values; + array->ar_data = calloc(real_nr_values, sizeof(struct b_object *)); + if (!array->ar_data) { + b_array_release(array); + return NULL; + } + + size_t index = 0; + for (size_t i = 0; i < nr_values; i++) { + array->ar_data[index++] = b_retain(values[i]); + } + + return array; +} + +static b_status resize_array(struct b_array *array, size_t new_capacity) +{ + if (array->ar_cap < new_capacity) { + void *new_data = realloc( + array->ar_data, new_capacity * sizeof(struct b_object *)); + if (!new_data) { + return B_ERR_NO_MEMORY; + } + + array->ar_data = new_data; + } else { + for (size_t i = new_capacity; i < array->ar_len; i++) { + b_release(array->ar_data[i]); + } + + void *new_data = realloc( + array->ar_data, new_capacity * sizeof(struct b_object *)); + if (!new_data) { + return B_ERR_NO_MEMORY; + } + + array->ar_data = new_data; + } + + array->ar_cap = new_capacity; + if (array->ar_len > new_capacity) { + array->ar_len = new_capacity; + } + + return B_SUCCESS; +} + +b_status b_array_append(struct b_array *array, struct b_object *value) +{ + return b_array_insert(array, value, B_NPOS); +} + +b_status b_array_prepend(struct b_array *array, struct b_object *value) +{ + return b_array_insert(array, value, 0); +} + +b_status b_array_insert(struct b_array *array, struct b_object *value, size_t at) +{ + if (at == B_NPOS) { + at = array->ar_len; + } + + if (at > array->ar_len) { + return B_ERR_OUT_OF_BOUNDS; + } + + b_status status = B_SUCCESS; + + if (array->ar_len + 1 > array->ar_cap) { + status = resize_array(array, array->ar_cap + 8); + + if (status != B_SUCCESS) { + return status; + } + } + + struct b_object **src = array->ar_data + at; + struct b_object **dest = src + 1; + size_t move_len = (array->ar_len - at) * sizeof(struct b_object *); + + memmove(dest, src, move_len); + + array->ar_data[at] = b_retain(value); + array->ar_len++; + + return B_SUCCESS; +} + +b_status b_array_remove(struct b_array *array, size_t at) +{ + if (at >= array->ar_len) { + return B_ERR_OUT_OF_BOUNDS; + } + + struct b_object **src = array->ar_data + at; + struct b_object **dest = src + 1; + size_t move_len = array->ar_len * sizeof(struct b_object *); + + b_release(array->ar_data[at]); + + memmove(dest, src, move_len); + + array->ar_len--; + + return B_SUCCESS; +} + +b_status b_array_remove_front(struct b_array *array) +{ + return b_array_remove(array, 0); +} + +b_status b_array_remove_back(struct b_array *array) +{ + return b_array_remove(array, array->ar_len - 1); +} + +struct b_object *b_array_pop(b_array *array, size_t at) +{ + if (at >= array->ar_len) { + return NULL; + } + + struct b_object **src = array->ar_data + at; + struct b_object **dest = src + 1; + size_t move_len = array->ar_len * sizeof(struct b_object *); + + struct b_object *out = array->ar_data[at]; + + memmove(dest, src, move_len); + + array->ar_len--; + + return out; +} + +struct b_object *b_array_pop_front(struct b_array *array) +{ + return b_array_pop(array, 0); +} + +struct b_object *b_array_pop_back(struct b_array *array) +{ + return b_array_pop(array, array->ar_len - 1); +} + +struct b_object *b_array_at(const struct b_array *array, size_t at) +{ + if (at >= array->ar_len) { + return NULL; + } + + return array->ar_data[at]; +} + +struct b_object *b_array_get(struct b_array *array, size_t at) +{ + if (at >= array->ar_len) { + return NULL; + } + + return b_retain(array->ar_data[at]); +} + +size_t b_array_size(const struct b_array *array) +{ + return array->ar_len; +} + +size_t b_array_capacity(const struct b_array *array) +{ + return array->ar_cap; +} + +void array_release(struct b_object *obj) +{ + struct b_array *array = B_ARRAY(obj); + + if (array->ar_data) { + for (size_t i = 0; i < array->ar_len; i++) { + b_release(array->ar_data[i]); + } + + free(array->ar_data); + array->ar_data = NULL; + } +} + +void b_array_clear(struct b_array *array) +{ + while (array->ar_len) { + b_array_remove_back(array); + } +} + +static bool array_iterator_next(struct b_iterator *it) +{ + return b_array_iterator_next((struct b_array_iterator *)it); +} + +static b_status array_iterator_erase(struct b_iterator *it) +{ + return b_array_iterator_erase((struct b_array_iterator *)it); +} + +static bool array_iterator_is_valid(const struct b_iterator *it) +{ + return b_array_iterator_is_valid((const struct b_array_iterator *)it); +} + +static b_iterator_ops it_ops = { + .it_next = array_iterator_next, + .it_close = NULL, + .it_erase = array_iterator_erase, + .it_is_valid = array_iterator_is_valid, +}; + +int b_array_iterator_begin(struct b_array *array, struct b_array_iterator *it) +{ + it->_a = array; + it->i = 0; + it->_base.it_ops = &it_ops; + + if (array->ar_len > 0) { + it->value = array->ar_data[0]; + } else { + it->value = NULL; + } + + return 0; +} + +bool b_array_iterator_next(struct b_array_iterator *it) +{ + struct b_array *array = it->_a; + + if (it->value == NULL || it->i >= array->ar_len) { + return false; + } + + it->i++; + + if (it->i >= array->ar_len) { + it->value = NULL; + } else { + it->value = array->ar_data[it->i]; + } + + return it->value != NULL; +} + +b_status b_array_iterator_erase(struct b_array_iterator *it) +{ + struct b_array *array = it->_a; + if (it->i >= array->ar_len) { + return B_ERR_OUT_OF_BOUNDS; + } + + if (array->ar_data[it->i] != it->value) { + return B_ERR_BAD_STATE; + } + + b_array_remove(array, it->i); + + if (it->i < array->ar_len) { + it->value = array->ar_data[it->i]; + } else { + it->value = NULL; + } + + return B_SUCCESS; +} + +bool b_array_iterator_is_valid(const struct b_array_iterator *it) +{ + struct b_array *array = it->_a; + if (it->i >= array->ar_len) { + return false; + } + + if (array->ar_data[it->i] != it->value) { + return false; + } + + return it->value != NULL; +} + +b_object_type_id b_array_type_id(void) +{ + return (b_object_type_id)&array_type; +} diff --git a/object/array.h b/object/array.h new file mode 100644 index 0000000..1236e45 --- /dev/null +++ b/object/array.h @@ -0,0 +1,15 @@ +#ifndef _BLUELIB_ARRAY_H_ +#define _BLUELIB_ARRAY_H_ + +#include "../object.h" + +struct b_array { + struct b_object ar_base; + /* number of items in array */ + unsigned int ar_len; + /* maximum number of items that can currently be stored in array */ + unsigned int ar_cap; + struct b_object **ar_data; +}; + +#endif diff --git a/object/bitmap.c b/object/bitmap.c new file mode 100644 index 0000000..614705c --- /dev/null +++ b/object/bitmap.c @@ -0,0 +1,167 @@ +#include +#include + +void b_bitmap_zero(b_bitmap_word *map, unsigned long nbits) +{ + unsigned long words = B_BITMAP_WORDS(nbits); + memset(map, 0x00, words * sizeof *map); +} + +void b_bitmap_fill(b_bitmap_word *map, unsigned long nbits) +{ + unsigned long words = B_BITMAP_WORDS(nbits); + memset(map, 0xFF, words * sizeof *map); +} + +void b_bitmap_set(b_bitmap_word *map, unsigned long bit) +{ + unsigned long index = bit / Z__B_BITS_PER_WORD; + unsigned long offset = (Z__B_BITS_PER_WORD - bit - 1) & (Z__B_BITS_PER_WORD - 1); + unsigned long mask = 1ul << offset; + + map[index] |= mask; +} + +void b_bitmap_clear(b_bitmap_word *map, unsigned long bit) +{ + unsigned long index = bit / Z__B_BITS_PER_WORD; + unsigned long offset = bit & (Z__B_BITS_PER_WORD - 1); + unsigned long mask = 1ul << offset; + + map[index] &= ~mask; +} + +bool b_bitmap_check(const b_bitmap_word *map, unsigned long bit) +{ + unsigned long index = bit / Z__B_BITS_PER_WORD; + unsigned long offset = (Z__B_BITS_PER_WORD - bit - 1) & (Z__B_BITS_PER_WORD - 1); + unsigned long mask = 1ul << offset; + + return (map[index] & mask) != 0; + +} + +unsigned int b_bitmap_count_set(const b_bitmap_word *map, unsigned long nbits) +{ + unsigned long words = B_BITMAP_WORDS(nbits); + unsigned int set_bits = 0; + + for (unsigned long i = 0; i < words; i++) { + set_bits += __builtin_popcountl(map[i]); + } + + if (set_bits > nbits) { + set_bits = nbits; + } + + return set_bits; +} + +unsigned int b_bitmap_count_clear(const b_bitmap_word *map, unsigned long nbits) +{ + unsigned long words = B_BITMAP_WORDS(nbits); + unsigned int clear_bits = 0; + + for (unsigned long i = 0; i < words; i++) { + clear_bits += __builtin_popcountl(~map[i]); + } + + if (clear_bits > nbits) { + clear_bits = nbits; + } + + return clear_bits; +} + +unsigned int b_bitmap_highest_set(const b_bitmap_word *map, unsigned long nbits) +{ + unsigned long words = B_BITMAP_WORDS(nbits); + unsigned long bit_index = 0; + b_bitmap_word last_word = 0; + + unsigned long i; + for (i = 0; i < words; i++) { + if (map[i] != 0x00) { + last_word = map[i]; + bit_index = i * Z__B_BITS_PER_WORD; + } + } + + if (last_word == 0x00) { + return B_BITMAP_NPOS; + } + + return bit_index + (Z__B_BITS_PER_WORD - __builtin_ctzl(last_word) - 1); +} + +unsigned int b_bitmap_highest_clear(const b_bitmap_word *map, unsigned long nbits) +{ + unsigned long words = B_BITMAP_WORDS(nbits); + unsigned long bit_index = 0; + b_bitmap_word last_word = ~(b_bitmap_word)0; + + for (unsigned long i = 0; i < words; i++) { + if (map[i] != (~(unsigned long)0)) { + last_word = map[i]; + bit_index = i * Z__B_BITS_PER_WORD; + } + } + + if (last_word == ~(unsigned long)0) { + return B_BITMAP_NPOS; + } + + if (last_word == 0) { + return bit_index + Z__B_BITS_PER_WORD - 1; + } + + return bit_index + (Z__B_BITS_PER_WORD - __builtin_ctzl(~last_word)) - 1; +} + +unsigned int b_bitmap_lowest_set(const b_bitmap_word *map, unsigned long nbits) +{ + unsigned long words = B_BITMAP_WORDS(nbits); + unsigned long bit_index = 0; + b_bitmap_word last_word = 0; + + unsigned long i; + for (i = 0; i < words; i++) { + if (map[i] != 0x00) { + last_word = map[i]; + bit_index = i * Z__B_BITS_PER_WORD; + break; + } + } + + if (last_word == 0x00) { + return B_BITMAP_NPOS; + } + + return bit_index + __builtin_clzl(last_word); +} + +unsigned int b_bitmap_lowest_clear(const b_bitmap_word *map, unsigned long nbits) +{ + unsigned long words = B_BITMAP_WORDS(nbits); + unsigned long bit_index = 0; + b_bitmap_word last_word = 0; + + unsigned long i; + for (i = 0; i < words; i++) { + if (map[i] != (~(unsigned long)0)) { + last_word = map[i]; + bit_index = i * Z__B_BITS_PER_WORD; + break; + } + } + + if (last_word == 0) { + return bit_index; + } + + if (last_word == (~(b_bitmap_word)0)) { + return B_BITMAP_NPOS; + } + + return bit_index + __builtin_clzl(~last_word); +} diff --git a/object/dict.c b/object/dict.c new file mode 100644 index 0000000..5953c18 --- /dev/null +++ b/object/dict.c @@ -0,0 +1,472 @@ +#include "dict.h" + +#include +#include +#include +#include +#include +#include +#include + +#define HASH_OFFSET_BASIS 0xcbf29ce484222325 +#define HASH_PRIME 0x100000001b3 + +uint64_t b_cstr_hash(const char *s) +{ + uint64_t hash = HASH_OFFSET_BASIS; + + for (size_t i = 0; s[i]; i++) { + hash *= HASH_PRIME; + hash ^= s[i]; + } + + return hash; +} + +static void dict_release(struct b_object *obj); +static void dict_to_string(struct b_object *obj, struct b_stringstream *out); + +static struct b_object_type dict_type = { + .t_name = "corelib::dict", + .t_flags = B_OBJECT_FUNDAMENTAL, + .t_id = B_OBJECT_TYPE_DICT, + .t_instance_size = sizeof(struct b_dict), + .t_release = dict_release, + .t_to_string = dict_to_string, +}; + +struct b_dict *b_dict_create(void) +{ + struct b_dict *dict + = (struct b_dict *)b_object_type_instantiate(&dict_type); + if (!dict) { + return NULL; + } + + return dict; +} + +struct b_dict *b_dict_create_with_items(const b_dict_item *items) +{ + struct b_dict *dict = b_dict_create(); + if (!dict) { + return NULL; + } + + for (size_t i = 0; items[i].key; i++) { + b_dict_put(dict, items[i].key, items[i].value); + } + + return dict; +} + +static B_BTREE_DEFINE_SIMPLE_GET( + struct b_dict_bucket, uint64_t, bk_node, bk_hash, + get_bucket) static B_BTREE_DEFINE_SIMPLE_INSERT(struct b_dict_bucket, bk_node, bk_hash, put_bucket) + + static struct b_dict_bucket *create_bucket(void) +{ + struct b_dict_bucket *bucket = malloc(sizeof *bucket); + if (!bucket) { + return NULL; + } + + memset(bucket, 0x0, sizeof *bucket); + return bucket; +} + +static struct b_dict_bucket_item *create_bucket_item(void) +{ + struct b_dict_bucket_item *item = malloc(sizeof *item); + if (!item) { + return NULL; + } + + memset(item, 0x0, sizeof *item); + return item; +} + +b_status b_dict_put(struct b_dict *dict, const char *key, b_object *value) +{ + uint64_t hash = b_cstr_hash(key); + struct b_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash); + if (!bucket) { + bucket = create_bucket(); + if (!bucket) { + return B_ERR_NO_MEMORY; + } + + bucket->bk_hash = hash; + put_bucket(&dict->d_buckets, bucket); + } + + struct b_dict_bucket_item *item = create_bucket_item(); + if (!item) { + return B_ERR_NO_MEMORY; + } + + item->bi_str = b_strdup(key); + item->bi_value = b_retain(value); + + b_queue_push_back(&bucket->bk_items, &item->bi_entry); + + return B_SUCCESS; +} + +b_object *b_dict_at(const struct b_dict *dict, const char *key) +{ + uint64_t hash = b_cstr_hash(key); + struct b_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash); + if (!bucket) { + return NULL; + } + + b_queue_iterator it; + b_queue_foreach (&it, &bucket->bk_items) { + struct b_dict_bucket_item *item + = b_unbox(struct b_dict_bucket_item, it.entry, bi_entry); + + if (!strcmp(item->bi_str, key)) { + return item->bi_value; + } + } + + return NULL; +} + +b_object *b_dict_get(struct b_dict *dict, const char *key) +{ + b_object *value = b_dict_at(dict, key); + if (value) { + b_retain(value); + } + + return value; +} + +bool b_dict_has_key(const struct b_dict *dict, const char *key) +{ + return b_dict_at(dict, key) != NULL; +} + +size_t b_dict_get_size(const struct b_dict *dict) +{ + size_t count = 0; + b_btree_iterator it1; + b_queue_iterator it2; + + b_btree_foreach (&it1, &dict->d_buckets) { + struct b_dict_bucket *bucket + = b_unbox(struct b_dict_bucket, it1.node, bk_node); + + b_queue_foreach (&it2, &bucket->bk_items) { + count++; + } + } + + return count; +} + +bool b_dict_is_empty(const b_dict *dict) +{ + b_btree_node *first_node = b_btree_first(&dict->d_buckets); + struct b_dict_bucket *first_bucket + = b_unbox(struct b_dict_bucket, first_node, bk_node); + if (!first_bucket) { + return true; + } + + b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items); + struct b_dict_bucket_item *first_item + = b_unbox(struct b_dict_bucket_item, first_entry, bi_entry); + if (!first_item) { + return true; + } + + return false; +} + +static void dict_to_string(struct b_object *obj, struct b_stringstream *out) +{ + struct b_dict *dict = B_DICT(obj); + + if (b_dict_is_empty(dict)) { + b_stringstream_add(out, "{}"); + return; + } + + b_stringstream_add(out, "{\n"); + + b_stringstream_push_indent(out, 1); + size_t len = b_dict_get_size(dict); + + b_dict_iterator it; + b_dict_foreach(&it, dict) + { + b_stringstream_addf(out, "%s: ", it.key); + b_to_string(it.value, out); + + if (it.i < len - 1) { + b_stringstream_add(out, ","); + } + + b_stringstream_add(out, "\n"); + } + + b_stringstream_pop_indent(out); + b_stringstream_add(out, "}"); +} + +static bool dict_iterator_next(struct b_iterator *it) +{ + return b_dict_iterator_next((struct b_dict_iterator *)it); +} + +static b_status dict_iterator_erase(struct b_iterator *it) +{ + return b_dict_iterator_erase((struct b_dict_iterator *)it); +} + +static bool dict_iterator_is_valid(const struct b_iterator *it) +{ + return b_dict_iterator_is_valid((struct b_dict_iterator *)it); +} + +static struct b_iterator_ops it_ops + = {.it_next = dict_iterator_next, + .it_close = NULL, + .it_erase = dict_iterator_erase, + .it_is_valid = dict_iterator_is_valid}; + +int b_dict_iterator_begin(struct b_dict *dict, b_dict_iterator *it) +{ + it->_base.it_ops = &it_ops; + + it->i = 0; + if (b_dict_is_empty(dict)) { + it->key = NULL; + it->value = NULL; + return -1; + } + + b_btree_node *first_node = b_btree_first(&dict->d_buckets); + struct b_dict_bucket *first_bucket + = b_unbox(struct b_dict_bucket, first_node, bk_node); + if (!first_bucket) { + it->key = NULL; + it->value = NULL; + return -1; + } + + b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items); + struct b_dict_bucket_item *first_item + = b_unbox(struct b_dict_bucket_item, first_entry, bi_entry); + if (!first_item) { + it->key = NULL; + it->value = NULL; + return -1; + } + + it->key = first_item->bi_str; + it->value = first_item->bi_value; + + it->_d = dict; + it->_cbn = first_node; + it->_cqe = first_entry; + + return 0; +} + +static bool get_next_node( + struct b_btree_node *cur_node, struct b_queue_entry *cur_entry, + struct b_btree_node **out_next_node, struct b_queue_entry **out_next_entry) +{ + struct b_dict_bucket *cur_bucket + = b_unbox(struct b_dict_bucket, cur_node, bk_node); + if (!cur_bucket) { + return false; + } + + struct b_dict_bucket_item *cur_item + = b_unbox(struct b_dict_bucket_item, cur_entry, bi_entry); + if (!cur_item) { + return false; + } + + struct b_btree_node *next_node = cur_node; + struct b_queue_entry *next_entry = b_queue_next(cur_entry); + if (!next_entry) { + next_node = b_btree_next(cur_node); + if (!next_node) { + return false; + } + + struct b_dict_bucket *next_bucket + = b_unbox(struct b_dict_bucket, next_node, bk_node); + if (!next_bucket) { + return false; + } + + next_entry = b_queue_first(&next_bucket->bk_items); + if (!next_entry) { + return false; + } + } + + struct b_dict_bucket_item *next_item + = b_unbox(struct b_dict_bucket_item, next_entry, bi_entry); + if (!next_item) { + return false; + } + + *out_next_node = next_node; + *out_next_entry = next_entry; + + return true; +} + +bool b_dict_iterator_next(b_dict_iterator *it) +{ + struct b_btree_node *next_node; + struct b_queue_entry *next_entry; + if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) { + it->key = NULL; + it->value = NULL; + return -1; + } + + struct b_dict_bucket_item *next_item + = b_unbox(struct b_dict_bucket_item, next_entry, bi_entry); + + if (!next_item) { + it->key = NULL; + it->value = NULL; + return -1; + } + + it->i++; + it->key = next_item->bi_str; + it->value = next_item->bi_value; + + it->_cbn = next_node; + it->_cqe = next_entry; + + return 0; +} + +static b_status delete_item( + struct b_dict *dict, struct b_dict_bucket *bucket, + struct b_dict_bucket_item *item) +{ + b_queue_delete(&bucket->bk_items, &item->bi_entry); + free(item); + + if (b_queue_empty(&bucket->bk_items)) { + b_btree_delete(&dict->d_buckets, &bucket->bk_node); + free(bucket); + } + + return B_SUCCESS; +} + +b_status b_dict_iterator_erase(struct b_dict_iterator *it) +{ + if ((it->key || it->value) && !(it->_cbn && it->_cqe)) { + return B_ERR_BAD_STATE; + } + + if (!it->key || !it->_cqe) { + return B_ERR_OUT_OF_BOUNDS; + } + + struct b_btree_node *next_node; + struct b_queue_entry *next_entry; + if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) { + it->key = NULL; + it->value = NULL; + return false; + } + + struct b_dict_bucket *cur_bucket + = b_unbox(struct b_dict_bucket, it->_cbn, bk_node); + struct b_dict_bucket_item *cur_item + = b_unbox(struct b_dict_bucket_item, it->_cqe, bi_entry); + + struct b_dict_bucket_item *next_item + = b_unbox(struct b_dict_bucket_item, next_entry, bi_entry); + + b_status status = delete_item(it->_d, cur_bucket, cur_item); + if (B_ERR(status)) { + return status; + } + + if (next_item) { + it->key = next_item->bi_str; + it->value = next_item->bi_value; + + it->_cbn = next_node; + it->_cqe = next_entry; + } else { + it->key = NULL; + it->value = NULL; + + it->_cbn = NULL; + it->_cqe = NULL; + } + + return B_SUCCESS; +} + +bool b_dict_iterator_is_valid(const struct b_dict_iterator *it) +{ + return it->key != NULL; +} + +static void dict_release(struct b_object *obj) +{ + struct b_dict *dict = B_DICT(obj); + + b_btree_iterator tree_it; + b_btree_iterator_begin(&dict->d_buckets, &tree_it); + while (b_btree_iterator_is_valid(&tree_it)) { + struct b_dict_bucket *bucket + = b_unbox(struct b_dict_bucket, tree_it.node, bk_node); + b_btree_iterator_erase(&tree_it); + + if (!bucket) { + continue; + } + + b_queue_iterator bucket_it; + b_queue_iterator_begin(&bucket->bk_items, &bucket_it); + while (b_queue_iterator_is_valid(&bucket_it)) { + struct b_dict_bucket_item *item = b_unbox( + struct b_dict_bucket_item, bucket_it.entry, + bi_entry); + b_queue_iterator_erase(&bucket_it); + + if (!item) { + continue; + } + + free(item->bi_str); + b_release(item->bi_value); + free(item); + } + + free(bucket); + } + +#if 0 + b_dict_iterator it; + b_dict_iterator_begin(dict, &it); + while (b_dict_iterator_is_valid(&it)) { + b_dict_iterator_erase(&it); + } +#endif +} + +b_object_type_id b_dict_type_id(void) +{ + return (b_object_type_id)&dict_type; +} diff --git a/object/dict.h b/object/dict.h new file mode 100644 index 0000000..e0bc013 --- /dev/null +++ b/object/dict.h @@ -0,0 +1,26 @@ +#ifndef _B_DICT_H_ +#define _B_DICT_H_ + +#include "object.h" + +#include +#include + +struct b_dict_bucket_item { + b_queue_entry bi_entry; + char *bi_str; + struct b_object *bi_value; +}; + +struct b_dict_bucket { + b_btree_node bk_node; + uint64_t bk_hash; + b_queue bk_items; +}; + +struct b_dict { + struct b_object d_base; + b_btree d_buckets; +}; + +#endif diff --git a/object/hashmap.c b/object/hashmap.c new file mode 100644 index 0000000..461d561 --- /dev/null +++ b/object/hashmap.c @@ -0,0 +1,434 @@ +#include "hashmap.h" + +#include +#include +#include +#include +#include +#include +#include + +#define HASH_OFFSET_BASIS 0xcbf29ce484222325 +#define HASH_PRIME 0x100000001b3 + +static uint64_t hash_data(const void *p, size_t size) +{ + const unsigned char *s = p; + uint64_t hash = HASH_OFFSET_BASIS; + + for (size_t i = 0; s[i]; i++) { + hash *= HASH_PRIME; + hash ^= s[i]; + } + + return hash; +} + +static void hashmap_release(struct b_object *obj); + +static struct b_object_type hashmap_type = { + .t_name = "corelib::hashmap", + .t_flags = B_OBJECT_FUNDAMENTAL, + .t_id = B_OBJECT_TYPE_HASHMAP, + .t_instance_size = sizeof(struct b_hashmap), + .t_release = hashmap_release, +}; + +struct b_hashmap *b_hashmap_create(void) +{ + struct b_hashmap *hashmap + = (struct b_hashmap *)b_object_type_instantiate(&hashmap_type); + if (!hashmap) { + return NULL; + } + + return hashmap; +} + +struct b_hashmap *b_hashmap_create_with_items(const b_hashmap_item *items) +{ + struct b_hashmap *hashmap = b_hashmap_create(); + if (!hashmap) { + return NULL; + } + + for (size_t i = 0; items[i].key.key_data && items[i].key.key_size; i++) { + b_hashmap_put(hashmap, &items[i].key, &items[i].value); + } + + return hashmap; +} + +static B_BTREE_DEFINE_SIMPLE_GET( + struct b_hashmap_bucket, uint64_t, bk_node, bk_hash, + get_bucket) static B_BTREE_DEFINE_SIMPLE_INSERT(struct b_hashmap_bucket, bk_node, bk_hash, put_bucket) + + static struct b_hashmap_bucket *create_bucket(void) +{ + struct b_hashmap_bucket *bucket = malloc(sizeof *bucket); + if (!bucket) { + return NULL; + } + + memset(bucket, 0x0, sizeof *bucket); + return bucket; +} + +static struct b_hashmap_bucket_item *create_bucket_item(void) +{ + struct b_hashmap_bucket_item *item = malloc(sizeof *item); + if (!item) { + return NULL; + } + + memset(item, 0x0, sizeof *item); + return item; +} + +b_status b_hashmap_put( + struct b_hashmap *hashmap, const b_hashmap_key *key, + const b_hashmap_value *value) +{ + uint64_t hash = hash_data(key->key_data, key->key_size); + struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash); + + if (!bucket) { + bucket = create_bucket(); + if (!bucket) { + return B_ERR_NO_MEMORY; + } + + bucket->bk_hash = hash; + put_bucket(&hashmap->h_buckets, bucket); + } + + b_queue_iterator it; + b_queue_foreach (&it, &bucket->bk_items) { + struct b_hashmap_bucket_item *item = b_unbox( + struct b_hashmap_bucket_item, it.entry, bi_entry); + + if (item->bi_key.key_size != key->key_size) { + continue; + } + + if (!memcmp(item->bi_key.key_data, key->key_data, key->key_size)) { + return B_ERR_NAME_EXISTS; + } + } + + struct b_hashmap_bucket_item *item = create_bucket_item(); + if (!item) { + return B_ERR_NO_MEMORY; + } + + memcpy(&item->bi_key, key, sizeof *key); + memcpy(&item->bi_value, value, sizeof *value); + + b_queue_push_back(&bucket->bk_items, &item->bi_entry); + + return B_SUCCESS; +} + +const struct b_hashmap_value *b_hashmap_get( + const struct b_hashmap *hashmap, const struct b_hashmap_key *key) +{ + uint64_t hash = hash_data(key->key_data, key->key_size); + struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash); + if (!bucket) { + return NULL; + } + + b_queue_iterator it; + b_queue_foreach (&it, &bucket->bk_items) { + struct b_hashmap_bucket_item *item = b_unbox( + struct b_hashmap_bucket_item, it.entry, bi_entry); + + if (item->bi_key.key_size != key->key_size) { + continue; + } + + if (!memcmp(item->bi_key.key_data, key->key_data, key->key_size)) { + return &item->bi_value; + } + } + + return NULL; +} + +bool b_hashmap_has_key(const struct b_hashmap *hashmap, const b_hashmap_key *key) +{ + uint64_t hash = hash_data(key->key_data, key->key_size); + struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash); + if (!bucket) { + return false; + } + + b_queue_iterator it; + b_queue_foreach (&it, &bucket->bk_items) { + struct b_hashmap_bucket_item *item = b_unbox( + struct b_hashmap_bucket_item, it.entry, bi_entry); + + if (item->bi_key.key_size != key->key_size) { + continue; + } + + if (!memcmp(item->bi_key.key_data, key->key_data, key->key_size)) { + return true; + } + } + + return false; +} + +size_t b_hashmap_get_size(const struct b_hashmap *hashmap) +{ + size_t count = 0; + b_btree_iterator it1; + b_queue_iterator it2; + b_btree_foreach (&it1, &hashmap->h_buckets) { + struct b_hashmap_bucket *bucket + = b_unbox(struct b_hashmap_bucket, it1.node, bk_node); + + b_queue_foreach (&it2, &bucket->bk_items) { + count++; + } + } + + return count; +} + +bool b_hashmap_is_empty(const b_hashmap *hashmap) +{ + b_btree_node *first_node = b_btree_first(&hashmap->h_buckets); + struct b_hashmap_bucket *first_bucket + = b_unbox(struct b_hashmap_bucket, first_node, bk_node); + if (!first_bucket) { + return true; + } + + b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items); + struct b_hashmap_bucket_item *first_item + = b_unbox(struct b_hashmap_bucket_item, first_entry, bi_entry); + if (!first_item) { + return true; + } + + return false; +} + +static b_status delete_item( + struct b_hashmap *hashmap, struct b_hashmap_bucket *bucket, + struct b_hashmap_bucket_item *item) +{ + b_queue_delete(&bucket->bk_items, &item->bi_entry); + free(item); + + if (b_queue_empty(&bucket->bk_items)) { + b_btree_delete(&hashmap->h_buckets, &bucket->bk_node); + free(bucket); + } + + return B_SUCCESS; +} + +static bool hashmap_iterator_next(struct b_iterator *it) +{ + return b_hashmap_iterator_next((struct b_hashmap_iterator *)it); +} + +static b_status hashmap_iterator_erase(struct b_iterator *it) +{ + return b_hashmap_iterator_erase((struct b_hashmap_iterator *)it); +} + +static bool hashmap_iterator_is_valid(const struct b_iterator *it) +{ + return b_hashmap_iterator_is_valid((struct b_hashmap_iterator *)it); +} + +static struct b_iterator_ops it_ops = { + .it_next = hashmap_iterator_next, + .it_erase = hashmap_iterator_erase, + .it_close = NULL, + .it_is_valid = hashmap_iterator_is_valid, +}; + +int b_hashmap_iterator_begin( + struct b_hashmap *hashmap, struct b_hashmap_iterator *it) +{ + it->_h = hashmap; + it->_base.it_ops = &it_ops; + + it->i = 0; + if (b_hashmap_is_empty(hashmap)) { + it->key = NULL; + it->value = NULL; + return -1; + } + + struct b_btree_node *first_node = b_btree_first(&hashmap->h_buckets); + struct b_hashmap_bucket *first_bucket + = b_unbox(struct b_hashmap_bucket, first_node, bk_node); + if (!first_bucket) { + it->key = NULL; + it->value = NULL; + return -1; + } + + struct b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items); + struct b_hashmap_bucket_item *first_item + = b_unbox(struct b_hashmap_bucket_item, first_entry, bi_entry); + if (!first_item) { + it->key = NULL; + it->value = NULL; + return -1; + } + + it->key = &first_item->bi_key; + it->value = &first_item->bi_value; + + it->_cbn = first_node; + it->_cqe = first_entry; + + return 0; +} + +static bool get_next_node( + struct b_btree_node *cur_node, struct b_queue_entry *cur_entry, + struct b_btree_node **out_next_node, struct b_queue_entry **out_next_entry) +{ + struct b_hashmap_bucket *cur_bucket + = b_unbox(struct b_hashmap_bucket, cur_node, bk_node); + if (!cur_bucket) { + return false; + } + + struct b_hashmap_bucket_item *cur_item + = b_unbox(struct b_hashmap_bucket_item, cur_entry, bi_entry); + if (!cur_item) { + return false; + } + + struct b_btree_node *next_node = cur_node; + struct b_queue_entry *next_entry = b_queue_next(cur_entry); + if (!next_entry) { + next_node = b_btree_next(cur_node); + if (!next_node) { + return false; + } + + struct b_hashmap_bucket *next_bucket + = b_unbox(struct b_hashmap_bucket, next_node, bk_node); + if (!next_bucket) { + return false; + } + + next_entry = b_queue_first(&next_bucket->bk_items); + if (!next_entry) { + return false; + } + } + + struct b_hashmap_bucket_item *next_item + = b_unbox(struct b_hashmap_bucket_item, next_entry, bi_entry); + if (!next_item) { + return false; + } + + *out_next_node = next_node; + *out_next_entry = next_entry; + + return true; +} + +bool b_hashmap_iterator_next(struct b_hashmap_iterator *it) +{ + struct b_btree_node *next_node; + struct b_queue_entry *next_entry; + if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) { + it->key = NULL; + it->value = NULL; + return false; + } + + struct b_hashmap_bucket_item *next_item + = b_unbox(struct b_hashmap_bucket_item, next_entry, bi_entry); + + if (!next_item) { + it->key = NULL; + it->value = NULL; + return false; + } + + it->i++; + it->key = &next_item->bi_key; + it->value = &next_item->bi_value; + + it->_cbn = next_node; + it->_cqe = next_entry; + + return true; +} + +b_status b_hashmap_iterator_erase(struct b_hashmap_iterator *it) +{ + if ((it->key || it->value) && !(it->_cbn && it->_cqe)) { + return B_ERR_BAD_STATE; + } + + if (!it->key || !it->_cqe) { + return B_ERR_OUT_OF_BOUNDS; + } + + struct b_btree_node *next_node; + struct b_queue_entry *next_entry; + if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) { + it->key = NULL; + it->value = NULL; + return false; + } + + struct b_hashmap_bucket *cur_bucket + = b_unbox(struct b_hashmap_bucket, it->_cbn, bk_node); + struct b_hashmap_bucket_item *cur_item + = b_unbox(struct b_hashmap_bucket_item, it->_cqe, bi_entry); + + struct b_hashmap_bucket_item *next_item + = b_unbox(struct b_hashmap_bucket_item, next_entry, bi_entry); + + b_status status = delete_item(it->_h, cur_bucket, cur_item); + if (B_ERR(status)) { + return status; + } + + if (next_item) { + it->key = &next_item->bi_key; + it->value = &next_item->bi_value; + + it->_cbn = next_node; + it->_cqe = next_entry; + } else { + it->key = NULL; + it->value = NULL; + + it->_cbn = NULL; + it->_cqe = NULL; + } + + return B_SUCCESS; +} + +bool b_hashmap_iterator_is_valid(const struct b_hashmap_iterator *it) +{ + return it->key != NULL; +} + +static void hashmap_release(struct b_object *obj) +{ + struct b_hashmap *map = B_HASHMAP(obj); +} + +b_object_type_id b_hashmap_type_id(void) +{ + return (b_object_type_id)&hashmap_type; +} diff --git a/object/hashmap.h b/object/hashmap.h new file mode 100644 index 0000000..8b7c960 --- /dev/null +++ b/object/hashmap.h @@ -0,0 +1,25 @@ +#ifndef _B_HASHMAP_H_ +#define _B_HASHMAP_H_ + +#include +#include +#include + +struct b_hashmap_bucket_item { + struct b_queue_entry bi_entry; + struct b_hashmap_key bi_key; + struct b_hashmap_value bi_value; +}; + +struct b_hashmap_bucket { + struct b_btree_node bk_node; + uint64_t bk_hash; + struct b_queue bk_items; +}; + +struct b_hashmap { + struct b_object h_base; + struct b_btree h_buckets; +}; + +#endif diff --git a/object/include/blue/object.h b/object/include/blue/object.h new file mode 100644 index 0000000..e69de29 diff --git a/object/include/blue/object/array.h b/object/include/blue/object/array.h new file mode 100644 index 0000000..b20fd86 --- /dev/null +++ b/object/include/blue/object/array.h @@ -0,0 +1,304 @@ +#ifndef BLUELIB_ARRAY_H_ +#define BLUELIB_ARRAY_H_ + +#include +#include +#include +#include +#include + +/** + * Cast a generic b_object pointer to an b_array pointer. + */ +#define B_ARRAY(p) ((b_array *)(p)) + +/** + * Iterate through each object in an b_array. + * + * This should be used for read-only iterations only. Adding or removing objects + * while iterating though an array using b_array_foreach is NOT supported. + * + * @param it A pointer to an b_array_iterator. This iterator will contain the + * current object reference for the current loop iteration. + * @param array A pointer to the b_array to iterate over. + */ +#define b_array_foreach(it, array) \ + for (int z__b_unique_name() = b_array_iterator_begin(array, it); \ + (it)->value != NULL; b_array_iterator_next(it)) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A heterogeneous array of objects. b_array only stores references + * to the objects that it contains, not the object data itself. + * + * b_array stores pointers to objects in a single contiguous array, + * but this is an implementation detail that may change in the future. + * Users of b_array should not rely on this being the case. + */ +typedef struct b_array b_array; + +/** + * Iterator for traversing the contents of an b_array. + * + * The iterator provides the current b_object `value`, as well + * as the index `i` of that value within the array. + * + * Any members whose names begin with _ (underscore) are reserved + * and should not be accessed. + */ +typedef struct b_array_iterator { + b_iterator _base; + b_array *_a; + + /** The index of the current value */ + size_t i; + /** The current value */ + b_object *value; +} b_array_iterator; + +/** + * Creates an empty b_array. + * + * @return A pointer to the new array, or NULL if an error occurred. + */ +extern b_array *b_array_create(void); + +/** + * Creates an b_array initialised with the contents of the provided b_object + * pointer array. The b_array will take a reference to each object specified in + * `values`, and will increment the reference count. The order of objects in the + * new b_array will be the same as the order of objects in `values`. Any NULL + * pointers in the `values` array will be ignored, and will not result in gaps + * in the created b_array. However, `nr_values` should be large enough to cover + * the final non-NULL pointer in `values`, including any NULL pointers + * in-between. + * + * @param values The list of object pointers which should make up the contents + * of the new b_array. + * @param nr_values The size of the `values` array. + * @return A pointer to the new b_array, or NULL if an error occurred. + */ +extern b_array *b_array_create_with_values( + b_object *const *values, size_t nr_values); + +/** + * Increment the reference counter of an b_array. + * + * @param array The b_array to reference. + * @return The b_array pointer that was passed to the function. + */ +static inline b_array *b_array_retain(b_array *array) +{ + return B_ARRAY(b_retain(B_OBJECT(array))); +} + +/** + * Decrement the reference counter of an b_array, destroying the array if it reaches zero. + * @param array The b_array reference to release. + */ +static inline void b_array_release(b_array *array) +{ + b_release(B_OBJECT(array)); +} + +/** + * Remove all object references from an b_array, resetting the size of the array to zero. + * The reference counts of all objects in the array will be decremented. + * + * @param array The b_array to clear. + */ +extern void b_array_clear(b_array *array); + +/** + * Inserts an object at the end of an b_array. The reference count of the object + * will be incremented. + * + * @param array The b_array to append the object to. + * @param value The object to append. + * @return B_SUCCESS if the object was appended successfully, or an error code if an error occurred. + */ +extern b_status b_array_append(b_array *array, b_object *value); + +/** + * Inserts an object at the beginning of an b_array. The reference count of the object + * will be incremented. All other objects in the array will be moved to make space + * for the object being pre-pended. + * + * @param array The b_array to prepend the object to. + * @param value The object to prepend. + * @return B_SUCCESS if the object was prepended successfully, or an error code if an error occurred. + */ +extern b_status b_array_prepend(b_array *array, b_object *value); + +/** + * Inserts an object into an b_array at a given index. The reference count of the object + * will be incremented. If the specified index is at the beginning or mid-way through + * the array (i.e. not at the end), some or all of the objects already in the array will + * be moved to make space for the object being inserted. + * + * @param array The b_array to insert the object into. + * @param value The object to insert. + * @param at The index to insert the object at. If the index is `B_NPOS`, the object will + * be inserted at the end of the b_array. + * @return B_SUCCESS if the object was inserted, or a status code describing any error that occurred. + */ +extern b_status b_array_insert(b_array *array, b_object *value, size_t at); + +/** + * Removes the object at the specified index from an b_array. The reference count + * of the removed object will be decremented. If the specified index is at the beginning + * or mid-way through the array (i.e. not at the end), the remaining objects will be moved + * to fill the empty space created by the object's removal. + * + * @param array The b_array to remove the object from. + * @param at The index of the object to be removed. + * @return B_SUCCESS if the object was removed, or a status code describing any error that occurred. + */ +extern b_status b_array_remove(b_array *array, size_t at); + +/** + * Removes the object at the beginning of an b_array. The reference count + * of the removed object will be decremented. The remaining objects will be moved + * to fill the empty space created by the object's removal. + * + * @param array The b_array to remove the object from. + * @return B_SUCCESS if the object was removed, or a status code describing any error that occurred. + */ +extern b_status b_array_remove_front(b_array *array); + +/** + * Removes the object at the end of an b_array. The reference count + * of the removed object will be decremented. + * + * @param array The b_array to remove the object from. + * @return B_SUCCESS if the object was removed, or a status code describing any error that occurred. + */ +extern b_status b_array_remove_back(b_array *array); + +/** + * Removes the object at the specified index of an b_array, and returns a + * pointer to it. The reference count of the removed object will NOT be + * decremented. The caller becomes the owner of the array's reference to the + * object. If the specified index is at the beginning or mid-way through the + * array (i.e. not at the end), the remaining objects will be moved to fill the + * empty space created by the object's removal. + * + * @param array The b_array to remove the object from. + * @param at The index of the object to be removed. + * @return An pointer to the removed object. This pointer is owned by the + * caller. Returns NULL if an error occurred. + */ +extern b_object *b_array_pop(b_array *array, size_t at); + +/** + * Removes the object at the beginning of an b_array, and returns a pointer to + * it. The reference count of the removed object will NOT be decremented. The + * caller becomes the owner of the array's reference to the object. The + * remaining objects in the b_array will be moved to fill the empty space left + * by the removed object. + * + * @param array The b_array to remove the object from. + * @return An pointer to the removed object. This pointer is owned by the + * caller. Returns NULL if an error occurred. + */ +extern b_object *b_array_pop_front(b_array *array); + +/** + * Removes the object at the end of an b_array, and returns a pointer to it. The + * reference count of the removed object will NOT be decremented. The caller + * becomes the owner of the array's reference to the object. + * + * @param array The b_array to remove the object from. + * @return An pointer to the removed object. This pointer is owned by the + * caller. Returns NULL if an error occurred. + */ +extern b_object *b_array_pop_back(b_array *array); + +/** + * Returns an unowned pointer to the object at the given index of an b_array. + * The caller does not own the returned pointer, and MUST NOT release it. + * + * @param array The b_array. + * @param at The index of the object to return. + * @return A pointer to the object at the given index. This pointer is NOT owned + * by the caller. Returns NULL if an error occurred. + */ +extern b_object *b_array_at(const b_array *array, size_t at); + +/** + * Returns an owned pointer to the object at the given index of an b_array. The caller owns + * the returned pointer, and must release it when they are finished with it. + * + * @param array The b_array. + * @param at The index of the object to return. + * @return A pointer to the object at the given index. This pointer is owned by the caller. + * Returns NULL if an error occurred. + */ +extern b_object *b_array_get(b_array *array, size_t at); + +/** + * Returns the number of objects contained in an b_array. + * + * @param array The b_array. + * @return The number of objects contained in the b_array. + */ +extern size_t b_array_size(const b_array *array); + +/** + * Returns the current maximum capacity of an b_array. This represents the + * number of objects that can be stored in an b_array before its internal buffer + * would need to be re-sized. + * + * @param array The b_array. + * @return The maximum capacity of the b_array. + */ +extern size_t b_array_capacity(const b_array *array); + +/** + * Initialise an b_array_iterator to pointer to the first object in an b_array. + * If the b_array is empty, then `it` will be an invalid iterator. + * + * @param array + * @param it + * @return Always returns 0. + */ +extern int b_array_iterator_begin(b_array *array, b_array_iterator *it); + +/** + * Advances an b_array_iterator to pointer to the next object in an b_array. + * @param it The iterator to advance. + * @return True if the iterator contains a valid reference to an object, or + * False if the iterator has gone past the end of the array. + */ +extern bool b_array_iterator_next(b_array_iterator *it); + +/** + * Removes the object pointed to by an b_array_iterator from its container + * b_array, and advances the iterator to the next object in the b_array. + * + * The reference count of the removed object will be decremented. + * + * @param it The iterator whose object should be removed. + * @return B_SUCCESS if the object was removed, or a status code describing the error that occurred. + */ +extern b_status b_array_iterator_erase(b_array_iterator *it); + +/** + * Checks whether or not an iterator contains a valid reference to an object. + * An iterator will become invalid if it has moved past the end of the b_array + * it was iterating across, or if b_array_iterator_erase() was called on an + * iterator pointing to the last object in an b_array. + * + * @param it The iterator to check. + * @return True if the iterator is valid. False otherwise. + */ +extern bool b_array_iterator_is_valid(const b_array_iterator *it); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/object/include/blue/object/bitmap.h b/object/include/blue/object/bitmap.h new file mode 100644 index 0000000..3e9e0e8 --- /dev/null +++ b/object/include/blue/object/bitmap.h @@ -0,0 +1,34 @@ +#ifndef BLUELIB_BITMAP_H_ +#define BLUELIB_BITMAP_H_ + +#include + +typedef unsigned long b_bitmap_word; + +#define Z__B_BITS_PER_WORD (8 * sizeof(b_bitmap_word)) +#define Z__B_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define B_BITMAP_WORDS(nbits) Z__B_DIV_ROUND_UP(nbits, Z__B_BITS_PER_WORD) +#define B_BITMAP_NPOS ((unsigned int)-1) + +#define B_DECLARE_BITMAP(name, nbits) b_bitmap_word name[B_BITMAP_WORDS(nbits)] + +extern void b_bitmap_zero(b_bitmap_word *map, unsigned long nbits); +extern void b_bitmap_fill(b_bitmap_word *map, unsigned long nbits); +extern void b_bitmap_set(b_bitmap_word *map, unsigned long bit); +extern void b_bitmap_clear(b_bitmap_word *map, unsigned long bit); +extern bool b_bitmap_check(const b_bitmap_word *map, unsigned long bit); + +extern unsigned int b_bitmap_count_set(const b_bitmap_word *map, unsigned long nbits); +extern unsigned int b_bitmap_count_clear(const b_bitmap_word *map, unsigned long nbits); + +extern unsigned int b_bitmap_highest_set(const b_bitmap_word *map, unsigned long nbits); +extern unsigned int b_bitmap_highest_clear(const b_bitmap_word *map, unsigned long nbits); +extern unsigned int b_bitmap_lowest_set(const b_bitmap_word *map, unsigned long nbits); +extern unsigned int b_bitmap_lowest_clear(const b_bitmap_word *map, unsigned long nbits); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/object/include/blue/object/buffer.h b/object/include/blue/object/buffer.h new file mode 100644 index 0000000..857c2d6 --- /dev/null +++ b/object/include/blue/object/buffer.h @@ -0,0 +1,33 @@ +#ifndef BLUELIB_BUFFER_H_ +#define BLUELIB_BUFFER_H_ + +#include +#include +#include +#include + +#define B_BUFFER(p) ((b_buffer *)(p)) + +typedef struct b_buffer b_buffer; + +extern b_buffer *b_buffer_create(size_t item_sz); +extern b_buffer *b_buffer_create_from_bytes(const void *p, size_t len); +extern b_buffer *b_buffer_create_from_array(const void *p, size_t item_sz, size_t len); + +static inline b_buffer *b_buffer_retain(b_buffer *buf) { return B_BUFFER(b_retain(B_OBJECT(buf))); } +static inline void b_buffer_release(b_buffer *buf) { b_release(B_OBJECT(buf)); } +extern void *b_buffer_steal(b_buffer *buf); +extern b_status b_buffer_reserve(b_buffer *buf, size_t capacity); + +extern b_status b_buffer_append(b_buffer *dest, const void *p, size_t count); +extern b_status b_buffer_prepend(b_buffer *dest, const void *p, size_t count); +extern b_status b_buffer_insert(b_buffer *dest, const void *p, size_t count, size_t at); +extern b_status b_buffer_clear(b_buffer *str); + +extern size_t b_buffer_get_size(const b_buffer *str); +extern size_t b_buffer_get_item_size(const b_buffer *str); +extern size_t b_buffer_get_capacity(const b_buffer *str); + +extern void *b_buffer_ptr(const b_buffer *str); + +#endif diff --git a/object/include/blue/object/dict.h b/object/include/blue/object/dict.h new file mode 100644 index 0000000..481c4bd --- /dev/null +++ b/object/include/blue/object/dict.h @@ -0,0 +1,69 @@ +#ifndef BLUELIB_DICT_H_ +#define BLUELIB_DICT_H_ + +#include +#include +#include +#include +#include +#include + +#define B_DICT(p) ((b_dict *)(p)) + +#define B_DICT_ITEM(k, v) \ + { \ + .key = (k), .value = (v) \ + } +#define B_DICT_ITEM_END \ + { \ + .key = NULL, .value = NULL \ + } + +#define b_dict_foreach(it, dict) \ + for (int z__b_unique_name() = b_dict_iterator_begin(dict, it); \ + (it)->key != NULL; b_dict_iterator_next(it)) + +typedef struct b_dict b_dict; + +typedef struct b_dict_iterator { + b_iterator _base; + size_t i; + const char *key; + b_object *value; + + b_dict *_d; + b_btree_node *_cbn; + b_queue_entry *_cqe; +} b_dict_iterator; + +typedef struct b_dict_item { + const char *key; + b_object *value; +} b_dict_item; + +extern b_dict *b_dict_create(void); +extern b_dict *b_dict_create_with_items(const b_dict_item *items); + +static inline b_dict *b_dict_retain(b_dict *dict) +{ + return B_DICT(b_retain(B_OBJECT(dict))); +} +static inline void b_dict_release(b_dict *dict) +{ + b_release(B_OBJECT(dict)); +} + +extern b_status b_dict_put(b_dict *dict, const char *key, b_object *value); +extern b_object *b_dict_at(const b_dict *dict, const char *key); +extern b_object *b_dict_get(b_dict *dict, const char *key); + +extern bool b_dict_has_key(const b_dict *dict, const char *key); +extern size_t b_dict_get_size(const b_dict *dict); +extern bool b_dict_is_empty(const b_dict *dict); + +extern int b_dict_iterator_begin(b_dict *dict, b_dict_iterator *it); +extern bool b_dict_iterator_next(b_dict_iterator *it); +extern b_status b_dict_iterator_erase(b_dict_iterator *it); +extern bool b_dict_iterator_is_valid(const b_dict_iterator *it); + +#endif diff --git a/object/include/blue/object/hashmap.h b/object/include/blue/object/hashmap.h new file mode 100644 index 0000000..7fef3c7 --- /dev/null +++ b/object/include/blue/object/hashmap.h @@ -0,0 +1,92 @@ +#ifndef BLUELIB_HASHMAP_H_ +#define BLUELIB_HASHMAP_H_ + +#include +#include +#include +#include +#include +#include + +#define B_HASHMAP(p) ((b_hashmap *)(p)) + +#define B_HASHMAP_KEY(k, ks) \ + { \ + .key_data = (k), .key_size = (ks) \ + } +#define B_HASHMAP_VALUE(v, vs) \ + { \ + .value_data = (v), .value_size = (vs) \ + } + +#define B_HASHMAP_ITEM(k, ks, v, vs) \ + { \ + .key = B_HASHMAP_KEY(k, ks), .value = B_HASHMAP_VALUE(v, vs) \ + } + +#define B_HASHMAP_ITEM_END \ + { \ + .key = {}, .value = {} \ + } + +#define b_hashmap_foreach(it, hashmap) \ + for (int z__b_unique_name() = b_hashmap_iterator_begin(hashmap, it); \ + (it)->key != NULL; b_hashmap_iterator_next(it)) + +typedef struct b_hashmap b_hashmap; + +typedef struct b_hashmap_key { + const void *key_data; + size_t key_size; + bool key_owned; +} b_hashmap_key; + +typedef struct b_hashmap_value { + void *value_data; + size_t value_size; + bool value_owned; +} b_hashmap_value; + +typedef struct b_hashmap_item { + b_hashmap_key key; + b_hashmap_value value; +} b_hashmap_item; + +typedef struct b_hashmap_iterator { + b_iterator _base; + size_t i; + const b_hashmap_key *key; + const b_hashmap_value *value; + + b_hashmap *_h; + b_btree_node *_cbn; + b_queue_entry *_cqe; +} b_hashmap_iterator; + +extern b_hashmap *b_hashmap_create(void); +extern b_hashmap *b_hashmap_create_with_items(const b_hashmap_item *items); + +static inline b_hashmap *b_hashmap_retain(b_hashmap *hashmap) +{ + return B_HASHMAP(b_retain(B_OBJECT(hashmap))); +} +static inline void b_hashmap_release(b_hashmap *hashmap) +{ + b_release(B_OBJECT(hashmap)); +} + +extern b_status b_hashmap_put( + b_hashmap *hashmap, const b_hashmap_key *key, const b_hashmap_value *value); +extern const b_hashmap_value *b_hashmap_get( + const b_hashmap *hashmap, const b_hashmap_key *key); + +extern bool b_hashmap_has_key(const b_hashmap *hashmap, const b_hashmap_key *key); +extern size_t b_hashmap_get_size(const b_hashmap *hashmap); +extern bool b_hashmap_is_empty(const b_hashmap *hashmap); + +extern int b_hashmap_iterator_begin(b_hashmap *hashmap, b_hashmap_iterator *it); +extern bool b_hashmap_iterator_next(b_hashmap_iterator *it); +extern b_status b_hashmap_iterator_erase(b_hashmap_iterator *it); +extern bool b_hashmap_iterator_is_valid(const b_hashmap_iterator *it); + +#endif diff --git a/object/include/blue/object/number.h b/object/include/blue/object/number.h new file mode 100644 index 0000000..489c363 --- /dev/null +++ b/object/include/blue/object/number.h @@ -0,0 +1,285 @@ +#ifndef BLUELIB_NUMBER_H +#define BLUELIB_NUMBER_H + +#include +#include +#include + +#define B_NUMBER(p) ((b_number *)(p)) + +#define B_INT8(v) (b_number_create_int8(v)) +#define B_INT16(v) (b_number_create_int16(v)) +#define B_INT32(v) (b_number_create_int32(v)) +#define B_INT64(v) (b_number_create_int64(v)) +#define B_FLOAT32(v) (b_number_create_float32(v)) +#define B_FLOAT64(v) (b_number_create_float64(v)) +#define B_CHAR(v) (b_number_create_char(v)) +#define B_SHORT(v) (b_number_create_short(v)) +#define B_INT(v) (b_number_create_int(v)) +#define B_LONG(v) (b_number_create_long(v)) +#define B_LONGLONG(v) (b_number_create_longlong(v)) +#define B_FLOAT(v) (b_number_create_float(v)) +#define B_DOUBLE(v) (b_number_create_double(v)) +#define B_SIZE_T(v) (b_number_create_size_t(v)) + +#define B_RV_INT8(v) B_RV(b_number_create_int8(v)) +#define B_RV_INT16(v) B_RV(b_number_create_int16(v)) +#define B_RV_INT32(v) B_RV(b_number_create_int32(v)) +#define B_RV_INT64(v) B_RV(b_number_create_int64(v)) +#define B_RV_FLOAT32(v) B_RV(b_number_create_float32(v)) +#define B_RV_FLOAT64(v) B_RV(b_number_create_float64(v)) +#define B_RV_CHAR(v) B_RV(b_number_create_char(v)) +#define B_RV_SHORT(v) B_RV(b_number_create_short(v)) +#define B_RV_INT(v) B_RV(b_number_create_int(v)) +#define B_RV_LONG(v) B_RV(b_number_create_long(v)) +#define B_RV_LONGLONG(v) B_RV(b_number_create_longlong(v)) +#define B_RV_FLOAT(v) B_RV(b_number_create_float(v)) +#define B_RV_DOUBLE(v) B_RV(b_number_create_double(v)) +#define B_RV_SIZE_T(v) B_RV(b_number_create_size_t(v)) + +#define B_NUMBER_IVAL(p) (b_number_get_size_t(p)) +#define B_NUMBER_FVAL(p) (b_number_get_double(p)) + +typedef struct b_number b_number; + +typedef enum b_number_type { + B_NUMBER_INT8, + B_NUMBER_INT16, + B_NUMBER_INT32, + B_NUMBER_INT64, + B_NUMBER_FLOAT32, + B_NUMBER_FLOAT64, + B_NUMBER_CHAR, + B_NUMBER_SHORT, + B_NUMBER_INT, + B_NUMBER_LONG, + B_NUMBER_LONGLONG, + B_NUMBER_FLOAT, + B_NUMBER_DOUBLE, + B_NUMBER_SIZE_T, + B_NUMBER_HANDLE, + B_NUMBER_TYPE_COUNT, + + B_NUMBER_BYTE = B_NUMBER_INT8, + B_NUMBER_WORD = B_NUMBER_INT16, + B_NUMBER_DWORD = B_NUMBER_INT32, + B_NUMBER_QWORD = B_NUMBER_INT64, +} b_number_type; + +typedef struct { + union { + unsigned char i_bytes[sizeof(uint16_t)]; + int16_t i_val; + uint16_t i_uval; + }; +} b_i16; + +typedef struct { + union { + unsigned char i_bytes[sizeof(uint32_t)]; + int32_t i_val; + uint32_t i_uval; + }; +} b_i32; + +typedef struct { + union { + unsigned char i_bytes[sizeof(uint64_t)]; + int64_t i_val; + uint64_t i_uval; + }; +} b_i64; + +extern b_number *b_number_create(b_number_type type, void *value_ptr); +static inline b_number *b_number_retain(b_number *number) +{ + return B_NUMBER(b_retain(B_OBJECT(number))); +} +static inline void b_number_release(b_number *number) +{ + b_release(B_OBJECT(number)); +} + +static inline b_number *b_number_create_int8(int8_t value) +{ + return b_number_create(B_NUMBER_INT8, &value); +} +static inline b_number *b_number_create_int16(int16_t value) +{ + return b_number_create(B_NUMBER_INT16, &value); +} +static inline b_number *b_number_create_int32(int32_t value) +{ + return b_number_create(B_NUMBER_INT32, &value); +} +static inline b_number *b_number_create_int64(int64_t value) +{ + return b_number_create(B_NUMBER_INT64, &value); +} +static inline b_number *b_number_create_float32(float value) +{ + return b_number_create(B_NUMBER_FLOAT32, &value); +} +static inline b_number *b_number_create_float64(double value) +{ + return b_number_create(B_NUMBER_FLOAT64, &value); +} +static inline b_number *b_number_create_char(char value) +{ + return b_number_create(B_NUMBER_CHAR, &value); +} +static inline b_number *b_number_create_short(short value) +{ + return b_number_create(B_NUMBER_SHORT, &value); +} +static inline b_number *b_number_create_int(int value) +{ + return b_number_create(B_NUMBER_INT, &value); +} +static inline b_number *b_number_create_long(long value) +{ + return b_number_create(B_NUMBER_LONG, &value); +} +static inline b_number *b_number_create_longlong(long long value) +{ + return b_number_create(B_NUMBER_LONGLONG, &value); +} +static inline b_number *b_number_create_float(float value) +{ + return b_number_create(B_NUMBER_FLOAT, &value); +} +static inline b_number *b_number_create_double(double value) +{ + return b_number_create(B_NUMBER_DOUBLE, &value); +} +static inline b_number *b_number_create_size_t(size_t value) +{ + return b_number_create(B_NUMBER_SIZE_T, &value); +} + +extern b_number_type b_number_get_type(const b_number *number); +extern int b_number_get_value( + const b_number *number, b_number_type type, void *value_ptr); + +static inline int8_t b_number_get_int8(const b_number *number) +{ + int8_t v; + b_number_get_value(number, B_NUMBER_INT8, &v); + return v; +} + +static inline int16_t b_number_get_int16(const b_number *number) +{ + int16_t v; + b_number_get_value(number, B_NUMBER_INT16, &v); + return v; +} + +static inline int32_t b_number_get_int32(const b_number *number) +{ + int32_t v; + b_number_get_value(number, B_NUMBER_INT32, &v); + return v; +} + +static inline int64_t b_number_get_int64(const b_number *number) +{ + int64_t v; + b_number_get_value(number, B_NUMBER_INT64, &v); + return v; +} + +static inline float b_number_get_float32(const b_number *number) +{ + float v; + b_number_get_value(number, B_NUMBER_FLOAT32, &v); + return v; +} + +static inline double b_number_get_float64(const b_number *number) +{ + double v; + b_number_get_value(number, B_NUMBER_FLOAT64, &v); + return v; +} + +static inline char b_number_get_char(const b_number *number) +{ + char v; + b_number_get_value(number, B_NUMBER_CHAR, &v); + return v; +} + +static inline short b_number_get_short(const b_number *number) +{ + short v; + b_number_get_value(number, B_NUMBER_SHORT, &v); + return v; +} + +static inline int b_number_get_int(const b_number *number) +{ + int v; + b_number_get_value(number, B_NUMBER_INT, &v); + return v; +} + +static inline long b_number_get_long(const b_number *number) +{ + long v; + b_number_get_value(number, B_NUMBER_LONG, &v); + return v; +} + +static inline long long b_number_get_longlong(const b_number *number) +{ + long long v; + b_number_get_value(number, B_NUMBER_LONGLONG, &v); + return v; +} + +static inline float b_number_get_float(const b_number *number) +{ + float v; + b_number_get_value(number, B_NUMBER_FLOAT, &v); + return v; +} + +static inline double b_number_get_double(const b_number *number) +{ + double v; + b_number_get_value(number, B_NUMBER_DOUBLE, &v); + return v; +} + +static inline size_t b_number_get_size_t(const b_number *number) +{ + size_t v; + b_number_get_value(number, B_NUMBER_SIZE_T, &v); + return v; +} + +extern bool b_number_is_integer(const b_number *number); +extern bool b_number_is_float(const b_number *number); + +extern size_t b_number_data_size(const b_number *number); + +extern b_i16 b_i16_htob(uint16_t v); +extern b_i16 b_i16_htos(uint16_t v); + +extern uint16_t b_i16_btoh(b_i16 v); +extern uint16_t b_i16_stoh(b_i16 v); + +extern b_i32 b_i32_htob(uint32_t v); +extern b_i32 b_i32_htos(uint32_t v); + +extern uint32_t b_i32_btoh(b_i32 v); +extern uint32_t b_i32_stoh(b_i32 v); + +extern b_i64 b_i64_htob(uint64_t v); +extern b_i64 b_i64_htos(uint64_t v); + +extern uint64_t b_i64_btoh(b_i64 v); +extern uint64_t b_i64_stoh(b_i64 v); + +#endif diff --git a/object/include/blue/object/object.h b/object/include/blue/object/object.h new file mode 100644 index 0000000..934744f --- /dev/null +++ b/object/include/blue/object/object.h @@ -0,0 +1,38 @@ +#ifndef BLUELIB_OBJECT_H_ +#define BLUELIB_OBJECT_H_ + +#include + +#define B_OBJECT(p) ((b_object *)(p)) + +#define B_TYPEOF(object) ((struct b_object *)(object)->ob_type) +#define B_TYPEID(object) (b_typeid(B_OBJECT(object))) + +#define B_RV(p) (b_make_rvalue(B_OBJECT(p))) +#define B_RVT(t, p) ((t *)(b_make_rvalue(B_OBJECT(p)))) + +struct b_string; +struct b_stringstream; + +typedef enum b_comparison_result { + B_LESS = -1, + B_EQUAL = 0, + B_GREATER = 1, +} b_comparison_result_t; + +typedef struct b_object { + unsigned int ob_ref; + const struct b_object_type *ob_type; +} b_object; + +extern b_object *b_make_rvalue(b_object *obj); + +extern b_object *b_retain(b_object *obj); +extern void b_release(b_object *obj); + +extern void b_to_string(b_object *obj, struct b_stringstream *out); +extern b_object_type_id b_typeid(const b_object *obj); + +extern b_comparison_result_t b_compare(const b_object *a, const b_object *b); + +#endif diff --git a/object/include/blue/object/string.h b/object/include/blue/object/string.h new file mode 100644 index 0000000..4cf24f5 --- /dev/null +++ b/object/include/blue/object/string.h @@ -0,0 +1,77 @@ +#ifndef BLUELIB_STRING_H_ +#define BLUELIB_STRING_H_ + +#include +#include +#include + +#define B_STRING(p) ((b_string *)(p)) + +#define B_CSTR(s) (b_string_create_from_cstr(s)) +#define B_RV_CSTR(s) (B_RV(b_string_create_from_cstr(s))) + +typedef struct b_string b_string; + +typedef enum b_strlen_flags { + B_STRLEN_NORMAL = 0, + B_STRLEN_IGNORE_ESC = 0x01u, +} b_strlen_flags; + +typedef struct b_strv_builder { + char *strv_buf; + size_t strv_len; + size_t strv_max; + unsigned char strv_alloc; +} b_strv_builder; + +extern b_string *b_string_create(void); +extern b_string *b_string_create_from_cstr(const char *s); +extern b_string *b_string_create_from_c(char c, size_t count); + +static inline b_string *b_string_retain(b_string *str) +{ + return B_STRING(b_retain(B_OBJECT(str))); +} +static inline void b_string_release(b_string *str) +{ + b_release(B_OBJECT(str)); +} +extern char *b_string_steal(b_string *str); +extern b_status b_string_reserve(b_string *str, size_t capacity); + +extern void b_string_append_s(b_string *dest, const b_string *src); +extern void b_string_append_cstr(b_string *dest, const char *src); +extern void b_string_append_cstrf(b_string *dest, const char *format, ...); +extern void b_string_prepend_s(b_string *dest, const b_string *src); +extern void b_string_prepend_cstr(b_string *dest, const char *src); +extern void b_string_prepend_cstrf(b_string *dest, const char *format, ...); +extern void b_string_insert_s(b_string *dest, const b_string *src, size_t at); +extern void b_string_insert_cstr(b_string *dest, const char *src, size_t at); +extern void b_string_insert_cstrn( + b_string *dest, const char *src, size_t len, size_t at); +extern void b_string_insert_cstrf( + b_string *dest, size_t at, const char *format, ...); +extern void b_string_clear(b_string *str); + +extern size_t b_string_get_size(const b_string *str, b_strlen_flags flags); +extern size_t b_string_get_capacity(const b_string *str); + +extern const char *b_string_ptr(const b_string *str); + +extern void b_strv_builder_begin(b_strv_builder *strv, char *buf, size_t max); +extern void b_strv_builder_begin_dynamic(b_strv_builder *strv); + +extern b_status b_strv_builder_add(b_strv_builder *strv, const char *str); +extern b_status b_strv_builder_addf(b_strv_builder *strv, const char *format, ...); +extern b_status b_strv_builder_addv(b_strv_builder *strv, const char **strs); +extern b_status b_strv_builder_addvl( + b_strv_builder *strv, const char **strs, size_t count); +extern b_status b_strv_builder_add_many(b_strv_builder *strv, ...); +extern char *b_strv_builder_end(b_strv_builder *strv); + +extern char *b_strdup(const char *s); +extern size_t b_strlen(const char *s, b_strlen_flags flags); + +extern uint64_t b_cstr_hash(const char *s); + +#endif diff --git a/object/include/blue/object/string_formatter.h b/object/include/blue/object/string_formatter.h new file mode 100644 index 0000000..798f2eb --- /dev/null +++ b/object/include/blue/object/string_formatter.h @@ -0,0 +1,25 @@ +#ifndef BLUELIB_STRING_FORMATTER_H +#define BLUELIB_STRING_FORMATTER_H + +#include +#include + +typedef struct b_stringstream b_stringstream; + +extern b_stringstream *b_stringstream_create(void); +extern b_string *b_stringstream_end(b_stringstream *f); +extern void b_stringstream_destroy(b_stringstream *f); +extern const b_string *b_stringstream_str(b_stringstream *f); +extern const char *b_stringstream_cstr(b_stringstream *f); +extern void b_stringstream_clear(b_stringstream *f); + +extern void b_stringstream_push_indent(b_stringstream *f, int indent); +extern void b_stringstream_push_indent_abs(b_stringstream *f, int indent); +extern void b_stringstream_pop_indent(b_stringstream *f); + +extern void b_stringstream_add(b_stringstream *f, const char *s); +extern void b_stringstream_addf(b_stringstream *f, const char *format, ...); +extern void b_stringstream_addvf(b_stringstream *f, const char *format, va_list arg); +extern void b_stringstream_add_str(b_stringstream *f, const b_string *str); + +#endif diff --git a/object/include/blue/object/tree.h b/object/include/blue/object/tree.h new file mode 100644 index 0000000..091437c --- /dev/null +++ b/object/include/blue/object/tree.h @@ -0,0 +1,72 @@ +#ifndef BLUELIB_TREE_H_ +#define BLUELIB_TREE_H_ + +#include +#include +#include + +#define B_TREE(p) ((b_tree *)(p)) +#define B_TREE_NODE_INIT ((b_tree_node) {}) + +#define B_TREE_CONTAINER(t, m, v) \ + ((void *)((v) ? (uintptr_t)(v) - (offsetof(t, m)) : 0)) + +typedef struct b_tree b_tree; + +#define b_tree_node_foreach(it, node) \ + for (int z__b_unique_name() = b_tree_iterator_begin_at_node(node, it); \ + (it)->node != NULL; b_tree_iterator_next(it)) + +#define b_tree_node_foreach_recursive(it, node) \ + for (int z__b_unique_name() \ + = b_tree_iterator_begin_at_node_recursive(node, it); \ + (it)->node != NULL; b_tree_iterator_next(it)) + +#define b_tree_foreach(it, tree) \ + for (int z__b_unique_name() = b_tree_iterator_begin(tree, it); \ + (it)->node != NULL; b_tree_iterator_next(it)) + +typedef struct b_tree_node { + struct b_tree_node *__p01, *__p02, *__p03; + struct b_queue_entry __q01; + // struct b_tree_node *parent; + // struct b_tree_node *first_child, *next_sibling; +} b_tree_node; + +typedef struct b_tree_iterator { + b_iterator _base; + size_t i, depth; + b_tree_node *node; + + unsigned char _f01; +} b_tree_iterator; + +extern b_tree *b_tree_create(void); + +static inline b_tree *b_tree_retain(b_tree *tree) +{ + return B_TREE(b_retain(B_OBJECT(tree))); +} +static inline void b_tree_release(b_tree *tree) +{ + b_release(B_OBJECT(tree)); +} + +extern void b_tree_set_root(b_tree *tree, struct b_tree_node *node); + +extern void b_tree_node_add_child(b_tree_node *parent, b_tree_node *child); +extern void b_tree_node_add_sibling(b_tree_node *node, b_tree_node *to_add); + +extern b_tree_node *b_tree_node_get_child(b_tree_node *node, size_t at); +extern b_tree_node *b_tree_node_get_parent(b_tree_node *node); + +extern int b_tree_iterator_begin(b_tree *tree, b_tree_iterator *it); +extern int b_tree_iterator_begin_at_node(b_tree_node *node, b_tree_iterator *it); +extern int b_tree_iterator_begin_at_node_recursive( + b_tree_node *node, b_tree_iterator *it); + +extern bool b_tree_iterator_next(b_tree_iterator *it); +extern b_status b_tree_iterator_erase(b_tree_iterator *it); +extern bool b_tree_iterator_is_valid(const b_tree_iterator *it); + +#endif diff --git a/object/include/blue/object/type.h b/object/include/blue/object/type.h new file mode 100644 index 0000000..c88a1f0 --- /dev/null +++ b/object/include/blue/object/type.h @@ -0,0 +1,51 @@ +#ifndef BLUELIB_TYPE_H_ +#define BLUELIB_TYPE_H_ + +#include +#include +#include +#include +#include + +#define B_NPOS ((size_t)INTPTR_MAX) + +struct b_object; +struct b_stringstream; + +typedef uintptr_t b_object_type_id; + +typedef enum b_fundamental_type_id { + B_OBJECT_TYPE_NONE = 0, + B_OBJECT_TYPE_ANY, + B_OBJECT_TYPE_ARRAY, + B_OBJECT_TYPE_BUFFER, + B_OBJECT_TYPE_DICT, + B_OBJECT_TYPE_ERROR, + B_OBJECT_TYPE_HASHMAP, + B_OBJECT_TYPE_NUMBER, + B_OBJECT_TYPE_STRING, + B_OBJECT_TYPE_TREE, + B_OBJECT_TYPE_UUID, + B_OBJECT_TYPE_FILE, + B_OBJECT_TYPE_DIRECTORY, +} b_fundamental_type_id; + +typedef enum b_object_type_flags { + B_OBJECT_FUNDAMENTAL = 0x01u, +} b_object_type_flags; + +typedef struct b_object_type { + b_object_type_flags t_flags; + char t_name[64]; + size_t t_instance_size; + b_object_type_id t_id; + b_queue_entry t_entry; + void (*t_init)(struct b_object *); + void (*t_release)(struct b_object *); + void (*t_to_string)(struct b_object *, struct b_stringstream *); +} b_object_type; + +extern b_status b_object_type_register(b_object_type *type); +extern struct b_object *b_object_type_instantiate(const b_object_type *type); + +#endif diff --git a/object/include/blue/object/uuid.h b/object/include/blue/object/uuid.h new file mode 100644 index 0000000..054f496 --- /dev/null +++ b/object/include/blue/object/uuid.h @@ -0,0 +1,52 @@ +#ifndef BLUELIB_UUID_H_ +#define BLUELIB_UUID_H_ + +#include +#include +#include + +#define B_UUID(p) ((b_uuid *)(p)) + +#define B_UUID_NBYTES 16 +#define B_UUID_STRING_MAX 37 + +struct b_string; +struct b_strv_builder; + +typedef struct b_uuid b_uuid; + +typedef struct b_uuid_bytes { + unsigned char uuid_bytes[B_UUID_NBYTES]; +} b_uuid_bytes; + +extern b_uuid *b_uuid_create(void); +extern b_uuid *b_uuid_create_from_bytes( + unsigned char u00, unsigned char u01, unsigned char u02, + unsigned char u03, unsigned char u04, unsigned char u05, + unsigned char u06, unsigned char u07, unsigned char u08, + unsigned char u09, unsigned char u10, unsigned char u11, unsigned char u12, + unsigned char u13, unsigned char u14, unsigned char u15); +extern b_uuid *b_uuid_create_from_bytev(const unsigned char bytes[B_UUID_NBYTES]); +extern b_uuid *b_uuid_create_from_uuid_bytes(const b_uuid_bytes *bytes); +extern b_uuid *b_uuid_create_from_string(const struct b_string *string); +extern b_uuid *b_uuid_create_from_cstr(const char *s); + +static inline b_uuid *b_uuid_retain(b_uuid *uuid) +{ + return B_UUID(b_retain(B_OBJECT(uuid))); +} +static inline void b_uuid_release(b_uuid *uuid) +{ + b_release(B_OBJECT(uuid)); +} + +extern b_status b_uuid_to_string(const b_uuid *uuid, struct b_string *out); +extern b_status b_uuid_to_cstr(const b_uuid *uuid, char out[B_UUID_STRING_MAX]); +extern b_status b_uuid_to_strv_builder( + const b_uuid *uuid, struct b_strv_builder *out); +extern void b_uuid_get_bytes( + const b_uuid *uuid, unsigned char bytes[B_UUID_NBYTES]); +extern void b_uuid_get_uuid_bytes(const b_uuid *uuid, b_uuid_bytes *bytes); +extern b_uuid_bytes *b_uuid_ptr(b_uuid *uuid); + +#endif diff --git a/object/number.c b/object/number.c new file mode 100644 index 0000000..134e9b9 --- /dev/null +++ b/object/number.c @@ -0,0 +1,1681 @@ +#include "number.h" + +#include +#include +#include +#include +#include + +typedef int (*number_converter_t)(const struct b_number *, void *); + +static number_converter_t converters[B_NUMBER_TYPE_COUNT][B_NUMBER_TYPE_COUNT]; + +static void number_to_string(struct b_object *obj, struct b_stringstream *out); + +static struct b_object_type number_type = { + .t_name = "corelib::number", + .t_flags = B_OBJECT_FUNDAMENTAL, + .t_id = B_OBJECT_TYPE_NUMBER, + .t_instance_size = sizeof(b_number), + .t_to_string = number_to_string, +}; + +struct b_number *b_number_create(b_number_type type, void *value_ptr) +{ + struct b_number *n + = (struct b_number *)b_object_type_instantiate(&number_type); + if (!n) { + return NULL; + } + + n->n_type = type; + + if (!value_ptr) { + return n; + } + + switch (n->n_type) { + case B_NUMBER_INT8: + memcpy(&n->n_value.v_int8, value_ptr, sizeof n->n_value.v_int8); + break; + case B_NUMBER_INT16: + memcpy(&n->n_value.v_int16, value_ptr, sizeof n->n_value.v_int16); + break; + case B_NUMBER_INT32: + memcpy(&n->n_value.v_int32, value_ptr, sizeof n->n_value.v_int32); + break; + case B_NUMBER_INT64: + memcpy(&n->n_value.v_int64, value_ptr, sizeof n->n_value.v_int64); + break; + case B_NUMBER_FLOAT32: + memcpy(&n->n_value.v_float32, value_ptr, + sizeof n->n_value.v_float32); + break; + case B_NUMBER_FLOAT64: + memcpy(&n->n_value.v_float64, value_ptr, + sizeof n->n_value.v_float64); + break; + case B_NUMBER_CHAR: + memcpy(&n->n_value.v_char, value_ptr, sizeof n->n_value.v_char); + break; + case B_NUMBER_SHORT: + memcpy(&n->n_value.v_short, value_ptr, sizeof n->n_value.v_short); + break; + case B_NUMBER_INT: + memcpy(&n->n_value.v_int, value_ptr, sizeof n->n_value.v_int); + break; + case B_NUMBER_LONG: + memcpy(&n->n_value.v_long, value_ptr, sizeof n->n_value.v_long); + break; + case B_NUMBER_LONGLONG: + memcpy(&n->n_value.v_longlong, value_ptr, + sizeof n->n_value.v_longlong); + break; + case B_NUMBER_FLOAT: + memcpy(&n->n_value.v_float, value_ptr, sizeof n->n_value.v_float); + break; + case B_NUMBER_DOUBLE: + memcpy(&n->n_value.v_double, value_ptr, sizeof n->n_value.v_double); + break; + case B_NUMBER_SIZE_T: + memcpy(&n->n_value.v_size_t, value_ptr, sizeof n->n_value.v_size_t); + break; + default: + break; + } + + return n; +} + +b_number_type b_number_get_type(const struct b_number *number) +{ + return number->n_type; +} + +int b_number_get_value( + const struct b_number *number, b_number_type type, void *value_ptr) +{ + b_number_type srb_type = number->n_type; + b_number_type dest_type = type; + + number_converter_t converter = converters[srb_type][dest_type]; + if (!converter) { + return -1; + } + + return converter(number, value_ptr); +} + +bool b_number_is_integer(const struct b_number *number) +{ + switch (number->n_type) { + case B_NUMBER_INT8: + case B_NUMBER_INT16: + case B_NUMBER_INT32: + case B_NUMBER_INT64: + case B_NUMBER_SIZE_T: + case B_NUMBER_CHAR: + case B_NUMBER_SHORT: + case B_NUMBER_INT: + case B_NUMBER_LONG: + case B_NUMBER_LONGLONG: + case B_NUMBER_HANDLE: + return true; + default: + return false; + } +} + +bool b_number_is_float(const struct b_number *number) +{ + switch (number->n_type) { + case B_NUMBER_FLOAT: + case B_NUMBER_DOUBLE: + case B_NUMBER_FLOAT32: + case B_NUMBER_FLOAT64: + return true; + default: + return false; + } +} + +size_t b_number_data_size(const struct b_number *number) +{ + switch (number->n_type) { + case B_NUMBER_INT8: + return sizeof number->n_value.v_int8; + case B_NUMBER_INT16: + return sizeof number->n_value.v_int16; + case B_NUMBER_INT32: + return sizeof number->n_value.v_int32; + case B_NUMBER_INT64: + return sizeof number->n_value.v_int64; + case B_NUMBER_FLOAT32: + return sizeof number->n_value.v_float32; + case B_NUMBER_FLOAT64: + return sizeof number->n_value.v_float64; + case B_NUMBER_CHAR: + return sizeof number->n_value.v_char; + case B_NUMBER_SHORT: + return sizeof number->n_value.v_short; + case B_NUMBER_INT: + return sizeof number->n_value.v_int; + case B_NUMBER_LONG: + return sizeof number->n_value.v_long; + case B_NUMBER_LONGLONG: + return sizeof number->n_value.v_longlong; + case B_NUMBER_FLOAT: + return sizeof number->n_value.v_float; + case B_NUMBER_DOUBLE: + return sizeof number->n_value.v_double; + case B_NUMBER_SIZE_T: + return sizeof number->n_value.v_size_t; + default: + return 0; + } +} + +static void number_to_string(struct b_object *obj, struct b_stringstream *out) +{ + struct b_number *number = B_NUMBER(obj); + switch (number->n_type) { + case B_NUMBER_INT8: + b_stringstream_addf(out, "%" PRIu8, number->n_value.v_int8); + break; + case B_NUMBER_INT16: + b_stringstream_addf(out, "%" PRIu16, number->n_value.v_int16); + break; + case B_NUMBER_INT32: + b_stringstream_addf(out, "%" PRIu32, number->n_value.v_int32); + break; + case B_NUMBER_INT64: + b_stringstream_addf(out, "%" PRIu64, number->n_value.v_int64); + break; + case B_NUMBER_FLOAT32: + b_stringstream_addf(out, "%f", number->n_value.v_float32); + break; + case B_NUMBER_FLOAT64: + b_stringstream_addf(out, "%lf", number->n_value.v_float64); + break; + case B_NUMBER_CHAR: + b_stringstream_addf(out, "%d", number->n_value.v_char); + break; + case B_NUMBER_SHORT: + b_stringstream_addf(out, "%d", number->n_value.v_short); + break; + case B_NUMBER_INT: + b_stringstream_addf(out, "%d", number->n_value.v_int); + break; + case B_NUMBER_LONG: + b_stringstream_addf(out, "%ld", number->n_value.v_long); + break; + case B_NUMBER_LONGLONG: + b_stringstream_addf(out, "%lld", number->n_value.v_longlong); + break; + case B_NUMBER_FLOAT: + b_stringstream_addf(out, "%f", number->n_value.v_float); + break; + case B_NUMBER_DOUBLE: + b_stringstream_addf(out, "%lf", number->n_value.v_double); + break; + case B_NUMBER_SIZE_T: + b_stringstream_addf(out, "%zu", number->n_value.v_size_t); + break; + case B_NUMBER_HANDLE: + b_stringstream_addf( + out, "%016" PRIx64, number->n_value.v_size_t); + break; + default: + break; + } +} + +/* ++++++++++++++++++ int8 -> xyz CONVERTER CALLBACKS ++++++++++++++++++ */ + +static int int8_to_int8(const struct b_number *number, void *value_ptr) +{ + *(int8_t *)value_ptr = number->n_value.v_int8; + return 0; +} + +static int int8_to_int16(const struct b_number *number, void *value_ptr) +{ + *(int16_t *)value_ptr = (int16_t)number->n_value.v_int8; + return 0; +} + +static int int8_to_int32(const struct b_number *number, void *value_ptr) +{ + *(int32_t *)value_ptr = (int32_t)number->n_value.v_int8; + return 0; +} + +static int int8_to_int64(const struct b_number *number, void *value_ptr) +{ + *(int64_t *)value_ptr = (int64_t)number->n_value.v_int8; + return 0; +} + +static int int8_to_float32(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_int8; + return 0; +} + +static int int8_to_float64(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_int8; + return 0; +} + +static int int8_to_char(const struct b_number *number, void *value_ptr) +{ + *(char *)value_ptr = number->n_value.v_int8; + return 0; +} + +static int int8_to_short(const struct b_number *number, void *value_ptr) +{ + *(short *)value_ptr = (short)number->n_value.v_int8; + return 0; +} + +static int int8_to_int(const struct b_number *number, void *value_ptr) +{ + *(int *)value_ptr = (int)number->n_value.v_int8; + return 0; +} + +static int int8_to_long(const struct b_number *number, void *value_ptr) +{ + *(long *)value_ptr = (long)number->n_value.v_int8; + return 0; +} + +static int int8_to_longlong(const struct b_number *number, void *value_ptr) +{ + *(long long *)value_ptr = (long long)number->n_value.v_int8; + return 0; +} + +static int int8_to_float(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_int8; + return 0; +} + +static int int8_to_double(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_int8; + return 0; +} + +static int int8_to_size_t(const struct b_number *number, void *value_ptr) +{ + *(size_t *)value_ptr = (size_t)number->n_value.v_int8; + return 0; +} + +/* ++++++++++++++++++ int16 -> xyz CONVERTER CALLBACKS ++++++++++++++++++ */ + +static int int16_to_int8(const struct b_number *number, void *value_ptr) +{ + *(int8_t *)value_ptr = (int8_t)number->n_value.v_int16; + return 0; +} + +static int int16_to_int16(const struct b_number *number, void *value_ptr) +{ + *(int16_t *)value_ptr = number->n_value.v_int16; + return 0; +} + +static int int16_to_int32(const struct b_number *number, void *value_ptr) +{ + *(int32_t *)value_ptr = number->n_value.v_int16; + return 0; +} + +static int int16_to_int64(const struct b_number *number, void *value_ptr) +{ + *(int64_t *)value_ptr = number->n_value.v_int16; + return 0; +} + +static int int16_to_float32(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_int16; + return 0; +} + +static int int16_to_float64(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_int16; + return 0; +} + +static int int16_to_char(const struct b_number *number, void *value_ptr) +{ + *(char *)value_ptr = (char)number->n_value.v_int16; + return 0; +} + +static int int16_to_short(const struct b_number *number, void *value_ptr) +{ + *(short *)value_ptr = number->n_value.v_int16; + return 0; +} + +static int int16_to_int(const struct b_number *number, void *value_ptr) +{ + *(int *)value_ptr = number->n_value.v_int16; + return 0; +} + +static int int16_to_long(const struct b_number *number, void *value_ptr) +{ + *(long *)value_ptr = number->n_value.v_int16; + return 0; +} + +static int int16_to_longlong(const struct b_number *number, void *value_ptr) +{ + *(long long *)value_ptr = number->n_value.v_int16; + return 0; +} + +static int int16_to_float(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_int16; + return 0; +} + +static int int16_to_double(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_int16; + return 0; +} + +static int int16_to_size_t(const struct b_number *number, void *value_ptr) +{ + *(size_t *)value_ptr = number->n_value.v_int16; + return 0; +} + +/* ++++++++++++++++++ int32 -> xyz CONVERTER CALLBACKS ++++++++++++++++++ */ + +static int int32_to_int8(const struct b_number *number, void *value_ptr) +{ + *(int8_t *)value_ptr = (int8_t)number->n_value.v_int32; + return 0; +} + +static int int32_to_int16(const struct b_number *number, void *value_ptr) +{ + *(int16_t *)value_ptr = (int16_t)number->n_value.v_int32; + return 0; +} + +static int int32_to_int32(const struct b_number *number, void *value_ptr) +{ + *(int32_t *)value_ptr = number->n_value.v_int32; + return 0; +} + +static int int32_to_int64(const struct b_number *number, void *value_ptr) +{ + *(int64_t *)value_ptr = number->n_value.v_int32; + return 0; +} + +static int int32_to_float32(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = (float)number->n_value.v_int32; + return 0; +} + +static int int32_to_float64(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_int32; + return 0; +} + +static int int32_to_char(const struct b_number *number, void *value_ptr) +{ + *(char *)value_ptr = (char)number->n_value.v_int32; + return 0; +} + +static int int32_to_short(const struct b_number *number, void *value_ptr) +{ + *(short *)value_ptr = (short)number->n_value.v_int32; + return 0; +} + +static int int32_to_int(const struct b_number *number, void *value_ptr) +{ + *(int *)value_ptr = number->n_value.v_int32; + return 0; +} + +static int int32_to_long(const struct b_number *number, void *value_ptr) +{ + *(long *)value_ptr = number->n_value.v_int32; + return 0; +} + +static int int32_to_longlong(const struct b_number *number, void *value_ptr) +{ + *(long long *)value_ptr = number->n_value.v_int32; + return 0; +} + +static int int32_to_float(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = (float)number->n_value.v_int32; + return 0; +} + +static int int32_to_double(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_int32; + return 0; +} + +static int int32_to_size_t(const struct b_number *number, void *value_ptr) +{ + *(size_t *)value_ptr = number->n_value.v_int32; + return 0; +} + +/* ++++++++++++++++++ int64 -> xyz CONVERTER CALLBACKS ++++++++++++++++++ */ + +static int int64_to_int8(const struct b_number *number, void *value_ptr) +{ + *(int8_t *)value_ptr = (int8_t)number->n_value.v_int64; + return 0; +} + +static int int64_to_int16(const struct b_number *number, void *value_ptr) +{ + *(int16_t *)value_ptr = (int16_t)number->n_value.v_int64; + return 0; +} + +static int int64_to_int32(const struct b_number *number, void *value_ptr) +{ + *(int32_t *)value_ptr = (int32_t)number->n_value.v_int64; + return 0; +} + +static int int64_to_int64(const struct b_number *number, void *value_ptr) +{ + *(int64_t *)value_ptr = number->n_value.v_int64; + return 0; +} + +static int int64_to_float32(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = (float)number->n_value.v_int64; + return 0; +} + +static int int64_to_float64(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = (double)number->n_value.v_int64; + return 0; +} + +static int int64_to_char(const struct b_number *number, void *value_ptr) +{ + *(char *)value_ptr = (char)number->n_value.v_int64; + return 0; +} + +static int int64_to_short(const struct b_number *number, void *value_ptr) +{ + *(short *)value_ptr = (short)number->n_value.v_int64; + return 0; +} + +static int int64_to_int(const struct b_number *number, void *value_ptr) +{ + *(int *)value_ptr = (int)number->n_value.v_int64; + return 0; +} + +static int int64_to_long(const struct b_number *number, void *value_ptr) +{ + *(long *)value_ptr = number->n_value.v_int64; + return 0; +} + +static int int64_to_longlong(const struct b_number *number, void *value_ptr) +{ + *(long long *)value_ptr = number->n_value.v_int64; + return 0; +} + +static int int64_to_float(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = (float)number->n_value.v_int64; + return 0; +} + +static int int64_to_double(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = (double)number->n_value.v_int64; + return 0; +} + +static int int64_to_size_t(const struct b_number *number, void *value_ptr) +{ + *(size_t *)value_ptr = number->n_value.v_int64; + return 0; +} + +/* ++++++++++++++++++ float32 -> xyz CONVERTER CALLBACKS ++++++++++++++++++ */ + +static int float32_to_int8(const struct b_number *number, void *value_ptr) +{ + *(int8_t *)value_ptr = (int8_t)number->n_value.v_float32; + return 0; +} + +static int float32_to_int16(const struct b_number *number, void *value_ptr) +{ + *(int16_t *)value_ptr = (int16_t)number->n_value.v_float32; + return 0; +} + +static int float32_to_int32(const struct b_number *number, void *value_ptr) +{ + *(int32_t *)value_ptr = (int32_t)number->n_value.v_float32; + return 0; +} + +static int float32_to_int64(const struct b_number *number, void *value_ptr) +{ + *(int64_t *)value_ptr = (int64_t)number->n_value.v_float32; + return 0; +} + +static int float32_to_float32(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_float32; + return 0; +} + +static int float32_to_float64(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_float32; + return 0; +} + +static int float32_to_char(const struct b_number *number, void *value_ptr) +{ + *(char *)value_ptr = (char)number->n_value.v_float32; + return 0; +} + +static int float32_to_short(const struct b_number *number, void *value_ptr) +{ + *(short *)value_ptr = (short)number->n_value.v_float32; + return 0; +} + +static int float32_to_int(const struct b_number *number, void *value_ptr) +{ + *(int *)value_ptr = (int)number->n_value.v_float32; + return 0; +} + +static int float32_to_long(const struct b_number *number, void *value_ptr) +{ + *(long *)value_ptr = number->n_value.v_float32; + return 0; +} + +static int float32_to_longlong(const struct b_number *number, void *value_ptr) +{ + *(long long *)value_ptr = number->n_value.v_float32; + return 0; +} + +static int float32_to_float(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_float32; + return 0; +} + +static int float32_to_double(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_float32; + return 0; +} + +static int float32_to_size_t(const struct b_number *number, void *value_ptr) +{ + *(size_t *)value_ptr = number->n_value.v_float32; + return 0; +} + +/* ++++++++++++++++++ float64 -> xyz CONVERTER CALLBACKS ++++++++++++++++++ */ + +static int float64_to_int8(const struct b_number *number, void *value_ptr) +{ + *(int8_t *)value_ptr = number->n_value.v_float64; + return 0; +} + +static int float64_to_int16(const struct b_number *number, void *value_ptr) +{ + *(int16_t *)value_ptr = number->n_value.v_float64; + return 0; +} + +static int float64_to_int32(const struct b_number *number, void *value_ptr) +{ + *(int32_t *)value_ptr = number->n_value.v_float64; + return 0; +} + +static int float64_to_int64(const struct b_number *number, void *value_ptr) +{ + *(int64_t *)value_ptr = number->n_value.v_float64; + return 0; +} + +static int float64_to_float32(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_float64; + return 0; +} + +static int float64_to_float64(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_float64; + return 0; +} + +static int float64_to_char(const struct b_number *number, void *value_ptr) +{ + *(char *)value_ptr = number->n_value.v_float64; + return 0; +} + +static int float64_to_short(const struct b_number *number, void *value_ptr) +{ + *(short *)value_ptr = number->n_value.v_float64; + return 0; +} + +static int float64_to_int(const struct b_number *number, void *value_ptr) +{ + *(int *)value_ptr = number->n_value.v_float64; + return 0; +} + +static int float64_to_long(const struct b_number *number, void *value_ptr) +{ + *(long *)value_ptr = number->n_value.v_float64; + return 0; +} + +static int float64_to_longlong(const struct b_number *number, void *value_ptr) +{ + *(long long *)value_ptr = number->n_value.v_float64; + return 0; +} + +static int float64_to_float(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_float64; + return 0; +} + +static int float64_to_double(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_float64; + return 0; +} + +static int float64_to_size_t(const struct b_number *number, void *value_ptr) +{ + *(size_t *)value_ptr = number->n_value.v_float64; + return 0; +} + +/* ++++++++++++++++++ char -> xyz CONVERTER CALLBACKS ++++++++++++++++++ */ + +static int char_to_int8(const struct b_number *number, void *value_ptr) +{ + *(int8_t *)value_ptr = number->n_value.v_char; + return 0; +} + +static int char_to_int16(const struct b_number *number, void *value_ptr) +{ + *(int16_t *)value_ptr = number->n_value.v_char; + return 0; +} + +static int char_to_int32(const struct b_number *number, void *value_ptr) +{ + *(int32_t *)value_ptr = number->n_value.v_char; + return 0; +} + +static int char_to_int64(const struct b_number *number, void *value_ptr) +{ + *(int64_t *)value_ptr = number->n_value.v_char; + return 0; +} + +static int char_to_float32(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_char; + return 0; +} + +static int char_to_float64(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_char; + return 0; +} + +static int char_to_char(const struct b_number *number, void *value_ptr) +{ + *(char *)value_ptr = number->n_value.v_char; + return 0; +} + +static int char_to_short(const struct b_number *number, void *value_ptr) +{ + *(short *)value_ptr = number->n_value.v_char; + return 0; +} + +static int char_to_int(const struct b_number *number, void *value_ptr) +{ + *(int *)value_ptr = number->n_value.v_char; + return 0; +} + +static int char_to_long(const struct b_number *number, void *value_ptr) +{ + *(long *)value_ptr = number->n_value.v_char; + return 0; +} + +static int char_to_longlong(const struct b_number *number, void *value_ptr) +{ + *(long long *)value_ptr = number->n_value.v_char; + return 0; +} + +static int char_to_float(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_char; + return 0; +} + +static int char_to_double(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_char; + return 0; +} + +static int char_to_size_t(const struct b_number *number, void *value_ptr) +{ + *(size_t *)value_ptr = number->n_value.v_char; + return 0; +} + +/* ++++++++++++++++++ short -> xyz CONVERTER CALLBACKS ++++++++++++++++++ */ + +static int short_to_int8(const struct b_number *number, void *value_ptr) +{ + *(int8_t *)value_ptr = number->n_value.v_short; + return 0; +} + +static int short_to_int16(const struct b_number *number, void *value_ptr) +{ + *(int16_t *)value_ptr = number->n_value.v_short; + return 0; +} + +static int short_to_int32(const struct b_number *number, void *value_ptr) +{ + *(int32_t *)value_ptr = number->n_value.v_short; + return 0; +} + +static int short_to_int64(const struct b_number *number, void *value_ptr) +{ + *(int64_t *)value_ptr = number->n_value.v_short; + return 0; +} + +static int short_to_float32(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_short; + return 0; +} + +static int short_to_float64(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_short; + return 0; +} + +static int short_to_char(const struct b_number *number, void *value_ptr) +{ + *(char *)value_ptr = number->n_value.v_short; + return 0; +} + +static int short_to_short(const struct b_number *number, void *value_ptr) +{ + *(short *)value_ptr = number->n_value.v_short; + return 0; +} + +static int short_to_int(const struct b_number *number, void *value_ptr) +{ + *(int *)value_ptr = number->n_value.v_short; + return 0; +} + +static int short_to_long(const struct b_number *number, void *value_ptr) +{ + *(long *)value_ptr = number->n_value.v_short; + return 0; +} + +static int short_to_longlong(const struct b_number *number, void *value_ptr) +{ + *(long long *)value_ptr = number->n_value.v_short; + return 0; +} + +static int short_to_float(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_short; + return 0; +} + +static int short_to_double(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_short; + return 0; +} + +static int short_to_size_t(const struct b_number *number, void *value_ptr) +{ + *(size_t *)value_ptr = number->n_value.v_short; + return 0; +} + +/* ++++++++++++++++++ int -> xyz CONVERTER CALLBACKS ++++++++++++++++++ */ + +static int int_to_int8(const struct b_number *number, void *value_ptr) +{ + *(int8_t *)value_ptr = number->n_value.v_int; + return 0; +} + +static int int_to_int16(const struct b_number *number, void *value_ptr) +{ + *(int16_t *)value_ptr = number->n_value.v_int; + return 0; +} + +static int int_to_int32(const struct b_number *number, void *value_ptr) +{ + *(int32_t *)value_ptr = number->n_value.v_int; + return 0; +} + +static int int_to_int64(const struct b_number *number, void *value_ptr) +{ + *(int64_t *)value_ptr = number->n_value.v_int; + return 0; +} + +static int int_to_float32(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_int; + return 0; +} + +static int int_to_float64(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_int; + return 0; +} + +static int int_to_char(const struct b_number *number, void *value_ptr) +{ + *(char *)value_ptr = number->n_value.v_int; + return 0; +} + +static int int_to_short(const struct b_number *number, void *value_ptr) +{ + *(short *)value_ptr = number->n_value.v_int; + return 0; +} + +static int int_to_int(const struct b_number *number, void *value_ptr) +{ + *(int *)value_ptr = number->n_value.v_int; + return 0; +} + +static int int_to_long(const struct b_number *number, void *value_ptr) +{ + *(long *)value_ptr = number->n_value.v_int; + return 0; +} + +static int int_to_longlong(const struct b_number *number, void *value_ptr) +{ + *(long long *)value_ptr = number->n_value.v_int; + return 0; +} + +static int int_to_float(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_int; + return 0; +} + +static int int_to_double(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_int; + return 0; +} + +static int int_to_size_t(const struct b_number *number, void *value_ptr) +{ + *(size_t *)value_ptr = number->n_value.v_int; + return 0; +} + +/* ++++++++++++++++++ long -> xyz CONVERTER CALLBACKS ++++++++++++++++++ */ + +static int long_to_int8(const struct b_number *number, void *value_ptr) +{ + *(int8_t *)value_ptr = number->n_value.v_long; + return 0; +} + +static int long_to_int16(const struct b_number *number, void *value_ptr) +{ + *(int16_t *)value_ptr = number->n_value.v_long; + return 0; +} + +static int long_to_int32(const struct b_number *number, void *value_ptr) +{ + *(int32_t *)value_ptr = number->n_value.v_long; + return 0; +} + +static int long_to_int64(const struct b_number *number, void *value_ptr) +{ + *(int64_t *)value_ptr = number->n_value.v_long; + return 0; +} + +static int long_to_float32(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_long; + return 0; +} + +static int long_to_float64(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_long; + return 0; +} + +static int long_to_char(const struct b_number *number, void *value_ptr) +{ + *(char *)value_ptr = number->n_value.v_long; + return 0; +} + +static int long_to_short(const struct b_number *number, void *value_ptr) +{ + *(short *)value_ptr = number->n_value.v_long; + return 0; +} + +static int long_to_int(const struct b_number *number, void *value_ptr) +{ + *(int *)value_ptr = number->n_value.v_long; + return 0; +} + +static int long_to_long(const struct b_number *number, void *value_ptr) +{ + *(long *)value_ptr = number->n_value.v_long; + return 0; +} + +static int long_to_longlong(const struct b_number *number, void *value_ptr) +{ + *(long long *)value_ptr = number->n_value.v_long; + return 0; +} + +static int long_to_float(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_long; + return 0; +} + +static int long_to_double(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_long; + return 0; +} + +static int long_to_size_t(const struct b_number *number, void *value_ptr) +{ + *(size_t *)value_ptr = number->n_value.v_long; + return 0; +} + +/* ++++++++++++++++++ longlong -> xyz CONVERTER CALLBACKS ++++++++++++++++++ */ + +static int longlong_to_int8(const struct b_number *number, void *value_ptr) +{ + *(int8_t *)value_ptr = number->n_value.v_longlong; + return 0; +} + +static int longlong_to_int16(const struct b_number *number, void *value_ptr) +{ + *(int16_t *)value_ptr = number->n_value.v_longlong; + return 0; +} + +static int longlong_to_int32(const struct b_number *number, void *value_ptr) +{ + *(int32_t *)value_ptr = number->n_value.v_longlong; + return 0; +} + +static int longlong_to_int64(const struct b_number *number, void *value_ptr) +{ + *(int64_t *)value_ptr = number->n_value.v_longlong; + return 0; +} + +static int longlong_to_float32(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_longlong; + return 0; +} + +static int longlong_to_float64(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_longlong; + return 0; +} + +static int longlong_to_char(const struct b_number *number, void *value_ptr) +{ + *(char *)value_ptr = number->n_value.v_longlong; + return 0; +} + +static int longlong_to_short(const struct b_number *number, void *value_ptr) +{ + *(short *)value_ptr = number->n_value.v_longlong; + return 0; +} + +static int longlong_to_int(const struct b_number *number, void *value_ptr) +{ + *(int *)value_ptr = number->n_value.v_longlong; + return 0; +} + +static int longlong_to_long(const struct b_number *number, void *value_ptr) +{ + *(long *)value_ptr = number->n_value.v_longlong; + return 0; +} + +static int longlong_to_longlong(const struct b_number *number, void *value_ptr) +{ + *(long long *)value_ptr = number->n_value.v_longlong; + return 0; +} + +static int longlong_to_float(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_longlong; + return 0; +} + +static int longlong_to_double(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_longlong; + return 0; +} + +static int longlong_to_size_t(const struct b_number *number, void *value_ptr) +{ + *(size_t *)value_ptr = number->n_value.v_longlong; + return 0; +} + +/* ++++++++++++++++++ float -> xyz CONVERTER CALLBACKS ++++++++++++++++++ */ + +static int float_to_int8(const struct b_number *number, void *value_ptr) +{ + *(int8_t *)value_ptr = number->n_value.v_float; + return 0; +} + +static int float_to_int16(const struct b_number *number, void *value_ptr) +{ + *(int16_t *)value_ptr = number->n_value.v_float; + return 0; +} + +static int float_to_int32(const struct b_number *number, void *value_ptr) +{ + *(int32_t *)value_ptr = number->n_value.v_float; + return 0; +} + +static int float_to_int64(const struct b_number *number, void *value_ptr) +{ + *(int64_t *)value_ptr = number->n_value.v_float; + return 0; +} + +static int float_to_float32(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_float; + return 0; +} + +static int float_to_float64(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_float; + return 0; +} + +static int float_to_char(const struct b_number *number, void *value_ptr) +{ + *(char *)value_ptr = number->n_value.v_float; + return 0; +} + +static int float_to_short(const struct b_number *number, void *value_ptr) +{ + *(short *)value_ptr = number->n_value.v_float; + return 0; +} + +static int float_to_int(const struct b_number *number, void *value_ptr) +{ + *(int *)value_ptr = number->n_value.v_float; + return 0; +} + +static int float_to_long(const struct b_number *number, void *value_ptr) +{ + *(long *)value_ptr = number->n_value.v_float; + return 0; +} + +static int float_to_longlong(const struct b_number *number, void *value_ptr) +{ + *(long long *)value_ptr = number->n_value.v_float; + return 0; +} + +static int float_to_float(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_float; + return 0; +} + +static int float_to_double(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_float; + return 0; +} + +static int float_to_size_t(const struct b_number *number, void *value_ptr) +{ + *(size_t *)value_ptr = number->n_value.v_float; + return 0; +} + +/* ++++++++++++++++++ double -> xyz CONVERTER CALLBACKS ++++++++++++++++++ */ + +static int double_to_int8(const struct b_number *number, void *value_ptr) +{ + *(int8_t *)value_ptr = number->n_value.v_double; + return 0; +} + +static int double_to_int16(const struct b_number *number, void *value_ptr) +{ + *(int16_t *)value_ptr = number->n_value.v_double; + return 0; +} + +static int double_to_int32(const struct b_number *number, void *value_ptr) +{ + *(int32_t *)value_ptr = number->n_value.v_double; + return 0; +} + +static int double_to_int64(const struct b_number *number, void *value_ptr) +{ + *(int64_t *)value_ptr = number->n_value.v_double; + return 0; +} + +static int double_to_float32(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_double; + return 0; +} + +static int double_to_float64(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_double; + return 0; +} + +static int double_to_char(const struct b_number *number, void *value_ptr) +{ + *(char *)value_ptr = number->n_value.v_double; + return 0; +} + +static int double_to_short(const struct b_number *number, void *value_ptr) +{ + *(short *)value_ptr = number->n_value.v_double; + return 0; +} + +static int double_to_int(const struct b_number *number, void *value_ptr) +{ + *(int *)value_ptr = number->n_value.v_double; + return 0; +} + +static int double_to_long(const struct b_number *number, void *value_ptr) +{ + *(long *)value_ptr = number->n_value.v_double; + return 0; +} + +static int double_to_longlong(const struct b_number *number, void *value_ptr) +{ + *(long long *)value_ptr = number->n_value.v_double; + return 0; +} + +static int double_to_float(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_double; + return 0; +} + +static int double_to_double(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_double; + return 0; +} + +static int double_to_size_t(const struct b_number *number, void *value_ptr) +{ + *(size_t *)value_ptr = number->n_value.v_double; + return 0; +} + +/* ++++++++++++++++++ size_t -> xyz CONVERTER CALLBACKS ++++++++++++++++++ */ + +static int size_t_to_int8(const struct b_number *number, void *value_ptr) +{ + *(int8_t *)value_ptr = number->n_value.v_size_t; + return 0; +} + +static int size_t_to_int16(const struct b_number *number, void *value_ptr) +{ + *(int16_t *)value_ptr = number->n_value.v_size_t; + return 0; +} + +static int size_t_to_int32(const struct b_number *number, void *value_ptr) +{ + *(int32_t *)value_ptr = number->n_value.v_size_t; + return 0; +} + +static int size_t_to_int64(const struct b_number *number, void *value_ptr) +{ + *(int64_t *)value_ptr = number->n_value.v_size_t; + return 0; +} + +static int size_t_to_float32(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_size_t; + return 0; +} + +static int size_t_to_float64(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_size_t; + return 0; +} + +static int size_t_to_char(const struct b_number *number, void *value_ptr) +{ + *(char *)value_ptr = number->n_value.v_size_t; + return 0; +} + +static int size_t_to_short(const struct b_number *number, void *value_ptr) +{ + *(short *)value_ptr = number->n_value.v_size_t; + return 0; +} + +static int size_t_to_int(const struct b_number *number, void *value_ptr) +{ + *(int *)value_ptr = number->n_value.v_size_t; + return 0; +} + +static int size_t_to_long(const struct b_number *number, void *value_ptr) +{ + *(long *)value_ptr = number->n_value.v_size_t; + return 0; +} + +static int size_t_to_longlong(const struct b_number *number, void *value_ptr) +{ + *(long long *)value_ptr = number->n_value.v_size_t; + return 0; +} + +static int size_t_to_float(const struct b_number *number, void *value_ptr) +{ + *(float *)value_ptr = number->n_value.v_size_t; + return 0; +} + +static int size_t_to_double(const struct b_number *number, void *value_ptr) +{ + *(double *)value_ptr = number->n_value.v_size_t; + return 0; +} + +static int size_t_to_size_t(const struct b_number *number, void *value_ptr) +{ + *(size_t *)value_ptr = number->n_value.v_size_t; + return 0; +} + +static number_converter_t converters[B_NUMBER_TYPE_COUNT][B_NUMBER_TYPE_COUNT] = { + /* int8_t -> xyz CONVERTER CALLBACKS */ + [B_NUMBER_INT8] = { + [B_NUMBER_INT8] = int8_to_int8, + [B_NUMBER_INT16] = int8_to_int16, + [B_NUMBER_INT32] = int8_to_int32, + [B_NUMBER_INT64] = int8_to_int64, + [B_NUMBER_FLOAT32] = int8_to_float32, + [B_NUMBER_FLOAT64] = int8_to_float64, + [B_NUMBER_CHAR] = int8_to_char, + [B_NUMBER_SHORT] = int8_to_short, + [B_NUMBER_INT] = int8_to_int, + [B_NUMBER_LONG] = int8_to_long, + [B_NUMBER_LONGLONG] = int8_to_longlong, + [B_NUMBER_FLOAT] = int8_to_float, + [B_NUMBER_DOUBLE] = int8_to_double, + [B_NUMBER_SIZE_T] = int8_to_size_t, + }, + /* int16 -> xyz CONVERTER CALLBACKS */ + [B_NUMBER_INT16] = { + [B_NUMBER_INT8] = int16_to_int8, + [B_NUMBER_INT16] = int16_to_int16, + [B_NUMBER_INT32] = int16_to_int32, + [B_NUMBER_INT64] = int16_to_int64, + [B_NUMBER_FLOAT32] = int16_to_float32, + [B_NUMBER_FLOAT64] = int16_to_float64, + [B_NUMBER_CHAR] = int16_to_char, + [B_NUMBER_SHORT] = int16_to_short, + [B_NUMBER_INT] = int16_to_int, + [B_NUMBER_LONG] = int16_to_long, + [B_NUMBER_LONGLONG] = int16_to_longlong, + [B_NUMBER_FLOAT] = int16_to_float, + [B_NUMBER_DOUBLE] = int16_to_double, + [B_NUMBER_SIZE_T] = int16_to_size_t, + }, + /* int32 -> xyz CONVERTER CALLBACKS */ + [B_NUMBER_INT32] = { + [B_NUMBER_INT8] = int32_to_int8, + [B_NUMBER_INT16] = int32_to_int16, + [B_NUMBER_INT32] = int32_to_int32, + [B_NUMBER_INT64] = int32_to_int64, + [B_NUMBER_FLOAT32] = int32_to_float32, + [B_NUMBER_FLOAT64] = int32_to_float64, + [B_NUMBER_CHAR] = int32_to_char, + [B_NUMBER_SHORT] = int32_to_short, + [B_NUMBER_INT] = int32_to_int, + [B_NUMBER_LONG] = int32_to_long, + [B_NUMBER_LONGLONG] = int32_to_longlong, + [B_NUMBER_FLOAT] = int32_to_float, + [B_NUMBER_DOUBLE] = int32_to_double, + [B_NUMBER_SIZE_T] = int32_to_size_t, + }, + /* int64 -> xyz CONVERTER CALLBACKS */ + [B_NUMBER_INT64] = { + [B_NUMBER_INT8] = int64_to_int8, + [B_NUMBER_INT16] = int64_to_int16, + [B_NUMBER_INT32] = int64_to_int32, + [B_NUMBER_INT64] = int64_to_int64, + [B_NUMBER_FLOAT32] = int64_to_float32, + [B_NUMBER_FLOAT64] = int64_to_float64, + [B_NUMBER_CHAR] = int64_to_char, + [B_NUMBER_SHORT] = int64_to_short, + [B_NUMBER_INT] = int64_to_int, + [B_NUMBER_LONG] = int64_to_long, + [B_NUMBER_LONGLONG] = int64_to_longlong, + [B_NUMBER_FLOAT] = int64_to_float, + [B_NUMBER_DOUBLE] = int64_to_double, + [B_NUMBER_SIZE_T] = int64_to_size_t, + }, + /* float32 -> xyz CONVERTER CALLBACKS */ + [B_NUMBER_FLOAT32] = { + [B_NUMBER_INT8] = float32_to_int8, + [B_NUMBER_INT16] = float32_to_int16, + [B_NUMBER_INT32] = float32_to_int32, + [B_NUMBER_INT64] = float32_to_int64, + [B_NUMBER_FLOAT32] = float32_to_float32, + [B_NUMBER_FLOAT64] = float32_to_float64, + [B_NUMBER_CHAR] = float32_to_char, + [B_NUMBER_SHORT] = float32_to_short, + [B_NUMBER_INT] = float32_to_int, + [B_NUMBER_LONG] = float32_to_long, + [B_NUMBER_LONGLONG] = float32_to_longlong, + [B_NUMBER_FLOAT] = float32_to_float, + [B_NUMBER_DOUBLE] = float32_to_double, + [B_NUMBER_SIZE_T] = float32_to_size_t, + }, + /* float64 -> xyz CONVERTER CALLBACKS */ + [B_NUMBER_FLOAT64] = { + [B_NUMBER_INT8] = float64_to_int8, + [B_NUMBER_INT16] = float64_to_int16, + [B_NUMBER_INT32] = float64_to_int32, + [B_NUMBER_INT64] = float64_to_int64, + [B_NUMBER_FLOAT32] = float64_to_float32, + [B_NUMBER_FLOAT64] = float64_to_float64, + [B_NUMBER_CHAR] = float64_to_char, + [B_NUMBER_SHORT] = float64_to_short, + [B_NUMBER_INT] = float64_to_int, + [B_NUMBER_LONG] = float64_to_long, + [B_NUMBER_LONGLONG] = float64_to_longlong, + [B_NUMBER_FLOAT] = float64_to_float, + [B_NUMBER_DOUBLE] = float64_to_double, + [B_NUMBER_SIZE_T] = float64_to_size_t, + }, + /* char > xyz CONVERTER CALLBACKS */ + [B_NUMBER_CHAR] = { + [B_NUMBER_INT8] = char_to_int8, + [B_NUMBER_INT16] = char_to_int16, + [B_NUMBER_INT32] = char_to_int32, + [B_NUMBER_INT64] = char_to_int64, + [B_NUMBER_FLOAT32] = char_to_float32, + [B_NUMBER_FLOAT64] = char_to_float64, + [B_NUMBER_CHAR] = char_to_char, + [B_NUMBER_SHORT] = char_to_short, + [B_NUMBER_INT] = char_to_int, + [B_NUMBER_LONG] = char_to_long, + [B_NUMBER_LONGLONG] = char_to_longlong, + [B_NUMBER_FLOAT] = char_to_float, + [B_NUMBER_DOUBLE] = char_to_double, + [B_NUMBER_SIZE_T] = char_to_size_t, + }, + /* short -> xyz CONVERTER CALLBACKS */ + [B_NUMBER_SHORT] = { + [B_NUMBER_INT8] = short_to_int8, + [B_NUMBER_INT16] = short_to_int16, + [B_NUMBER_INT32] = short_to_int32, + [B_NUMBER_INT64] = short_to_int64, + [B_NUMBER_FLOAT32] = short_to_float32, + [B_NUMBER_FLOAT64] = short_to_float64, + [B_NUMBER_CHAR] = short_to_char, + [B_NUMBER_SHORT] = short_to_short, + [B_NUMBER_INT] = short_to_int, + [B_NUMBER_LONG] = short_to_long, + [B_NUMBER_LONGLONG] = short_to_longlong, + [B_NUMBER_FLOAT] = short_to_float, + [B_NUMBER_DOUBLE] = short_to_double, + [B_NUMBER_SIZE_T] = short_to_size_t, + }, + /* int -> xyz CONVERTER CALLBACKS */ + [B_NUMBER_INT] = { + [B_NUMBER_INT8] = int_to_int8, + [B_NUMBER_INT16] = int_to_int16, + [B_NUMBER_INT32] = int_to_int32, + [B_NUMBER_INT64] = int_to_int64, + [B_NUMBER_FLOAT32] = int_to_float32, + [B_NUMBER_FLOAT64] = int_to_float64, + [B_NUMBER_CHAR] = int_to_char, + [B_NUMBER_SHORT] = int_to_short, + [B_NUMBER_INT] = int_to_int, + [B_NUMBER_LONG] = int_to_long, + [B_NUMBER_LONGLONG] = int_to_longlong, + [B_NUMBER_FLOAT] = int_to_float, + [B_NUMBER_DOUBLE] = int_to_double, + [B_NUMBER_SIZE_T] = int_to_size_t, + }, + /* long -> xyz CONVERTER CALLBACKS */ + [B_NUMBER_LONG] = { + [B_NUMBER_INT8] = long_to_int8, + [B_NUMBER_INT16] = long_to_int16, + [B_NUMBER_INT32] = long_to_int32, + [B_NUMBER_INT64] = long_to_int64, + [B_NUMBER_FLOAT32] = long_to_float32, + [B_NUMBER_FLOAT64] = long_to_float64, + [B_NUMBER_CHAR] = long_to_char, + [B_NUMBER_SHORT] = long_to_short, + [B_NUMBER_INT] = long_to_int, + [B_NUMBER_LONG] = long_to_long, + [B_NUMBER_LONGLONG] = long_to_longlong, + [B_NUMBER_FLOAT] = long_to_float, + [B_NUMBER_DOUBLE] = long_to_double, + [B_NUMBER_SIZE_T] = long_to_size_t, + }, + /* longlong -> xyz CONVERTER CALLBACKS */ + [B_NUMBER_LONGLONG] = { + [B_NUMBER_INT8] = longlong_to_int8, + [B_NUMBER_INT16] = longlong_to_int16, + [B_NUMBER_INT32] = longlong_to_int32, + [B_NUMBER_INT64] = longlong_to_int64, + [B_NUMBER_FLOAT32] = longlong_to_float32, + [B_NUMBER_FLOAT64] = longlong_to_float64, + [B_NUMBER_CHAR] = longlong_to_char, + [B_NUMBER_SHORT] = longlong_to_short, + [B_NUMBER_INT] = longlong_to_int, + [B_NUMBER_LONG] = longlong_to_long, + [B_NUMBER_LONGLONG] = longlong_to_longlong, + [B_NUMBER_FLOAT] = longlong_to_float, + [B_NUMBER_DOUBLE] = longlong_to_double, + [B_NUMBER_SIZE_T] = longlong_to_size_t, + }, + /* float -> xyz CONVERTER CALLBACKS */ + [B_NUMBER_FLOAT] = { + [B_NUMBER_INT8] = float_to_int8, + [B_NUMBER_INT16] = float_to_int16, + [B_NUMBER_INT32] = float_to_int32, + [B_NUMBER_INT64] = float_to_int64, + [B_NUMBER_FLOAT32] = float_to_float32, + [B_NUMBER_FLOAT64] = float_to_float64, + [B_NUMBER_CHAR] = float_to_char, + [B_NUMBER_SHORT] = float_to_short, + [B_NUMBER_INT] = float_to_int, + [B_NUMBER_LONG] = float_to_long, + [B_NUMBER_LONGLONG] = float_to_longlong, + [B_NUMBER_FLOAT] = float_to_float, + [B_NUMBER_DOUBLE] = float_to_double, + [B_NUMBER_SIZE_T] = float_to_size_t, + }, + /* double -> xyz CONVERTER CALLBACKS */ + [B_NUMBER_DOUBLE] = { + [B_NUMBER_INT8] = double_to_int8, + [B_NUMBER_INT16] = double_to_int16, + [B_NUMBER_INT32] = double_to_int32, + [B_NUMBER_INT64] = double_to_int64, + [B_NUMBER_FLOAT32] = double_to_float32, + [B_NUMBER_FLOAT64] = double_to_float64, + [B_NUMBER_CHAR] = double_to_char, + [B_NUMBER_SHORT] = double_to_short, + [B_NUMBER_INT] = double_to_int, + [B_NUMBER_LONG] = double_to_long, + [B_NUMBER_LONGLONG] = double_to_longlong, + [B_NUMBER_FLOAT] = double_to_float, + [B_NUMBER_DOUBLE] = double_to_double, + [B_NUMBER_SIZE_T] = double_to_size_t, + }, + /* size_t -> xyz CONVERTER CALLBACKS */ + [B_NUMBER_SIZE_T] = { + [B_NUMBER_INT8] = size_t_to_int8, + [B_NUMBER_INT16] = size_t_to_int16, + [B_NUMBER_INT32] = size_t_to_int32, + [B_NUMBER_INT64] = size_t_to_int64, + [B_NUMBER_FLOAT32] = size_t_to_float32, + [B_NUMBER_FLOAT64] = size_t_to_float64, + [B_NUMBER_CHAR] = size_t_to_char, + [B_NUMBER_SHORT] = size_t_to_short, + [B_NUMBER_INT] = size_t_to_int, + [B_NUMBER_LONG] = size_t_to_long, + [B_NUMBER_LONGLONG] = size_t_to_longlong, + [B_NUMBER_FLOAT] = size_t_to_float, + [B_NUMBER_DOUBLE] = size_t_to_double, + [B_NUMBER_SIZE_T] = size_t_to_size_t, + }, +}; + +b_object_type_id b_number_type_id(void) +{ + return (b_object_type_id)&number_type; +} diff --git a/object/number.h b/object/number.h new file mode 100644 index 0000000..fe29158 --- /dev/null +++ b/object/number.h @@ -0,0 +1,29 @@ +#ifndef _BLUELIB_NUMBER_H_ +#define _BLUELIB_NUMBER_H_ + +#include "object.h" + +#include + +struct b_number { + struct b_object n_base; + b_number_type n_type; + union { + int8_t v_int8; + int16_t v_int16; + int32_t v_int32; + int64_t v_int64; + float v_float32; + double v_float64; + char v_char; + short v_short; + int v_int; + long v_long; + long long v_longlong; + float v_float; + double v_double; + size_t v_size_t; + } n_value; +}; + +#endif diff --git a/object/object.c b/object/object.c new file mode 100644 index 0000000..e00a288 --- /dev/null +++ b/object/object.c @@ -0,0 +1,65 @@ +#include "object.h" +#include +#include +#include +#include +#include +#include + +void b_object_init(struct b_object *obj, struct b_object_type *type) +{ + obj->ob_ref = 1; + obj->ob_type = type; +} + +struct b_object *b_make_rvalue(struct b_object *obj) +{ + obj->ob_ref = 0; + return obj; +} + +struct b_object *b_retain(struct b_object *obj) +{ + obj->ob_ref++; + return obj; +} + +void b_release(struct b_object *obj) +{ + if (obj->ob_ref > 1) { + obj->ob_ref--; + return; + } + + obj->ob_ref = 0; + + if (obj->ob_type && obj->ob_type->t_release) { + obj->ob_type->t_release(obj); + } + + free(obj); +} + +void b_to_string(struct b_object *obj, struct b_stringstream *out) +{ + if (obj->ob_type->t_to_string) { + obj->ob_type->t_to_string(obj, out); + return; + } + + const char *name = "corelib::object"; + if (obj->ob_type) { + name = obj->ob_type->t_name; + } + + b_stringstream_addf(out, "<%s@%p>", name, obj); +} + +b_object_type_id b_typeid(const struct b_object *obj) +{ + if (obj->ob_type->t_flags & B_OBJECT_FUNDAMENTAL) { + return obj->ob_type->t_id; + } + + return (b_object_type_id)obj->ob_type; +} diff --git a/object/object.h b/object/object.h new file mode 100644 index 0000000..251efc5 --- /dev/null +++ b/object/object.h @@ -0,0 +1,6 @@ +#ifndef _BLUELIB_OBJECT_H_ +#define _BLUELIB_OBJECT_H_ + +#include + +#endif diff --git a/object/string.c b/object/string.c new file mode 100644 index 0000000..76c615f --- /dev/null +++ b/object/string.c @@ -0,0 +1,497 @@ +#include "string.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void string_release(struct b_object *obj); +static void string_to_string(struct b_object *obj, struct b_stringstream *out); + +static struct b_object_type string_type = { + .t_name = "corelib::string", + .t_flags = B_OBJECT_FUNDAMENTAL, + .t_id = B_OBJECT_TYPE_STRING, + .t_instance_size = sizeof(struct b_string), + .t_release = string_release, + .t_to_string = string_to_string, +}; + +struct b_string *b_string_create(void) +{ + struct b_string *str + = (struct b_string *)b_object_type_instantiate(&string_type); + if (!str) { + return NULL; + } + + str->s_len = 0; + str->s_max = STRING_INLINE_CAPACITY; + + return str; +} + +static bool string_is_inline(const struct b_string *str) +{ + /* strings cannot go below STRING_INLINE_CAPACITY capacity */ + return str->s_max == STRING_INLINE_CAPACITY; +} + +static char *string_ptr(struct b_string *str) +{ + if (string_is_inline(str)) { + return str->s_data.d_inline; + } + + return str->s_data.d_external; +} + +static int string_make_inline(struct b_string *str) +{ + char *buffer = string_ptr(str); + memcpy(str->s_data.d_inline, buffer, sizeof str->s_data.d_inline); + str->s_data.d_inline[sizeof str->s_data.d_inline - 1] = '\0'; + + str->s_max = STRING_INLINE_CAPACITY; + + if (str->s_len >= str->s_max) { + str->s_len = str->s_max; + } + + free(buffer); + return 0; +} + +static int string_resize_large(struct b_string *str, size_t capacity) +{ + char *buffer = string_ptr(str); + char *new_buffer = realloc(buffer, capacity + 1); + if (!new_buffer) { + return -1; + } + + str->s_max = capacity; + str->s_data.d_external = new_buffer; + return 0; +} + +static int string_make_large(struct b_string *str, size_t capacity) +{ + const char *old_buffer = string_ptr(str); + char *buffer = malloc(capacity + 1); + if (!buffer) { + return -1; + } + + memcpy(buffer, old_buffer, sizeof str->s_data.d_inline); + buffer[str->s_len] = '\0'; + + str->s_max = capacity; + str->s_data.d_external = buffer; + return 0; +} + +static int string_change_capacity(struct b_string *str, size_t capacity) +{ + size_t old_capacity = str->s_max; + + if (capacity < STRING_INLINE_CAPACITY) { + capacity = STRING_INLINE_CAPACITY; + } + + bool was_inline = string_is_inline(str); + bool is_now_inline = capacity == STRING_INLINE_CAPACITY; + + if (capacity == old_capacity) { + /* this also handles the case where the old and new capacity both fit into the inline buffer. */ + return 0; + } + + if (!was_inline && is_now_inline) { + /* string was large, is now small enough to fit inline. */ + return string_make_inline(str); + } + + if (!was_inline) { + /* string was large, and is still large. */ + return string_resize_large(str, capacity); + } + + if (!is_now_inline) { + /* string was inline, and now large enough to require a buffer. */ + return string_make_large(str, capacity); + } + + /* nothing to do */ + return 0; +} + +struct b_string *b_string_create_from_cstr(const char *s) +{ + struct b_string *str = b_string_create(); + if (!str) { + return NULL; + } + + if (!s) { + return str; + } + + str->s_len = strlen(s); + string_change_capacity(str, str->s_len); + + char *dest = string_ptr(str); + memcpy(dest, s, str->s_len); + dest[str->s_len] = 0; + + return str; +} + +struct b_string *b_string_create_from_c(char c, size_t count) +{ + struct b_string *str = b_string_create(); + if (!str) { + return NULL; + } + + string_change_capacity(str, count); + char *s = string_ptr(str); + for (size_t i = 0; i < count; i++) { + s[i] = c; + } + + str->s_len = count; + return str; +} + +char *b_string_steal(struct b_string *str) +{ + char *dest = NULL; + char *src = string_ptr(str); + + if (string_is_inline(str)) { + dest = b_strdup(src); + } else { + dest = src; + str->s_data.d_external = NULL; + str->s_max = 0; + } + + str->s_len = 0; + return dest; +} + +b_status b_string_reserve(struct b_string *str, size_t capacity) +{ + if (str->s_max >= capacity) { + return B_SUCCESS; + } + + int err = string_change_capacity(str, capacity); + + return err == 0 ? B_SUCCESS : B_ERR_NO_MEMORY; +} + +static void string_insert( + struct b_string *dest, const char *src, size_t len, size_t at) +{ + if (at >= dest->s_len) { + at = dest->s_len; + } + + size_t new_size = dest->s_len + len; + if (dest->s_max < new_size) { + string_change_capacity(dest, new_size); + } + + char *dest_buf = string_ptr(dest); + char *from = dest_buf + at; + char *to = dest_buf + at + len; + + memmove(to, from, dest->s_len - at); + memcpy(from, src, len); + dest_buf[new_size] = '\0'; + + dest->s_len = new_size; +} + +static void string_insertf( + struct b_string *dest, size_t at, const char *format, va_list arg) +{ + char buf[1024]; + size_t len = vsnprintf(buf, sizeof buf, format, arg); + string_insert(dest, buf, len, at); +} + +void b_string_insert_s(struct b_string *dest, const struct b_string *src, size_t at) +{ + string_insert(dest, b_string_ptr(src), src->s_len, at); +} + +void b_string_insert_cstr(struct b_string *dest, const char *src, size_t at) +{ + string_insert(dest, src, strlen(src), at); +} + +void b_string_insert_cstrf(struct b_string *dest, size_t at, const char *format, ...) +{ + va_list arg; + va_start(arg, format); + string_insertf(dest, at, format, arg); + va_end(arg); +} + +void b_string_insert_cstrn(b_string *dest, const char *src, size_t len, size_t at) +{ + string_insert(dest, src, len, at); +} + +void b_string_append_s(struct b_string *dest, const struct b_string *src) +{ + b_string_insert_s(dest, src, SIZE_MAX); +} + +void b_string_append_cstr(struct b_string *dest, const char *src) +{ + b_string_insert_cstr(dest, src, SIZE_MAX); +} + +void b_string_append_cstrf(struct b_string *dest, const char *format, ...) +{ + va_list arg; + va_start(arg, format); + string_insertf(dest, SIZE_MAX, format, arg); + va_end(arg); +} + +void b_string_prepend_s(struct b_string *dest, const struct b_string *src) +{ + b_string_insert_s(dest, src, 0); +} + +void b_string_prepend_cstr(struct b_string *dest, const char *src) +{ + b_string_insert_cstr(dest, src, 0); +} + +void b_string_prepend_cstrf(struct b_string *dest, const char *format, ...) +{ + va_list arg; + va_start(arg, format); + string_insertf(dest, 0, format, arg); + va_end(arg); +} + +void b_string_clear(struct b_string *str) +{ + if (str->s_len == 0) { + return; + } + + char *s = string_ptr(str); + *s = '\0'; + str->s_len = 0; +} + +size_t b_string_get_size(const struct b_string *str, b_strlen_flags flags) +{ + if (flags != B_STRLEN_NORMAL) { + return b_strlen(b_string_ptr(str), flags); + } + + return str->s_len; +} + +size_t b_string_get_capacity(const struct b_string *str) +{ + return str->s_max; +} + +const char *b_string_ptr(const struct b_string *str) +{ + if (string_is_inline(str)) { + return str->s_data.d_inline; + } + + return str->s_data.d_external; +} + +static void string_release(struct b_object *obj) +{ + struct b_string *str = B_STRING(obj); + if (!string_is_inline(str)) { + free(string_ptr(str)); + } +} + +static void string_to_string(struct b_object *obj, struct b_stringstream *out) +{ + b_string *str = B_STRING(obj); + b_stringstream_add(out, b_string_ptr(str)); +} + +void b_strv_builder_begin(b_strv_builder *strv, char *buf, size_t max) +{ + strv->strv_buf = buf; + strv->strv_max = max; + strv->strv_len = 0; + strv->strv_alloc = 0; +} + +void b_strv_builder_begin_dynamic(b_strv_builder *strv) +{ + strv->strv_buf = NULL; + strv->strv_max = 0; + strv->strv_len = 0; + strv->strv_alloc = 1; +} + +static b_status strv_builder_push_string( + b_strv_builder *strv, const char *s, size_t len) +{ + if (strv->strv_len + len >= strv->strv_max && strv->strv_alloc == 1) { + char *new_buf = realloc(strv->strv_buf, strv->strv_len + len + 1); + if (!new_buf) { + return B_ERR_NO_MEMORY; + } + + strv->strv_buf = new_buf; + strv->strv_max = strv->strv_len + len + 1; + } + + for (size_t i = 0; i < len; i++) { + if (strv->strv_len < strv->strv_max) { + strv->strv_buf[strv->strv_len++] = s[i]; + strv->strv_buf[strv->strv_len] = 0; + } + } + + return B_SUCCESS; +} + +b_status b_strv_builder_add(struct b_strv_builder *strv, const char *str) +{ + return strv_builder_push_string(strv, str, strlen(str)); +} + +b_status b_strv_builder_addf(struct b_strv_builder *strv, const char *format, ...) +{ + char str[1024]; + va_list arg; + va_start(arg, format); + size_t len = vsnprintf(str, sizeof str, format, arg); + va_end(arg); + + return strv_builder_push_string(strv, str, len); +} + +b_status b_strv_builder_addv(b_strv_builder *strv, const char **strs) +{ + for (size_t i = 0; strs[i]; i++) { + size_t len = strlen(strs[i]); + b_status status = strv_builder_push_string(strv, strs[i], len); + if (B_ERR(status)) { + return status; + } + } + + return B_SUCCESS; +} + +b_status b_strv_builder_addvl(b_strv_builder *strv, const char **strs, size_t count) +{ + for (size_t i = 0; i < count; i++) { + if (!strs[i]) { + continue; + } + + size_t len = strlen(strs[i]); + b_status status = strv_builder_push_string(strv, strs[i], len); + if (B_ERR(status)) { + return status; + } + } + + return B_SUCCESS; +} + +b_status b_strv_builder_add_many(b_strv_builder *strv, ...) +{ + va_list arg; + va_start(arg, strv); + while (1) { + const char *s = va_arg(arg, const char *); + if (!s) { + return B_SUCCESS; + } + + size_t len = strlen(s); + b_status status = strv_builder_push_string(strv, s, len); + if (B_ERR(status)) { + return status; + } + } + + return B_SUCCESS; +} + +char *b_strv_builder_end(b_strv_builder *strv) +{ + char *out = strv->strv_buf; + + strv->strv_alloc = 0; + strv->strv_len = 0; + strv->strv_max = 0; + strv->strv_buf = NULL; + + return out; +} + +char *b_strdup(const char *s) +{ + size_t len = strlen(s); + char *p = malloc(len + 1); + if (!p) { + return NULL; + } + + memcpy(p, s, len); + p[len] = '\0'; + + return p; +} + +size_t b_strlen(const char *s, b_strlen_flags flags) +{ + if (!(flags & B_STRLEN_IGNORE_ESC)) { + return strlen(s); + } + + size_t out = 0; + bool esc = false; + for (size_t i = 0; s[i]; i++) { + if (s[i] == '\033') { + esc = true; + } + + if (!esc) { + out++; + } + + if (isalpha(s[i])) { + esc = false; + } + } + + return out; +} + +b_object_type_id b_string_type_id(void) +{ + return (b_object_type_id)&string_type; +} diff --git a/object/string.h b/object/string.h new file mode 100644 index 0000000..fecf196 --- /dev/null +++ b/object/string.h @@ -0,0 +1,21 @@ +#ifndef _BLUELIB_STRING_H_ +#define _BLUELIB_STRING_H_ + +#include "object.h" + +/* maximum length of string that can be stored inline, not including null-terminator */ +#define STRING_INLINE_CAPACITY 15 + +struct b_string { + struct b_object s_base; + /* length of string, not including null-terminator */ + unsigned int s_len; + /* maximum length of string storable in the currently-allocated buffer, not including null terminator */ + unsigned int s_max; + union { + char d_inline[STRING_INLINE_CAPACITY + 1]; + char *d_external; + } s_data; +}; + +#endif diff --git a/object/tree.c b/object/tree.c new file mode 100644 index 0000000..90c47ce --- /dev/null +++ b/object/tree.c @@ -0,0 +1,300 @@ +#include "tree.h" + +#include +#include +#include +#include +#include + +#define ITERATOR_RECURSIVE 0x01u + +#define ITERATOR_IS_RECURSIVE(it) (((it)->_f01 & ITERATOR_RECURSIVE) != 0) +#define ITERATOR_UNSET_RECURSIVE(it) ((it)->_f01 &= ~ITERATOR_RECURSIVE) +#define ITERATOR_SET_RECURSIVE(it) ((it)->_f01 |= ITERATOR_RECURSIVE) + +#define NODE_PARENT(n) ((n)->__p01) +#define NODE_FIRST_CHILD(n) ((n)->__p02) +#define NODE_NEXT_SIBLING(n) ((n)->__p03) + +static struct b_object_type tree_type = { + .t_name = "corelib::tree", + .t_flags = B_OBJECT_FUNDAMENTAL, + .t_id = B_OBJECT_TYPE_TREE, + .t_instance_size = sizeof(struct b_tree), +}; + +struct b_tree *b_tree_create(void) +{ + struct b_tree *tree + = (struct b_tree *)b_object_type_instantiate(&tree_type); + if (!tree) { + return NULL; + } + + return tree; +} + +void b_tree_set_root(struct b_tree *tree, struct b_tree_node *node) +{ + tree->t_root = node; +} + +void b_tree_node_add_child(struct b_tree_node *parent, struct b_tree_node *child) +{ + if (NODE_PARENT(child)) { + return; + } + + NODE_PARENT(child) = parent; + if (!NODE_FIRST_CHILD(parent)) { + NODE_FIRST_CHILD(parent) = child; + return; + } + + struct b_tree_node *cur = NODE_FIRST_CHILD(parent); + while (NODE_NEXT_SIBLING(cur)) { + cur = NODE_NEXT_SIBLING(cur); + } + + NODE_NEXT_SIBLING(cur) = child; +} + +void b_tree_node_add_sibling(struct b_tree_node *node, struct b_tree_node *to_add) +{ + if (NODE_PARENT(to_add) || !NODE_PARENT(node)) { + return; + } + + b_tree_node_add_child(NODE_PARENT(node), to_add); +} + +struct b_tree_node *b_tree_node_get_child(struct b_tree_node *node, size_t at) +{ + size_t i = 0; + struct b_tree_node *cur = NODE_FIRST_CHILD(node); + + while (i < at) { + if (!cur) { + return NULL; + } + + cur = NODE_NEXT_SIBLING(cur); + i++; + } + + return cur; +} + +static bool tree_iterator_next(struct b_iterator *it) +{ + return b_tree_iterator_next((struct b_tree_iterator *)it); +} + +static b_status tree_iterator_erase(struct b_iterator *it) +{ + return b_tree_iterator_erase((struct b_tree_iterator *)it); +} + +static bool tree_iterator_is_valid(const struct b_iterator *it) +{ + return b_tree_iterator_is_valid((const struct b_tree_iterator *)it); +} + +struct b_tree_node *b_tree_node_get_parent(struct b_tree_node *node) +{ + return NODE_PARENT(node); +} + +int b_tree_iterator_begin(struct b_tree *tree, b_tree_iterator *it) +{ + return b_tree_iterator_begin_at_node_recursive(tree->t_root, it); +} + +static b_iterator_ops it_ops = { + .it_next = tree_iterator_next, + .it_erase = tree_iterator_erase, + .it_close = NULL, + .it_is_valid = tree_iterator_is_valid, +}; + +int b_tree_iterator_begin_at_node(struct b_tree_node *node, b_tree_iterator *it) +{ + it->node = NODE_FIRST_CHILD(node); + it->i = 0; + it->depth = 0; + + it->_base.it_ops = &it_ops; + + ITERATOR_UNSET_RECURSIVE(it); + + return 0; +} + +int b_tree_iterator_begin_at_node_recursive( + struct b_tree_node *node, b_tree_iterator *it) +{ + it->node = node; + it->i = 0; + it->depth = 0; + it->_base.it_ops = &it_ops; + + ITERATOR_SET_RECURSIVE(it); + + return 0; +} + +static const struct b_tree_node *next_node( + const struct b_tree_node *node, bool recursive, int *depth_diff) +{ + if (!node) { + return NULL; + } + + if (!recursive) { + node = NODE_NEXT_SIBLING(node); + return node; + } + + int d = 0; + struct b_tree_node *next = NODE_FIRST_CHILD(node); + if (next) { + d = 1; + *depth_diff = d; + return next; + } + + const struct b_tree_node *n = node; + next = NODE_NEXT_SIBLING(n); + while (!next) { + n = NODE_PARENT(n); + if (!n) { + break; + } + + d--; + next = NODE_NEXT_SIBLING(n); + } + + *depth_diff = d; + return next; +} + +bool b_tree_iterator_next(struct b_tree_iterator *it) +{ + int depth_diff = 0; + const struct b_tree_node *next + = next_node(it->node, ITERATOR_IS_RECURSIVE(it), &depth_diff); + + if (next) { + it->depth += depth_diff; + it->i++; + } else { + it->depth = 0; + it->i = 0; + } + + it->node = (struct b_tree_node *)next; + return it->node != NULL; +} + +static void remove_node(struct b_tree_node *node) +{ + struct b_tree_node *parent = NODE_PARENT(node); + if (!parent) { + return; + } + + struct b_tree_node *n0 = NULL, *n1 = NULL; + n0 = NODE_FIRST_CHILD(parent); + + while (n0) { + if (n0 == node) { + break; + } + + n1 = n0; + n0 = NODE_NEXT_SIBLING(n0); + } + + if (!n0) { + return; + } + + if (n1) { + NODE_NEXT_SIBLING(n1) = NODE_NEXT_SIBLING(n0); + } else { + NODE_FIRST_CHILD(parent) = NODE_NEXT_SIBLING(n0); + } + + NODE_PARENT(n0) = NODE_NEXT_SIBLING(n0) = NULL; +} + +static void reparent_children( + struct b_tree_node *old_parent, struct b_tree_node *new_parent) +{ + struct b_tree_node *last = NODE_FIRST_CHILD(new_parent); + while (last && NODE_NEXT_SIBLING(last)) { + last = NODE_NEXT_SIBLING(last); + } + + struct b_tree_node *cur = NODE_FIRST_CHILD(old_parent); + while (cur) { + struct b_tree_node *next = NODE_NEXT_SIBLING(cur); + NODE_PARENT(cur) = new_parent; + NODE_NEXT_SIBLING(cur) = NULL; + + if (last) { + NODE_NEXT_SIBLING(last) = cur; + } else { + NODE_FIRST_CHILD(new_parent) = cur; + } + + last = cur; + cur = next; + } +} + +b_status b_tree_iterator_erase(struct b_tree_iterator *it) +{ + if (!it->node) { + return B_ERR_OUT_OF_BOUNDS; + } + + struct b_tree_node *parent = NODE_PARENT(it->node); + if (!parent) { + return B_ERR_NOT_SUPPORTED; + } + + int d = 0; + struct b_tree_node *n = it->node; + struct b_tree_node *next = NODE_NEXT_SIBLING(n); + + if (!next) { + next = NODE_FIRST_CHILD(n); + } + + while (!next) { + n = NODE_PARENT(n); + if (!n) { + break; + } + + d--; + next = NODE_NEXT_SIBLING(n); + } + + remove_node(it->node); + reparent_children(it->node, parent); + + return B_SUCCESS; +} + +bool b_tree_iterator_is_valid(const struct b_tree_iterator *it) +{ + return it->node != NULL; +} + +b_object_type_id b_tree_type_id(void) +{ + return (b_object_type_id)&tree_type; +} diff --git a/object/tree.h b/object/tree.h new file mode 100644 index 0000000..f9cc809 --- /dev/null +++ b/object/tree.h @@ -0,0 +1,14 @@ +#ifndef _B_TREE_H_ +#define _B_TREE_H_ + +#include "../object.h" + +#include +#include + +struct b_tree { + struct b_object t_base; + struct b_tree_node *t_root; +}; + +#endif diff --git a/object/type.c b/object/type.c new file mode 100644 index 0000000..2532a49 --- /dev/null +++ b/object/type.c @@ -0,0 +1,29 @@ +#include "object.h" + +#include +#include +#include +#include + +struct b_object *b_object_type_instantiate(const b_object_type *type) +{ + if (!type || type->t_instance_size < sizeof(struct b_object)) { + return NULL; + } + + struct b_object *out = malloc(type->t_instance_size); + if (!out) { + return NULL; + } + + memset(out, 0x0, type->t_instance_size); + + out->ob_ref = 1; + out->ob_type = type; + + if (type->t_init) { + type->t_init(out); + } + + return out; +} diff --git a/object/uuid.c b/object/uuid.c new file mode 100644 index 0000000..a3b3744 --- /dev/null +++ b/object/uuid.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include +#include +#include "uuid.h" + +static struct b_object_type uuid_type = { + .t_name = "corelib::uuid", + .t_flags = B_OBJECT_FUNDAMENTAL, + .t_id = B_OBJECT_TYPE_UUID, + .t_instance_size = sizeof(struct b_uuid), +}; + +struct b_uuid *b_uuid_create(void) +{ + struct b_uuid *out = (struct b_uuid *)b_object_type_instantiate(&uuid_type); + if (!out) { + return NULL; + } + + return out; +} + +struct b_uuid *b_uuid_create_from_bytes( + unsigned char u00, unsigned char u01, unsigned char u02, unsigned char u03, + unsigned char u04, unsigned char u05, unsigned char u06, unsigned char u07, + unsigned char u08, unsigned char u09, unsigned char u10, unsigned char u11, + unsigned char u12, unsigned char u13, unsigned char u14, unsigned char u15) +{ + struct b_uuid *uuid = b_uuid_create(); + if (!uuid) { + return NULL; + } + + uuid->uuid_bytes.uuid_bytes[ 0] = u00; + uuid->uuid_bytes.uuid_bytes[ 1] = u01; + uuid->uuid_bytes.uuid_bytes[ 2] = u02; + uuid->uuid_bytes.uuid_bytes[ 3] = u03; + uuid->uuid_bytes.uuid_bytes[ 4] = u04; + uuid->uuid_bytes.uuid_bytes[ 5] = u05; + uuid->uuid_bytes.uuid_bytes[ 6] = u06; + uuid->uuid_bytes.uuid_bytes[ 7] = u07; + uuid->uuid_bytes.uuid_bytes[ 8] = u08; + uuid->uuid_bytes.uuid_bytes[ 9] = u09; + uuid->uuid_bytes.uuid_bytes[10] = u10; + uuid->uuid_bytes.uuid_bytes[11] = u11; + uuid->uuid_bytes.uuid_bytes[12] = u12; + uuid->uuid_bytes.uuid_bytes[13] = u13; + uuid->uuid_bytes.uuid_bytes[14] = u14; + uuid->uuid_bytes.uuid_bytes[15] = u15; + + return uuid; +} + +struct b_uuid *b_uuid_create_from_bytev(const unsigned char bytes[B_UUID_NBYTES]) +{ + struct b_uuid *uuid = b_uuid_create(); + if (!uuid) { + return NULL; + } + + memcpy(uuid->uuid_bytes.uuid_bytes, bytes, B_UUID_NBYTES); + + return uuid; +} + +struct b_uuid *b_uuid_create_from_uuid_bytes(const struct b_uuid_bytes *bytes) +{ + return b_uuid_create_from_bytev(bytes->uuid_bytes); +} + +struct b_uuid *b_uuid_create_from_string(const struct b_string *string) +{ + return b_uuid_create_from_cstr(b_string_ptr(string)); +} + +struct b_uuid *b_uuid_create_from_cstr(const char *str) +{ + struct b_uuid_bytes bytes; + + bool valid = true; + bool is_guid = false; + if (*str == '{') { + is_guid = true; + str++; + } + + size_t i, byte = 0; + for (i = 0; str[i] && byte < B_UUID_NBYTES;) { + if (i == 8 || i == 13 || i == 18 || i == 23) { + if (str[i] != '-') { + valid = false; + break; + } + + i++; + continue; + } + + char n[3]; + n[0] = str[i]; + n[1] = str[i + 1]; + n[2] = '\0'; + + if (!isxdigit(n[0]) || !isxdigit(n[1])) { + valid = false; + break; + } + + char *p; + unsigned long v = strtoul(n, &p, 16); + bytes.uuid_bytes[byte] = v; + + byte++; + i += 2; + } + + if (str[i] == '}') { + if (is_guid) { + i++; + } else { + valid = false; + } + } + + if (str[i] != '\0' || byte != B_UUID_NBYTES) { + valid = false; + } + + if (!valid) { + return NULL; + } + + return b_uuid_create_from_uuid_bytes(&bytes); +} + +b_status b_uuid_to_string(const struct b_uuid *uuid, struct b_string *out) +{ + char str[B_UUID_STRING_MAX]; + b_uuid_to_cstr(uuid, str); + b_string_append_cstr(out, str); + + return B_SUCCESS; +} + +b_status b_uuid_to_cstr(const struct b_uuid *uuid, char out[B_UUID_STRING_MAX]) +{ + snprintf(out, B_UUID_STRING_MAX, + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid->uuid_bytes.uuid_bytes[ 0], uuid->uuid_bytes.uuid_bytes[ 1], uuid->uuid_bytes.uuid_bytes[ 2], uuid->uuid_bytes.uuid_bytes[ 3], + uuid->uuid_bytes.uuid_bytes[ 4], uuid->uuid_bytes.uuid_bytes[ 5], uuid->uuid_bytes.uuid_bytes[ 6], uuid->uuid_bytes.uuid_bytes[ 7], + uuid->uuid_bytes.uuid_bytes[ 8], uuid->uuid_bytes.uuid_bytes[ 9], uuid->uuid_bytes.uuid_bytes[10], uuid->uuid_bytes.uuid_bytes[11], + uuid->uuid_bytes.uuid_bytes[12], uuid->uuid_bytes.uuid_bytes[13], uuid->uuid_bytes.uuid_bytes[14], uuid->uuid_bytes.uuid_bytes[15]); + return B_SUCCESS; +} + +b_status b_uuid_to_strv_builder(const struct b_uuid *uuid, struct b_strv_builder *out) +{ + char str[B_UUID_STRING_MAX]; + b_uuid_to_cstr(uuid, str); + b_strv_builder_add(out, str); + + return B_SUCCESS; +} + +void b_uuid_get_bytes(const struct b_uuid *uuid, unsigned char bytes[B_UUID_NBYTES]) +{ + memcpy(bytes, uuid->uuid_bytes.uuid_bytes, B_UUID_NBYTES); +} + +void b_uuid_get_uuid_bytes(const struct b_uuid *uuid, struct b_uuid_bytes *bytes) +{ + memcpy(bytes, &uuid->uuid_bytes, sizeof *bytes); +} + +struct b_uuid_bytes *b_uuid_ptr(struct b_uuid *uuid) +{ + return &uuid->uuid_bytes; +} + +b_object_type_id b_uuid_type_id(void) +{ + return (b_object_type_id)&uuid_type; +} diff --git a/object/uuid.h b/object/uuid.h new file mode 100644 index 0000000..6a1bde6 --- /dev/null +++ b/object/uuid.h @@ -0,0 +1,11 @@ +#ifndef _BLUELIB_UUID_H_ +#define _BLUELIB_UUID_H_ + +#include + +struct b_uuid { + struct b_object u_base; + struct b_uuid_bytes uuid_bytes; +}; + +#endif