meta: rename ds module to fx.collections namespace

This commit is contained in:
2026-05-02 14:38:11 +01:00
parent c04c2e8f12
commit 9b8c0f8763
26 changed files with 0 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
include(../cmake/Templates.cmake)
add_fx_module(NAME ds DEPENDENCIES core)
+528
View File
@@ -0,0 +1,528 @@
#include <fx/core/iterator.h>
#include <fx/core/stream.h>
#include <fx/ds/array.h>
#include <fx/ds/string.h>
#include <stdlib.h>
#include <string.h>
/*** PRIVATE DATA *************************************************************/
struct fx_array_p {
/* number of items in array */
size_t ar_len;
/* maximum number of items that can currently be stored in array */
size_t ar_cap;
fx_object **ar_data;
};
struct fx_array_iterator_p {
fx_array *_a;
struct fx_array_p *_a_p;
/** The index of the current value */
size_t i;
/** The current value */
fx_object *value;
};
/*** PRIVATE FUNCTIONS ********************************************************/
static fx_status resize_array(struct fx_array_p *array, size_t new_capacity)
{
if (array->ar_cap < new_capacity) {
void *new_data = realloc(
array->ar_data,
new_capacity * sizeof(struct fx_dsref *));
if (!new_data) {
return FX_ERR_NO_MEMORY;
}
array->ar_data = new_data;
} else {
for (size_t i = new_capacity; i < array->ar_len; i++) {
fx_object_unref(array->ar_data[i]);
}
void *new_data = realloc(
array->ar_data,
new_capacity * sizeof(struct fx_dsref *));
if (!new_data) {
return FX_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 FX_SUCCESS;
}
static fx_status array_insert(
struct fx_array_p *array,
fx_object *value,
size_t at)
{
if (at == FX_NPOS) {
at = array->ar_len;
}
if (at > array->ar_len) {
return FX_ERR_OUT_OF_BOUNDS;
}
fx_status status = FX_SUCCESS;
if (array->ar_len + 1 > array->ar_cap) {
status = resize_array(array, array->ar_cap + 8);
if (status != FX_SUCCESS) {
return status;
}
}
fx_object **src = array->ar_data + at;
fx_object **dest = src + 1;
size_t move_len = (array->ar_len - at) * sizeof(struct fx_dsref *);
memmove(dest, src, move_len);
array->ar_data[at] = fx_object_ref(value);
array->ar_len++;
return FX_SUCCESS;
}
static fx_status array_remove(struct fx_array_p *array, size_t at)
{
if (at >= array->ar_len) {
return FX_ERR_OUT_OF_BOUNDS;
}
fx_object **src = array->ar_data + at;
fx_object **dest = src + 1;
size_t move_len = array->ar_len * sizeof(struct fx_dsref *);
fx_object_unref(array->ar_data[at]);
memmove(dest, src, move_len);
array->ar_len--;
return FX_SUCCESS;
}
static fx_status array_remove_front(struct fx_array_p *array)
{
return array_remove(array, 0);
}
static fx_status array_remove_back(struct fx_array_p *array)
{
return array_remove(array, array->ar_len - 1);
}
static fx_object *array_pop(struct fx_array_p *array, size_t at)
{
if (at >= array->ar_len) {
return NULL;
}
fx_object **src = array->ar_data + at;
fx_object **dest = src + 1;
size_t move_len = array->ar_len * sizeof(struct fx_dsref *);
fx_object *out = array->ar_data[at];
memmove(dest, src, move_len);
array->ar_len--;
return out;
}
static fx_object *array_pop_front(struct fx_array_p *array)
{
return array_pop(array, 0);
}
static fx_object *array_pop_back(struct fx_array_p *array)
{
return array_pop(array, array->ar_len - 1);
}
static fx_object *array_at(const struct fx_array_p *array, size_t at)
{
if (at >= array->ar_len) {
return NULL;
}
return array->ar_data[at];
}
static fx_object *array_get(struct fx_array_p *array, size_t at)
{
if (at >= array->ar_len) {
return NULL;
}
return fx_object_ref(array->ar_data[at]);
}
static size_t array_size(const struct fx_array_p *array)
{
return array->ar_len;
}
static size_t array_capacity(const struct fx_array_p *array)
{
return array->ar_cap;
}
static void array_clear(struct fx_array_p *array)
{
if (!array->ar_len) {
return;
}
for (size_t i = 0; i < array->ar_len; i++) {
fx_object_unref(array->ar_data[i]);
}
memset(array->ar_data, 0x0, array->ar_cap * sizeof(fx_object *));
array->ar_len = 0;
}
/*** PUBLIC FUNCTIONS *********************************************************/
fx_array *fx_array_create_with_values(
fx_object *const *values,
size_t nr_values)
{
fx_array *array = fx_array_create();
if (!array) {
return NULL;
}
struct fx_array_p *p = fx_object_get_private(array, FX_TYPE_ARRAY);
size_t real_nr_values = 0;
for (size_t i = 0; i < nr_values; i++) {
if (values[i]) {
real_nr_values++;
}
}
p->ar_len = real_nr_values;
p->ar_cap = real_nr_values;
p->ar_data = calloc(real_nr_values, sizeof(struct fx_dsref *));
if (!p->ar_data) {
fx_array_unref(array);
return NULL;
}
size_t index = 0;
for (size_t i = 0; i < nr_values; i++) {
p->ar_data[index++] = fx_object_ref(values[i]);
}
return array;
}
fx_status fx_array_insert(fx_array *array, fx_object *value, size_t at)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_insert, array, value, at);
}
fx_status fx_array_remove(fx_array *array, size_t at)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_remove, array, at);
}
fx_status fx_array_remove_front(fx_array *array)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_remove_front, array);
}
fx_status fx_array_remove_back(fx_array *array)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_remove_back, array);
}
fx_object *fx_array_pop(fx_array *array, size_t at)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_pop, array, at);
}
fx_object *fx_array_pop_front(fx_array *array)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_pop_front, array);
}
fx_object *fx_array_pop_back(fx_array *array)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_pop_back, array);
}
fx_object *fx_array_at(const fx_array *array, size_t at)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_at, array, at);
}
fx_object *fx_array_get(fx_array *array, size_t at)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_get, array, at);
}
size_t fx_array_size(const fx_array *array)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_size, array);
}
size_t fx_array_capacity(const fx_array *array)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_capacity, array);
}
void fx_array_clear(fx_array *array)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_clear, array);
}
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
fx_status fx_array_append(fx_array *array, fx_object *value)
{
return fx_array_insert(array, value, FX_NPOS);
}
fx_status fx_array_prepend(fx_array *array, fx_object *value)
{
return fx_array_insert(array, value, 0);
}
/*** VIRTUAL FUNCTIONS ********************************************************/
static void array_init(fx_object *obj, void *priv)
{
struct fx_array_p *array = priv;
}
static void array_fini(fx_object *obj, void *priv)
{
struct fx_array_p *array = priv;
if (array->ar_data) {
for (size_t i = 0; i < array->ar_len; i++) {
fx_object_unref(array->ar_data[i]);
}
free(array->ar_data);
array->ar_data = NULL;
}
}
static void array_to_string(const fx_object *obj, fx_stream *out)
{
struct fx_array_p *array = fx_object_get_private(obj, FX_TYPE_ARRAY);
if (!array->ar_len) {
fx_stream_write_cstr(out, "[]", NULL);
return;
}
fx_stream_write_cstr(out, "[\n", NULL);
fx_stream_push_indent(out, 1);
size_t len = array_size(array);
for (size_t i = 0; i < array->ar_len; i++) {
fx_object *value = array->ar_data[i];
bool is_string = fx_object_is_type(value, FX_TYPE_STRING);
if (is_string) {
fx_stream_write_char(out, '"');
}
fx_object_to_string(value, out);
if (is_string) {
fx_stream_write_char(out, '"');
}
if (i < len - 1) {
fx_stream_write_cstr(out, ",", NULL);
}
fx_stream_write_char(out, '\n');
}
fx_stream_pop_indent(out);
fx_stream_write_char(out, ']');
}
/*** ITERATOR FUNCTIONS *******************************************************/
static fx_iterator *iterable_begin(fx_object *obj)
{
fx_array_iterator *it_obj = fx_object_create(FX_TYPE_ARRAY_ITERATOR);
struct fx_array_iterator_p *it
= fx_object_get_private(it_obj, FX_TYPE_ARRAY_ITERATOR);
it->_a = obj;
it->_a_p = fx_object_get_private(obj, FX_TYPE_ARRAY);
it->i = 0;
if (it->_a_p->ar_len > 0) {
it->value = it->_a_p->ar_data[0];
} else {
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
it->value = NULL;
}
return it_obj;
}
static const fx_iterator *iterable_cbegin(const fx_object *obj)
{
fx_array_iterator *it_obj = fx_object_create(FX_TYPE_ARRAY_ITERATOR);
struct fx_array_iterator_p *it
= fx_object_get_private(it_obj, FX_TYPE_ARRAY_ITERATOR);
it->_a = (fx_array *)obj;
it->_a_p = fx_object_get_private(obj, FX_TYPE_ARRAY);
it->i = 0;
if (it->_a_p->ar_len > 0) {
it->value = it->_a_p->ar_data[0];
} else {
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
it->value = NULL;
}
return it_obj;
}
static enum fx_status iterator_move_next(const fx_iterator *obj)
{
struct fx_array_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR);
struct fx_array_p *array = it->_a_p;
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) ? FX_SUCCESS : FX_ERR_NO_DATA;
}
static enum fx_status iterator_erase(fx_iterator *obj)
{
struct fx_array_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR);
struct fx_array_p *array = it->_a_p;
if (it->i >= array->ar_len) {
return FX_ERR_OUT_OF_BOUNDS;
}
if (array->ar_data[it->i] != it->value) {
return FX_ERR_BAD_STATE;
}
array_remove(array, it->i);
if (it->i < array->ar_len) {
it->value = array->ar_data[it->i];
} else {
it->value = NULL;
}
return FX_SUCCESS;
}
static fx_iterator_value iterator_get_value(fx_iterator *obj)
{
struct fx_array_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR);
return FX_ITERATOR_VALUE_PTR(it->value);
}
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
{
struct fx_array_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR);
return FX_ITERATOR_VALUE_CPTR(it->value);
}
static enum fx_status iterator_is_valid(const fx_iterator *obj)
{
struct fx_array_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR);
struct fx_array_p *array = it->_a_p;
if (it->i >= array->ar_len) {
return false;
}
if (array->ar_data[it->i] != it->value) {
return false;
}
return (it->value != NULL) ? FX_SUCCESS : FX_ERR_NO_DATA;
}
/*** CLASS DEFINITION *********************************************************/
// ---- fx_array DEFINITION
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_array)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = array_to_string;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
FX_INTERFACE_ENTRY(it_begin) = iterable_begin;
FX_INTERFACE_ENTRY(it_cbegin) = iterable_cbegin;
FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
FX_TYPE_CLASS_DEFINITION_END(fx_array)
FX_TYPE_DEFINITION_BEGIN(fx_array)
FX_TYPE_ID(0xe3c46da1, 0x5f37, 0x4e44, 0xb53b, 0xff5a6200191b);
FX_TYPE_CLASS(fx_array_class);
FX_TYPE_IMPLEMENTS(FX_TYPE_ITERABLE);
FX_TYPE_INSTANCE_PRIVATE(struct fx_array_p);
FX_TYPE_INSTANCE_INIT(array_init);
FX_TYPE_INSTANCE_FINI(array_fini);
FX_TYPE_DEFINITION_END(fx_array)
// ---- fx_array_iterator DEFINITION
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_array_iterator)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
FX_TYPE_CLASS_DEFINITION_END(fx_array_iterator)
FX_TYPE_DEFINITION_BEGIN(fx_array_iterator)
FX_TYPE_ID(0xe5e9e8b8, 0x14cb, 0x4192, 0x8138, 0xf45238a2ae73);
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
FX_TYPE_CLASS(fx_array_iterator_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_array_iterator_p);
FX_TYPE_DEFINITION_END(fx_array_iterator)
+38
View File
@@ -0,0 +1,38 @@
#include <fx/ds/bitbuffer.h>
/*** PRIVATE DATA *************************************************************/
struct fx_bitbuffer_p {
int x;
};
/*** PRIVATE FUNCTIONS ********************************************************/
/*** PUBLIC FUNCTIONS *********************************************************/
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
/*** VIRTUAL FUNCTIONS ********************************************************/
static void bitbuffer_init(fx_object *obj, void *priv)
{
struct fx_bitbuffer_p *bitbuffer = priv;
}
static void bitbuffer_fini(fx_object *obj, void *priv)
{
struct fx_bitbuffer_p *bitbuffer = priv;
}
/*** CLASS DEFINITION *********************************************************/
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_bitbuffer)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_DEFINITION_END(fx_bitbuffer)
FX_TYPE_DEFINITION_BEGIN(fx_bitbuffer)
FX_TYPE_ID(0x628e33da, 0x3109, 0x4a5d, 0x98d5, 0xb0e4cb3ccb65);
FX_TYPE_CLASS(fx_bitbuffer_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_bitbuffer_p);
FX_TYPE_INSTANCE_INIT(bitbuffer_init);
FX_TYPE_INSTANCE_FINI(bitbuffer_fini);
FX_TYPE_DEFINITION_END(fx_bitbuffer)
+330
View File
@@ -0,0 +1,330 @@
#include <fx/core/bitop.h>
#include <fx/core/stream.h>
#include <fx/ds/bitmap.h>
#include <string.h>
#define BITS_PER_WORD (8 * sizeof(bitmap_word_t))
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define BITMAP_WORDS(nbits) DIV_ROUND_UP(nbits, BITS_PER_WORD)
/*** PRIVATE DATA *************************************************************/
typedef unsigned long bitmap_word_t;
struct fx_bitmap_p {
bitmap_word_t *map_words;
size_t map_nr_words, map_nr_bits;
};
/*** PRIVATE FUNCTIONS ********************************************************/
static void bitmap_set_bit(struct fx_bitmap_p *map, size_t bit)
{
unsigned long index = bit / BITS_PER_WORD;
unsigned long offset = (BITS_PER_WORD - bit - 1) & (BITS_PER_WORD - 1);
unsigned long mask = 1ul << offset;
map->map_words[index] |= mask;
}
static void bitmap_clear_bit(struct fx_bitmap_p *map, size_t bit)
{
unsigned long index = bit / BITS_PER_WORD;
unsigned long offset = bit & (BITS_PER_WORD - 1);
unsigned long mask = 1ul << offset;
map->map_words[index] &= ~mask;
}
static void bitmap_set_range(struct fx_bitmap_p *map, size_t first_bit, size_t nbits)
{
}
static void bitmap_clear_range(struct fx_bitmap_p *map, size_t first_bit, size_t nbits)
{
}
static void bitmap_set_all(struct fx_bitmap_p *map)
{
memset(map->map_words, 0xFF, map->map_nr_words * sizeof(bitmap_word_t));
}
static void bitmap_clear_all(struct fx_bitmap_p *map)
{
memset(map->map_words, 0x00, map->map_nr_words * sizeof(bitmap_word_t));
}
static bool bitmap_check_bit(const struct fx_bitmap_p *map, size_t bit)
{
unsigned long index = bit / BITS_PER_WORD;
unsigned long offset = (BITS_PER_WORD - bit - 1) & (BITS_PER_WORD - 1);
unsigned long mask = 1ul << offset;
return (map->map_words[index] & mask) != 0;
}
static size_t bitmap_count_set_bits(const struct fx_bitmap_p *map)
{
size_t set_bits = 0;
for (size_t i = 0; i < map->map_nr_words; i++) {
set_bits += fx_popcountl(map->map_words[i]);
}
if (set_bits > map->map_nr_bits) {
set_bits = map->map_nr_bits;
}
return set_bits;
}
static size_t bitmap_count_clear_bits(const struct fx_bitmap_p *map)
{
size_t clear_bits = 0;
for (size_t i = 0; i < map->map_nr_words; i++) {
clear_bits += fx_popcountl(~map->map_words[i]);
}
if (clear_bits > map->map_nr_bits) {
clear_bits = map->map_nr_bits;
}
return clear_bits;
}
static size_t bitmap_highest_set_bit(const struct fx_bitmap_p *map)
{
unsigned long bit_index = 0;
bitmap_word_t last_word = 0;
unsigned long i;
for (i = 0; i < map->map_nr_words; i++) {
if (map->map_words[i] != 0x00) {
last_word = map->map_words[i];
bit_index = i * BITS_PER_WORD;
}
}
if (last_word == 0x00) {
return FX_NPOS;
}
return bit_index + (BITS_PER_WORD - fx_ctzl(last_word) - 1);
}
static size_t bitmap_highest_clear_bit(const struct fx_bitmap_p *map)
{
unsigned long bit_index = 0;
bitmap_word_t last_word = ~(bitmap_word_t)0;
for (unsigned long i = 0; i < map->map_nr_words; i++) {
if (map->map_words[i] != (~(unsigned long)0)) {
last_word = map->map_words[i];
bit_index = i * BITS_PER_WORD;
}
}
if (last_word == ~(unsigned long)0) {
return FX_NPOS;
}
if (last_word == 0) {
return bit_index + BITS_PER_WORD - 1;
}
return bit_index + (BITS_PER_WORD - fx_ctzl(~last_word)) - 1;
}
static size_t bitmap_lowest_set_bit(const struct fx_bitmap_p *map)
{
unsigned long bit_index = 0;
bitmap_word_t last_word = 0;
unsigned long i;
for (i = 0; i < map->map_nr_words; i++) {
if (map->map_words[i] != 0x00) {
last_word = map->map_words[i];
bit_index = i * BITS_PER_WORD;
break;
}
}
if (last_word == 0x00) {
return FX_NPOS;
}
return bit_index + fx_clzl(last_word);
}
static size_t bitmap_lowest_clear_bit(const struct fx_bitmap_p *map)
{
unsigned long bit_index = 0;
bitmap_word_t last_word = 0;
unsigned long i;
for (i = 0; i < map->map_nr_words; i++) {
if (map->map_words[i] != (~(unsigned long)0)) {
last_word = map->map_words[i];
bit_index = i * BITS_PER_WORD;
break;
}
}
if (last_word == 0) {
return bit_index;
}
if (last_word == (~(bitmap_word_t)0)) {
return FX_NPOS;
}
return bit_index + fx_clzl(~last_word);
}
/*** PUBLIC FUNCTIONS *********************************************************/
fx_bitmap *fx_bitmap_create(size_t nr_bits)
{
fx_bitmap *map = fx_object_create(FX_TYPE_BITMAP);
if (!map) {
return NULL;
}
struct fx_bitmap_p *p = fx_object_get_private(map, FX_TYPE_BITMAP);
p->map_nr_bits = nr_bits;
p->map_nr_words = BITMAP_WORDS(nr_bits);
p->map_words = calloc(p->map_nr_words, sizeof(bitmap_word_t));
if (!p->map_words) {
fx_bitmap_unref(map);
return NULL;
}
return map;
}
void fx_bitmap_set_bit(fx_bitmap *map, size_t bit)
{
FX_CLASS_DISPATCH_STATIC_V(FX_TYPE_BITMAP, bitmap_set_bit, map, bit);
}
void fx_bitmap_clear_bit(fx_bitmap *map, size_t bit)
{
FX_CLASS_DISPATCH_STATIC_V(FX_TYPE_BITMAP, bitmap_clear_bit, map, bit);
}
void fx_bitmap_set_range(fx_bitmap *map, size_t first_bit, size_t nbits)
{
FX_CLASS_DISPATCH_STATIC_V(
FX_TYPE_BITMAP, bitmap_set_range, map, first_bit, nbits);
}
void fx_bitmap_clear_range(fx_bitmap *map, size_t first_bit, size_t nbits)
{
FX_CLASS_DISPATCH_STATIC_V(
FX_TYPE_BITMAP, bitmap_clear_range, map, first_bit, nbits);
}
void fx_bitmap_set_all(fx_bitmap *map)
{
FX_CLASS_DISPATCH_STATIC_V0(FX_TYPE_BITMAP, bitmap_set_all, map);
}
void fx_bitmap_clear_all(fx_bitmap *map)
{
FX_CLASS_DISPATCH_STATIC_V0(FX_TYPE_BITMAP, bitmap_clear_all, map);
}
bool fx_bitmap_check_bit(const fx_bitmap *map, size_t bit)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BITMAP, bitmap_check_bit, map, bit);
}
size_t fx_bitmap_count_set_bits(const fx_bitmap *map)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BITMAP, bitmap_count_set_bits, map);
}
size_t fx_bitmap_count_clear_bits(const fx_bitmap *map)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BITMAP, bitmap_count_clear_bits, map);
}
size_t fx_bitmap_highest_set_bit(const fx_bitmap *map)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BITMAP, bitmap_highest_set_bit, map);
}
size_t fx_bitmap_highest_clear_bit(const fx_bitmap *map)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BITMAP, bitmap_highest_clear_bit, map);
}
size_t fx_bitmap_lowest_set_bit(const fx_bitmap *map)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BITMAP, bitmap_lowest_set_bit, map);
}
size_t fx_bitmap_lowest_clear_bit(const fx_bitmap *map)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BITMAP, bitmap_lowest_clear_bit, map);
}
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
/*** VIRTUAL FUNCTIONS ********************************************************/
static void bitmap_init(fx_object *obj, void *priv)
{
struct fx_bitmap_p *map = priv;
}
static void bitmap_fini(fx_object *obj, void *priv)
{
struct fx_bitmap_p *map = priv;
}
static void bitmap_to_string(const fx_object *obj, fx_stream *out)
{
const struct fx_bitmap_p *map = fx_object_get_private(obj, FX_TYPE_BITMAP);
unsigned char *bytes = (unsigned char *)map->map_words;
size_t nr_bytes = map->map_nr_words * sizeof(bitmap_word_t);
unsigned char c = 0;
for (size_t i = 0; i < nr_bytes - 1; i++) {
c = bytes[i];
fx_stream_write_fmt(
out, NULL, "%c%c%c%c%c%c%c%c", c & 0x80 ? '1' : '0',
c & 0x40 ? '1' : '0', c & 0x20 ? '1' : '0',
c & 0x10 ? '1' : '0', c & 0x08 ? '1' : '0',
c & 0x04 ? '1' : '0', c & 0x02 ? '1' : '0',
c & 0x01 ? '1' : '0');
}
unsigned char mask = 0x80;
size_t remaining_bits = map->map_nr_bits - ((nr_bytes - 1) * 8);
c = bytes[nr_bytes - 1];
for (size_t i = 0; i < remaining_bits; i++) {
fx_stream_write_fmt(out, NULL, "%c", (c & mask) ? '1' : '0');
}
}
/*** CLASS DEFINITION *********************************************************/
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_bitmap)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = bitmap_to_string;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_DEFINITION_END(fx_bitmap)
FX_TYPE_DEFINITION_BEGIN(fx_bitmap)
FX_TYPE_ID(0xea115cef, 0x8a63, 0x445f, 0x9474, 0xba9309d5dde8);
FX_TYPE_CLASS(fx_bitmap_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_bitmap_p);
FX_TYPE_INSTANCE_INIT(bitmap_init);
FX_TYPE_INSTANCE_FINI(bitmap_fini);
FX_TYPE_DEFINITION_END(fx_bitmap)
/*** ITERATOR FUNCTIONS *******************************************************/
+441
View File
@@ -0,0 +1,441 @@
#include <fx/core/iterator.h>
#include <fx/ds/buffer.h>
#include <stdlib.h>
#include <string.h>
/*** PRIVATE DATA *************************************************************/
struct fx_buffer_p {
/* number of items in buffer */
unsigned int buf_len;
/* maximum number of items that can currently be stored in array */
unsigned int buf_cap;
/* the size of each individual item in the buffer */
unsigned int buf_itemsz;
void *buf_data;
};
/*** PRIVATE FUNCTIONS ********************************************************/
static fx_status resize_buffer(struct fx_buffer_p *buffer, size_t new_capacity)
{
if (buffer->buf_cap < new_capacity) {
void *new_data = realloc(
buffer->buf_data, new_capacity * buffer->buf_itemsz);
if (!new_data) {
return FX_ERR_NO_MEMORY;
}
buffer->buf_data = new_data;
} else {
void *new_data = realloc(
buffer->buf_data, new_capacity * buffer->buf_itemsz);
if (!new_data) {
return FX_ERR_NO_MEMORY;
}
buffer->buf_data = new_data;
}
buffer->buf_cap = new_capacity;
if (buffer->buf_len > new_capacity) {
buffer->buf_len = new_capacity;
}
return FX_SUCCESS;
}
static void *buffer_steal(struct fx_buffer_p *buf)
{
void *p = buf->buf_data;
buf->buf_data = NULL;
buf->buf_len = 0;
buf->buf_cap = 0;
return p;
}
static enum fx_status buffer_reserve(struct fx_buffer_p *buf, size_t capacity)
{
if (buf->buf_cap >= capacity) {
return FX_SUCCESS;
}
return resize_buffer(buf, capacity);
}
static enum fx_status buffer_resize(struct fx_buffer_p *buf, size_t length)
{
enum fx_status status = resize_buffer(buf, length);
if (!FX_OK(status)) {
return status;
}
buf->buf_len = length;
return FX_SUCCESS;
}
static enum fx_status buffer_insert(
struct fx_buffer_p *buffer, const void *p, size_t count, size_t at)
{
if (at == FX_NPOS) {
at = buffer->buf_len;
}
if (at > buffer->buf_len) {
return FX_ERR_OUT_OF_BOUNDS;
}
fx_status status = FX_SUCCESS;
if (buffer->buf_len + count > buffer->buf_cap) {
status = resize_buffer(buffer, buffer->buf_cap + count);
if (status != FX_SUCCESS) {
return status;
}
}
unsigned char *src
= (unsigned char *)buffer->buf_data + (at * buffer->buf_itemsz);
unsigned char *dest = src + (count * buffer->buf_itemsz);
size_t move_len = (buffer->buf_len - at) * buffer->buf_itemsz;
memmove(dest, src, move_len);
memcpy(src, p, count * buffer->buf_itemsz);
buffer->buf_len += count;
return FX_SUCCESS;
}
static enum fx_status buffer_remove(struct fx_buffer_p *buffer, size_t at, size_t count)
{
if (at >= buffer->buf_len) {
return FX_ERR_OUT_OF_BOUNDS;
}
if (at + count >= buffer->buf_len) {
count = buffer->buf_len - at;
}
unsigned char *dest = buffer->buf_data + (at * buffer->buf_itemsz);
unsigned char *src = dest + (count * buffer->buf_itemsz);
size_t move_len = (buffer->buf_len - at - count) * buffer->buf_itemsz;
memmove(dest, src, move_len);
buffer->buf_len -= count;
return FX_SUCCESS;
}
static void *buffer_ptr(const struct fx_buffer_p *buffer)
{
return buffer->buf_data;
}
static void *buffer_get(const struct fx_buffer_p *buffer, size_t at)
{
if (at >= buffer->buf_len) {
return NULL;
}
return (unsigned char *)buffer->buf_data + (at * buffer->buf_itemsz);
}
static size_t buffer_size(const struct fx_buffer_p *buffer)
{
return buffer->buf_len;
}
static size_t buffer_capacity(const struct fx_buffer_p *buffer)
{
return buffer->buf_cap;
}
static enum fx_status buffer_clear(struct fx_buffer_p *buffer)
{
buffer->buf_len = 0;
return FX_SUCCESS;
}
static enum fx_status buffer_push_back(
struct fx_buffer_p *buf, size_t count, void **p)
{
enum fx_status status = FX_SUCCESS;
if (buf->buf_len + count > buf->buf_cap) {
status = resize_buffer(buf, buf->buf_len + count);
}
if (!FX_OK(status)) {
return status;
}
buf->buf_len += count;
*p = buffer_get(buf, buf->buf_len - count);
return FX_SUCCESS;
}
static enum fx_status buffer_push_front(
struct fx_buffer_p *buf, size_t count, void **p)
{
enum fx_status status = FX_SUCCESS;
if (buf->buf_len + count > buf->buf_cap) {
status = resize_buffer(buf, buf->buf_len + count);
}
if (!FX_OK(status)) {
return status;
}
void *src = buf->buf_data;
void *dest = fx_buffer_get(buf->buf_data, count);
size_t len = count * buf->buf_itemsz;
memmove(dest, src, len);
buf->buf_len += count;
*p = buffer_get(buf, 0);
return FX_SUCCESS;
}
static enum fx_status buffer_pop_back(struct fx_buffer_p *buf, size_t count)
{
if (count > buf->buf_len) {
return FX_ERR_OUT_OF_BOUNDS;
}
buf->buf_len -= count;
return FX_SUCCESS;
}
static enum fx_status buffer_pop_front(struct fx_buffer_p *buf, size_t count)
{
if (count > buf->buf_len) {
return FX_ERR_OUT_OF_BOUNDS;
}
void *src = fx_buffer_get(buf->buf_data, count);
void *dest = buf->buf_data;
size_t len = (buf->buf_len - count) * buf->buf_itemsz;
memmove(dest, src, len);
buf->buf_len -= count;
return FX_SUCCESS;
}
static size_t buffer_get_size(const struct fx_buffer_p *buf)
{
return buf->buf_len;
}
static size_t buffer_get_item_size(const struct fx_buffer_p *buf)
{
return buf->buf_itemsz;
}
static size_t buffer_get_capacity(const struct fx_buffer_p *buf)
{
return buf->buf_cap;
}
/*** PUBLIC FUNCTIONS *********************************************************/
fx_buffer *fx_buffer_create(size_t item_sz)
{
fx_buffer *buffer = fx_object_create(FX_TYPE_BUFFER);
if (!buffer) {
return NULL;
}
struct fx_buffer_p *p = fx_object_get_private(buffer, FX_TYPE_BUFFER);
p->buf_itemsz = item_sz;
return buffer;
}
fx_buffer *fx_buffer_create_from_bytes(const void *buf, size_t len)
{
fx_buffer *buffer = fx_object_create(FX_TYPE_BUFFER);
if (!buffer) {
return NULL;
}
struct fx_buffer_p *p = fx_object_get_private(buffer, FX_TYPE_BUFFER);
p->buf_len = len;
p->buf_cap = len;
p->buf_itemsz = 1;
p->buf_data = calloc(len, 1);
if (!p->buf_data) {
fx_buffer_unref(buffer);
return NULL;
}
memcpy(p->buf_data, buf, len);
return buffer;
}
fx_buffer *fx_buffer_create_from_array(const void *buf, size_t item_sz, size_t len)
{
fx_buffer *buffer = fx_object_create(FX_TYPE_BUFFER);
if (!buffer) {
return NULL;
}
struct fx_buffer_p *p = fx_object_get_private(buffer, FX_TYPE_BUFFER);
p->buf_len = len;
p->buf_cap = len;
p->buf_itemsz = item_sz;
p->buf_data = calloc(len, item_sz);
if (!p->buf_data) {
fx_buffer_unref(buffer);
return NULL;
}
memcpy(p->buf_data, buf, len * item_sz);
return buffer;
}
void *fx_buffer_steal(fx_buffer *buf)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_steal, buf);
}
enum fx_status fx_buffer_reserve(fx_buffer *buf, size_t capacity)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_reserve, buf, capacity);
}
enum fx_status fx_buffer_resize(fx_buffer *buf, size_t length)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_resize, buf, length);
}
enum fx_status fx_buffer_insert(
fx_buffer *buffer, const void *p, size_t count, size_t at)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_insert, buffer, p, count, at);
}
enum fx_status fx_buffer_remove(fx_buffer *buffer, size_t at, size_t count)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_remove, buffer, at, count);
}
void *fx_buffer_ptr(const fx_buffer *buffer)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_ptr, buffer);
}
void *fx_buffer_get(const fx_buffer *buffer, size_t at)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_get, buffer, at);
}
size_t fx_buffer_size(const fx_buffer *buffer)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_size, buffer);
}
size_t fx_buffer_capacity(const fx_buffer *buffer)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_capacity, buffer);
}
enum fx_status fx_buffer_clear(fx_buffer *buffer)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_clear, buffer);
}
enum fx_status fx_buffer_push_back(fx_buffer *buf, size_t count, void **p)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_push_back, buf, count, p);
}
enum fx_status fx_buffer_push_front(fx_buffer *buf, size_t count, void **p)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_push_front, buf, count, p);
}
enum fx_status fx_buffer_pop_back(fx_buffer *buf, size_t count)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_pop_back, buf, count);
}
enum fx_status fx_buffer_pop_front(fx_buffer *buf, size_t count)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_pop_front, buf, count);
}
size_t fx_buffer_get_size(const fx_buffer *buf)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_get_size, buf);
}
size_t fx_buffer_get_item_size(const fx_buffer *buf)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_get_item_size, buf);
}
size_t fx_buffer_get_capacity(const fx_buffer *buf)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_get_capacity, buf);
}
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
enum fx_status fx_buffer_append(fx_buffer *buffer, const void *p, size_t count)
{
return fx_buffer_insert(buffer, p, count, FX_NPOS);
}
enum fx_status fx_buffer_prepend(fx_buffer *buffer, const void *p, size_t count)
{
return fx_buffer_insert(buffer, p, count, 0);
}
/*** VIRTUAL FUNCTIONS ********************************************************/
void buffer_init(fx_object *obj, void *priv)
{
struct fx_buffer_p *buffer = priv;
}
void buffer_fini(fx_object *obj, void *priv)
{
struct fx_buffer_p *buffer = priv;
if (buffer->buf_data) {
free(buffer->buf_data);
buffer->buf_data = NULL;
}
}
/*** CLASS DEFINITION *********************************************************/
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_buffer)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_DEFINITION_END(fx_buffer)
FX_TYPE_DEFINITION_BEGIN(fx_buffer)
FX_TYPE_ID(0x323e6858, 0x7a43, 0x4484, 0xa6fb, 0xe3d1e47ae637);
FX_TYPE_CLASS(fx_buffer_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_buffer_p);
FX_TYPE_INSTANCE_INIT(buffer_init);
FX_TYPE_INSTANCE_FINI(buffer_fini);
FX_TYPE_DEFINITION_END(fx_buffer)
+587
View File
@@ -0,0 +1,587 @@
#include <fx/core/stream.h>
#include <fx/ds/datetime.h>
#include <fx/ds/string.h>
/*** PRIVATE DATA *************************************************************/
struct fx_datetime_p {
unsigned int dt_year, dt_month, dt_day;
unsigned short dt_hour, dt_min, dt_sec;
unsigned int dt_msec;
bool dt_has_date, dt_has_time, dt_localtime;
unsigned short dt_zone_offset_hour, dt_zone_offset_minute;
bool dt_zone_offset_negative;
};
/*** PRIVATE FUNCTIONS ********************************************************/
static bool is_leap_year(const struct fx_datetime_p *dt)
{
if ((dt->dt_year % 400) == 0) {
return true;
}
if ((dt->dt_year % 4) == 0 && (dt->dt_year % 100) != 0) {
return true;
}
return false;
}
static bool is_year_valid(const struct fx_datetime_p *dt)
{
return dt->dt_year >= 0;
}
static bool is_month_valid(const struct fx_datetime_p *dt)
{
return dt->dt_month >= 1 && dt->dt_month <= 12;
}
static bool is_day_valid(const struct fx_datetime_p *dt)
{
if (dt->dt_day < 1) {
return false;
}
switch (dt->dt_month) {
case 2:
return dt->dt_day <= (is_leap_year(dt) ? 29 : 28);
case 4:
case 6:
case 9:
case 11:
return dt->dt_day <= 30;
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
return dt->dt_day <= 31;
default:
return false;
}
}
static bool is_time_valid(const struct fx_datetime_p *dt)
{
if (!(dt->dt_hour >= 0 && dt->dt_hour <= 23)) {
return false;
}
if (!(dt->dt_min >= 0 && dt->dt_min <= 59)) {
return false;
}
if (!(dt->dt_sec >= 0 && dt->dt_sec <= 60)) {
return false;
}
return true;
}
static bool is_zone_valid(const struct fx_datetime_p *dt)
{
if (!(dt->dt_zone_offset_hour >= 0 && dt->dt_zone_offset_hour <= 23)) {
return false;
}
if (!(dt->dt_zone_offset_minute >= 0 && dt->dt_zone_offset_minute <= 59)) {
return false;
}
return true;
}
static bool validate(const struct fx_datetime_p *dt)
{
if (dt->dt_has_date) {
if (!is_year_valid(dt)) {
return false;
}
if (!is_month_valid(dt)) {
return false;
}
if (!is_day_valid(dt)) {
return false;
}
}
if (dt->dt_has_time) {
if (!is_time_valid(dt)) {
return false;
}
if (!is_zone_valid(dt)) {
return false;
}
}
return true;
}
static fx_datetime *parse_rfc3339(const char *s)
{
fx_datetime *d = fx_datetime_create();
if (!d) {
return NULL;
}
struct fx_datetime_p *dt = fx_object_get_private(d, FX_TYPE_DATETIME);
size_t len = strlen(s);
size_t i = 0, c = 0;
bool has_date = false, has_time = false;
dt->dt_localtime = true;
if (len >= 10 && s[4] == '-' && s[7] == '-') {
has_date = true;
}
if (len >= 8 && s[2] == ':' && s[5] == ':') {
has_time = true;
}
if (len >= 19 && s[4] == '-' && s[7] == '-'
&& (s[10] == 'T' || s[10] == 't' || s[10] == ' ') && s[13] == ':'
&& s[16] == ':') {
has_date = true;
has_time = true;
}
if (!has_date && !has_time) {
goto fail;
}
if (has_date) {
for (c = 0; c < 4; c++, i++) {
if (!isdigit(s[i])) {
goto fail;
}
dt->dt_year *= 10;
dt->dt_year += (s[i] - '0');
}
if (s[i++] != '-') {
goto fail;
}
for (c = 0; c < 2; c++, i++) {
if (!isdigit(s[i])) {
goto fail;
}
dt->dt_month *= 10;
dt->dt_month += (s[i] - '0');
}
if (s[i++] != '-' || dt->dt_month > 12) {
goto fail;
}
for (c = 0; c < 2; c++, i++) {
if (!isdigit(s[i])) {
goto fail;
}
dt->dt_day *= 10;
dt->dt_day += (s[i] - '0');
}
if (dt->dt_day > 31) {
goto fail;
}
}
if ((s[i] == 'T' || s[i] == 't' || s[i] == ' ') && !has_time) {
goto fail;
}
if (has_date && has_time) {
if (s[i] != 'T' && s[i] != 't' && s[i] != ' ') {
goto fail;
}
i++;
}
if (has_time) {
for (c = 0; c < 2; c++, i++) {
if (!isdigit(s[i])) {
goto fail;
}
dt->dt_hour *= 10;
dt->dt_hour += (s[i] - '0');
}
if (s[i++] != ':') {
goto fail;
}
for (c = 0; c < 2; c++, i++) {
if (!isdigit(s[i])) {
goto fail;
}
dt->dt_min *= 10;
dt->dt_min += (s[i] - '0');
}
if (s[i++] != ':') {
goto fail;
}
for (c = 0; c < 2; c++, i++) {
if (!isdigit(s[i])) {
goto fail;
}
dt->dt_sec *= 10;
dt->dt_sec += (s[i] - '0');
}
if (s[i] == '.') {
i++;
for (c = 0; s[i]; c++, i++) {
if (!isdigit(s[i])) {
break;
}
dt->dt_msec *= 10;
dt->dt_msec += (s[i] - '0');
}
if (c == 0) {
goto fail;
}
}
if (s[i] == '+' || s[i] == '-') {
dt->dt_localtime = false;
dt->dt_zone_offset_negative = s[i] == '-';
i++;
for (c = 0; c < 2; c++, i++) {
if (!isdigit(s[i])) {
goto fail;
}
dt->dt_zone_offset_hour *= 10;
dt->dt_zone_offset_hour += (s[i] - '0');
}
if (s[i++] != ':') {
goto fail;
}
for (c = 0; c < 2; c++, i++) {
if (!isdigit(s[i])) {
goto fail;
}
dt->dt_zone_offset_minute *= 10;
dt->dt_zone_offset_minute += (s[i] - '0');
}
} else if (s[i] == 'Z' || s[i] == 'z') {
dt->dt_localtime = false;
i++;
}
}
if (s[i] != 0) {
goto fail;
}
dt->dt_has_date = has_date;
dt->dt_has_time = has_time;
return d;
fail:
fx_datetime_unref(d);
return NULL;
}
static enum fx_status encode_rfc3339(const struct fx_datetime_p *dt, fx_stream *out)
{
if (dt->dt_has_date) {
fx_stream_write_fmt(
out, NULL, "%04ld-%02ld-%02ld", dt->dt_year,
dt->dt_month, dt->dt_day);
}
if (dt->dt_has_date && dt->dt_has_time) {
fx_stream_write_char(out, 'T');
}
if (dt->dt_has_time) {
fx_stream_write_fmt(
out, NULL, "%02ld:%02ld:%02ld", dt->dt_hour, dt->dt_min,
dt->dt_sec);
if (dt->dt_msec > 0) {
fx_stream_write_fmt(out, NULL, ".%04ld", dt->dt_msec);
}
if (!dt->dt_localtime) {
if (dt->dt_zone_offset_hour == 0
&& dt->dt_zone_offset_minute == 0) {
fx_stream_write_char(out, 'Z');
} else {
fx_stream_write_fmt(
out, NULL, "%c%02ld:%02ld",
dt->dt_zone_offset_negative ? '-' : '+',
dt->dt_zone_offset_hour,
dt->dt_zone_offset_minute);
}
}
}
return FX_SUCCESS;
}
static void datetime_to_string(
const struct fx_datetime_p *dt, fx_datetime_format format, fx_stream *dest)
{
switch (format) {
case FX_DATETIME_FORMAT_RFC3339:
encode_rfc3339(dt, dest);
break;
default:
break;
}
}
static bool datetime_is_localtime(const struct fx_datetime_p *dt)
{
return dt->dt_localtime;
}
static bool datetime_has_date(const struct fx_datetime_p *dt)
{
return dt->dt_has_date;
}
static bool datetime_has_time(const struct fx_datetime_p *dt)
{
return dt->dt_has_time;
}
static long datetime_year(const struct fx_datetime_p *dt)
{
return dt->dt_year;
}
static long datetime_month(const struct fx_datetime_p *dt)
{
return dt->dt_month;
}
static long datetime_day(const struct fx_datetime_p *dt)
{
return dt->dt_day;
}
static long datetime_hour(const struct fx_datetime_p *dt)
{
return dt->dt_hour;
}
static long datetime_minute(const struct fx_datetime_p *dt)
{
return dt->dt_min;
}
static long datetime_second(const struct fx_datetime_p *dt)
{
return dt->dt_sec;
}
static long datetime_subsecond(const struct fx_datetime_p *dt)
{
return dt->dt_msec;
}
static bool datetime_zone_offset_is_negative(const struct fx_datetime_p *dt)
{
return dt->dt_zone_offset_negative;
}
static long datetime_zone_offset_hour(const struct fx_datetime_p *dt)
{
return dt->dt_zone_offset_hour;
}
static long datetime_zone_offset_minute(const struct fx_datetime_p *dt)
{
return dt->dt_zone_offset_minute;
}
/*** PUBLIC FUNCTIONS *********************************************************/
fx_datetime *fx_datetime_parse(enum fx_datetime_format format, const char *s)
{
fx_datetime *dt = NULL;
switch (format) {
case FX_DATETIME_FORMAT_RFC3339:
dt = parse_rfc3339(s);
break;
default:
return NULL;
}
if (!dt) {
return NULL;
}
struct fx_datetime_p *p = fx_object_get_private(dt, FX_TYPE_DATETIME);
if (!validate(p)) {
fx_datetime_unref(dt);
return NULL;
}
return dt;
}
void fx_datetime_to_string(
const fx_datetime *dt, fx_datetime_format format, fx_stream *dest)
{
FX_CLASS_DISPATCH_STATIC(
FX_TYPE_DATETIME, datetime_to_string, dt, format, dest);
}
bool fx_datetime_is_localtime(const fx_datetime *dt)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_is_localtime, dt);
}
bool fx_datetime_has_date(const fx_datetime *dt)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_has_date, dt);
}
bool fx_datetime_has_time(const fx_datetime *dt)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_has_time, dt);
}
long fx_datetime_year(const fx_datetime *dt)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_year, dt);
}
long fx_datetime_month(const fx_datetime *dt)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_month, dt);
}
long fx_datetime_day(const fx_datetime *dt)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_day, dt);
}
long fx_datetime_hour(const fx_datetime *dt)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_hour, dt);
}
long fx_datetime_minute(const fx_datetime *dt)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_minute, dt);
}
long fx_datetime_second(const fx_datetime *dt)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_second, dt);
}
long fx_datetime_subsecond(const fx_datetime *dt)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_subsecond, dt);
}
bool fx_datetime_zone_offset_is_negative(const fx_datetime *dt)
{
FX_CLASS_DISPATCH_STATIC_0(
FX_TYPE_DATETIME, datetime_zone_offset_is_negative, dt);
}
long fx_datetime_zone_offset_hour(const fx_datetime *dt)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_zone_offset_hour, dt);
}
long fx_datetime_zone_offset_minute(const fx_datetime *dt)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_zone_offset_minute, dt);
}
/*** VIRTUAL FUNCTIONS ********************************************************/
static void datetime_init(fx_object *obj, void *priv)
{
struct fx_datetime_p *dt = priv;
}
static void datetime_fini(fx_object *obj, void *priv)
{
struct fx_datetime_p *dt = priv;
}
static void _datetime_to_string(const fx_object *obj, fx_stream *out)
{
struct fx_datetime_p *dt = fx_object_get_private(obj, FX_TYPE_DATETIME);
if (dt->dt_has_date) {
fx_stream_write_fmt(
out, NULL, "%04ld-%02ld-%02ld", dt->dt_year,
dt->dt_month, dt->dt_day);
}
if (dt->dt_has_date && dt->dt_has_time) {
fx_stream_write_char(out, ' ');
}
if (dt->dt_has_time) {
fx_stream_write_fmt(
out, NULL, "%02ld:%02ld:%02ld", dt->dt_hour, dt->dt_min,
dt->dt_sec);
if (dt->dt_msec > 0) {
fx_stream_write_fmt(out, NULL, ".%04ld", dt->dt_msec);
}
if (!dt->dt_localtime) {
fx_stream_write_fmt(
out, NULL, " %c%02ld:%02ld",
dt->dt_zone_offset_negative ? '-' : '+',
dt->dt_zone_offset_hour,
dt->dt_zone_offset_minute);
}
}
}
/*** CLASS DEFINITION *********************************************************/
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_datetime)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = _datetime_to_string;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_DEFINITION_END(fx_datetime)
FX_TYPE_DEFINITION_BEGIN(fx_datetime)
FX_TYPE_ID(0x06a6030b, 0x1e3c, 0x4be2, 0xbd23, 0xf34f4a8e68be);
FX_TYPE_CLASS(fx_datetime_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_datetime_p);
FX_TYPE_INSTANCE_INIT(datetime_init);
FX_TYPE_INSTANCE_FINI(datetime_fini);
FX_TYPE_DEFINITION_END(fx_datetime)
+746
View File
@@ -0,0 +1,746 @@
#include <fx/core/status.h>
#include <fx/core/stream.h>
#include <fx/ds/dict.h>
#include <fx/ds/string.h>
#include <stdbool.h>
#include <stdlib.h>
/*** PRIVATE DATA *************************************************************/
struct fx_dict_bucket_item {
fx_queue_entry bi_entry;
fx_string *bi_str;
fx_object *bi_value;
};
struct fx_dict_bucket {
fx_bst_node bk_node;
uint64_t bk_hash;
fx_queue bk_items;
};
struct fx_dict_p {
fx_bst d_buckets;
};
struct fx_dict_iterator_p {
size_t i;
fx_dict_item item;
fx_dict *_d;
struct fx_dict_p *_d_p;
fx_bst_node *_cbn;
fx_queue_entry *_cqe;
};
/*** MISC FUNCTIONS ***********************************************************/
static FX_BST_DEFINE_SIMPLE_GET(
struct fx_dict_bucket,
uint64_t,
bk_node,
bk_hash,
get_bucket);
static FX_BST_DEFINE_SIMPLE_INSERT(
struct fx_dict_bucket,
bk_node,
bk_hash,
put_bucket);
uint64_t fx_cstr_hash(const char *s)
{
#define FNV1_OFFSET_BASIS 0xcbf29ce484222325
#define FNV1_PRIME 0x100000001b3
uint64_t hash = FNV1_OFFSET_BASIS;
size_t i = 0;
for (i = 0; s[i]; i++) {
hash ^= s[i];
hash *= FNV1_PRIME;
}
return hash;
}
/*** PRIVATE FUNCTIONS ********************************************************/
static struct fx_dict_bucket *create_bucket(void)
{
struct fx_dict_bucket *bucket = malloc(sizeof *bucket);
if (!bucket) {
return NULL;
}
memset(bucket, 0x0, sizeof *bucket);
return bucket;
}
static struct fx_dict_bucket_item *create_bucket_item(void)
{
struct fx_dict_bucket_item *item = malloc(sizeof *item);
if (!item) {
return NULL;
}
memset(item, 0x0, sizeof *item);
return item;
}
static fx_status dict_put(
struct fx_dict_p *dict,
const char *key,
fx_object *value)
{
uint64_t hash = fx_cstr_hash(key);
struct fx_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
if (!bucket) {
bucket = create_bucket();
if (!bucket) {
return FX_ERR_NO_MEMORY;
}
bucket->bk_hash = hash;
put_bucket(&dict->d_buckets, bucket);
}
struct fx_dict_bucket_item *item = create_bucket_item();
if (!item) {
return FX_ERR_NO_MEMORY;
}
item->bi_str = fx_string_create_from_cstr(key);
item->bi_value = fx_object_ref(value);
fx_queue_push_back(&bucket->bk_items, &item->bi_entry);
return FX_SUCCESS;
}
static fx_status dict_put_sk(
struct fx_dict_p *dict,
const fx_string *key,
fx_object *value)
{
uint64_t hash = fx_string_hash(key);
struct fx_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
if (!bucket) {
bucket = create_bucket();
if (!bucket) {
return FX_ERR_NO_MEMORY;
}
bucket->bk_hash = hash;
put_bucket(&dict->d_buckets, bucket);
}
struct fx_dict_bucket_item *item = create_bucket_item();
if (!item) {
return FX_ERR_NO_MEMORY;
}
item->bi_str = fx_string_duplicate(key);
item->bi_value = fx_object_ref(value);
fx_queue_push_back(&bucket->bk_items, &item->bi_entry);
return FX_SUCCESS;
}
static fx_object *dict_at(const struct fx_dict_p *dict, const char *key)
{
uint64_t hash = fx_cstr_hash(key);
struct fx_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
if (!bucket) {
return NULL;
}
struct fx_queue_entry *entry = fx_queue_first(&bucket->bk_items);
while (entry) {
struct fx_dict_bucket_item *item
= fx_unbox(struct fx_dict_bucket_item, entry, bi_entry);
if (!strcmp(fx_string_get_cstr(item->bi_str), key)) {
return item->bi_value;
}
entry = fx_queue_next(entry);
}
return NULL;
}
static fx_object *dict_at_sk(const struct fx_dict_p *dict, const fx_string *key)
{
uint64_t hash = fx_string_hash(key);
struct fx_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
if (!bucket) {
return NULL;
}
struct fx_queue_entry *entry = fx_queue_first(&bucket->bk_items);
while (entry) {
struct fx_dict_bucket_item *item
= fx_unbox(struct fx_dict_bucket_item, entry, bi_entry);
if (fx_string_compare(item->bi_str, key)) {
return item->bi_value;
}
entry = fx_queue_next(entry);
}
return NULL;
}
static fx_object *dict_get(struct fx_dict_p *dict, const char *key)
{
fx_object *value = dict_at(dict, key);
if (value) {
fx_object_ref(value);
}
return value;
}
static fx_object *dict_get_sk(struct fx_dict_p *dict, const fx_string *key)
{
fx_object *value = dict_at_sk(dict, key);
if (value) {
fx_object_ref(value);
}
return value;
}
static bool dict_has_key(const struct fx_dict_p *dict, const char *key)
{
return dict_at(dict, key) != NULL;
}
static bool dict_has_skey(const struct fx_dict_p *dict, const fx_string *key)
{
return dict_at_sk(dict, key) != NULL;
}
static size_t dict_get_size(const struct fx_dict_p *dict)
{
size_t count = 0;
#if 0
fx_bst_iterator it1;
fx_queue_iterator it2;
fx_bst_foreach (&it1, &dict->d_buckets) {
struct fx_dict_bucket *bucket
= fx_unbox(struct fx_dict_bucket, it1.node, bk_node);
fx_queue_foreach (&it2, &bucket->bk_items) {
count++;
}
}
#endif
return count;
}
static bool dict_is_empty(const struct fx_dict_p *dict)
{
fx_bst_node *first_node = fx_bst_first(&dict->d_buckets);
struct fx_dict_bucket *first_bucket
= fx_unbox(struct fx_dict_bucket, first_node, bk_node);
if (!first_bucket) {
return true;
}
fx_queue_entry *first_entry = fx_queue_first(&first_bucket->bk_items);
struct fx_dict_bucket_item *first_item
= fx_unbox(struct fx_dict_bucket_item, first_entry, bi_entry);
if (!first_item) {
return true;
}
return false;
}
static bool get_next_node(
struct fx_bst_node *cur_node,
struct fx_queue_entry *cur_entry,
struct fx_bst_node **out_next_node,
struct fx_queue_entry **out_next_entry)
{
struct fx_dict_bucket *cur_bucket
= fx_unbox(struct fx_dict_bucket, cur_node, bk_node);
if (!cur_bucket) {
return false;
}
struct fx_dict_bucket_item *cur_item
= fx_unbox(struct fx_dict_bucket_item, cur_entry, bi_entry);
if (!cur_item) {
return false;
}
struct fx_bst_node *next_node = cur_node;
struct fx_queue_entry *next_entry = fx_queue_next(cur_entry);
if (!next_entry) {
next_node = fx_bst_next(cur_node);
if (!next_node) {
return false;
}
struct fx_dict_bucket *next_bucket
= fx_unbox(struct fx_dict_bucket, next_node, bk_node);
if (!next_bucket) {
return false;
}
next_entry = fx_queue_first(&next_bucket->bk_items);
if (!next_entry) {
return false;
}
}
struct fx_dict_bucket_item *next_item
= fx_unbox(struct fx_dict_bucket_item, next_entry, bi_entry);
if (!next_item) {
return false;
}
*out_next_node = next_node;
*out_next_entry = next_entry;
return true;
}
static fx_status delete_item(
struct fx_dict_p *dict,
struct fx_dict_bucket *bucket,
struct fx_dict_bucket_item *item)
{
fx_queue_delete(&bucket->bk_items, &item->bi_entry);
free(item);
if (fx_queue_empty(&bucket->bk_items)) {
fx_bst_delete(&dict->d_buckets, &bucket->bk_node);
free(bucket);
}
return FX_SUCCESS;
}
/*** PUBLIC FUNCTIONS *********************************************************/
#if 0
fx_dict *fx_dict_create_with_items(const fx_dict_item *items)
{
fx_dict *dict = fx_dict_create();
if (!dict) {
return NULL;
}
struct fx_dict_p *p = fx_object_get_private(dict, FX_TYPE_DICT);
for (size_t i = 0; items[i].key; i++) {
dict_put(p, items[i].key, items[i].value);
}
return dict;
}
#endif
fx_status fx_dict_put(fx_dict *dict, const char *key, fx_object *value)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_put, dict, key, value);
}
fx_status fx_dict_put_sk(fx_dict *dict, const fx_string *key, fx_object *value)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_put_sk, dict, key, value);
}
fx_object *fx_dict_at(const fx_dict *dict, const char *key)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_at, dict, key);
}
fx_object *fx_dict_at_sk(const fx_dict *dict, const fx_string *key)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_at_sk, dict, key);
}
fx_object *fx_dict_get(fx_dict *dict, const char *key)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_get, dict, key);
}
fx_object *fx_dict_get_sk(fx_dict *dict, const fx_string *key)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_get_sk, dict, key);
}
bool fx_dict_has_key(const fx_dict *dict, const char *key)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_has_key, dict, key);
}
bool fx_dict_has_skey(const fx_dict *dict, const fx_string *key)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_has_skey, dict, key);
}
size_t fx_dict_get_size(const fx_dict *dict)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DICT, dict_get_size, dict);
}
bool fx_dict_is_empty(const fx_dict *dict)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DICT, dict_is_empty, dict);
}
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
/*** VIRTUAL FUNCTIONS ********************************************************/
static void dict_init(fx_object *obj, void *priv)
{
struct fx_dict_p *dict = priv;
}
static void dict_fini(fx_object *obj, void *priv)
{
struct fx_dict_p *dict = priv;
struct fx_bst_node *node = fx_bst_first(&dict->d_buckets);
while (node) {
struct fx_dict_bucket *bucket
= fx_unbox(struct fx_dict_bucket, node, bk_node);
struct fx_bst_node *next_node = fx_bst_next(node);
fx_bst_delete(&dict->d_buckets, node);
struct fx_queue_entry *entry
= fx_queue_first(&bucket->bk_items);
while (entry) {
struct fx_dict_bucket_item *item = fx_unbox(
struct fx_dict_bucket_item,
entry,
bi_entry);
struct fx_queue_entry *next_entry
= fx_queue_next(entry);
fx_queue_delete(&bucket->bk_items, entry);
free(item->bi_str);
fx_object_unref(item->bi_value);
free(item);
entry = next_entry;
}
free(bucket);
node = next_node;
}
}
static void dict_to_string(const fx_object *obj, fx_stream *out)
{
struct fx_dict_p *dict = fx_object_get_private(obj, FX_TYPE_DICT);
if (dict_is_empty(dict)) {
fx_stream_write_cstr(out, "{}", NULL);
return;
}
fx_stream_write_cstr(out, "{\n", NULL);
fx_stream_push_indent(out, 1);
size_t len = dict_get_size(dict);
size_t i = 0;
struct fx_bst_node *node = fx_bst_first(&dict->d_buckets);
while (node) {
struct fx_dict_bucket *bucket
= fx_unbox(struct fx_dict_bucket, node, bk_node);
struct fx_queue_entry *entry
= fx_queue_first(&bucket->bk_items);
while (entry) {
struct fx_dict_bucket_item *item = fx_unbox(
struct fx_dict_bucket_item,
entry,
bi_entry);
fx_object_to_string(item->bi_str, out);
fx_stream_write_cstr(out, ": ", NULL);
bool is_string = fx_object_is_type(
item->bi_value,
FX_TYPE_STRING);
if (is_string) {
fx_stream_write_char(out, '"');
}
fx_object_to_string(item->bi_value, out);
if (is_string) {
fx_stream_write_char(out, '"');
}
if (i < len - 1) {
fx_stream_write_cstr(out, ",", NULL);
}
fx_stream_write_char(out, '\n');
entry = fx_queue_next(entry);
i++;
}
node = fx_bst_next(node);
}
fx_stream_pop_indent(out);
fx_stream_write_char(out, '}');
}
/*** ITERATOR FUNCTIONS *******************************************************/
static fx_iterator *iterable_begin(fx_dict *dict)
{
fx_iterator *it_obj = fx_object_create(FX_TYPE_DICT_ITERATOR);
if (!it_obj) {
return NULL;
}
struct fx_dict_iterator_p *it
= fx_object_get_private(it_obj, FX_TYPE_DICT_ITERATOR);
it->i = 0;
it->_d = dict;
it->_d_p = fx_object_get_private(dict, FX_TYPE_DICT);
if (dict_is_empty(it->_d_p)) {
it->item.key = NULL;
it->item.value = NULL;
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
return it_obj;
}
fx_bst_node *first_node = fx_bst_first(&it->_d_p->d_buckets);
struct fx_dict_bucket *first_bucket
= fx_unbox(struct fx_dict_bucket, first_node, bk_node);
if (!first_bucket) {
it->item.key = NULL;
it->item.value = NULL;
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
return it_obj;
}
fx_queue_entry *first_entry = fx_queue_first(&first_bucket->bk_items);
struct fx_dict_bucket_item *first_item
= fx_unbox(struct fx_dict_bucket_item, first_entry, bi_entry);
if (!first_item) {
it->item.key = NULL;
it->item.value = NULL;
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
return it_obj;
}
it->item.key = first_item->bi_str;
it->item.value = first_item->bi_value;
it->_d = dict;
it->_cbn = first_node;
it->_cqe = first_entry;
return it_obj;
}
static const fx_iterator *iterable_cbegin(const fx_dict *dict)
{
fx_iterator *it_obj = fx_object_create(FX_TYPE_DICT_ITERATOR);
if (!it_obj) {
return NULL;
}
struct fx_dict_iterator_p *it
= fx_object_get_private(it_obj, FX_TYPE_DICT_ITERATOR);
it->i = 0;
it->_d = (fx_dict *)dict;
it->_d_p = fx_object_get_private(dict, FX_TYPE_DICT);
if (dict_is_empty(it->_d_p)) {
it->item.key = NULL;
it->item.value = NULL;
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
return it_obj;
}
fx_bst_node *first_node = fx_bst_first(&it->_d_p->d_buckets);
struct fx_dict_bucket *first_bucket
= fx_unbox(struct fx_dict_bucket, first_node, bk_node);
if (!first_bucket) {
it->item.key = NULL;
it->item.value = NULL;
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
return it_obj;
}
fx_queue_entry *first_entry = fx_queue_first(&first_bucket->bk_items);
struct fx_dict_bucket_item *first_item
= fx_unbox(struct fx_dict_bucket_item, first_entry, bi_entry);
if (!first_item) {
it->item.key = NULL;
it->item.value = NULL;
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
return it_obj;
}
it->item.key = first_item->bi_str;
it->item.value = first_item->bi_value;
it->_cbn = first_node;
it->_cqe = first_entry;
return it_obj;
}
static enum fx_status iterator_move_next(const fx_iterator *obj)
{
struct fx_dict_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_DICT_ITERATOR);
struct fx_bst_node *next_node;
struct fx_queue_entry *next_entry;
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
it->item.key = NULL;
it->item.value = NULL;
return FX_ERR_NO_DATA;
}
struct fx_dict_bucket_item *next_item
= fx_unbox(struct fx_dict_bucket_item, next_entry, bi_entry);
if (!next_item) {
it->item.key = NULL;
it->item.value = NULL;
return FX_ERR_NO_DATA;
}
it->i++;
it->item.key = next_item->bi_str;
it->item.value = next_item->bi_value;
it->_cbn = next_node;
it->_cqe = next_entry;
return FX_SUCCESS;
}
static enum fx_status iterator_erase(fx_iterator *obj)
{
struct fx_dict_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_DICT_ITERATOR);
if ((it->item.key || it->item.value) && !(it->_cbn && it->_cqe)) {
return FX_ERR_BAD_STATE;
}
if (!it->item.key || !it->_cqe) {
return FX_ERR_NO_DATA;
}
struct fx_bst_node *next_node;
struct fx_queue_entry *next_entry;
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
it->item.key = NULL;
it->item.value = NULL;
return FX_ERR_NO_DATA;
}
struct fx_dict_bucket *cur_bucket
= fx_unbox(struct fx_dict_bucket, it->_cbn, bk_node);
struct fx_dict_bucket_item *cur_item
= fx_unbox(struct fx_dict_bucket_item, it->_cqe, bi_entry);
struct fx_dict_bucket_item *next_item
= fx_unbox(struct fx_dict_bucket_item, next_entry, bi_entry);
fx_status status = delete_item(it->_d_p, cur_bucket, cur_item);
if (FX_ERR(status)) {
return status;
}
if (next_item) {
it->item.key = next_item->bi_str;
it->item.value = next_item->bi_value;
it->_cbn = next_node;
it->_cqe = next_entry;
} else {
it->item.key = NULL;
it->item.value = NULL;
it->_cbn = NULL;
it->_cqe = NULL;
}
return FX_SUCCESS;
}
static fx_iterator_value iterator_get_value(fx_iterator *obj)
{
struct fx_dict_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_DICT_ITERATOR);
return FX_ITERATOR_VALUE_PTR(&it->item);
}
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
{
struct fx_dict_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_DICT_ITERATOR);
return FX_ITERATOR_VALUE_CPTR(&it->item);
}
/*** CLASS DEFINITION *********************************************************/
// ---- fx_dict DEFINITION
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_dict)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = dict_to_string;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
FX_INTERFACE_ENTRY(it_begin) = iterable_begin;
FX_INTERFACE_ENTRY(it_cbegin) = iterable_cbegin;
FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
FX_TYPE_CLASS_DEFINITION_END(fx_dict)
FX_TYPE_DEFINITION_BEGIN(fx_dict)
FX_TYPE_ID(0xd2af61d9, 0xd0be, 0x4960, 0xbe3f, 0x509749814c10);
FX_TYPE_CLASS(fx_dict_class);
FX_TYPE_IMPLEMENTS(FX_TYPE_ITERABLE);
FX_TYPE_INSTANCE_PRIVATE(struct fx_dict_p);
FX_TYPE_INSTANCE_INIT(dict_init);
FX_TYPE_INSTANCE_FINI(dict_fini);
FX_TYPE_DEFINITION_END(fx_dict)
// ---- fx_dict_iterator DEFINITION
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_dict_iterator)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
FX_TYPE_CLASS_DEFINITION_END(fx_dict_iterator)
FX_TYPE_DEFINITION_BEGIN(fx_dict_iterator)
FX_TYPE_ID(0x9ea96701, 0x1713, 0x4a3e, 0xbf63, 0xdc856b456f3b);
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
FX_TYPE_CLASS(fx_dict_iterator_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_dict_iterator_p);
FX_TYPE_DEFINITION_END(fx_dict_iterator)
+598
View File
@@ -0,0 +1,598 @@
#include <fx/core/misc.h>
#include <fx/core/status.h>
#include <fx/ds/hashmap.h>
#include <fx/ds/string.h>
#include <stdbool.h>
#include <stdlib.h>
#define HASH_OFFSET_BASIS 0xcbf29ce484222325
#define HASH_PRIME 0x100000001b3
/*** PRIVATE DATA *************************************************************/
struct fx_hashmap_bucket_item {
struct fx_queue_entry bi_entry;
struct fx_hashmap_key bi_key;
struct fx_hashmap_value bi_value;
};
struct fx_hashmap_bucket {
struct fx_bst_node bk_node;
uint64_t bk_hash;
struct fx_queue bk_items;
};
struct fx_hashmap_p {
size_t h_count;
struct fx_bst h_buckets;
fx_hashmap_key_destructor h_key_dtor;
fx_hashmap_value_destructor h_value_dtor;
};
struct fx_hashmap_iterator_p {
size_t i;
fx_hashmap_item item;
fx_hashmap *_h;
struct fx_hashmap_p *_h_p;
fx_bst_node *_cbn;
fx_queue_entry *_cqe;
};
/*** PRIVATE FUNCTIONS ********************************************************/
static FX_BST_DEFINE_SIMPLE_GET(
struct fx_hashmap_bucket, uint64_t, bk_node, bk_hash, get_bucket);
static FX_BST_DEFINE_SIMPLE_INSERT(
struct fx_hashmap_bucket, bk_node, bk_hash, put_bucket);
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 uint64_t hash_key(const struct fx_hashmap_key *key)
{
if (key->key_flags & FX_HASHMAP_KEY_F_INTVALUE) {
return hash_data(&key->key_data, sizeof key->key_data);
} else {
return hash_data(key->key_data, key->key_size);
}
}
static bool compare_key(
const struct fx_hashmap_key *a, const struct fx_hashmap_key *b)
{
const void *a_data = NULL, *fx_data = NULL;
size_t a_len = 0, fx_len = 0;
if (a->key_flags & FX_HASHMAP_KEY_F_INTVALUE) {
a_data = &a->key_data;
a_len = sizeof a->key_data;
} else {
a_data = a->key_data;
a_len = a->key_size;
}
if (b->key_flags & FX_HASHMAP_KEY_F_INTVALUE) {
fx_data = &b->key_data;
fx_len = sizeof b->key_data;
} else {
fx_data = b->key_data;
fx_len = b->key_size;
}
if (a_len != fx_len) {
return false;
}
size_t cmp_len = a_len;
return memcmp(a_data, fx_data, cmp_len) == 0;
}
static bool get_next_node(
struct fx_bst_node *cur_node, struct fx_queue_entry *cur_entry,
struct fx_bst_node **out_next_node, struct fx_queue_entry **out_next_entry)
{
struct fx_hashmap_bucket *cur_bucket
= fx_unbox(struct fx_hashmap_bucket, cur_node, bk_node);
if (!cur_bucket) {
return false;
}
struct fx_hashmap_bucket_item *cur_item
= fx_unbox(struct fx_hashmap_bucket_item, cur_entry, bi_entry);
if (!cur_item) {
return false;
}
struct fx_bst_node *next_node = cur_node;
struct fx_queue_entry *next_entry = fx_queue_next(cur_entry);
if (!next_entry) {
next_node = fx_bst_next(cur_node);
if (!next_node) {
return false;
}
struct fx_hashmap_bucket *next_bucket
= fx_unbox(struct fx_hashmap_bucket, next_node, bk_node);
if (!next_bucket) {
return false;
}
next_entry = fx_queue_first(&next_bucket->bk_items);
if (!next_entry) {
return false;
}
}
struct fx_hashmap_bucket_item *next_item
= fx_unbox(struct fx_hashmap_bucket_item, next_entry, bi_entry);
if (!next_item) {
return false;
}
*out_next_node = next_node;
*out_next_entry = next_entry;
return true;
}
static struct fx_hashmap_bucket *create_bucket(void)
{
struct fx_hashmap_bucket *bucket = malloc(sizeof *bucket);
if (!bucket) {
return NULL;
}
memset(bucket, 0x0, sizeof *bucket);
return bucket;
}
static struct fx_hashmap_bucket_item *create_bucket_item(void)
{
struct fx_hashmap_bucket_item *item = malloc(sizeof *item);
if (!item) {
return NULL;
}
memset(item, 0x0, sizeof *item);
return item;
}
static fx_status hashmap_put(
struct fx_hashmap_p *hashmap, const fx_hashmap_key *key,
const fx_hashmap_value *value)
{
uint64_t hash = hash_key(key);
struct fx_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
if (!bucket) {
bucket = create_bucket();
if (!bucket) {
return FX_ERR_NO_MEMORY;
}
bucket->bk_hash = hash;
put_bucket(&hashmap->h_buckets, bucket);
}
struct fx_queue_entry *entry = fx_queue_first(&bucket->bk_items);
while (entry) {
struct fx_hashmap_bucket_item *item
= fx_unbox(struct fx_hashmap_bucket_item, entry, bi_entry);
if (compare_key(&item->bi_key, key)) {
memcpy(&item->bi_value, value, sizeof *value);
return FX_SUCCESS;
}
entry = fx_queue_next(entry);
}
struct fx_hashmap_bucket_item *item = create_bucket_item();
if (!item) {
return FX_ERR_NO_MEMORY;
}
memcpy(&item->bi_key, key, sizeof *key);
memcpy(&item->bi_value, value, sizeof *value);
fx_queue_push_back(&bucket->bk_items, &item->bi_entry);
hashmap->h_count++;
return FX_SUCCESS;
}
static const struct fx_hashmap_value *hashmap_get(
const struct fx_hashmap_p *hashmap, const struct fx_hashmap_key *key)
{
uint64_t hash = hash_key(key);
struct fx_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
if (!bucket) {
return NULL;
}
struct fx_queue_entry *entry = fx_queue_first(&bucket->bk_items);
while (entry) {
struct fx_hashmap_bucket_item *item
= fx_unbox(struct fx_hashmap_bucket_item, entry, bi_entry);
if (compare_key(&item->bi_key, key)) {
return &item->bi_value;
}
entry = fx_queue_next(entry);
}
return NULL;
}
static bool hashmap_has_key(
const struct fx_hashmap_p *hashmap, const fx_hashmap_key *key)
{
uint64_t hash = hash_key(key);
struct fx_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
if (!bucket) {
return false;
}
struct fx_queue_entry *entry = fx_queue_first(&bucket->bk_items);
while (entry) {
struct fx_hashmap_bucket_item *item
= fx_unbox(struct fx_hashmap_bucket_item, entry, bi_entry);
if (compare_key(&item->bi_key, key)) {
return true;
}
entry = fx_queue_next(entry);
}
return false;
}
static size_t hashmap_get_size(const struct fx_hashmap_p *hashmap)
{
return hashmap->h_count;
}
static bool hashmap_is_empty(const struct fx_hashmap_p *hashmap)
{
fx_bst_node *first_node = fx_bst_first(&hashmap->h_buckets);
struct fx_hashmap_bucket *first_bucket
= fx_unbox(struct fx_hashmap_bucket, first_node, bk_node);
if (!first_bucket) {
return true;
}
fx_queue_entry *first_entry = fx_queue_first(&first_bucket->bk_items);
struct fx_hashmap_bucket_item *first_item
= fx_unbox(struct fx_hashmap_bucket_item, first_entry, bi_entry);
if (!first_item) {
return true;
}
return false;
}
static fx_status delete_item(
struct fx_hashmap_p *hashmap, struct fx_hashmap_bucket *bucket,
struct fx_hashmap_bucket_item *item)
{
fx_queue_delete(&bucket->bk_items, &item->bi_entry);
if (hashmap->h_key_dtor) {
hashmap->h_key_dtor((void *)item->bi_key.key_data);
}
if (hashmap->h_value_dtor) {
hashmap->h_value_dtor((void *)item->bi_value.value_data);
}
free(item);
if (fx_queue_empty(&bucket->bk_items)) {
fx_bst_delete(&hashmap->h_buckets, &bucket->bk_node);
free(bucket);
}
hashmap->h_count--;
return FX_SUCCESS;
}
/*** PUBLIC FUNCTIONS *********************************************************/
fx_hashmap *fx_hashmap_create(
fx_hashmap_key_destructor key_dtor, fx_hashmap_value_destructor value_dtor)
{
fx_hashmap *hashmap = fx_object_create(FX_TYPE_HASHMAP);
if (!hashmap) {
return NULL;
}
return hashmap;
}
fx_hashmap *fx_hashmap_create_with_items(const fx_hashmap_item *items)
{
fx_hashmap *hashmap = fx_hashmap_create(NULL, NULL);
if (!hashmap) {
return NULL;
}
struct fx_hashmap_p *p = fx_object_get_private(hashmap, FX_TYPE_HASHMAP);
for (size_t i = 0; items[i].key.key_data && items[i].key.key_size; i++) {
hashmap_put(p, &items[i].key, &items[i].value);
}
return hashmap;
}
fx_status fx_hashmap_put(
fx_hashmap *hashmap, const fx_hashmap_key *key, const fx_hashmap_value *value)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_HASHMAP, hashmap_put, hashmap, key, value);
}
const struct fx_hashmap_value *fx_hashmap_get(
const fx_hashmap *hashmap, const struct fx_hashmap_key *key)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_HASHMAP, hashmap_get, hashmap, key);
}
bool fx_hashmap_has_key(const fx_hashmap *hashmap, const fx_hashmap_key *key)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_HASHMAP, hashmap_has_key, hashmap, key);
}
size_t fx_hashmap_get_size(const fx_hashmap *hashmap)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_HASHMAP, hashmap_get_size, hashmap);
}
bool fx_hashmap_is_empty(const fx_hashmap *hashmap)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_HASHMAP, hashmap_is_empty, hashmap);
}
fx_iterator *fx_hashmap_begin(fx_hashmap *hashmap)
{
fx_hashmap_iterator *it_obj = fx_object_create(FX_TYPE_HASHMAP_ITERATOR);
struct fx_hashmap_iterator_p *it
= fx_object_get_private(it_obj, FX_TYPE_HASHMAP_ITERATOR);
it->_h = hashmap;
it->_h_p = fx_object_get_private(hashmap, FX_TYPE_HASHMAP);
it->i = 0;
if (fx_hashmap_is_empty(hashmap)) {
memset(&it->item, 0x0, sizeof it->item);
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
return it_obj;
}
struct fx_bst_node *first_node = fx_bst_first(&it->_h_p->h_buckets);
struct fx_hashmap_bucket *first_bucket
= fx_unbox(struct fx_hashmap_bucket, first_node, bk_node);
if (!first_bucket) {
memset(&it->item, 0x0, sizeof it->item);
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
return it_obj;
}
struct fx_queue_entry *first_entry = fx_queue_first(&first_bucket->bk_items);
struct fx_hashmap_bucket_item *first_item
= fx_unbox(struct fx_hashmap_bucket_item, first_entry, bi_entry);
if (!first_item) {
memset(&it->item, 0x0, sizeof it->item);
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
return it_obj;
}
memcpy(&it->item.key, &first_item->bi_key, sizeof it->item.key);
memcpy(&it->item.value, &first_item->bi_value, sizeof it->item.value);
it->_cbn = first_node;
it->_cqe = first_entry;
return it_obj;
}
const fx_iterator *fx_hashmap_cbegin(const fx_hashmap *hashmap)
{
return fx_hashmap_begin((fx_hashmap *)hashmap);
}
/*** VIRTUAL FUNCTIONS ********************************************************/
static void hashmap_init(fx_object *obj, void *priv)
{
struct fx_hashmap_p *map = priv;
}
static void hashmap_fini(fx_object *obj, void *priv)
{
struct fx_hashmap_p *map = priv;
struct fx_bst_node *node = fx_bst_first(&map->h_buckets);
while (node) {
struct fx_hashmap_bucket *b
= fx_unbox(struct fx_hashmap_bucket, node, bk_node);
struct fx_bst_node *next_node = fx_bst_next(node);
fx_bst_delete(&map->h_buckets, node);
struct fx_queue_entry *entry = fx_queue_first(&b->bk_items);
while (entry) {
struct fx_hashmap_bucket_item *item = fx_unbox(
struct fx_hashmap_bucket_item, entry, bi_entry);
struct fx_queue_entry *next_entry = fx_queue_next(entry);
fx_queue_delete(&b->bk_items, entry);
if (map->h_key_dtor) {
map->h_key_dtor((void *)item->bi_key.key_data);
}
if (map->h_value_dtor) {
map->h_value_dtor((void *)item->bi_value.value_data);
}
free(item);
entry = next_entry;
}
free(b);
node = next_node;
}
}
/*** ITERATOR FUNCTIONS *******************************************************/
static enum fx_status iterator_move_next(const fx_iterator *obj)
{
struct fx_hashmap_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_HASHMAP_ITERATOR);
struct fx_bst_node *next_node;
struct fx_queue_entry *next_entry;
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
memset(&it->item, 0x0, sizeof it->item);
return FX_ERR_NO_DATA;
}
struct fx_hashmap_bucket_item *next_item
= fx_unbox(struct fx_hashmap_bucket_item, next_entry, bi_entry);
if (!next_item) {
memset(&it->item, 0x0, sizeof it->item);
return FX_ERR_NO_DATA;
}
it->i++;
memcpy(&it->item.key, &next_item->bi_key, sizeof it->item.key);
memcpy(&it->item.value, &next_item->bi_value, sizeof it->item.value);
it->_cbn = next_node;
it->_cqe = next_entry;
return FX_SUCCESS;
}
static enum fx_status iterator_erase(fx_iterator *obj)
{
struct fx_hashmap_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_HASHMAP_ITERATOR);
if ((it->item.key.key_data || it->item.value.value_data)
&& !(it->_cbn && it->_cqe)) {
return FX_ERR_BAD_STATE;
}
if (!it->item.key.key_data || !it->_cqe) {
return FX_ERR_NO_DATA;
}
struct fx_bst_node *next_node;
struct fx_queue_entry *next_entry;
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
memset(&it->item, 0x0, sizeof it->item);
return FX_ERR_NO_DATA;
}
struct fx_hashmap_bucket *cur_bucket
= fx_unbox(struct fx_hashmap_bucket, it->_cbn, bk_node);
struct fx_hashmap_bucket_item *cur_item
= fx_unbox(struct fx_hashmap_bucket_item, it->_cqe, bi_entry);
struct fx_hashmap_bucket_item *next_item
= fx_unbox(struct fx_hashmap_bucket_item, next_entry, bi_entry);
fx_status status = delete_item(it->_h_p, cur_bucket, cur_item);
if (FX_ERR(status)) {
return status;
}
if (next_item) {
memcpy(&it->item.key, &next_item->bi_key, sizeof it->item.key);
memcpy(&it->item.value, &next_item->bi_value,
sizeof it->item.value);
it->_cbn = next_node;
it->_cqe = next_entry;
} else {
memset(&it->item, 0x0, sizeof it->item);
it->_cbn = NULL;
it->_cqe = NULL;
}
return FX_SUCCESS;
}
static fx_iterator_value iterator_get_value(fx_iterator *obj)
{
struct fx_hashmap_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_HASHMAP_ITERATOR);
return FX_ITERATOR_VALUE_PTR(&it->item);
}
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
{
const struct fx_hashmap_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_HASHMAP_ITERATOR);
return FX_ITERATOR_VALUE_CPTR(&it->item);
}
/*** CLASS DEFINITION *********************************************************/
// ---- fx_hashmap DEFINITION
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_hashmap)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
FX_INTERFACE_ENTRY(it_begin) = fx_hashmap_begin;
FX_INTERFACE_ENTRY(it_cbegin) = fx_hashmap_cbegin;
FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
FX_TYPE_CLASS_DEFINITION_END(fx_hashmap)
FX_TYPE_DEFINITION_BEGIN(fx_hashmap)
FX_TYPE_ID(0x7bf5bcd1, 0x1ff3, 0x4e43, 0xbed8, 0x7c74f28348bf);
FX_TYPE_CLASS(fx_hashmap_class);
FX_TYPE_IMPLEMENTS(FX_TYPE_ITERABLE);
FX_TYPE_INSTANCE_PRIVATE(struct fx_hashmap_p);
FX_TYPE_INSTANCE_INIT(hashmap_init);
FX_TYPE_INSTANCE_FINI(hashmap_fini);
FX_TYPE_DEFINITION_END(fx_hashmap)
// ---- fx_hashmap_iterator DEFINITION
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_hashmap_iterator)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
FX_TYPE_CLASS_DEFINITION_END(fx_hashmap_iterator)
FX_TYPE_DEFINITION_BEGIN(fx_hashmap_iterator)
FX_TYPE_ID(0xd9658456, 0xdd80, 0x419a, 0xb23a, 0xb513013e6431);
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
FX_TYPE_CLASS(fx_hashmap_iterator_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_hashmap_iterator_p);
FX_TYPE_DEFINITION_END(fx_hashmap_iterator)
View File
+218
View File
@@ -0,0 +1,218 @@
/**
* A heterogeneous array of objects. fx_array only stores references
* to the objects that it contains, not the object data itself.
*
* fx_array stores pointers to objects in a single contiguous array,
* but this is an implementation detail that may change in the future.
* Users of fx_array should not rely on this being the case.
*/
#ifndef FX_DS_ARRAY_H_
#define FX_DS_ARRAY_H_
#include <fx/core/iterator.h>
#include <fx/core/macros.h>
#include <fx/core/misc.h>
#include <fx/core/status.h>
FX_DECLS_BEGIN;
#define FX_TYPE_ARRAY (fx_array_get_type())
#define FX_TYPE_ARRAY_ITERATOR (fx_array_iterator_get_type())
struct fx_array_p;
FX_DECLARE_TYPE(fx_array);
FX_DECLARE_TYPE(fx_array_iterator);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_array)
FX_TYPE_CLASS_DECLARATION_END(fx_array)
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_array_iterator)
FX_TYPE_CLASS_DECLARATION_END(fx_array_iterator)
FX_API fx_type fx_array_get_type(void);
FX_API fx_type fx_array_iterator_get_type(void);
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_array, FX_TYPE_ARRAY);
/**
* Creates an fx_array initialised with the contents of the provided
* fx_object pointer array. The fx_array will take a reference to each
* object specified in `values`, and will increment the reference count.
* The order of objects in the new fx_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 fx_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 fx_array.
* @param nr_values The size of the `values` array.
* @return A pointer to the new fx_array, or NULL if an error occurred.
*/
FX_API fx_array *fx_array_create_with_values(
fx_object *const *values, size_t nr_values);
/**
* Remove all object references from an fx_array, resetting the size of the array to zero.
* The reference counts of all objects in the array will be decremented.
*
* @param array The fx_array to clear.
*/
FX_API void fx_array_clear(fx_array *array);
/**
* Inserts an object at the end of an fx_array. The reference count of
* the object will be incremented.
*
* @param array The fx_array to append the object to.
* @param value The object to append.
* @return FX_SUCCESS if the object was appended successfully, or an
* error code if an error occurred.
*/
FX_API fx_status fx_array_append(fx_array *array, fx_object *value);
/**
* Inserts an object at the beginning of an fx_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 fx_array to prepend the object to.
* @param value The object to prepend.
* @return FX_SUCCESS if the object was prepended successfully, or an
* error code if an error occurred.
*/
FX_API fx_status fx_array_prepend(fx_array *array, fx_object *value);
/**
* Inserts an object into an fx_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 fx_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
* `FX_NPOS`, the object will be inserted at the end of the fx_array.
* @return FX_SUCCESS if the object was inserted, or a status code
* describing any error that occurred.
*/
FX_API fx_status fx_array_insert(fx_array *array, fx_object *value, size_t at);
/**
* Removes the object at the specified index from an fx_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 fx_array to remove the object from.
* @param at The index of the object to be removed.
* @return FX_SUCCESS if the object was removed, or a status code
* describing any error that occurred.
*/
FX_API fx_status fx_array_remove(fx_array *array, size_t at);
/**
* Removes the object at the beginning of an fx_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 fx_array to remove the object from.
* @return FX_SUCCESS if the object was removed, or a status code describing any error that occurred.
*/
FX_API fx_status fx_array_remove_front(fx_array *array);
/**
* Removes the object at the end of an fx_array. The reference count
* of the removed object will be decremented.
*
* @param array The fx_array to remove the object from.
* @return FX_SUCCESS if the object was removed, or a status code describing any error that occurred.
*/
FX_API fx_status fx_array_remove_back(fx_array *array);
/**
* Removes the object at the specified index of an fx_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 fx_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.
*/
FX_API fx_object *fx_array_pop(fx_array *array, size_t at);
/**
* Removes the object at the beginning of an fx_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 fx_array will be moved to
* fill the empty space left by the removed object.
*
* @param array The fx_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.
*/
FX_API fx_object *fx_array_pop_front(fx_array *array);
/**
* Removes the object at the end of an fx_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 fx_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.
*/
FX_API fx_object *fx_array_pop_back(fx_array *array);
/**
* Returns an unowned pointer to the object at the given index of an fx_array.
* The caller does not own the returned pointer, and MUST NOT release it.
*
* @param array The fx_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.
*/
FX_API fx_object *fx_array_at(const fx_array *array, size_t at);
/**
* Returns an owned pointer to the object at the given index of an
* fx_array. The caller owns the returned pointer, and must release it
* when they are finished with it.
*
* @param array The fx_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.
*/
FX_API fx_object *fx_array_get(fx_array *array, size_t at);
/**
* Returns the number of objects contained in an fx_array.
*
* @param array The fx_array.
* @return The number of objects contained in the fx_array.
*/
FX_API size_t fx_array_size(const fx_array *array);
/**
* Returns the current maximum capacity of an fx_array. This represents
* the number of objects that can be stored in an fx_array before its
* internal buffer would need to be re-sized.
*
* @param array The fx_array.
* @return The maximum capacity of the fx_array.
*/
FX_API size_t fx_array_capacity(const fx_array *array);
FX_DECLS_END;
#endif
+25
View File
@@ -0,0 +1,25 @@
#ifndef FX_DS_BITBUFFER_H_
#define FX_DS_BITBUFFER_H_
#include <fx/core/macros.h>
FX_DECLS_BEGIN;
FX_DECLARE_TYPE(fx_bitbuffer);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_bitbuffer)
;
FX_TYPE_CLASS_DECLARATION_END(fx_bitbuffer);
FX_API fx_status fx_bitbuffer_put_bit(fx_bitbuffer *buf, int bit);
FX_API fx_status fx_bitbuffer_put_bool(fx_bitbuffer *buf, bool b);
FX_API fx_status fx_bitbuffer_put_int(
fx_bitbuffer *buf, uint64_t v, unsigned int nr_bits);
FX_API fx_status fx_bitbuffer_put_bytes(
fx_bitbuffer *buf, const void *p, size_t len, size_t bits_per_byte);
FX_API fx_status fx_bitbuffer_put_string(
fx_bitbuffer *buf, const char *p, size_t len, size_t bits_per_char);
FX_DECLS_END;
#endif
+40
View File
@@ -0,0 +1,40 @@
#ifndef FX_DS_BITMAP_H_
#define FX_DS_BITMAP_H_
#include <fx/core/macros.h>
#include <fx/core/misc.h>
#include <stdbool.h>
FX_DECLS_BEGIN;
#define FX_TYPE_BITMAP (fx_bitmap_get_type())
FX_DECLARE_TYPE(fx_bitmap);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_bitmap)
FX_TYPE_CLASS_DECLARATION_END(fx_bitmap)
FX_API fx_type fx_bitmap_get_type(void);
FX_API fx_bitmap *fx_bitmap_create(size_t nr_bits);
FX_API void fx_bitmap_set_bit(fx_bitmap *map, size_t bit);
FX_API void fx_bitmap_clear_bit(fx_bitmap *map, size_t bit);
FX_API void fx_bitmap_set_range(fx_bitmap *map, size_t first_bit, size_t nbits);
FX_API void fx_bitmap_clear_range(fx_bitmap *map, size_t first_bit, size_t nbits);
FX_API void fx_bitmap_set_all(fx_bitmap *map);
FX_API void fx_bitmap_clear_all(fx_bitmap *map);
FX_API bool fx_bitmap_check_bit(const fx_bitmap *map, size_t bit);
FX_API size_t fx_bitmap_count_set_bits(const fx_bitmap *map);
FX_API size_t fx_bitmap_count_clear_bits(const fx_bitmap *map);
FX_API size_t fx_bitmap_highest_set_bit(const fx_bitmap *map);
FX_API size_t fx_bitmap_highest_clear_bit(const fx_bitmap *map);
FX_API size_t fx_bitmap_lowest_set_bit(const fx_bitmap *map);
FX_API size_t fx_bitmap_lowest_clear_bit(const fx_bitmap *map);
FX_DECLS_END;
#endif
+49
View File
@@ -0,0 +1,49 @@
#ifndef FX_DS_BUFFER_H_
#define FX_DS_BUFFER_H_
#include <fx/core/macros.h>
#include <stddef.h>
FX_DECLS_BEGIN;
#define FX_TYPE_BUFFER (fx_buffer_get_type())
FX_DECLARE_TYPE(fx_buffer);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_buffer)
FX_TYPE_CLASS_DECLARATION_END(fx_buffer)
FX_API fx_type fx_buffer_get_type(void);
FX_API fx_buffer *fx_buffer_create(size_t item_sz);
FX_API fx_buffer *fx_buffer_create_from_bytes(const void *p, size_t len);
FX_API fx_buffer *fx_buffer_create_from_array(
const void *p, size_t item_sz, size_t len);
FX_API void *fx_buffer_steal(fx_buffer *buf);
FX_API fx_status fx_buffer_reserve(fx_buffer *buf, size_t capacity);
FX_API fx_status fx_buffer_resize(fx_buffer *buf, size_t length);
FX_API fx_status fx_buffer_append(fx_buffer *dest, const void *p, size_t count);
FX_API fx_status fx_buffer_prepend(fx_buffer *dest, const void *p, size_t count);
FX_API fx_status fx_buffer_insert(
fx_buffer *dest, const void *p, size_t count, size_t at);
FX_API fx_status fx_buffer_remove(fx_buffer *dest, size_t at, size_t count);
FX_API fx_status fx_buffer_clear(fx_buffer *buf);
FX_API fx_status fx_buffer_push_back(fx_buffer *buf, size_t count, void **p);
FX_API fx_status fx_buffer_push_front(fx_buffer *buf, size_t count, void **p);
FX_API fx_status fx_buffer_pop_back(fx_buffer *buf, size_t count);
FX_API fx_status fx_buffer_pop_front(fx_buffer *buf, size_t count);
FX_API size_t fx_buffer_get_size(const fx_buffer *buf);
FX_API size_t fx_buffer_get_item_size(const fx_buffer *buf);
FX_API size_t fx_buffer_get_capacity(const fx_buffer *buf);
FX_API void *fx_buffer_ptr(const fx_buffer *buf);
FX_API void *fx_buffer_get(const fx_buffer *buf, size_t at);
FX_DECLS_END;
#endif
+48
View File
@@ -0,0 +1,48 @@
#ifndef FX_DS_DATETIME_H_
#define FX_DS_DATETIME_H_
#include <fx/core/macros.h>
#include <fx/core/status.h>
#include <ctype.h>
FX_DECLS_BEGIN;
#define FX_TYPE_DATETIME (fx_datetime_get_type())
FX_DECLARE_TYPE(fx_datetime);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_datetime)
FX_TYPE_CLASS_DECLARATION_END(fx_datetime)
typedef enum fx_datetime_format {
FX_DATETIME_FORMAT_RFC3339 = 1,
} fx_datetime_format;
FX_API fx_type fx_datetime_get_type(void);
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_datetime, FX_TYPE_DATETIME);
FX_API fx_datetime *fx_datetime_parse(fx_datetime_format format, const char *s);
FX_API void fx_datetime_to_string(
const fx_datetime *dt, fx_datetime_format format,
FX_TYPE_FWDREF(fx_stream) * dest);
FX_API bool fx_datetime_is_localtime(const fx_datetime *dt);
FX_API bool fx_datetime_has_date(const fx_datetime *dt);
FX_API bool fx_datetime_has_time(const fx_datetime *dt);
FX_API long fx_datetime_year(const fx_datetime *dt);
FX_API long fx_datetime_month(const fx_datetime *dt);
FX_API long fx_datetime_day(const fx_datetime *dt);
FX_API long fx_datetime_hour(const fx_datetime *dt);
FX_API long fx_datetime_minute(const fx_datetime *dt);
FX_API long fx_datetime_second(const fx_datetime *dt);
FX_API long fx_datetime_subsecond(const fx_datetime *dt);
FX_API bool fx_datetime_zone_offset_is_negative(const fx_datetime *dt);
FX_API long fx_datetime_zone_offset_hour(const fx_datetime *dt);
FX_API long fx_datetime_zone_offset_minute(const fx_datetime *dt);
FX_DECLS_END;
#endif
+62
View File
@@ -0,0 +1,62 @@
#ifndef FX_DS_DICT_H_
#define FX_DS_DICT_H_
#include <fx/core/bst.h>
#include <fx/core/macros.h>
#include <fx/core/misc.h>
#include <fx/core/queue.h>
#include <fx/core/status.h>
#include <fx/ds/string.h>
FX_DECLS_BEGIN;
#define FX_TYPE_DICT (fx_dict_get_type())
#define FX_TYPE_DICT_ITERATOR (fx_dict_iterator_get_type())
struct fx_dict_p;
FX_DECLARE_TYPE(fx_dict);
FX_DECLARE_TYPE(fx_dict_iterator);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_dict)
FX_TYPE_CLASS_DECLARATION_END(fx_dict)
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_dict_iterator)
FX_TYPE_CLASS_DECLARATION_END(fx_dict_iterator)
#define FX_DICT_ITEM(k, v) {.key = (k), .value = (v)}
#define FX_DICT_ITEM_END {.key = NULL, .value = NULL}
#define fx_dict_foreach(it, dict) \
for (int z__fx_unique_name() = fx_dict_iterator_begin(dict, it); \
(it)->key != NULL; fx_dict_iterator_next(it))
typedef struct fx_dict_item {
const fx_string *key;
fx_object *value;
} fx_dict_item;
FX_API fx_type fx_dict_get_type(void);
FX_API fx_type fx_dict_iterator_get_type(void);
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_dict, FX_TYPE_DICT);
#if 0
FX_API fx_dict *fx_dict_create_with_items(const fx_dict_item *items);
#endif
FX_API fx_status fx_dict_put(fx_dict *dict, const char *key, fx_object *value);
FX_API fx_status fx_dict_put_sk(fx_dict *dict, const fx_string *key, fx_object *value);
FX_API fx_object *fx_dict_at(const fx_dict *dict, const char *key);
FX_API fx_object *fx_dict_at_sk(const fx_dict *dict, const fx_string *key);
FX_API fx_object *fx_dict_get(fx_dict *dict, const char *key);
FX_API fx_object *fx_dict_get_sk(fx_dict *dict, const fx_string *key);
FX_API bool fx_dict_has_key(const fx_dict *dict, const char *key);
FX_API bool fx_dict_has_skey(const fx_dict *dict, const fx_string *key);
FX_API size_t fx_dict_get_size(const fx_dict *dict);
FX_API bool fx_dict_is_empty(const fx_dict *dict);
FX_DECLS_END;
#endif
+83
View File
@@ -0,0 +1,83 @@
#ifndef FX_DS_HASHMAP_H_
#define FX_DS_HASHMAP_H_
#include <fx/core/bst.h>
#include <fx/core/macros.h>
#include <fx/core/misc.h>
#include <fx/core/queue.h>
#include <fx/core/status.h>
#include <stddef.h>
FX_DECLS_BEGIN;
struct fx_hashmap_p;
#define FX_TYPE_HASHMAP (fx_hashmap_get_type())
#define FX_TYPE_HASHMAP_ITERATOR (fx_hashmap_iterator_get_type())
FX_DECLARE_TYPE(fx_hashmap);
FX_DECLARE_TYPE(fx_hashmap_iterator);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_hashmap)
FX_TYPE_CLASS_DECLARATION_END(fx_hashmap)
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_hashmap_iterator)
FX_TYPE_CLASS_DECLARATION_END(fx_hashmap_iterator)
#define FX_HASHMAP_KEY(k, ks) {.key_data = (k), .key_size = (ks)}
#define FX_HASHMAP_VALUE(v, vs) {.value_data = (v), .value_size = (vs)}
#define FX_HASHMAP_ITEM(k, ks, v, vs) \
{.key = FX_HASHMAP_KEY(k, ks), .value = FX_HASHMAP_VALUE(v, vs)}
#define FX_HASHMAP_ITEM_END {.key = {0}, .value = {0}}
#define fx_hashmap_foreach(it, hashmap) \
for (int z__fx_unique_name() = fx_hashmap_iterator_begin(hashmap, it); \
(it)->key != NULL; fx_hashmap_iterator_next(it))
typedef void (*fx_hashmap_key_destructor)(void *);
typedef void (*fx_hashmap_value_destructor)(void *);
typedef enum fx_hashmap_key_flags {
FX_HASHMAP_KEY_F_INTVALUE = 0x01u,
} fx_hashmap_key_flags;
typedef struct fx_hashmap_key {
fx_hashmap_key_flags key_flags;
const void *key_data;
size_t key_size;
} fx_hashmap_key;
typedef struct fx_hashmap_value {
void *value_data;
size_t value_size;
} fx_hashmap_value;
typedef struct fx_hashmap_item {
fx_hashmap_key key;
fx_hashmap_value value;
} fx_hashmap_item;
FX_API fx_type fx_hashmap_get_type(void);
FX_API fx_type fx_hashmap_iterator_get_type(void);
FX_API fx_hashmap *fx_hashmap_create(
fx_hashmap_key_destructor key_dtor, fx_hashmap_value_destructor value_dtor);
FX_API fx_hashmap *fx_hashmap_create_with_items(const fx_hashmap_item *items);
FX_API fx_status fx_hashmap_put(
fx_hashmap *hashmap, const fx_hashmap_key *key, const fx_hashmap_value *value);
FX_API const fx_hashmap_value *fx_hashmap_get(
const fx_hashmap *hashmap, const fx_hashmap_key *key);
FX_API bool fx_hashmap_has_key(const fx_hashmap *hashmap, const fx_hashmap_key *key);
FX_API size_t fx_hashmap_get_size(const fx_hashmap *hashmap);
FX_API bool fx_hashmap_is_empty(const fx_hashmap *hashmap);
FX_API fx_iterator *fx_hashmap_begin(fx_hashmap *hashmap);
FX_API const fx_iterator *fx_hashmap_cbegin(const fx_hashmap *hashmap);
FX_DECLS_END;
#endif
+63
View File
@@ -0,0 +1,63 @@
#ifndef FX_DS_LIST_H_
#define FX_DS_LIST_H_
#include <fx/core/iterator.h>
#include <fx/core/macros.h>
#include <fx/core/status.h>
FX_DECLS_BEGIN;
#define FX_TYPE_LIST (fx_list_get_type())
#define FX_TYPE_LIST_ITERATOR (fx_list_iterator_get_type())
struct fx_list_p;
FX_DECLARE_TYPE(fx_list);
FX_DECLARE_TYPE(fx_list_iterator);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_list)
FX_TYPE_CLASS_DECLARATION_END(fx_list)
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_list_iterator)
FX_TYPE_CLASS_DECLARATION_END(fx_list_iterator)
typedef struct fx_list_entry fx_list_entry;
FX_API fx_type fx_list_get_type(void);
FX_API fx_type fx_list_iterator_get_type(void);
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_list, FX_TYPE_LIST);
FX_API bool fx_list_empty(fx_list *q);
FX_API void *fx_list_first_item(const fx_list *q);
FX_API void *fx_list_last_item(const fx_list *q);
FX_API fx_list_entry *fx_list_first_entry(const fx_list *q);
FX_API fx_list_entry *fx_list_last_entry(const fx_list *q);
FX_API fx_list_entry *fx_list_next(const fx_list_entry *entry);
FX_API fx_list_entry *fx_list_prev(const fx_list_entry *entry);
FX_API size_t fx_list_length(const fx_list *q);
FX_API fx_list_entry *fx_list_insert_before(
fx_list *q, void *ptr, fx_list_entry *before);
FX_API fx_list_entry *fx_list_insert_after(
fx_list *q, void *ptr, fx_list_entry *after);
FX_API fx_list_entry *fx_list_push_front(fx_list *q, void *ptr);
FX_API fx_list_entry *fx_list_push_back(fx_list *q, void *ptr);
FX_API void *fx_list_pop_front(fx_list *q);
FX_API void *fx_list_pop_back(fx_list *q);
FX_API fx_status fx_list_delete_item(fx_list *q, void *ptr);
FX_API fx_status fx_list_delete_entry(fx_list *q, fx_list_entry *entry);
FX_API void fx_list_delete_all(fx_list *q);
FX_API void *fx_list_entry_value(const fx_list_entry *entry);
FX_API fx_iterator *fx_list_begin(fx_list *q);
FX_API const fx_iterator *fx_list_cbegin(const fx_list *q);
FX_DECLS_END;
#endif
+254
View File
@@ -0,0 +1,254 @@
#ifndef FX_DS_NUMBER_H
#define FX_DS_NUMBER_H
#include <fx/core/macros.h>
#include <stdbool.h>
FX_DECLS_BEGIN;
#define FX_INT8(v) (fx_number_create_int8(v))
#define FX_INT16(v) (fx_number_create_int16(v))
#define FX_INT32(v) (fx_number_create_int32(v))
#define FX_INT64(v) (fx_number_create_int64(v))
#define FX_FLOAT32(v) (fx_number_create_float32(v))
#define FX_FLOAT64(v) (fx_number_create_float64(v))
#define FX_CHAR(v) (fx_number_create_char(v))
#define FX_SHORT(v) (fx_number_create_short(v))
#define FX_INT(v) (fx_number_create_int(v))
#define FX_LONG(v) (fx_number_create_long(v))
#define FX_LONGLONG(v) (fx_number_create_longlong(v))
#define FX_FLOAT(v) (fx_number_create_float(v))
#define FX_DOUBLE(v) (fx_number_create_double(v))
#define FX_SIZE_T(v) (fx_number_create_size_t(v))
#define FX_RV_INT8(v) FX_RV(fx_number_create_int8(v))
#define FX_RV_INT16(v) FX_RV(fx_number_create_int16(v))
#define FX_RV_INT32(v) FX_RV(fx_number_create_int32(v))
#define FX_RV_INT64(v) FX_RV(fx_number_create_int64(v))
#define FX_RV_FLOAT32(v) FX_RV(fx_number_create_float32(v))
#define FX_RV_FLOAT64(v) FX_RV(fx_number_create_float64(v))
#define FX_RV_CHAR(v) FX_RV(fx_number_create_char(v))
#define FX_RV_SHORT(v) FX_RV(fx_number_create_short(v))
#define FX_RV_INT(v) FX_RV(fx_number_create_int(v))
#define FX_RV_LONG(v) FX_RV(fx_number_create_long(v))
#define FX_RV_LONGLONG(v) FX_RV(fx_number_create_longlong(v))
#define FX_RV_FLOAT(v) FX_RV(fx_number_create_float(v))
#define FX_RV_DOUBLE(v) FX_RV(fx_number_create_double(v))
#define FX_RV_SIZE_T(v) FX_RV(fx_number_create_size_t(v))
#define FX_NUMBER_IVAL(p) (fx_number_get_size_t(p))
#define FX_NUMBER_FVAL(p) (fx_number_get_double(p))
#define FX_TYPE_NUMBER (fx_number_get_type())
FX_DECLARE_TYPE(fx_number);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_number)
FX_TYPE_CLASS_DECLARATION_END(fx_number)
typedef enum fx_number_type {
FX_NUMBER_INT8,
FX_NUMBER_INT16,
FX_NUMBER_INT32,
FX_NUMBER_INT64,
FX_NUMBER_FLOAT32,
FX_NUMBER_FLOAT64,
FX_NUMBER_CHAR,
FX_NUMBER_SHORT,
FX_NUMBER_INT,
FX_NUMBER_LONG,
FX_NUMBER_LONGLONG,
FX_NUMBER_FLOAT,
FX_NUMBER_DOUBLE,
FX_NUMBER_SIZE_T,
FX_NUMBER_HANDLE,
FX_NUMBER_TYPE_COUNT,
FX_NUMBER_BYTE = FX_NUMBER_INT8,
FX_NUMBER_WORD = FX_NUMBER_INT16,
FX_NUMBER_DWORD = FX_NUMBER_INT32,
FX_NUMBER_QWORD = FX_NUMBER_INT64,
} fx_number_type;
FX_API fx_type fx_number_get_type(void);
FX_API fx_number *fx_number_create(fx_number_type type, void *value_ptr);
static inline fx_number *fx_number_create_int8(int8_t value)
{
return fx_number_create(FX_NUMBER_INT8, &value);
}
static inline fx_number *fx_number_create_int16(int16_t value)
{
return fx_number_create(FX_NUMBER_INT16, &value);
}
static inline fx_number *fx_number_create_int32(int32_t value)
{
return fx_number_create(FX_NUMBER_INT32, &value);
}
static inline fx_number *fx_number_create_int64(int64_t value)
{
return fx_number_create(FX_NUMBER_INT64, &value);
}
static inline fx_number *fx_number_create_float32(float value)
{
return fx_number_create(FX_NUMBER_FLOAT32, &value);
}
static inline fx_number *fx_number_create_float64(double value)
{
return fx_number_create(FX_NUMBER_FLOAT64, &value);
}
static inline fx_number *fx_number_create_char(char value)
{
return fx_number_create(FX_NUMBER_CHAR, &value);
}
static inline fx_number *fx_number_create_short(short value)
{
return fx_number_create(FX_NUMBER_SHORT, &value);
}
static inline fx_number *fx_number_create_int(int value)
{
return fx_number_create(FX_NUMBER_INT, &value);
}
static inline fx_number *fx_number_create_long(long value)
{
return fx_number_create(FX_NUMBER_LONG, &value);
}
static inline fx_number *fx_number_create_longlong(long long value)
{
return fx_number_create(FX_NUMBER_LONGLONG, &value);
}
static inline fx_number *fx_number_create_float(float value)
{
return fx_number_create(FX_NUMBER_FLOAT, &value);
}
static inline fx_number *fx_number_create_double(double value)
{
return fx_number_create(FX_NUMBER_DOUBLE, &value);
}
static inline fx_number *fx_number_create_size_t(size_t value)
{
return fx_number_create(FX_NUMBER_SIZE_T, &value);
}
FX_API fx_number_type fx_number_get_number_type(const fx_number *number);
FX_API int fx_number_get_value(
const fx_number *number, fx_number_type type, void *value_ptr);
static inline int8_t fx_number_get_int8(const fx_number *number)
{
int8_t v;
fx_number_get_value(number, FX_NUMBER_INT8, &v);
return v;
}
static inline int16_t fx_number_get_int16(const fx_number *number)
{
int16_t v;
fx_number_get_value(number, FX_NUMBER_INT16, &v);
return v;
}
static inline int32_t fx_number_get_int32(const fx_number *number)
{
int32_t v;
fx_number_get_value(number, FX_NUMBER_INT32, &v);
return v;
}
static inline int64_t fx_number_get_int64(const fx_number *number)
{
int64_t v;
fx_number_get_value(number, FX_NUMBER_INT64, &v);
return v;
}
static inline float fx_number_get_float32(const fx_number *number)
{
float v;
fx_number_get_value(number, FX_NUMBER_FLOAT32, &v);
return v;
}
static inline double fx_number_get_float64(const fx_number *number)
{
double v;
fx_number_get_value(number, FX_NUMBER_FLOAT64, &v);
return v;
}
static inline char fx_number_get_char(const fx_number *number)
{
char v;
fx_number_get_value(number, FX_NUMBER_CHAR, &v);
return v;
}
static inline short fx_number_get_short(const fx_number *number)
{
short v;
fx_number_get_value(number, FX_NUMBER_SHORT, &v);
return v;
}
static inline int fx_number_get_int(const fx_number *number)
{
int v;
fx_number_get_value(number, FX_NUMBER_INT, &v);
return v;
}
static inline long fx_number_get_long(const fx_number *number)
{
long v;
fx_number_get_value(number, FX_NUMBER_LONG, &v);
return v;
}
static inline long long fx_number_get_longlong(const fx_number *number)
{
long long v;
fx_number_get_value(number, FX_NUMBER_LONGLONG, &v);
return v;
}
static inline float fx_number_get_float(const fx_number *number)
{
float v;
fx_number_get_value(number, FX_NUMBER_FLOAT, &v);
return v;
}
static inline double fx_number_get_double(const fx_number *number)
{
double v;
fx_number_get_value(number, FX_NUMBER_DOUBLE, &v);
return v;
}
static inline size_t fx_number_get_size_t(const fx_number *number)
{
size_t v;
fx_number_get_value(number, FX_NUMBER_SIZE_T, &v);
return v;
}
FX_API bool fx_number_is_integer(const fx_number *number);
FX_API bool fx_number_is_float(const fx_number *number);
FX_API bool fx_number_is_inf(const fx_number *number);
FX_API bool fx_number_is_inf_positive(const fx_number *number);
FX_API bool fx_number_is_inf_negative(const fx_number *number);
FX_API bool fx_number_is_nan(const fx_number *number);
FX_API bool fx_number_is_nan_positive(const fx_number *number);
FX_API bool fx_number_is_nan_negative(const fx_number *number);
FX_API void fx_number_set_inf_positive(fx_number *number, bool v);
FX_API void fx_number_set_inf_negative(fx_number *number, bool v);
FX_API void fx_number_set_nan_positive(fx_number *number, bool v);
FX_API void fx_number_set_nan_negative(fx_number *number, bool v);
FX_API size_t fx_number_data_size(const fx_number *number);
FX_DECLS_END;
#endif
+144
View File
@@ -0,0 +1,144 @@
#ifndef FX_DS_STRING_H_
#define FX_DS_STRING_H_
#include <ctype.h>
#include <fx/core/encoding.h>
#include <fx/core/iterator.h>
#include <fx/core/macros.h>
#include <fx/core/status.h>
#include <fx/core/stringstream.h>
FX_DECLS_BEGIN;
struct fx_stream;
struct fx_string_p;
#define FX_TYPE_STRING (fx_string_get_type())
#define FX_TYPE_STRING_ITERATOR (fx_string_iterator_get_type())
FX_DECLARE_TYPE(fx_string);
FX_DECLARE_TYPE(fx_string_iterator);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_string)
FX_TYPE_CLASS_DECLARATION_END(fx_string)
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_string_iterator)
FX_TYPE_CLASS_DECLARATION_END(fx_string_iterator)
#define FX_CSTR(s) (fx_string_create_from_cstr(s))
#define FX_RV_CSTR(s) (FX_RV(fx_string_create_from_cstr(s)))
typedef enum fx_strlen_flags {
FX_STRLEN_NORMAL = 0,
FX_STRLEN_IGNORE_ESC = 0x01u,
FX_STRLEN_IGNORE_MOD = 0x02u,
FX_STRLEN_CODEPOINTS = 0x04u,
} fx_strlen_flags;
typedef enum fx_string_tokenise_flags {
FX_STRING_TOK_F_NORMAL = 0x00u,
FX_STRING_TOK_F_INCLUDE_EMPTY_TOKENS = 0x01u,
} fx_string_tokenise_flags;
FX_API fx_type fx_string_get_type(void);
FX_API fx_type fx_string_iterator_get_type(void);
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_string, FX_TYPE_STRING);
FX_API fx_string *fx_string_create_from_cstr(const char *s);
FX_API fx_string *fx_string_create_from_wstr(const fx_wchar *s);
FX_API fx_string *fx_string_create_from_c(char c, size_t count);
FX_API fx_string *fx_string_duplicate(const fx_string *str);
FX_API char *fx_string_steal(fx_string *str);
FX_API fx_status fx_string_reserve(fx_string *str, size_t capacity);
FX_API fx_status fx_string_replace(
fx_string *str,
size_t start,
size_t length,
const char *new_data);
FX_API fx_status fx_string_replace_all(fx_string *str, const char *new_data);
FX_API fx_status fx_string_replace_all_with_stringstream(
fx_string *str,
const fx_stringstream *new_data);
FX_API fx_status fx_string_remove(fx_string *str, size_t start, size_t length);
FX_API fx_status fx_string_transform(fx_string *str, int (*transformer)(int));
FX_API fx_status fx_string_trim(fx_string *str);
static inline fx_status fx_string_transform_uppercase(fx_string *str)
{
return fx_string_transform(str, toupper);
}
static inline fx_status fx_string_transform_lowercase(fx_string *str)
{
return fx_string_transform(str, tolower);
}
FX_API fx_status fx_string_append_c(fx_string *dest, char c);
FX_API fx_status fx_string_append_wc(fx_string *dest, fx_wchar c);
FX_API fx_status fx_string_append_s(fx_string *dest, const fx_string *src);
FX_API fx_status fx_string_append_cstr(fx_string *dest, const char *src);
FX_API fx_status fx_string_append_wstr(fx_string *dest, const fx_wchar *src);
FX_API fx_status
fx_string_append_cstrf(fx_string *dest, const char *format, ...);
FX_API fx_status fx_string_prepend_c(fx_string *dest, char c);
FX_API fx_status fx_string_prepend_wc(fx_string *dest, fx_wchar c);
FX_API fx_status fx_string_prepend_cstr(fx_string *dest, const char *src);
FX_API fx_status fx_string_prepend_wstr(fx_string *dest, const fx_wchar *src);
FX_API fx_status
fx_string_prepend_cstrf(fx_string *dest, const char *format, ...);
FX_API fx_status fx_string_insert_c(fx_string *dest, char c, size_t at);
FX_API fx_status fx_string_insert_wc(fx_string *dest, fx_wchar c, size_t at);
FX_API fx_status
fx_string_insert_s(fx_string *dest, const fx_string *src, size_t at);
FX_API fx_status
fx_string_insert_cstr(fx_string *dest, const char *src, size_t at);
FX_API fx_status
fx_string_insert_wstr(fx_string *dest, const fx_wchar *src, size_t at);
FX_API fx_status
fx_string_insert_cstrn(fx_string *dest, const char *src, size_t len, size_t at);
FX_API fx_status
fx_string_insert_wstrn(fx_string *dest, const char *src, size_t len, size_t at);
FX_API fx_status
fx_string_insert_cstrf(fx_string *dest, size_t at, const char *format, ...);
FX_API void fx_string_clear(fx_string *str);
FX_API fx_iterator *fx_string_tokenise(
fx_string *str,
const char *delims[],
size_t nr_delims,
fx_string_tokenise_flags flags);
FX_API size_t fx_string_get_size(const fx_string *str, fx_strlen_flags flags);
FX_API size_t fx_string_get_capacity(const fx_string *str);
FX_API bool fx_string_compare(const fx_string *a, const fx_string *b);
FX_API char fx_string_get_first_char(const fx_string *str);
FX_API char fx_string_get_last_char(const fx_string *str);
FX_API void fx_string_pop_back(fx_string *str);
FX_API const char *fx_string_get_cstr(const fx_string *str);
FX_API fx_string *fx_string_get_substr(
const fx_string *str,
size_t start,
size_t len);
FX_API int fx_string_iterator_begin(
const fx_string *string,
fx_string_iterator *it);
FX_API bool fx_string_iterator_next(fx_string_iterator *it);
// FX_API fx_status fx_string_iterator_erase(fx_string_iterator *it);
FX_API bool fx_string_iterator_is_valid(const fx_string_iterator *it);
FX_API char *fx_strdup(const char *s);
FX_API size_t fx_strlen(const char *s, fx_strlen_flags flags);
FX_API fx_wchar *fx_wstrdup(const fx_wchar *s);
FX_API size_t fx_wstrlen(const fx_wchar *s);
FX_API uint64_t fx_string_hash(const fx_string *s);
FX_DECLS_END;
#endif
+57
View File
@@ -0,0 +1,57 @@
#ifndef FX_DS_TREE_H_
#define FX_DS_TREE_H_
#include <fx/core/macros.h>
#include <fx/core/misc.h>
#include <fx/core/queue.h>
#include <fx/ds/string.h>
FX_DECLS_BEGIN;
#define FX_TYPE_TREE (fx_tree_get_type())
#define FX_TYPE_TREE_ITERATOR (fx_tree_iterator_get_type())
FX_DECLARE_TYPE(fx_tree);
FX_DECLARE_TYPE(fx_tree_iterator);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_tree)
FX_TYPE_CLASS_DECLARATION_END(fx_tree)
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_tree_iterator)
FX_TYPE_CLASS_DECLARATION_END(fx_tree_iterator)
#define FX_TREE_NODE_INIT ((fx_tree_node) {0})
#define FX_TREE_CONTAINER(t, m, v) \
((void *)((v) ? (uintptr_t)(v) - (offsetof(t, m)) : 0))
typedef struct fx_tree_node {
struct fx_tree_node *__p01, *__p02, *__p03;
struct fx_queue_entry __q01;
} fx_tree_node;
FX_API fx_type fx_tree_get_type(void);
FX_API fx_type fx_tree_iterator_get_type(void);
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_tree, FX_TYPE_TREE);
FX_API void fx_tree_set_root(fx_tree *tree, struct fx_tree_node *node);
FX_API void fx_tree_node_add_child(fx_tree_node *parent, fx_tree_node *child);
FX_API void fx_tree_node_add_sibling(fx_tree_node *node, fx_tree_node *to_add);
FX_API fx_tree_node *fx_tree_node_get_child(fx_tree_node *node, size_t at);
FX_API fx_tree_node *fx_tree_node_get_parent(fx_tree_node *node);
FX_API fx_iterator *fx_tree_begin(fx_tree *tree);
FX_API const fx_iterator *fx_tree_cbegin(const fx_tree *tree);
FX_API fx_iterator *fx_tree_node_begin(fx_tree_node *node);
FX_API const fx_iterator *fx_tree_node_cbegin(const fx_tree_node *node);
FX_API fx_iterator *fx_tree_node_begin_recursive(fx_tree_node *node);
FX_API const fx_iterator *fx_tree_node_cbegin_recursive(const fx_tree_node *node);
FX_DECLS_END;
#endif
+50
View File
@@ -0,0 +1,50 @@
#ifndef FX_DS_UUID_H_
#define FX_DS_UUID_H_
#include <fx/core/macros.h>
#include <fx/core/status.h>
#include <fx/ds/string.h>
#define FX_UUID_NBYTES 16
#define FX_UUID_STRING_MAX 37
FX_DECLS_BEGIN;
#define FX_TYPE_UUID (fx_uuid_get_type())
FX_DECLARE_TYPE(fx_uuid);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_uuid)
FX_TYPE_CLASS_DECLARATION_END(fx_uuid)
typedef union fx_uuid_bytes {
uint8_t uuid_bytes[FX_UUID_NBYTES];
uint16_t uuid_words[FX_UUID_NBYTES / 2];
uint32_t uuid_dwords[FX_UUID_NBYTES / 4];
uint64_t uuid_qwords[FX_UUID_NBYTES / 8];
} fx_uuid_bytes;
FX_API fx_type fx_uuid_get_type(void);
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_uuid, FX_TYPE_UUID);
FX_API fx_uuid *fx_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);
FX_API fx_uuid *fx_uuid_create_from_bytev(const unsigned char bytes[FX_UUID_NBYTES]);
FX_API fx_uuid *fx_uuid_create_from_uuid_bytes(const fx_uuid_bytes *bytes);
FX_API fx_uuid *fx_uuid_create_from_string(const fx_string *string);
FX_API fx_uuid *fx_uuid_create_from_cstr(const char *s);
FX_API fx_status fx_uuid_to_cstr(const fx_uuid *uuid, char out[FX_UUID_STRING_MAX]);
FX_API void fx_uuid_get_bytes(
const fx_uuid *uuid, unsigned char bytes[FX_UUID_NBYTES]);
FX_API void fx_uuid_get_uuid_bytes(const fx_uuid *uuid, fx_uuid_bytes *bytes);
FX_API fx_uuid_bytes *fx_uuid_ptr(fx_uuid *uuid);
FX_DECLS_END;
#endif
+529
View File
@@ -0,0 +1,529 @@
#include <fx/core/iterator.h>
#include <fx/core/queue.h>
#include <fx/ds/list.h>
#include <stdlib.h>
#include <string.h>
/*** PRIVATE DATA *************************************************************/
struct fx_list_entry {
struct fx_queue_entry e_entry;
void *e_data;
};
struct fx_list_p {
struct fx_queue l_queue;
size_t l_len;
};
struct fx_list_iterator_p {
fx_list *_q;
struct fx_list_p *_q_p;
struct fx_queue_entry *_q_entry;
size_t i;
void *item;
fx_list_entry *entry;
};
/*** PRIVATE FUNCTIONS ********************************************************/
static bool list_empty(struct fx_list_p *q)
{
return q->l_len == 0;
}
static void *list_first_item(const struct fx_list_p *q)
{
struct fx_queue_entry *entry = fx_queue_first(&q->l_queue);
if (!entry) {
return NULL;
}
struct fx_list_entry *list_entry
= fx_unbox(struct fx_list_entry, entry, e_entry);
return list_entry->e_data;
}
static void *list_last_item(const struct fx_list_p *q)
{
struct fx_queue_entry *entry = fx_queue_last(&q->l_queue);
if (!entry) {
return NULL;
}
struct fx_list_entry *list_entry
= fx_unbox(struct fx_list_entry, entry, e_entry);
return list_entry->e_data;
}
static struct fx_list_entry *list_first_entry(const struct fx_list_p *q)
{
struct fx_queue_entry *entry = fx_queue_first(&q->l_queue);
if (!entry) {
return NULL;
}
struct fx_list_entry *list_entry
= fx_unbox(struct fx_list_entry, entry, e_entry);
return list_entry;
}
static struct fx_list_entry *list_last_entry(const struct fx_list_p *q)
{
struct fx_queue_entry *entry = fx_queue_last(&q->l_queue);
if (!entry) {
return NULL;
}
struct fx_list_entry *list_entry
= fx_unbox(struct fx_list_entry, entry, e_entry);
return list_entry;
}
static size_t list_length(const struct fx_list_p *q)
{
return q->l_len;
}
static struct fx_list_entry *make_entry(void *item)
{
struct fx_list_entry *entry = malloc(sizeof *entry);
if (!entry) {
return NULL;
}
memset(entry, 0x0, sizeof *entry);
entry->e_data = item;
return entry;
}
static struct fx_list_entry *list_insert_before(
struct fx_list_p *q, void *ptr, struct fx_list_entry *before)
{
struct fx_list_entry *entry = make_entry(ptr);
if (!entry) {
return NULL;
}
fx_queue_insert_before(&q->l_queue, &entry->e_entry, &before->e_entry);
q->l_len++;
return entry;
}
static struct fx_list_entry *list_insert_after(
struct fx_list_p *q, void *ptr, struct fx_list_entry *after)
{
struct fx_list_entry *entry = make_entry(ptr);
if (!entry) {
return NULL;
}
fx_queue_insert_after(&q->l_queue, &entry->e_entry, &after->e_entry);
q->l_len++;
return entry;
}
static struct fx_list_entry *list_push_front(struct fx_list_p *q, void *ptr)
{
struct fx_list_entry *entry = make_entry(ptr);
if (!entry) {
return NULL;
}
fx_queue_push_front(&q->l_queue, &entry->e_entry);
q->l_len++;
return entry;
}
static struct fx_list_entry *list_push_back(struct fx_list_p *q, void *ptr)
{
struct fx_list_entry *entry = make_entry(ptr);
if (!entry) {
return NULL;
}
fx_queue_push_back(&q->l_queue, &entry->e_entry);
q->l_len++;
return entry;
}
static void *list_pop_front(struct fx_list_p *q)
{
struct fx_queue_entry *entry = fx_queue_pop_front(&q->l_queue);
if (!entry) {
return NULL;
}
struct fx_list_entry *list_entry
= fx_unbox(struct fx_list_entry, entry, e_entry);
void *item = list_entry->e_data;
free(list_entry);
q->l_len--;
return item;
}
static void *list_pop_back(struct fx_list_p *q)
{
struct fx_queue_entry *entry = fx_queue_pop_back(&q->l_queue);
if (!entry) {
return NULL;
}
struct fx_list_entry *list_entry
= fx_unbox(struct fx_list_entry, entry, e_entry);
void *item = list_entry->e_data;
free(list_entry);
q->l_len--;
return item;
}
static struct fx_list_entry *find_item(struct fx_list_p *list, void *item)
{
struct fx_queue_entry *entry = fx_queue_first(&list->l_queue);
while (entry) {
struct fx_list_entry *list_entry
= fx_unbox(struct fx_list_entry, entry, e_entry);
if (list_entry->e_data == item) {
return list_entry;
}
entry = fx_queue_next(entry);
}
return NULL;
}
static fx_status list_delete_item(struct fx_list_p *q, void *ptr)
{
struct fx_list_entry *entry = find_item(q, ptr);
if (!entry) {
return FX_ERR_NO_ENTRY;
}
fx_queue_delete(&q->l_queue, &entry->e_entry);
q->l_len--;
free(entry);
return FX_SUCCESS;
}
static fx_status list_delete_entry(struct fx_list_p *q, struct fx_list_entry *entry)
{
fx_queue_delete(&q->l_queue, &entry->e_entry);
q->l_len--;
free(entry);
return FX_SUCCESS;
}
static void list_delete_all(struct fx_list_p *q)
{
struct fx_queue_entry *entry = fx_queue_first(&q->l_queue);
while (entry) {
struct fx_list_entry *list_entry
= fx_unbox(struct fx_list_entry, entry, e_entry);
struct fx_queue_entry *next = fx_queue_next(entry);
free(list_entry);
entry = next;
}
q->l_len = 0;
}
/*** PUBLIC FUNCTIONS *********************************************************/
bool fx_list_empty(fx_list *q)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_LIST, list_empty, q);
}
void *fx_list_first_item(const fx_list *q)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_LIST, list_first_item, q);
}
void *fx_list_last_item(const fx_list *q)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_LIST, list_last_item, q);
}
struct fx_list_entry *fx_list_first_entry(const fx_list *q)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_LIST, list_first_entry, q);
}
struct fx_list_entry *fx_list_last_entry(const fx_list *q)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_LIST, fx_list_last_entry, q);
}
struct fx_list_entry *fx_list_next(const struct fx_list_entry *entry)
{
if (!entry) {
return NULL;
}
struct fx_queue_entry *next = fx_queue_next(&entry->e_entry);
if (!next) {
return NULL;
}
return fx_unbox(struct fx_list_entry, next, e_entry);
}
struct fx_list_entry *fx_list_prev(const struct fx_list_entry *entry)
{
if (!entry) {
return NULL;
}
struct fx_queue_entry *next = fx_queue_prev(&entry->e_entry);
if (!next) {
return NULL;
}
return fx_unbox(struct fx_list_entry, next, e_entry);
}
size_t fx_list_length(const fx_list *q)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_LIST, list_length, q);
}
struct fx_list_entry *fx_list_insert_before(
fx_list *q, void *ptr, struct fx_list_entry *before)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_LIST, list_insert_before, q, ptr, before);
}
struct fx_list_entry *fx_list_insert_after(
fx_list *q, void *ptr, struct fx_list_entry *after)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_LIST, list_insert_after, q, ptr, after);
}
struct fx_list_entry *fx_list_push_front(fx_list *q, void *ptr)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_LIST, list_push_front, q, ptr);
}
struct fx_list_entry *fx_list_push_back(fx_list *q, void *ptr)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_LIST, list_push_back, q, ptr);
}
void *fx_list_pop_front(fx_list *q)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_LIST, list_pop_front, q);
}
void *fx_list_pop_back(fx_list *q)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_LIST, list_pop_back, q);
}
fx_status fx_list_delete_item(fx_list *q, void *ptr)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_LIST, list_delete_item, q, ptr);
}
fx_status fx_list_delete_entry(fx_list *q, struct fx_list_entry *entry)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_LIST, list_delete_entry, q, entry);
}
void fx_list_delete_all(fx_list *q)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_LIST, list_delete_all, q);
}
void *fx_list_entry_value(const struct fx_list_entry *entry)
{
return entry ? entry->e_data : NULL;
}
fx_iterator *fx_list_begin(fx_list *q)
{
fx_list_iterator *it_obj = fx_object_create(FX_TYPE_LIST_ITERATOR);
struct fx_list_iterator_p *it
= fx_object_get_private(it_obj, FX_TYPE_LIST_ITERATOR);
it->_q = q;
it->_q_p = fx_object_get_private(q, FX_TYPE_LIST);
it->_q_entry = fx_queue_first(&it->_q_p->l_queue);
it->i = 0;
it->entry = fx_unbox(struct fx_list_entry, it->_q_entry, e_entry);
if (it->entry) {
it->item = it->entry->e_data;
}
return 0;
}
const fx_iterator *fx_list_cbegin(const fx_list *q)
{
fx_list_iterator *it_obj = fx_object_create(FX_TYPE_LIST_ITERATOR);
struct fx_list_iterator_p *it
= fx_object_get_private(it_obj, FX_TYPE_LIST_ITERATOR);
it->_q = (fx_list *)q;
it->_q_p = fx_object_get_private(q, FX_TYPE_LIST);
it->_q_entry = fx_queue_first(&it->_q_p->l_queue);
it->i = 0;
it->entry = fx_unbox(struct fx_list_entry, it->_q_entry, e_entry);
if (it->entry) {
it->item = it->entry->e_data;
}
return 0;
}
/*** VIRTUAL FUNCTIONS ********************************************************/
static void list_init(fx_object *obj, void *priv)
{
struct fx_list_p *list = priv;
}
static void list_fini(fx_object *obj, void *priv)
{
struct fx_list_p *list = priv;
list_delete_all(list);
}
/*** ITERATOR FUNCTIONS *******************************************************/
static enum fx_status iterator_move_next(const fx_iterator *obj)
{
struct fx_list_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_LIST_ITERATOR);
if (!it->_q_entry) {
it->entry = NULL;
it->item = NULL;
return FX_ERR_NO_DATA;
}
it->_q_entry = fx_queue_next(it->_q_entry);
if (!it->_q_entry) {
it->entry = NULL;
it->item = NULL;
return FX_ERR_NO_DATA;
}
it->i++;
it->entry = fx_unbox(struct fx_list_entry, it->_q_entry, e_entry);
if (it->entry) {
it->item = it->entry->e_data;
}
return it->entry != NULL;
}
static enum fx_status iterator_erase(fx_iterator *obj)
{
struct fx_list_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_LIST_ITERATOR);
if (!it->entry || !it->_q_entry) {
return FX_ERR_OUT_OF_BOUNDS;
}
struct fx_queue_entry *next = fx_queue_next(it->_q_entry);
fx_queue_delete(&it->_q_p->l_queue, it->_q_entry);
free(it->entry);
it->_q_entry = next;
it->entry = fx_unbox(struct fx_list_entry, it->_q_entry, e_entry);
if (it->entry) {
it->item = it->entry->e_data;
}
return FX_SUCCESS;
}
static fx_iterator_value iterator_get_value(fx_iterator *obj)
{
struct fx_list_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_LIST_ITERATOR);
return FX_ITERATOR_VALUE_PTR(it->item);
}
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
{
struct fx_list_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_LIST_ITERATOR);
return FX_ITERATOR_VALUE_CPTR(it->item);
}
/*** CLASS DEFINITION *********************************************************/
// ---- fx_list DEFINITION
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_list)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
FX_INTERFACE_ENTRY(it_begin) = fx_list_begin;
FX_INTERFACE_ENTRY(it_cbegin) = fx_list_cbegin;
FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
FX_TYPE_CLASS_DEFINITION_END(fx_list)
FX_TYPE_DEFINITION_BEGIN(fx_list)
FX_TYPE_ID(0x8730e66f, 0x0fd9, 0x4773, 0x9bbd, 0x6428f6e495eb);
FX_TYPE_CLASS(fx_list_class);
FX_TYPE_IMPLEMENTS(FX_TYPE_ITERABLE);
FX_TYPE_INSTANCE_PRIVATE(struct fx_list_p);
FX_TYPE_INSTANCE_INIT(list_init);
FX_TYPE_INSTANCE_FINI(list_fini);
FX_TYPE_DEFINITION_END(fx_list)
// ---- fx_list_iterator DEFINITION
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_list_iterator)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
FX_TYPE_CLASS_DEFINITION_END(fx_list_iterator)
FX_TYPE_DEFINITION_BEGIN(fx_list_iterator)
FX_TYPE_ID(0xd9658456, 0xdd80, 0x419a, 0xb23a, 0xb513013e6431);
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
FX_TYPE_CLASS(fx_list_iterator_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_list_iterator_p);
FX_TYPE_DEFINITION_END(fx_list_iterator)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+380
View File
@@ -0,0 +1,380 @@
#include <fx/ds/tree.h>
#include <stdlib.h>
#include <string.h>
#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)
/*** PRIVATE DATA *************************************************************/
struct fx_tree_p {
struct fx_tree_node *t_root;
};
struct fx_tree_iterator_p {
size_t i, depth;
fx_tree_node *node;
unsigned char _f01;
};
/*** PRIVATE FUNCTIONS ********************************************************/
static void tree_set_root(struct fx_tree_p *tree, struct fx_tree_node *node)
{
tree->t_root = node;
}
static const struct fx_tree_node *next_node(
const struct fx_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 fx_tree_node *next = NODE_FIRST_CHILD(node);
if (next) {
d = 1;
*depth_diff = d;
return next;
}
const struct fx_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;
}
static void remove_node(struct fx_tree_node *node)
{
struct fx_tree_node *parent = NODE_PARENT(node);
if (!parent) {
return;
}
struct fx_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 fx_tree_node *old_parent, struct fx_tree_node *new_parent)
{
struct fx_tree_node *last = NODE_FIRST_CHILD(new_parent);
while (last && NODE_NEXT_SIBLING(last)) {
last = NODE_NEXT_SIBLING(last);
}
struct fx_tree_node *cur = NODE_FIRST_CHILD(old_parent);
while (cur) {
struct fx_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;
}
}
/*** PUBLIC FUNCTIONS *********************************************************/
void fx_tree_set_root(fx_tree *tree, struct fx_tree_node *node)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_TREE, tree_set_root, tree, node);
}
void fx_tree_node_add_child(struct fx_tree_node *parent, struct fx_tree_node *child)
{
if (NODE_PARENT(child)) {
return;
}
NODE_PARENT(child) = parent;
if (!NODE_FIRST_CHILD(parent)) {
NODE_FIRST_CHILD(parent) = child;
return;
}
struct fx_tree_node *cur = NODE_FIRST_CHILD(parent);
while (NODE_NEXT_SIBLING(cur)) {
cur = NODE_NEXT_SIBLING(cur);
}
NODE_NEXT_SIBLING(cur) = child;
}
void fx_tree_node_add_sibling(struct fx_tree_node *node, struct fx_tree_node *to_add)
{
if (NODE_PARENT(to_add) || !NODE_PARENT(node)) {
return;
}
fx_tree_node_add_child(NODE_PARENT(node), to_add);
}
struct fx_tree_node *fx_tree_node_get_child(struct fx_tree_node *node, size_t at)
{
size_t i = 0;
struct fx_tree_node *cur = NODE_FIRST_CHILD(node);
while (i < at) {
if (!cur) {
return NULL;
}
cur = NODE_NEXT_SIBLING(cur);
i++;
}
return cur;
}
fx_iterator *fx_tree_begin(fx_tree *tree)
{
struct fx_tree_p *p = fx_object_get_private(tree, FX_TYPE_TREE);
return fx_tree_node_begin(p->t_root);
}
const fx_iterator *fx_tree_cbegin(const fx_tree *tree)
{
struct fx_tree_p *p = fx_object_get_private(tree, FX_TYPE_TREE);
return fx_tree_node_begin(p->t_root);
}
fx_iterator *fx_tree_node_begin(struct fx_tree_node *node)
{
fx_tree_iterator *it_obj = fx_object_create(FX_TYPE_TREE_ITERATOR);
struct fx_tree_iterator_p *it
= fx_object_get_private(it_obj, FX_TYPE_TREE_ITERATOR);
it->node = NODE_FIRST_CHILD(node);
it->i = 0;
it->depth = 0;
ITERATOR_UNSET_RECURSIVE(it);
if (!it->node) {
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
}
return it_obj;
}
const fx_iterator *fx_tree_node_cbegin(const struct fx_tree_node *node)
{
return fx_tree_node_begin((struct fx_tree_node *)node);
}
fx_iterator *fx_tree_node_begin_recursive(struct fx_tree_node *node)
{
fx_tree_iterator *it_obj = fx_object_create(FX_TYPE_TREE_ITERATOR);
struct fx_tree_iterator_p *it
= fx_object_get_private(it_obj, FX_TYPE_TREE_ITERATOR);
it->node = node;
it->i = 0;
it->depth = 0;
ITERATOR_SET_RECURSIVE(it);
if (!it->node) {
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
}
return it_obj;
}
const fx_iterator *fx_tree_node_cbegin_recursive(const struct fx_tree_node *node)
{
return fx_tree_node_begin_recursive((struct fx_tree_node *)node);
}
/*** VIRTUAL FUNCTIONS ********************************************************/
static void tree_init(fx_object *obj, void *priv)
{
struct fx_tree_p *tree = priv;
}
static void tree_fini(fx_object *obj, void *priv)
{
struct fx_tree_p *tree = priv;
}
/*** ITERATOR FUNCTIONS *******************************************************/
static enum fx_status iterator_move_next(const fx_iterator *obj)
{
struct fx_tree_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_TREE_ITERATOR);
int depth_diff = 0;
const struct fx_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 fx_tree_node *)next;
return (it->node != NULL) ? FX_SUCCESS : FX_ERR_NO_DATA;
}
static enum fx_status iterator_erase(fx_iterator *obj)
{
struct fx_tree_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_TREE_ITERATOR);
if (!it->node) {
return FX_ERR_OUT_OF_BOUNDS;
}
struct fx_tree_node *parent = NODE_PARENT(it->node);
if (!parent) {
return FX_ERR_NOT_SUPPORTED;
}
int d = 0;
struct fx_tree_node *n = it->node;
struct fx_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 FX_SUCCESS;
}
static fx_iterator_value iterator_get_value(fx_iterator *obj)
{
struct fx_tree_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_TREE_ITERATOR);
if (!it->node) {
return FX_ITERATOR_VALUE_NULL;
}
return FX_ITERATOR_VALUE_PTR(it->node);
}
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
{
struct fx_tree_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_TREE_ITERATOR);
if (!it->node) {
return FX_ITERATOR_VALUE_NULL;
}
return FX_ITERATOR_VALUE_CPTR(it->node);
}
/*** CLASS DEFINITION *********************************************************/
// ---- fx_tree DEFINITION
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_tree)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
FX_INTERFACE_ENTRY(it_begin) = fx_tree_begin;
FX_INTERFACE_ENTRY(it_cbegin) = fx_tree_cbegin;
FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
FX_TYPE_CLASS_DEFINITION_END(fx_tree)
FX_TYPE_DEFINITION_BEGIN(fx_tree)
FX_TYPE_ID(0x8d8fa36b, 0xc515, 0x4803, 0x8124, 0xfd704f01b8ae);
FX_TYPE_CLASS(fx_tree_class);
FX_TYPE_IMPLEMENTS(FX_TYPE_ITERABLE);
FX_TYPE_INSTANCE_PRIVATE(struct fx_tree_p);
FX_TYPE_INSTANCE_INIT(tree_init);
FX_TYPE_INSTANCE_FINI(tree_fini);
FX_TYPE_DEFINITION_END(fx_tree)
// ---- fx_tree_iterator DEFINITION
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_tree_iterator)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
FX_TYPE_CLASS_DEFINITION_END(fx_tree_iterator)
FX_TYPE_DEFINITION_BEGIN(fx_tree_iterator)
FX_TYPE_ID(0xb896e671, 0x84b2, 0x4892, 0xaf09, 0x407f305f4bf8);
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
FX_TYPE_CLASS(fx_tree_iterator_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_tree_iterator_p);
FX_TYPE_DEFINITION_END(fx_tree_iterator)
+254
View File
@@ -0,0 +1,254 @@
#include <ctype.h>
#include <fx/core/stringstream.h>
#include <fx/ds/string.h>
#include <fx/ds/uuid.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*** PRIVATE DATA *************************************************************/
struct fx_uuid_p {
union fx_uuid_bytes uuid_bytes;
};
/*** PRIVATE FUNCTIONS ********************************************************/
static fx_status uuid_to_cstr(
const struct fx_uuid_p *uuid,
char out[FX_UUID_STRING_MAX])
{
snprintf(
out,
FX_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 FX_SUCCESS;
}
static void uuid_get_bytes(
const struct fx_uuid_p *uuid,
unsigned char bytes[FX_UUID_NBYTES])
{
memcpy(bytes, uuid->uuid_bytes.uuid_bytes, FX_UUID_NBYTES);
}
static void uuid_get_uuid_bytes(
const struct fx_uuid_p *uuid,
union fx_uuid_bytes *bytes)
{
memcpy(bytes, &uuid->uuid_bytes, sizeof *bytes);
}
static union fx_uuid_bytes *uuid_ptr(struct fx_uuid_p *uuid)
{
return &uuid->uuid_bytes;
}
/*** PUBLIC FUNCTIONS *********************************************************/
fx_uuid *fx_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)
{
fx_uuid *uuid = fx_uuid_create();
if (!uuid) {
return NULL;
}
struct fx_uuid_p *p = fx_object_get_private(uuid, FX_TYPE_UUID);
p->uuid_bytes.uuid_bytes[0] = u00;
p->uuid_bytes.uuid_bytes[1] = u01;
p->uuid_bytes.uuid_bytes[2] = u02;
p->uuid_bytes.uuid_bytes[3] = u03;
p->uuid_bytes.uuid_bytes[4] = u04;
p->uuid_bytes.uuid_bytes[5] = u05;
p->uuid_bytes.uuid_bytes[6] = u06;
p->uuid_bytes.uuid_bytes[7] = u07;
p->uuid_bytes.uuid_bytes[8] = u08;
p->uuid_bytes.uuid_bytes[9] = u09;
p->uuid_bytes.uuid_bytes[10] = u10;
p->uuid_bytes.uuid_bytes[11] = u11;
p->uuid_bytes.uuid_bytes[12] = u12;
p->uuid_bytes.uuid_bytes[13] = u13;
p->uuid_bytes.uuid_bytes[14] = u14;
p->uuid_bytes.uuid_bytes[15] = u15;
return uuid;
}
fx_uuid *fx_uuid_create_from_bytev(const unsigned char bytes[FX_UUID_NBYTES])
{
fx_uuid *uuid = fx_uuid_create();
if (!uuid) {
return NULL;
}
struct fx_uuid_p *p = fx_object_get_private(uuid, FX_TYPE_UUID);
memcpy(p->uuid_bytes.uuid_bytes, bytes, FX_UUID_NBYTES);
return uuid;
}
fx_uuid *fx_uuid_create_from_cstr(const char *str)
{
union fx_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 < FX_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 != FX_UUID_NBYTES) {
valid = false;
}
if (!valid) {
return NULL;
}
return fx_uuid_create_from_uuid_bytes(&bytes);
}
fx_status fx_uuid_to_cstr(const fx_uuid *uuid, char out[FX_UUID_STRING_MAX])
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_UUID, uuid_to_cstr, uuid, out);
}
void fx_uuid_get_bytes(const fx_uuid *uuid, unsigned char bytes[FX_UUID_NBYTES])
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_UUID, uuid_get_bytes, uuid, bytes);
}
void fx_uuid_get_uuid_bytes(const fx_uuid *uuid, union fx_uuid_bytes *bytes)
{
FX_CLASS_DISPATCH_STATIC(
FX_TYPE_UUID,
uuid_get_uuid_bytes,
uuid,
bytes);
}
union fx_uuid_bytes *fx_uuid_ptr(fx_uuid *uuid)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_UUID, uuid_ptr, uuid);
}
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
fx_uuid *fx_uuid_create_from_uuid_bytes(const union fx_uuid_bytes *bytes)
{
return fx_uuid_create_from_bytev(bytes->uuid_bytes);
}
fx_uuid *fx_uuid_create_from_string(const fx_string *string)
{
return fx_uuid_create_from_cstr(fx_string_get_cstr(string));
}
/*** VIRTUAL FUNCTIONS ********************************************************/
static void uuid_init(fx_object *obj, void *priv)
{
struct fx_uuid_p *uuid = priv;
}
static void uuid_fini(fx_object *obj, void *priv)
{
struct fx_uuid_p *uuid = priv;
}
static void uuid_to_string(const fx_object *uuid, fx_stream *out)
{
char str[FX_UUID_STRING_MAX];
fx_uuid_to_cstr(uuid, str);
fx_stream_write_cstr(out, str, NULL);
}
/*** CLASS DEFINITION *********************************************************/
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_uuid)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = uuid_to_string;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_DEFINITION_END(fx_uuid)
FX_TYPE_DEFINITION_BEGIN(fx_uuid)
FX_TYPE_ID(0x17037068, 0x92f7, 0x4582, 0xad1f, 0x0dea43b628de);
FX_TYPE_CLASS(fx_uuid_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_uuid_p);
FX_TYPE_INSTANCE_INIT(uuid_init);
FX_TYPE_INSTANCE_FINI(uuid_fini);
FX_TYPE_DEFINITION_END(fx_uuid)