meta: rename legacy object module to 'ds'

This commit is contained in:
2025-08-09 19:57:42 +01:00
parent a5e3e06306
commit 0751ef469f
80 changed files with 460 additions and 460 deletions

3
ds/CMakeLists.txt Normal file
View File

@@ -0,0 +1,3 @@
include(../cmake/Templates.cmake)
add_bluelib_module(NAME ds DEPENDENCIES core)

380
ds/array.c Normal file
View File

@@ -0,0 +1,380 @@
#include "array.h"
#include <blue/core/iterator.h>
#include <blue/core/stream.h>
#include <blue/ds/array.h>
#include <blue/ds/type.h>
#include <stdlib.h>
#include <string.h>
static void array_release(struct b_dsref *obj);
static void array_to_string(struct b_dsref *obj, struct b_stream *out);
static struct b_dsref_type array_type = {
.t_flags = B_DSREF_FUNDAMENTAL,
.t_id = B_DSREF_TYPE_ARRAY,
.t_name = "corelib::array",
.t_instance_size = sizeof(struct b_array),
.t_release = array_release,
.t_to_string = array_to_string,
};
struct b_array *b_array_create(void)
{
struct b_array *array
= (struct b_array *)b_dsref_type_instantiate(&array_type);
if (!array) {
return NULL;
}
return array;
}
struct b_array *b_array_create_with_values(
struct b_dsref *const *values, size_t nr_values)
{
struct b_array *array = b_array_create();
if (!array) {
return NULL;
}
size_t real_nr_values = 0;
for (size_t i = 0; i < nr_values; i++) {
if (values[i]) {
real_nr_values++;
}
}
array->ar_len = real_nr_values;
array->ar_cap = real_nr_values;
array->ar_data = calloc(real_nr_values, sizeof(struct b_dsref *));
if (!array->ar_data) {
b_array_release(array);
return NULL;
}
size_t index = 0;
for (size_t i = 0; i < nr_values; i++) {
array->ar_data[index++] = b_retain(values[i]);
}
return array;
}
static b_status resize_array(struct b_array *array, size_t new_capacity)
{
if (array->ar_cap < new_capacity) {
void *new_data = realloc(
array->ar_data, new_capacity * sizeof(struct b_dsref *));
if (!new_data) {
return B_ERR_NO_MEMORY;
}
array->ar_data = new_data;
} else {
for (size_t i = new_capacity; i < array->ar_len; i++) {
b_release(array->ar_data[i]);
}
void *new_data = realloc(
array->ar_data, new_capacity * sizeof(struct b_dsref *));
if (!new_data) {
return B_ERR_NO_MEMORY;
}
array->ar_data = new_data;
}
array->ar_cap = new_capacity;
if (array->ar_len > new_capacity) {
array->ar_len = new_capacity;
}
return B_SUCCESS;
}
b_status b_array_append(struct b_array *array, struct b_dsref *value)
{
return b_array_insert(array, value, B_NPOS);
}
b_status b_array_prepend(struct b_array *array, struct b_dsref *value)
{
return b_array_insert(array, value, 0);
}
b_status b_array_insert(struct b_array *array, struct b_dsref *value, size_t at)
{
if (at == B_NPOS) {
at = array->ar_len;
}
if (at > array->ar_len) {
return B_ERR_OUT_OF_BOUNDS;
}
b_status status = B_SUCCESS;
if (array->ar_len + 1 > array->ar_cap) {
status = resize_array(array, array->ar_cap + 8);
if (status != B_SUCCESS) {
return status;
}
}
struct b_dsref **src = array->ar_data + at;
struct b_dsref **dest = src + 1;
size_t move_len = (array->ar_len - at) * sizeof(struct b_dsref *);
memmove(dest, src, move_len);
array->ar_data[at] = b_retain(value);
array->ar_len++;
return B_SUCCESS;
}
b_status b_array_remove(struct b_array *array, size_t at)
{
if (at >= array->ar_len) {
return B_ERR_OUT_OF_BOUNDS;
}
struct b_dsref **src = array->ar_data + at;
struct b_dsref **dest = src + 1;
size_t move_len = array->ar_len * sizeof(struct b_dsref *);
b_release(array->ar_data[at]);
memmove(dest, src, move_len);
array->ar_len--;
return B_SUCCESS;
}
b_status b_array_remove_front(struct b_array *array)
{
return b_array_remove(array, 0);
}
b_status b_array_remove_back(struct b_array *array)
{
return b_array_remove(array, array->ar_len - 1);
}
struct b_dsref *b_array_pop(b_array *array, size_t at)
{
if (at >= array->ar_len) {
return NULL;
}
struct b_dsref **src = array->ar_data + at;
struct b_dsref **dest = src + 1;
size_t move_len = array->ar_len * sizeof(struct b_dsref *);
struct b_dsref *out = array->ar_data[at];
memmove(dest, src, move_len);
array->ar_len--;
return out;
}
struct b_dsref *b_array_pop_front(struct b_array *array)
{
return b_array_pop(array, 0);
}
struct b_dsref *b_array_pop_back(struct b_array *array)
{
return b_array_pop(array, array->ar_len - 1);
}
struct b_dsref *b_array_at(const struct b_array *array, size_t at)
{
if (at >= array->ar_len) {
return NULL;
}
return array->ar_data[at];
}
struct b_dsref *b_array_get(struct b_array *array, size_t at)
{
if (at >= array->ar_len) {
return NULL;
}
return b_retain(array->ar_data[at]);
}
size_t b_array_size(const struct b_array *array)
{
return array->ar_len;
}
size_t b_array_capacity(const struct b_array *array)
{
return array->ar_cap;
}
static void array_to_string(struct b_dsref *obj, struct b_stream *out)
{
struct b_array *array = B_ARRAY(obj);
if (!array->ar_len) {
b_stream_write_string(out, "[]", NULL);
return;
}
b_stream_write_string(out, "[\n", NULL);
b_stream_push_indent(out, 1);
size_t len = b_array_size(array);
b_array_iterator it;
b_array_foreach(&it, array)
{
bool is_string = b_typeid(it.value) == B_DSREF_TYPE_STRING;
if (is_string) {
b_stream_write_char(out, '"');
}
b_to_string(it.value, out);
if (is_string) {
b_stream_write_char(out, '"');
}
if (it.i < len - 1) {
b_stream_write_string(out, ",", NULL);
}
b_stream_write_char(out, '\n');
}
b_stream_pop_indent(out);
b_stream_write_char(out, ']');
}
static void array_release(struct b_dsref *obj)
{
struct b_array *array = B_ARRAY(obj);
if (array->ar_data) {
for (size_t i = 0; i < array->ar_len; i++) {
b_release(array->ar_data[i]);
}
free(array->ar_data);
array->ar_data = NULL;
}
}
void b_array_clear(struct b_array *array)
{
while (array->ar_len) {
b_array_remove_back(array);
}
}
static bool array_iterator_next(struct b_iterator *it)
{
return b_array_iterator_next((struct b_array_iterator *)it);
}
static b_status array_iterator_erase(struct b_iterator *it)
{
return b_array_iterator_erase((struct b_array_iterator *)it);
}
static bool array_iterator_is_valid(const struct b_iterator *it)
{
return b_array_iterator_is_valid((const struct b_array_iterator *)it);
}
static b_iterator_ops it_ops = {
.it_next = array_iterator_next,
.it_close = NULL,
.it_erase = array_iterator_erase,
.it_is_valid = array_iterator_is_valid,
};
int b_array_iterator_begin(struct b_array *array, struct b_array_iterator *it)
{
it->_a = array;
it->i = 0;
it->_base.it_ops = &it_ops;
if (array->ar_len > 0) {
it->value = array->ar_data[0];
} else {
it->value = NULL;
}
return 0;
}
bool b_array_iterator_next(struct b_array_iterator *it)
{
struct b_array *array = it->_a;
if (it->value == NULL || it->i >= array->ar_len) {
return false;
}
it->i++;
if (it->i >= array->ar_len) {
it->value = NULL;
} else {
it->value = array->ar_data[it->i];
}
return it->value != NULL;
}
b_status b_array_iterator_erase(struct b_array_iterator *it)
{
struct b_array *array = it->_a;
if (it->i >= array->ar_len) {
return B_ERR_OUT_OF_BOUNDS;
}
if (array->ar_data[it->i] != it->value) {
return B_ERR_BAD_STATE;
}
b_array_remove(array, it->i);
if (it->i < array->ar_len) {
it->value = array->ar_data[it->i];
} else {
it->value = NULL;
}
return B_SUCCESS;
}
bool b_array_iterator_is_valid(const struct b_array_iterator *it)
{
struct b_array *array = it->_a;
if (it->i >= array->ar_len) {
return false;
}
if (array->ar_data[it->i] != it->value) {
return false;
}
return it->value != NULL;
}
b_dsref_type_id b_array_type_id(void)
{
return (b_dsref_type_id)&array_type;
}

15
ds/array.h Normal file
View File

@@ -0,0 +1,15 @@
#ifndef _BLUELIB_ARRAY_H_
#define _BLUELIB_ARRAY_H_
#include "../object.h"
struct b_array {
struct b_dsref ar_base;
/* number of items in array */
unsigned int ar_len;
/* maximum number of items that can currently be stored in array */
unsigned int ar_cap;
struct b_dsref **ar_data;
};
#endif

0
ds/bitbuffer.c Normal file
View File

0
ds/bitbuffer.h Normal file
View File

167
ds/bitmap.c Normal file
View File

@@ -0,0 +1,167 @@
#include <string.h>
#include <blue/ds/bitmap.h>
#include <blue/core/bitop.h>
void b_bitmap_zero(b_bitmap_word *map, unsigned long nbits)
{
unsigned long words = B_BITMAP_WORDS(nbits);
memset(map, 0x00, words * sizeof *map);
}
void b_bitmap_fill(b_bitmap_word *map, unsigned long nbits)
{
unsigned long words = B_BITMAP_WORDS(nbits);
memset(map, 0xFF, words * sizeof *map);
}
void b_bitmap_set(b_bitmap_word *map, unsigned long bit)
{
unsigned long index = bit / Z__B_BITS_PER_WORD;
unsigned long offset = (Z__B_BITS_PER_WORD - bit - 1) & (Z__B_BITS_PER_WORD - 1);
unsigned long mask = 1ul << offset;
map[index] |= mask;
}
void b_bitmap_clear(b_bitmap_word *map, unsigned long bit)
{
unsigned long index = bit / Z__B_BITS_PER_WORD;
unsigned long offset = bit & (Z__B_BITS_PER_WORD - 1);
unsigned long mask = 1ul << offset;
map[index] &= ~mask;
}
bool b_bitmap_check(const b_bitmap_word *map, unsigned long bit)
{
unsigned long index = bit / Z__B_BITS_PER_WORD;
unsigned long offset = (Z__B_BITS_PER_WORD - bit - 1) & (Z__B_BITS_PER_WORD - 1);
unsigned long mask = 1ul << offset;
return (map[index] & mask) != 0;
}
unsigned int b_bitmap_count_set(const b_bitmap_word *map, unsigned long nbits)
{
unsigned long words = B_BITMAP_WORDS(nbits);
unsigned int set_bits = 0;
for (unsigned long i = 0; i < words; i++) {
set_bits += b_popcountl(map[i]);
}
if (set_bits > nbits) {
set_bits = nbits;
}
return set_bits;
}
unsigned int b_bitmap_count_clear(const b_bitmap_word *map, unsigned long nbits)
{
unsigned long words = B_BITMAP_WORDS(nbits);
unsigned int clear_bits = 0;
for (unsigned long i = 0; i < words; i++) {
clear_bits += b_popcountl(~map[i]);
}
if (clear_bits > nbits) {
clear_bits = nbits;
}
return clear_bits;
}
unsigned int b_bitmap_highest_set(const b_bitmap_word *map, unsigned long nbits)
{
unsigned long words = B_BITMAP_WORDS(nbits);
unsigned long bit_index = 0;
b_bitmap_word last_word = 0;
unsigned long i;
for (i = 0; i < words; i++) {
if (map[i] != 0x00) {
last_word = map[i];
bit_index = i * Z__B_BITS_PER_WORD;
}
}
if (last_word == 0x00) {
return B_BITMAP_NPOS;
}
return bit_index + (Z__B_BITS_PER_WORD - b_ctzl(last_word) - 1);
}
unsigned int b_bitmap_highest_clear(const b_bitmap_word *map, unsigned long nbits)
{
unsigned long words = B_BITMAP_WORDS(nbits);
unsigned long bit_index = 0;
b_bitmap_word last_word = ~(b_bitmap_word)0;
for (unsigned long i = 0; i < words; i++) {
if (map[i] != (~(unsigned long)0)) {
last_word = map[i];
bit_index = i * Z__B_BITS_PER_WORD;
}
}
if (last_word == ~(unsigned long)0) {
return B_BITMAP_NPOS;
}
if (last_word == 0) {
return bit_index + Z__B_BITS_PER_WORD - 1;
}
return bit_index + (Z__B_BITS_PER_WORD - b_ctzl(~last_word)) - 1;
}
unsigned int b_bitmap_lowest_set(const b_bitmap_word *map, unsigned long nbits)
{
unsigned long words = B_BITMAP_WORDS(nbits);
unsigned long bit_index = 0;
b_bitmap_word last_word = 0;
unsigned long i;
for (i = 0; i < words; i++) {
if (map[i] != 0x00) {
last_word = map[i];
bit_index = i * Z__B_BITS_PER_WORD;
break;
}
}
if (last_word == 0x00) {
return B_BITMAP_NPOS;
}
return bit_index + b_clzl(last_word);
}
unsigned int b_bitmap_lowest_clear(const b_bitmap_word *map, unsigned long nbits)
{
unsigned long words = B_BITMAP_WORDS(nbits);
unsigned long bit_index = 0;
b_bitmap_word last_word = 0;
unsigned long i;
for (i = 0; i < words; i++) {
if (map[i] != (~(unsigned long)0)) {
last_word = map[i];
bit_index = i * Z__B_BITS_PER_WORD;
break;
}
}
if (last_word == 0) {
return bit_index;
}
if (last_word == (~(b_bitmap_word)0)) {
return B_BITMAP_NPOS;
}
return bit_index + b_clzl(~last_word);
}

325
ds/buffer.c Normal file
View File

@@ -0,0 +1,325 @@
#include "buffer.h"
#include <blue/core/iterator.h>
#include <blue/ds/buffer.h>
#include <blue/ds/type.h>
#include <stdlib.h>
#include <string.h>
static void buffer_release(struct b_dsref *obj);
static struct b_dsref_type buffer_type = {
.t_flags = B_DSREF_FUNDAMENTAL,
.t_id = B_DSREF_TYPE_BUFFER,
.t_name = "corelib::buffer",
.t_instance_size = sizeof(struct b_buffer),
.t_release = buffer_release,
};
struct b_buffer *b_buffer_create(size_t item_sz)
{
struct b_buffer *buffer
= (struct b_buffer *)b_dsref_type_instantiate(&buffer_type);
if (!buffer) {
return NULL;
}
buffer->buf_itemsz = item_sz;
return buffer;
}
struct b_buffer *b_buffer_create_from_bytes(const void *p, size_t len)
{
struct b_buffer *buffer = b_buffer_create(1);
if (!buffer) {
return NULL;
}
buffer->buf_len = len;
buffer->buf_cap = len;
buffer->buf_itemsz = 1;
buffer->buf_data = calloc(len, 1);
if (!buffer->buf_data) {
b_buffer_release(buffer);
return NULL;
}
memcpy(buffer->buf_data, p, len);
return buffer;
}
struct b_buffer *b_buffer_create_from_array(const void *p, size_t item_sz, size_t len)
{
struct b_buffer *buffer = b_buffer_create(1);
if (!buffer) {
return NULL;
}
buffer->buf_len = len;
buffer->buf_cap = len;
buffer->buf_itemsz = item_sz;
buffer->buf_data = calloc(len, item_sz);
if (!buffer->buf_data) {
b_buffer_release(buffer);
return NULL;
}
memcpy(buffer->buf_data, p, len * item_sz);
return buffer;
}
static b_status resize_buffer(struct b_buffer *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 B_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 B_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 B_SUCCESS;
}
void *b_buffer_steal(struct b_buffer *buf)
{
void *p = buf->buf_data;
buf->buf_data = NULL;
buf->buf_len = 0;
buf->buf_cap = 0;
return p;
}
enum b_status b_buffer_reserve(struct b_buffer *buf, size_t capacity)
{
if (buf->buf_cap >= capacity) {
return B_SUCCESS;
}
return resize_buffer(buf, capacity);
}
enum b_status b_buffer_resize(struct b_buffer *buf, size_t length)
{
enum b_status status = resize_buffer(buf, length);
if (!B_OK(status)) {
return status;
}
buf->buf_len = length;
return B_SUCCESS;
}
enum b_status b_buffer_append(struct b_buffer *buffer, const void *p, size_t count)
{
return b_buffer_insert(buffer, p, count, B_NPOS);
}
enum b_status b_buffer_prepend(struct b_buffer *buffer, const void *p, size_t count)
{
return b_buffer_insert(buffer, p, count, 0);
}
enum b_status b_buffer_insert(
struct b_buffer *buffer, const void *p, size_t count, size_t at)
{
if (at == B_NPOS) {
at = buffer->buf_len;
}
if (at > buffer->buf_len) {
return B_ERR_OUT_OF_BOUNDS;
}
b_status status = B_SUCCESS;
if (buffer->buf_len + count > buffer->buf_cap) {
status = resize_buffer(buffer, buffer->buf_cap + count);
if (status != B_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 B_SUCCESS;
}
enum b_status b_buffer_remove(struct b_buffer *buffer, size_t at, size_t count)
{
if (at >= buffer->buf_len) {
return B_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 B_SUCCESS;
}
void *b_buffer_ptr(const struct b_buffer *buffer)
{
return buffer->buf_data;
}
void *b_buffer_get(const struct b_buffer *buffer, size_t at)
{
if (at >= buffer->buf_len) {
return NULL;
}
return (unsigned char *)buffer->buf_data + (at * buffer->buf_itemsz);
}
size_t b_buffer_size(const struct b_buffer *buffer)
{
return buffer->buf_len;
}
size_t b_buffer_capacity(const struct b_buffer *buffer)
{
return buffer->buf_cap;
}
void buffer_release(struct b_dsref *obj)
{
struct b_buffer *buffer = B_BUFFER(obj);
if (buffer->buf_data) {
free(buffer->buf_data);
buffer->buf_data = NULL;
}
}
enum b_status b_buffer_clear(struct b_buffer *buffer)
{
buffer->buf_len = 0;
return B_SUCCESS;
}
enum b_status b_buffer_push_back(struct b_buffer *buf, size_t count, void **p)
{
enum b_status status = B_SUCCESS;
if (buf->buf_len + count > buf->buf_cap) {
status = resize_buffer(buf, buf->buf_len + count);
}
if (!B_OK(status)) {
return status;
}
buf->buf_len += count;
*p = b_buffer_get(buf, buf->buf_len - count);
return B_SUCCESS;
}
enum b_status b_buffer_push_front(struct b_buffer *buf, size_t count, void **p)
{
enum b_status status = B_SUCCESS;
if (buf->buf_len + count > buf->buf_cap) {
status = resize_buffer(buf, buf->buf_len + count);
}
if (!B_OK(status)) {
return status;
}
void *src = buf->buf_data;
void *dest = b_buffer_get(buf->buf_data, count);
size_t len = count * buf->buf_itemsz;
memmove(dest, src, len);
buf->buf_len += count;
*p = b_buffer_get(buf, 0);
return B_SUCCESS;
}
enum b_status b_buffer_pop_back(struct b_buffer *buf, size_t count)
{
if (count > buf->buf_len) {
return B_ERR_OUT_OF_BOUNDS;
}
buf->buf_len -= count;
return B_SUCCESS;
}
enum b_status b_buffer_pop_front(struct b_buffer *buf, size_t count)
{
if (count > buf->buf_len) {
return B_ERR_OUT_OF_BOUNDS;
}
void *src = b_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 B_SUCCESS;
}
size_t b_buffer_get_size(const struct b_buffer *buf)
{
return buf->buf_len;
}
size_t b_buffer_get_item_size(const struct b_buffer *buf)
{
return buf->buf_itemsz;
}
size_t b_buffer_get_capacity(const struct b_buffer *buf)
{
return buf->buf_cap;
}
b_dsref_type_id b_buffer_type_id(void)
{
return (b_dsref_type_id)&buffer_type;
}

17
ds/buffer.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef _BLUELIB_BUFFER_H_
#define _BLUELIB_BUFFER_H_
#include "../object.h"
struct b_buffer {
struct b_dsref buf_base;
/* 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;
};
#endif

483
ds/dict.c Normal file
View File

@@ -0,0 +1,483 @@
#include "dict.h"
#include <blue/core/status.h>
#include <blue/core/stream.h>
#include <blue/ds/dict.h>
#include <blue/ds/string.h>
#include <blue/ds/type.h>
#include <stdbool.h>
#include <stdlib.h>
#define HASH_OFFSET_BASIS 0xcbf29ce484222325
#define HASH_PRIME 0x100000001b3
uint64_t b_cstr_hash(const char *s)
{
uint64_t hash = HASH_OFFSET_BASIS;
for (size_t i = 0; s[i]; i++) {
hash *= HASH_PRIME;
hash ^= s[i];
}
return hash;
}
static void dict_release(struct b_dsref *obj);
static void dict_to_string(struct b_dsref *obj, struct b_stream *out);
static struct b_dsref_type dict_type = {
.t_name = "corelib::dict",
.t_flags = B_DSREF_FUNDAMENTAL,
.t_id = B_DSREF_TYPE_DICT,
.t_instance_size = sizeof(struct b_dict),
.t_release = dict_release,
.t_to_string = dict_to_string,
};
struct b_dict *b_dict_create(void)
{
struct b_dict *dict
= (struct b_dict *)b_dsref_type_instantiate(&dict_type);
if (!dict) {
return NULL;
}
return dict;
}
struct b_dict *b_dict_create_with_items(const b_dict_item *items)
{
struct b_dict *dict = b_dict_create();
if (!dict) {
return NULL;
}
for (size_t i = 0; items[i].key; i++) {
b_dict_put(dict, items[i].key, items[i].value);
}
return dict;
}
static B_BTREE_DEFINE_SIMPLE_GET(
struct b_dict_bucket, uint64_t, bk_node, bk_hash,
get_bucket) static B_BTREE_DEFINE_SIMPLE_INSERT(struct b_dict_bucket, bk_node, bk_hash, put_bucket)
static struct b_dict_bucket *create_bucket(void)
{
struct b_dict_bucket *bucket = malloc(sizeof *bucket);
if (!bucket) {
return NULL;
}
memset(bucket, 0x0, sizeof *bucket);
return bucket;
}
static struct b_dict_bucket_item *create_bucket_item(void)
{
struct b_dict_bucket_item *item = malloc(sizeof *item);
if (!item) {
return NULL;
}
memset(item, 0x0, sizeof *item);
return item;
}
b_status b_dict_put(struct b_dict *dict, const char *key, b_dsref *value)
{
uint64_t hash = b_cstr_hash(key);
struct b_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
if (!bucket) {
bucket = create_bucket();
if (!bucket) {
return B_ERR_NO_MEMORY;
}
bucket->bk_hash = hash;
put_bucket(&dict->d_buckets, bucket);
}
struct b_dict_bucket_item *item = create_bucket_item();
if (!item) {
return B_ERR_NO_MEMORY;
}
item->bi_str = b_strdup(key);
item->bi_value = b_retain(value);
b_queue_push_back(&bucket->bk_items, &item->bi_entry);
return B_SUCCESS;
}
b_dsref *b_dict_at(const struct b_dict *dict, const char *key)
{
uint64_t hash = b_cstr_hash(key);
struct b_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
if (!bucket) {
return NULL;
}
b_queue_iterator it;
b_queue_foreach (&it, &bucket->bk_items) {
struct b_dict_bucket_item *item
= b_unbox(struct b_dict_bucket_item, it.entry, bi_entry);
if (!strcmp(item->bi_str, key)) {
return item->bi_value;
}
}
return NULL;
}
b_dsref *b_dict_get(struct b_dict *dict, const char *key)
{
b_dsref *value = b_dict_at(dict, key);
if (value) {
b_retain(value);
}
return value;
}
bool b_dict_has_key(const struct b_dict *dict, const char *key)
{
return b_dict_at(dict, key) != NULL;
}
size_t b_dict_get_size(const struct b_dict *dict)
{
size_t count = 0;
b_btree_iterator it1;
b_queue_iterator it2;
b_btree_foreach (&it1, &dict->d_buckets) {
struct b_dict_bucket *bucket
= b_unbox(struct b_dict_bucket, it1.node, bk_node);
b_queue_foreach (&it2, &bucket->bk_items) {
count++;
}
}
return count;
}
bool b_dict_is_empty(const b_dict *dict)
{
b_btree_node *first_node = b_btree_first(&dict->d_buckets);
struct b_dict_bucket *first_bucket
= b_unbox(struct b_dict_bucket, first_node, bk_node);
if (!first_bucket) {
return true;
}
b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items);
struct b_dict_bucket_item *first_item
= b_unbox(struct b_dict_bucket_item, first_entry, bi_entry);
if (!first_item) {
return true;
}
return false;
}
static void dict_to_string(struct b_dsref *obj, struct b_stream *out)
{
struct b_dict *dict = B_DICT(obj);
if (b_dict_is_empty(dict)) {
b_stream_write_string(out, "{}", NULL);
return;
}
b_stream_write_string(out, "{\n", NULL);
b_stream_push_indent(out, 1);
size_t len = b_dict_get_size(dict);
b_dict_iterator it;
b_dict_foreach(&it, dict)
{
b_stream_write_fmt(out, NULL, "%s: ", it.key);
bool is_string = b_typeid(it.value) == B_DSREF_TYPE_STRING;
if (is_string) {
b_stream_write_char(out, '"');
}
b_to_string(it.value, out);
if (is_string) {
b_stream_write_char(out, '"');
}
if (it.i < len - 1) {
b_stream_write_string(out, ",", NULL);
}
b_stream_write_char(out, '\n');
}
b_stream_pop_indent(out);
b_stream_write_char(out, '}');
}
static bool dict_iterator_next(struct b_iterator *it)
{
return b_dict_iterator_next((struct b_dict_iterator *)it);
}
static b_status dict_iterator_erase(struct b_iterator *it)
{
return b_dict_iterator_erase((struct b_dict_iterator *)it);
}
static bool dict_iterator_is_valid(const struct b_iterator *it)
{
return b_dict_iterator_is_valid((struct b_dict_iterator *)it);
}
static struct b_iterator_ops it_ops
= {.it_next = dict_iterator_next,
.it_close = NULL,
.it_erase = dict_iterator_erase,
.it_is_valid = dict_iterator_is_valid};
int b_dict_iterator_begin(struct b_dict *dict, b_dict_iterator *it)
{
it->_base.it_ops = &it_ops;
it->i = 0;
if (b_dict_is_empty(dict)) {
it->key = NULL;
it->value = NULL;
return -1;
}
b_btree_node *first_node = b_btree_first(&dict->d_buckets);
struct b_dict_bucket *first_bucket
= b_unbox(struct b_dict_bucket, first_node, bk_node);
if (!first_bucket) {
it->key = NULL;
it->value = NULL;
return -1;
}
b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items);
struct b_dict_bucket_item *first_item
= b_unbox(struct b_dict_bucket_item, first_entry, bi_entry);
if (!first_item) {
it->key = NULL;
it->value = NULL;
return -1;
}
it->key = first_item->bi_str;
it->value = first_item->bi_value;
it->_d = dict;
it->_cbn = first_node;
it->_cqe = first_entry;
return 0;
}
static bool get_next_node(
struct b_btree_node *cur_node, struct b_queue_entry *cur_entry,
struct b_btree_node **out_next_node, struct b_queue_entry **out_next_entry)
{
struct b_dict_bucket *cur_bucket
= b_unbox(struct b_dict_bucket, cur_node, bk_node);
if (!cur_bucket) {
return false;
}
struct b_dict_bucket_item *cur_item
= b_unbox(struct b_dict_bucket_item, cur_entry, bi_entry);
if (!cur_item) {
return false;
}
struct b_btree_node *next_node = cur_node;
struct b_queue_entry *next_entry = b_queue_next(cur_entry);
if (!next_entry) {
next_node = b_btree_next(cur_node);
if (!next_node) {
return false;
}
struct b_dict_bucket *next_bucket
= b_unbox(struct b_dict_bucket, next_node, bk_node);
if (!next_bucket) {
return false;
}
next_entry = b_queue_first(&next_bucket->bk_items);
if (!next_entry) {
return false;
}
}
struct b_dict_bucket_item *next_item
= b_unbox(struct b_dict_bucket_item, next_entry, bi_entry);
if (!next_item) {
return false;
}
*out_next_node = next_node;
*out_next_entry = next_entry;
return true;
}
bool b_dict_iterator_next(b_dict_iterator *it)
{
struct b_btree_node *next_node;
struct b_queue_entry *next_entry;
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
it->key = NULL;
it->value = NULL;
return -1;
}
struct b_dict_bucket_item *next_item
= b_unbox(struct b_dict_bucket_item, next_entry, bi_entry);
if (!next_item) {
it->key = NULL;
it->value = NULL;
return -1;
}
it->i++;
it->key = next_item->bi_str;
it->value = next_item->bi_value;
it->_cbn = next_node;
it->_cqe = next_entry;
return 0;
}
static b_status delete_item(
struct b_dict *dict, struct b_dict_bucket *bucket,
struct b_dict_bucket_item *item)
{
b_queue_delete(&bucket->bk_items, &item->bi_entry);
free(item);
if (b_queue_empty(&bucket->bk_items)) {
b_btree_delete(&dict->d_buckets, &bucket->bk_node);
free(bucket);
}
return B_SUCCESS;
}
b_status b_dict_iterator_erase(struct b_dict_iterator *it)
{
if ((it->key || it->value) && !(it->_cbn && it->_cqe)) {
return B_ERR_BAD_STATE;
}
if (!it->key || !it->_cqe) {
return B_ERR_OUT_OF_BOUNDS;
}
struct b_btree_node *next_node;
struct b_queue_entry *next_entry;
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
it->key = NULL;
it->value = NULL;
return false;
}
struct b_dict_bucket *cur_bucket
= b_unbox(struct b_dict_bucket, it->_cbn, bk_node);
struct b_dict_bucket_item *cur_item
= b_unbox(struct b_dict_bucket_item, it->_cqe, bi_entry);
struct b_dict_bucket_item *next_item
= b_unbox(struct b_dict_bucket_item, next_entry, bi_entry);
b_status status = delete_item(it->_d, cur_bucket, cur_item);
if (B_ERR(status)) {
return status;
}
if (next_item) {
it->key = next_item->bi_str;
it->value = next_item->bi_value;
it->_cbn = next_node;
it->_cqe = next_entry;
} else {
it->key = NULL;
it->value = NULL;
it->_cbn = NULL;
it->_cqe = NULL;
}
return B_SUCCESS;
}
bool b_dict_iterator_is_valid(const struct b_dict_iterator *it)
{
return it->key != NULL;
}
static void dict_release(struct b_dsref *obj)
{
struct b_dict *dict = B_DICT(obj);
b_btree_iterator tree_it;
b_btree_iterator_begin(&dict->d_buckets, &tree_it);
while (b_btree_iterator_is_valid(&tree_it)) {
struct b_dict_bucket *bucket
= b_unbox(struct b_dict_bucket, tree_it.node, bk_node);
b_btree_iterator_erase(&tree_it);
if (!bucket) {
continue;
}
b_queue_iterator bucket_it;
b_queue_iterator_begin(&bucket->bk_items, &bucket_it);
while (b_queue_iterator_is_valid(&bucket_it)) {
struct b_dict_bucket_item *item = b_unbox(
struct b_dict_bucket_item, bucket_it.entry,
bi_entry);
b_queue_iterator_erase(&bucket_it);
if (!item) {
continue;
}
free(item->bi_str);
b_release(item->bi_value);
free(item);
}
free(bucket);
}
#if 0
b_dict_iterator it;
b_dict_iterator_begin(dict, &it);
while (b_dict_iterator_is_valid(&it)) {
b_dict_iterator_erase(&it);
}
#endif
}
b_dsref_type_id b_dict_type_id(void)
{
return (b_dsref_type_id)&dict_type;
}

26
ds/dict.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef _B_DICT_H_
#define _B_DICT_H_
#include "object.h"
#include <blue/core/btree.h>
#include <blue/core/queue.h>
struct b_dict_bucket_item {
b_queue_entry bi_entry;
char *bi_str;
struct b_dsref *bi_value;
};
struct b_dict_bucket {
b_btree_node bk_node;
uint64_t bk_hash;
b_queue bk_items;
};
struct b_dict {
struct b_dsref d_base;
b_btree d_buckets;
};
#endif

461
ds/hashmap.c Normal file
View File

@@ -0,0 +1,461 @@
#include "hashmap.h"
#include <blue/core/misc.h>
#include <blue/core/status.h>
#include <blue/ds/hashmap.h>
#include <blue/ds/string.h>
#include <blue/ds/type.h>
#include <stdbool.h>
#include <stdlib.h>
#define HASH_OFFSET_BASIS 0xcbf29ce484222325
#define HASH_PRIME 0x100000001b3
/* clang-format off */
static B_BTREE_DEFINE_SIMPLE_GET(
struct b_hashmap_bucket,
uint64_t,
bk_node,
bk_hash,
get_bucket)
static B_BTREE_DEFINE_SIMPLE_INSERT(
struct b_hashmap_bucket,
bk_node,
bk_hash,
put_bucket)
static uint64_t hash_data(const void *p, size_t size)
{
/* clang-format on */
const unsigned char *s = p;
uint64_t hash = HASH_OFFSET_BASIS;
for (size_t i = 0; s[i]; i++) {
hash *= HASH_PRIME;
hash ^= s[i];
}
return hash;
}
static void hashmap_release(struct b_dsref *obj);
static struct b_dsref_type hashmap_type = {
.t_name = "corelib::hashmap",
.t_flags = B_DSREF_FUNDAMENTAL,
.t_id = B_DSREF_TYPE_HASHMAP,
.t_instance_size = sizeof(struct b_hashmap),
.t_release = hashmap_release,
};
struct b_hashmap *b_hashmap_create(
b_hashmap_key_destructor key_dtor, b_hashmap_value_destructor value_dtor)
{
struct b_hashmap *hashmap
= (struct b_hashmap *)b_dsref_type_instantiate(&hashmap_type);
if (!hashmap) {
return NULL;
}
return hashmap;
}
struct b_hashmap *b_hashmap_create_with_items(const b_hashmap_item *items)
{
struct b_hashmap *hashmap = b_hashmap_create(NULL, NULL);
if (!hashmap) {
return NULL;
}
for (size_t i = 0; items[i].key.key_data && items[i].key.key_size; i++) {
b_hashmap_put(hashmap, &items[i].key, &items[i].value);
}
return hashmap;
}
static struct b_hashmap_bucket *create_bucket(void)
{
/* clang-format on */
struct b_hashmap_bucket *bucket = malloc(sizeof *bucket);
if (!bucket) {
return NULL;
}
memset(bucket, 0x0, sizeof *bucket);
return bucket;
}
static struct b_hashmap_bucket_item *create_bucket_item(void)
{
struct b_hashmap_bucket_item *item = malloc(sizeof *item);
if (!item) {
return NULL;
}
memset(item, 0x0, sizeof *item);
return item;
}
b_status b_hashmap_put(
struct b_hashmap *hashmap, const b_hashmap_key *key,
const b_hashmap_value *value)
{
uint64_t hash = hash_data(key->key_data, key->key_size);
struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
if (!bucket) {
bucket = create_bucket();
if (!bucket) {
return B_ERR_NO_MEMORY;
}
bucket->bk_hash = hash;
put_bucket(&hashmap->h_buckets, bucket);
}
b_queue_iterator it;
b_queue_foreach (&it, &bucket->bk_items) {
struct b_hashmap_bucket_item *item = b_unbox(
struct b_hashmap_bucket_item, it.entry, bi_entry);
if (item->bi_key.key_size != key->key_size) {
continue;
}
if (!memcmp(item->bi_key.key_data, key->key_data, key->key_size)) {
return B_ERR_NAME_EXISTS;
}
}
struct b_hashmap_bucket_item *item = create_bucket_item();
if (!item) {
return B_ERR_NO_MEMORY;
}
memcpy(&item->bi_key, key, sizeof *key);
memcpy(&item->bi_value, value, sizeof *value);
b_queue_push_back(&bucket->bk_items, &item->bi_entry);
return B_SUCCESS;
}
const struct b_hashmap_value *b_hashmap_get(
const struct b_hashmap *hashmap, const struct b_hashmap_key *key)
{
uint64_t hash = hash_data(key->key_data, key->key_size);
struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
if (!bucket) {
return NULL;
}
b_queue_iterator it;
b_queue_foreach (&it, &bucket->bk_items) {
struct b_hashmap_bucket_item *item = b_unbox(
struct b_hashmap_bucket_item, it.entry, bi_entry);
if (item->bi_key.key_size != key->key_size) {
continue;
}
if (!memcmp(item->bi_key.key_data, key->key_data, key->key_size)) {
return &item->bi_value;
}
}
return NULL;
}
bool b_hashmap_has_key(const struct b_hashmap *hashmap, const b_hashmap_key *key)
{
uint64_t hash = hash_data(key->key_data, key->key_size);
struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
if (!bucket) {
return false;
}
b_queue_iterator it;
b_queue_foreach (&it, &bucket->bk_items) {
struct b_hashmap_bucket_item *item = b_unbox(
struct b_hashmap_bucket_item, it.entry, bi_entry);
if (item->bi_key.key_size != key->key_size) {
continue;
}
if (!memcmp(item->bi_key.key_data, key->key_data, key->key_size)) {
return true;
}
}
return false;
}
size_t b_hashmap_get_size(const struct b_hashmap *hashmap)
{
size_t count = 0;
b_btree_iterator it1;
b_queue_iterator it2;
b_btree_foreach (&it1, &hashmap->h_buckets) {
struct b_hashmap_bucket *bucket
= b_unbox(struct b_hashmap_bucket, it1.node, bk_node);
b_queue_foreach (&it2, &bucket->bk_items) {
count++;
}
}
return count;
}
bool b_hashmap_is_empty(const b_hashmap *hashmap)
{
b_btree_node *first_node = b_btree_first(&hashmap->h_buckets);
struct b_hashmap_bucket *first_bucket
= b_unbox(struct b_hashmap_bucket, first_node, bk_node);
if (!first_bucket) {
return true;
}
b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items);
struct b_hashmap_bucket_item *first_item
= b_unbox(struct b_hashmap_bucket_item, first_entry, bi_entry);
if (!first_item) {
return true;
}
return false;
}
static b_status delete_item(
struct b_hashmap *hashmap, struct b_hashmap_bucket *bucket,
struct b_hashmap_bucket_item *item)
{
b_queue_delete(&bucket->bk_items, &item->bi_entry);
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 (b_queue_empty(&bucket->bk_items)) {
b_btree_delete(&hashmap->h_buckets, &bucket->bk_node);
free(bucket);
}
return B_SUCCESS;
}
static bool hashmap_iterator_next(struct b_iterator *it)
{
return b_hashmap_iterator_next((struct b_hashmap_iterator *)it);
}
static b_status hashmap_iterator_erase(struct b_iterator *it)
{
return b_hashmap_iterator_erase((struct b_hashmap_iterator *)it);
}
static bool hashmap_iterator_is_valid(const struct b_iterator *it)
{
return b_hashmap_iterator_is_valid((struct b_hashmap_iterator *)it);
}
static struct b_iterator_ops it_ops = {
.it_next = hashmap_iterator_next,
.it_erase = hashmap_iterator_erase,
.it_close = NULL,
.it_is_valid = hashmap_iterator_is_valid,
};
int b_hashmap_iterator_begin(
struct b_hashmap *hashmap, struct b_hashmap_iterator *it)
{
it->_h = hashmap;
it->_base.it_ops = &it_ops;
it->i = 0;
if (b_hashmap_is_empty(hashmap)) {
it->key = NULL;
it->value = NULL;
return -1;
}
struct b_btree_node *first_node = b_btree_first(&hashmap->h_buckets);
struct b_hashmap_bucket *first_bucket
= b_unbox(struct b_hashmap_bucket, first_node, bk_node);
if (!first_bucket) {
it->key = NULL;
it->value = NULL;
return -1;
}
struct b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items);
struct b_hashmap_bucket_item *first_item
= b_unbox(struct b_hashmap_bucket_item, first_entry, bi_entry);
if (!first_item) {
it->key = NULL;
it->value = NULL;
return -1;
}
it->key = &first_item->bi_key;
it->value = &first_item->bi_value;
it->_cbn = first_node;
it->_cqe = first_entry;
return 0;
}
static bool get_next_node(
struct b_btree_node *cur_node, struct b_queue_entry *cur_entry,
struct b_btree_node **out_next_node, struct b_queue_entry **out_next_entry)
{
struct b_hashmap_bucket *cur_bucket
= b_unbox(struct b_hashmap_bucket, cur_node, bk_node);
if (!cur_bucket) {
return false;
}
struct b_hashmap_bucket_item *cur_item
= b_unbox(struct b_hashmap_bucket_item, cur_entry, bi_entry);
if (!cur_item) {
return false;
}
struct b_btree_node *next_node = cur_node;
struct b_queue_entry *next_entry = b_queue_next(cur_entry);
if (!next_entry) {
next_node = b_btree_next(cur_node);
if (!next_node) {
return false;
}
struct b_hashmap_bucket *next_bucket
= b_unbox(struct b_hashmap_bucket, next_node, bk_node);
if (!next_bucket) {
return false;
}
next_entry = b_queue_first(&next_bucket->bk_items);
if (!next_entry) {
return false;
}
}
struct b_hashmap_bucket_item *next_item
= b_unbox(struct b_hashmap_bucket_item, next_entry, bi_entry);
if (!next_item) {
return false;
}
*out_next_node = next_node;
*out_next_entry = next_entry;
return true;
}
bool b_hashmap_iterator_next(struct b_hashmap_iterator *it)
{
struct b_btree_node *next_node;
struct b_queue_entry *next_entry;
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
it->key = NULL;
it->value = NULL;
return false;
}
struct b_hashmap_bucket_item *next_item
= b_unbox(struct b_hashmap_bucket_item, next_entry, bi_entry);
if (!next_item) {
it->key = NULL;
it->value = NULL;
return false;
}
it->i++;
it->key = &next_item->bi_key;
it->value = &next_item->bi_value;
it->_cbn = next_node;
it->_cqe = next_entry;
return true;
}
b_status b_hashmap_iterator_erase(struct b_hashmap_iterator *it)
{
if ((it->key || it->value) && !(it->_cbn && it->_cqe)) {
return B_ERR_BAD_STATE;
}
if (!it->key || !it->_cqe) {
return B_ERR_OUT_OF_BOUNDS;
}
struct b_btree_node *next_node;
struct b_queue_entry *next_entry;
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
it->key = NULL;
it->value = NULL;
return false;
}
struct b_hashmap_bucket *cur_bucket
= b_unbox(struct b_hashmap_bucket, it->_cbn, bk_node);
struct b_hashmap_bucket_item *cur_item
= b_unbox(struct b_hashmap_bucket_item, it->_cqe, bi_entry);
struct b_hashmap_bucket_item *next_item
= b_unbox(struct b_hashmap_bucket_item, next_entry, bi_entry);
b_status status = delete_item(it->_h, cur_bucket, cur_item);
if (B_ERR(status)) {
return status;
}
if (next_item) {
it->key = &next_item->bi_key;
it->value = &next_item->bi_value;
it->_cbn = next_node;
it->_cqe = next_entry;
} else {
it->key = NULL;
it->value = NULL;
it->_cbn = NULL;
it->_cqe = NULL;
}
return B_SUCCESS;
}
bool b_hashmap_iterator_is_valid(const struct b_hashmap_iterator *it)
{
return it->key != NULL;
}
static void hashmap_release(struct b_dsref *obj)
{
struct b_hashmap *map = B_HASHMAP(obj);
b_hashmap_iterator it;
b_hashmap_iterator_begin(map, &it);
while (b_hashmap_iterator_is_valid(&it)) {
b_hashmap_iterator_erase(&it);
}
}
b_dsref_type_id b_hashmap_type_id(void)
{
return (b_dsref_type_id)&hashmap_type;
}

27
ds/hashmap.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef _B_HASHMAP_H_
#define _B_HASHMAP_H_
#include <blue/core/btree.h>
#include <blue/core/queue.h>
#include <blue/ds/hashmap.h>
struct b_hashmap_bucket_item {
struct b_queue_entry bi_entry;
struct b_hashmap_key bi_key;
struct b_hashmap_value bi_value;
};
struct b_hashmap_bucket {
struct b_btree_node bk_node;
uint64_t bk_hash;
struct b_queue bk_items;
};
struct b_hashmap {
struct b_dsref h_base;
struct b_btree h_buckets;
b_hashmap_key_destructor h_key_dtor;
b_hashmap_value_destructor h_value_dtor;
};
#endif

0
ds/include/blue/ds.h Normal file
View File

304
ds/include/blue/ds/array.h Normal file
View File

@@ -0,0 +1,304 @@
#ifndef BLUELIB_ARRAY_H_
#define BLUELIB_ARRAY_H_
#include <blue/core/iterator.h>
#include <blue/core/misc.h>
#include <blue/core/status.h>
#include <blue/ds/object.h>
#include <blue/ds/type.h>
/**
* Cast a generic b_dsref pointer to an b_array pointer.
*/
#define B_ARRAY(p) ((b_array *)(p))
/**
* Iterate through each object in an b_array.
*
* This should be used for read-only iterations only. Adding or removing objects
* while iterating though an array using b_array_foreach is NOT supported.
*
* @param it A pointer to an b_array_iterator. This iterator will contain the
* current object reference for the current loop iteration.
* @param array A pointer to the b_array to iterate over.
*/
#define b_array_foreach(it, array) \
for (int z__b_unique_name() = b_array_iterator_begin(array, it); \
(it)->value != NULL; b_array_iterator_next(it))
#ifdef __cplusplus
extern "C" {
#endif
/**
* A heterogeneous array of objects. b_array only stores references
* to the objects that it contains, not the object data itself.
*
* b_array stores pointers to objects in a single contiguous array,
* but this is an implementation detail that may change in the future.
* Users of b_array should not rely on this being the case.
*/
typedef struct b_array b_array;
/**
* Iterator for traversing the contents of an b_array.
*
* The iterator provides the current b_dsref `value`, as well
* as the index `i` of that value within the array.
*
* Any members whose names begin with _ (underscore) are reserved
* and should not be accessed.
*/
typedef struct b_array_iterator {
b_iterator _base;
b_array *_a;
/** The index of the current value */
size_t i;
/** The current value */
b_dsref *value;
} b_array_iterator;
/**
* Creates an empty b_array.
*
* @return A pointer to the new array, or NULL if an error occurred.
*/
BLUE_API b_array *b_array_create(void);
/**
* Creates an b_array initialised with the contents of the provided b_dsref
* pointer array. The b_array will take a reference to each object specified in
* `values`, and will increment the reference count. The order of objects in the
* new b_array will be the same as the order of objects in `values`. Any NULL
* pointers in the `values` array will be ignored, and will not result in gaps
* in the created b_array. However, `nr_values` should be large enough to cover
* the final non-NULL pointer in `values`, including any NULL pointers
* in-between.
*
* @param values The list of object pointers which should make up the contents
* of the new b_array.
* @param nr_values The size of the `values` array.
* @return A pointer to the new b_array, or NULL if an error occurred.
*/
BLUE_API b_array *b_array_create_with_values(
b_dsref *const *values, size_t nr_values);
/**
* Increment the reference counter of an b_array.
*
* @param array The b_array to reference.
* @return The b_array pointer that was passed to the function.
*/
static inline b_array *b_array_retain(b_array *array)
{
return B_ARRAY(b_retain(B_DSREF(array)));
}
/**
* Decrement the reference counter of an b_array, destroying the array if it reaches zero.
* @param array The b_array reference to release.
*/
static inline void b_array_release(b_array *array)
{
b_release(B_DSREF(array));
}
/**
* Remove all object references from an b_array, resetting the size of the array to zero.
* The reference counts of all objects in the array will be decremented.
*
* @param array The b_array to clear.
*/
BLUE_API void b_array_clear(b_array *array);
/**
* Inserts an object at the end of an b_array. The reference count of the object
* will be incremented.
*
* @param array The b_array to append the object to.
* @param value The object to append.
* @return B_SUCCESS if the object was appended successfully, or an error code if an error occurred.
*/
BLUE_API b_status b_array_append(b_array *array, b_dsref *value);
/**
* Inserts an object at the beginning of an b_array. The reference count of the object
* will be incremented. All other objects in the array will be moved to make space
* for the object being pre-pended.
*
* @param array The b_array to prepend the object to.
* @param value The object to prepend.
* @return B_SUCCESS if the object was prepended successfully, or an error code if an error occurred.
*/
BLUE_API b_status b_array_prepend(b_array *array, b_dsref *value);
/**
* Inserts an object into an b_array at a given index. The reference count of the object
* will be incremented. If the specified index is at the beginning or mid-way through
* the array (i.e. not at the end), some or all of the objects already in the array will
* be moved to make space for the object being inserted.
*
* @param array The b_array to insert the object into.
* @param value The object to insert.
* @param at The index to insert the object at. If the index is `B_NPOS`, the object will
* be inserted at the end of the b_array.
* @return B_SUCCESS if the object was inserted, or a status code describing any error that occurred.
*/
BLUE_API b_status b_array_insert(b_array *array, b_dsref *value, size_t at);
/**
* Removes the object at the specified index from an b_array. The reference count
* of the removed object will be decremented. If the specified index is at the beginning
* or mid-way through the array (i.e. not at the end), the remaining objects will be moved
* to fill the empty space created by the object's removal.
*
* @param array The b_array to remove the object from.
* @param at The index of the object to be removed.
* @return B_SUCCESS if the object was removed, or a status code describing any error that occurred.
*/
BLUE_API b_status b_array_remove(b_array *array, size_t at);
/**
* Removes the object at the beginning of an b_array. The reference count
* of the removed object will be decremented. The remaining objects will be moved
* to fill the empty space created by the object's removal.
*
* @param array The b_array to remove the object from.
* @return B_SUCCESS if the object was removed, or a status code describing any error that occurred.
*/
BLUE_API b_status b_array_remove_front(b_array *array);
/**
* Removes the object at the end of an b_array. The reference count
* of the removed object will be decremented.
*
* @param array The b_array to remove the object from.
* @return B_SUCCESS if the object was removed, or a status code describing any error that occurred.
*/
BLUE_API b_status b_array_remove_back(b_array *array);
/**
* Removes the object at the specified index of an b_array, and returns a
* pointer to it. The reference count of the removed object will NOT be
* decremented. The caller becomes the owner of the array's reference to the
* object. If the specified index is at the beginning or mid-way through the
* array (i.e. not at the end), the remaining objects will be moved to fill the
* empty space created by the object's removal.
*
* @param array The b_array to remove the object from.
* @param at The index of the object to be removed.
* @return An pointer to the removed object. This pointer is owned by the
* caller. Returns NULL if an error occurred.
*/
BLUE_API b_dsref *b_array_pop(b_array *array, size_t at);
/**
* Removes the object at the beginning of an b_array, and returns a pointer to
* it. The reference count of the removed object will NOT be decremented. The
* caller becomes the owner of the array's reference to the object. The
* remaining objects in the b_array will be moved to fill the empty space left
* by the removed object.
*
* @param array The b_array to remove the object from.
* @return An pointer to the removed object. This pointer is owned by the
* caller. Returns NULL if an error occurred.
*/
BLUE_API b_dsref *b_array_pop_front(b_array *array);
/**
* Removes the object at the end of an b_array, and returns a pointer to it. The
* reference count of the removed object will NOT be decremented. The caller
* becomes the owner of the array's reference to the object.
*
* @param array The b_array to remove the object from.
* @return An pointer to the removed object. This pointer is owned by the
* caller. Returns NULL if an error occurred.
*/
BLUE_API b_dsref *b_array_pop_back(b_array *array);
/**
* Returns an unowned pointer to the object at the given index of an b_array.
* The caller does not own the returned pointer, and MUST NOT release it.
*
* @param array The b_array.
* @param at The index of the object to return.
* @return A pointer to the object at the given index. This pointer is NOT owned
* by the caller. Returns NULL if an error occurred.
*/
BLUE_API b_dsref *b_array_at(const b_array *array, size_t at);
/**
* Returns an owned pointer to the object at the given index of an b_array. The caller owns
* the returned pointer, and must release it when they are finished with it.
*
* @param array The b_array.
* @param at The index of the object to return.
* @return A pointer to the object at the given index. This pointer is owned by the caller.
* Returns NULL if an error occurred.
*/
BLUE_API b_dsref *b_array_get(b_array *array, size_t at);
/**
* Returns the number of objects contained in an b_array.
*
* @param array The b_array.
* @return The number of objects contained in the b_array.
*/
BLUE_API size_t b_array_size(const b_array *array);
/**
* Returns the current maximum capacity of an b_array. This represents the
* number of objects that can be stored in an b_array before its internal buffer
* would need to be re-sized.
*
* @param array The b_array.
* @return The maximum capacity of the b_array.
*/
BLUE_API size_t b_array_capacity(const b_array *array);
/**
* Initialise an b_array_iterator to pointer to the first object in an b_array.
* If the b_array is empty, then `it` will be an invalid iterator.
*
* @param array
* @param it
* @return Always returns 0.
*/
BLUE_API int b_array_iterator_begin(b_array *array, b_array_iterator *it);
/**
* Advances an b_array_iterator to pointer to the next object in an b_array.
* @param it The iterator to advance.
* @return True if the iterator contains a valid reference to an object, or
* False if the iterator has gone past the end of the array.
*/
BLUE_API bool b_array_iterator_next(b_array_iterator *it);
/**
* Removes the object pointed to by an b_array_iterator from its container
* b_array, and advances the iterator to the next object in the b_array.
*
* The reference count of the removed object will be decremented.
*
* @param it The iterator whose object should be removed.
* @return B_SUCCESS if the object was removed, or a status code describing the error that occurred.
*/
BLUE_API b_status b_array_iterator_erase(b_array_iterator *it);
/**
* Checks whether or not an iterator contains a valid reference to an object.
* An iterator will become invalid if it has moved past the end of the b_array
* it was iterating across, or if b_array_iterator_erase() was called on an
* iterator pointing to the last object in an b_array.
*
* @param it The iterator to check.
* @return True if the iterator is valid. False otherwise.
*/
BLUE_API bool b_array_iterator_is_valid(const b_array_iterator *it);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,30 @@
#ifndef BLUE_OBJECT_BITBUFFER_H_
#define BLUE_OBJECT_BITBUFFER_H_
#include <blue/ds/object.h>
#define B_BITBUFFER(p) ((b_bitbuffer *)(p))
typedef struct b_bitbuffer b_bitbuffer;
BLUE_API b_bitbuffer *b_bitbuffer_create(void);
static inline b_bitbuffer *b_bitbuffer_retain(b_bitbuffer *buf)
{
return B_BITBUFFER(b_retain(B_DSREF(buf)));
}
static inline void b_bitbuffer_release(b_bitbuffer *buf)
{
b_release(B_DSREF(buf));
}
BLUE_API b_status b_bitbuffer_put_bit(b_bitbuffer *buf, int bit);
BLUE_API b_status b_bitbuffer_put_bool(b_bitbuffer *buf, bool b);
BLUE_API b_status b_bitbuffer_put_int(
b_bitbuffer *buf, uint64_t v, unsigned int nr_bits);
BLUE_API b_status b_bitbuffer_put_bytes(
b_bitbuffer *buf, const void *p, size_t len, size_t bits_per_byte);
BLUE_API b_status b_bitbuffer_put_string(
b_bitbuffer *buf, const char *p, size_t len, size_t bits_per_char);
#endif

View File

@@ -0,0 +1,35 @@
#ifndef BLUELIB_BITMAP_H_
#define BLUELIB_BITMAP_H_
#include <blue/core/misc.h>
#include <stdbool.h>
typedef unsigned long b_bitmap_word;
#define Z__B_BITS_PER_WORD (8 * sizeof(b_bitmap_word))
#define Z__B_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define B_BITMAP_WORDS(nbits) Z__B_DIV_ROUND_UP(nbits, Z__B_BITS_PER_WORD)
#define B_BITMAP_NPOS ((unsigned int)-1)
#define B_DECLARE_BITMAP(name, nbits) b_bitmap_word name[B_BITMAP_WORDS(nbits)]
BLUE_API void b_bitmap_zero(b_bitmap_word *map, unsigned long nbits);
BLUE_API void b_bitmap_fill(b_bitmap_word *map, unsigned long nbits);
BLUE_API void b_bitmap_set(b_bitmap_word *map, unsigned long bit);
BLUE_API void b_bitmap_clear(b_bitmap_word *map, unsigned long bit);
BLUE_API bool b_bitmap_check(const b_bitmap_word *map, unsigned long bit);
BLUE_API unsigned int b_bitmap_count_set(const b_bitmap_word *map, unsigned long nbits);
BLUE_API unsigned int b_bitmap_count_clear(const b_bitmap_word *map, unsigned long nbits);
BLUE_API unsigned int b_bitmap_highest_set(const b_bitmap_word *map, unsigned long nbits);
BLUE_API unsigned int b_bitmap_highest_clear(const b_bitmap_word *map, unsigned long nbits);
BLUE_API unsigned int b_bitmap_lowest_set(const b_bitmap_word *map, unsigned long nbits);
BLUE_API unsigned int b_bitmap_lowest_clear(const b_bitmap_word *map, unsigned long nbits);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,49 @@
#ifndef BLUELIB_BUFFER_H_
#define BLUELIB_BUFFER_H_
#include <blue/ds/object.h>
#include <blue/ds/type.h>
#include <stddef.h>
#define B_BUFFER(p) ((b_buffer *)(p))
typedef struct b_buffer b_buffer;
BLUE_API b_buffer *b_buffer_create(size_t item_sz);
BLUE_API b_buffer *b_buffer_create_from_bytes(const void *p, size_t len);
BLUE_API b_buffer *b_buffer_create_from_array(
const void *p, size_t item_sz, size_t len);
static inline b_buffer *b_buffer_retain(b_buffer *buf)
{
return B_BUFFER(b_retain(B_DSREF(buf)));
}
static inline void b_buffer_release(b_buffer *buf)
{
b_release(B_DSREF(buf));
}
BLUE_API void *b_buffer_steal(b_buffer *buf);
BLUE_API b_status b_buffer_reserve(b_buffer *buf, size_t capacity);
BLUE_API b_status b_buffer_resize(b_buffer *buf, size_t length);
BLUE_API b_status b_buffer_append(b_buffer *dest, const void *p, size_t count);
BLUE_API b_status b_buffer_prepend(b_buffer *dest, const void *p, size_t count);
BLUE_API b_status b_buffer_insert(
b_buffer *dest, const void *p, size_t count, size_t at);
BLUE_API b_status b_buffer_remove(b_buffer *dest, size_t at, size_t count);
BLUE_API b_status b_buffer_clear(b_buffer *buf);
BLUE_API b_status b_buffer_push_back(b_buffer *buf, size_t count, void **p);
BLUE_API b_status b_buffer_push_front(b_buffer *buf, size_t count, void **p);
BLUE_API b_status b_buffer_pop_back(b_buffer *buf, size_t count);
BLUE_API b_status b_buffer_pop_front(b_buffer *buf, size_t count);
BLUE_API size_t b_buffer_get_size(const b_buffer *buf);
BLUE_API size_t b_buffer_get_item_size(const b_buffer *buf);
BLUE_API size_t b_buffer_get_capacity(const b_buffer *buf);
BLUE_API void *b_buffer_ptr(const b_buffer *buf);
BLUE_API void *b_buffer_get(const b_buffer *buf, size_t at);
#endif

69
ds/include/blue/ds/dict.h Normal file
View File

@@ -0,0 +1,69 @@
#ifndef BLUELIB_DICT_H_
#define BLUELIB_DICT_H_
#include <blue/core/btree.h>
#include <blue/core/misc.h>
#include <blue/core/queue.h>
#include <blue/core/status.h>
#include <blue/ds/object.h>
#include <blue/ds/type.h>
#define B_DICT(p) ((b_dict *)(p))
#define B_DICT_ITEM(k, v) \
{ \
.key = (k), .value = (v) \
}
#define B_DICT_ITEM_END \
{ \
.key = NULL, .value = NULL \
}
#define b_dict_foreach(it, dict) \
for (int z__b_unique_name() = b_dict_iterator_begin(dict, it); \
(it)->key != NULL; b_dict_iterator_next(it))
typedef struct b_dict b_dict;
typedef struct b_dict_iterator {
b_iterator _base;
size_t i;
const char *key;
b_dsref *value;
b_dict *_d;
b_btree_node *_cbn;
b_queue_entry *_cqe;
} b_dict_iterator;
typedef struct b_dict_item {
const char *key;
b_dsref *value;
} b_dict_item;
BLUE_API b_dict *b_dict_create(void);
BLUE_API b_dict *b_dict_create_with_items(const b_dict_item *items);
static inline b_dict *b_dict_retain(b_dict *dict)
{
return B_DICT(b_retain(B_DSREF(dict)));
}
static inline void b_dict_release(b_dict *dict)
{
b_release(B_DSREF(dict));
}
BLUE_API b_status b_dict_put(b_dict *dict, const char *key, b_dsref *value);
BLUE_API b_dsref *b_dict_at(const b_dict *dict, const char *key);
BLUE_API b_dsref *b_dict_get(b_dict *dict, const char *key);
BLUE_API bool b_dict_has_key(const b_dict *dict, const char *key);
BLUE_API size_t b_dict_get_size(const b_dict *dict);
BLUE_API bool b_dict_is_empty(const b_dict *dict);
BLUE_API int b_dict_iterator_begin(b_dict *dict, b_dict_iterator *it);
BLUE_API bool b_dict_iterator_next(b_dict_iterator *it);
BLUE_API b_status b_dict_iterator_erase(b_dict_iterator *it);
BLUE_API bool b_dict_iterator_is_valid(const b_dict_iterator *it);
#endif

View File

@@ -0,0 +1,94 @@
#ifndef BLUELIB_HASHMAP_H_
#define BLUELIB_HASHMAP_H_
#include <blue/core/btree.h>
#include <blue/core/misc.h>
#include <blue/core/queue.h>
#include <blue/core/status.h>
#include <blue/ds/object.h>
#include <blue/ds/type.h>
#define B_HASHMAP(p) ((b_hashmap *)(p))
#define B_HASHMAP_KEY(k, ks) \
{ \
.key_data = (k), .key_size = (ks) \
}
#define B_HASHMAP_VALUE(v, vs) \
{ \
.value_data = (v), .value_size = (vs) \
}
#define B_HASHMAP_ITEM(k, ks, v, vs) \
{ \
.key = B_HASHMAP_KEY(k, ks), .value = B_HASHMAP_VALUE(v, vs) \
}
#define B_HASHMAP_ITEM_END \
{ \
.key = {0}, .value = { 0 } \
}
#define b_hashmap_foreach(it, hashmap) \
for (int z__b_unique_name() = b_hashmap_iterator_begin(hashmap, it); \
(it)->key != NULL; b_hashmap_iterator_next(it))
typedef struct b_hashmap b_hashmap;
typedef void (*b_hashmap_key_destructor)(void *);
typedef void (*b_hashmap_value_destructor)(void *);
typedef struct b_hashmap_key {
const void *key_data;
size_t key_size;
} b_hashmap_key;
typedef struct b_hashmap_value {
void *value_data;
size_t value_size;
} b_hashmap_value;
typedef struct b_hashmap_item {
b_hashmap_key key;
b_hashmap_value value;
} b_hashmap_item;
typedef struct b_hashmap_iterator {
b_iterator _base;
size_t i;
const b_hashmap_key *key;
const b_hashmap_value *value;
b_hashmap *_h;
b_btree_node *_cbn;
b_queue_entry *_cqe;
} b_hashmap_iterator;
BLUE_API b_hashmap *b_hashmap_create(
b_hashmap_key_destructor key_dtor, b_hashmap_value_destructor value_dtor);
BLUE_API b_hashmap *b_hashmap_create_with_items(const b_hashmap_item *items);
static inline b_hashmap *b_hashmap_retain(b_hashmap *hashmap)
{
return B_HASHMAP(b_retain(B_DSREF(hashmap)));
}
static inline void b_hashmap_release(b_hashmap *hashmap)
{
b_release(B_DSREF(hashmap));
}
BLUE_API b_status b_hashmap_put(
b_hashmap *hashmap, const b_hashmap_key *key, const b_hashmap_value *value);
BLUE_API const b_hashmap_value *b_hashmap_get(
const b_hashmap *hashmap, const b_hashmap_key *key);
BLUE_API bool b_hashmap_has_key(const b_hashmap *hashmap, const b_hashmap_key *key);
BLUE_API size_t b_hashmap_get_size(const b_hashmap *hashmap);
BLUE_API bool b_hashmap_is_empty(const b_hashmap *hashmap);
BLUE_API int b_hashmap_iterator_begin(b_hashmap *hashmap, b_hashmap_iterator *it);
BLUE_API bool b_hashmap_iterator_next(b_hashmap_iterator *it);
BLUE_API b_status b_hashmap_iterator_erase(b_hashmap_iterator *it);
BLUE_API bool b_hashmap_iterator_is_valid(const b_hashmap_iterator *it);
#endif

67
ds/include/blue/ds/list.h Normal file
View File

@@ -0,0 +1,67 @@
#ifndef BLUE_OBJECT_LIST_H_
#define BLUE_OBJECT_LIST_H_
#include <blue/core/status.h>
#include <blue/ds/object.h>
#define B_LIST(p) ((b_list *)(p))
typedef struct b_list b_list;
typedef struct b_list_entry b_list_entry;
#define b_list_foreach(it, q) \
for (int z__b_unique_name() = b_list_iterator_begin(q, it); \
(it)->entry != NULL; b_list_iterator_next(it))
typedef struct b_list_iterator {
b_queue_iterator _base;
const b_list *_q;
size_t i;
void *item;
b_list_entry *entry;
} b_list_iterator;
BLUE_API b_list *b_list_create(void);
static inline b_list *b_list_retain(b_list *str)
{
return B_LIST(b_retain(B_DSREF(str)));
}
static inline void b_list_release(b_list *str)
{
b_release(B_DSREF(str));
}
BLUE_API bool b_list_empty(b_list *q);
BLUE_API void *b_list_first_item(const b_list *q);
BLUE_API void *b_list_last_item(const b_list *q);
BLUE_API b_list_entry *b_list_first_entry(const b_list *q);
BLUE_API b_list_entry *b_list_last_entry(const b_list *q);
BLUE_API b_list_entry *b_list_next(const b_list_entry *entry);
BLUE_API b_list_entry *b_list_prev(const b_list_entry *entry);
BLUE_API size_t b_list_length(const b_list *q);
BLUE_API b_list_entry *b_list_insert_before(
b_list *q, void *ptr, b_list_entry *before);
BLUE_API b_list_entry *b_list_insert_after(
b_list *q, void *ptr, b_list_entry *after);
BLUE_API b_list_entry *b_list_push_front(b_list *q, void *ptr);
BLUE_API b_list_entry *b_list_push_back(b_list *q, void *ptr);
BLUE_API void *b_list_pop_front(b_list *q);
BLUE_API void *b_list_pop_back(b_list *q);
BLUE_API b_status b_list_delete_item(b_list *q, void *ptr);
BLUE_API b_status b_list_delete_entry(b_list *q, b_list_entry *entry);
BLUE_API void b_list_delete_all(b_list *q);
BLUE_API int b_list_iterator_begin(const b_list *q, b_list_iterator *it);
BLUE_API bool b_list_iterator_next(b_list_iterator *it);
BLUE_API b_status b_list_iterator_erase(b_list_iterator *it);
BLUE_API bool b_list_iterator_is_valid(const b_list_iterator *it);
BLUE_API void *b_list_entry_value(const b_list_entry *entry);
#endif

243
ds/include/blue/ds/number.h Normal file
View File

@@ -0,0 +1,243 @@
#ifndef BLUELIB_NUMBER_H
#define BLUELIB_NUMBER_H
#include <blue/ds/object.h>
#include <blue/ds/type.h>
#include <stdbool.h>
#define B_NUMBER(p) ((b_number *)(p))
#define B_INT8(v) (b_number_create_int8(v))
#define B_INT16(v) (b_number_create_int16(v))
#define B_INT32(v) (b_number_create_int32(v))
#define B_INT64(v) (b_number_create_int64(v))
#define B_FLOAT32(v) (b_number_create_float32(v))
#define B_FLOAT64(v) (b_number_create_float64(v))
#define B_CHAR(v) (b_number_create_char(v))
#define B_SHORT(v) (b_number_create_short(v))
#define B_INT(v) (b_number_create_int(v))
#define B_LONG(v) (b_number_create_long(v))
#define B_LONGLONG(v) (b_number_create_longlong(v))
#define B_FLOAT(v) (b_number_create_float(v))
#define B_DOUBLE(v) (b_number_create_double(v))
#define B_SIZE_T(v) (b_number_create_size_t(v))
#define B_RV_INT8(v) B_RV(b_number_create_int8(v))
#define B_RV_INT16(v) B_RV(b_number_create_int16(v))
#define B_RV_INT32(v) B_RV(b_number_create_int32(v))
#define B_RV_INT64(v) B_RV(b_number_create_int64(v))
#define B_RV_FLOAT32(v) B_RV(b_number_create_float32(v))
#define B_RV_FLOAT64(v) B_RV(b_number_create_float64(v))
#define B_RV_CHAR(v) B_RV(b_number_create_char(v))
#define B_RV_SHORT(v) B_RV(b_number_create_short(v))
#define B_RV_INT(v) B_RV(b_number_create_int(v))
#define B_RV_LONG(v) B_RV(b_number_create_long(v))
#define B_RV_LONGLONG(v) B_RV(b_number_create_longlong(v))
#define B_RV_FLOAT(v) B_RV(b_number_create_float(v))
#define B_RV_DOUBLE(v) B_RV(b_number_create_double(v))
#define B_RV_SIZE_T(v) B_RV(b_number_create_size_t(v))
#define B_NUMBER_IVAL(p) (b_number_get_size_t(p))
#define B_NUMBER_FVAL(p) (b_number_get_double(p))
typedef struct b_number b_number;
typedef enum b_number_type {
B_NUMBER_INT8,
B_NUMBER_INT16,
B_NUMBER_INT32,
B_NUMBER_INT64,
B_NUMBER_FLOAT32,
B_NUMBER_FLOAT64,
B_NUMBER_CHAR,
B_NUMBER_SHORT,
B_NUMBER_INT,
B_NUMBER_LONG,
B_NUMBER_LONGLONG,
B_NUMBER_FLOAT,
B_NUMBER_DOUBLE,
B_NUMBER_SIZE_T,
B_NUMBER_HANDLE,
B_NUMBER_TYPE_COUNT,
B_NUMBER_BYTE = B_NUMBER_INT8,
B_NUMBER_WORD = B_NUMBER_INT16,
B_NUMBER_DWORD = B_NUMBER_INT32,
B_NUMBER_QWORD = B_NUMBER_INT64,
} b_number_type;
BLUE_API b_number *b_number_create(b_number_type type, void *value_ptr);
static inline b_number *b_number_retain(b_number *number)
{
return B_NUMBER(b_retain(B_DSREF(number)));
}
static inline void b_number_release(b_number *number)
{
b_release(B_DSREF(number));
}
static inline b_number *b_number_create_int8(int8_t value)
{
return b_number_create(B_NUMBER_INT8, &value);
}
static inline b_number *b_number_create_int16(int16_t value)
{
return b_number_create(B_NUMBER_INT16, &value);
}
static inline b_number *b_number_create_int32(int32_t value)
{
return b_number_create(B_NUMBER_INT32, &value);
}
static inline b_number *b_number_create_int64(int64_t value)
{
return b_number_create(B_NUMBER_INT64, &value);
}
static inline b_number *b_number_create_float32(float value)
{
return b_number_create(B_NUMBER_FLOAT32, &value);
}
static inline b_number *b_number_create_float64(double value)
{
return b_number_create(B_NUMBER_FLOAT64, &value);
}
static inline b_number *b_number_create_char(char value)
{
return b_number_create(B_NUMBER_CHAR, &value);
}
static inline b_number *b_number_create_short(short value)
{
return b_number_create(B_NUMBER_SHORT, &value);
}
static inline b_number *b_number_create_int(int value)
{
return b_number_create(B_NUMBER_INT, &value);
}
static inline b_number *b_number_create_long(long value)
{
return b_number_create(B_NUMBER_LONG, &value);
}
static inline b_number *b_number_create_longlong(long long value)
{
return b_number_create(B_NUMBER_LONGLONG, &value);
}
static inline b_number *b_number_create_float(float value)
{
return b_number_create(B_NUMBER_FLOAT, &value);
}
static inline b_number *b_number_create_double(double value)
{
return b_number_create(B_NUMBER_DOUBLE, &value);
}
static inline b_number *b_number_create_size_t(size_t value)
{
return b_number_create(B_NUMBER_SIZE_T, &value);
}
BLUE_API b_number_type b_number_get_type(const b_number *number);
BLUE_API int b_number_get_value(
const b_number *number, b_number_type type, void *value_ptr);
static inline int8_t b_number_get_int8(const b_number *number)
{
int8_t v;
b_number_get_value(number, B_NUMBER_INT8, &v);
return v;
}
static inline int16_t b_number_get_int16(const b_number *number)
{
int16_t v;
b_number_get_value(number, B_NUMBER_INT16, &v);
return v;
}
static inline int32_t b_number_get_int32(const b_number *number)
{
int32_t v;
b_number_get_value(number, B_NUMBER_INT32, &v);
return v;
}
static inline int64_t b_number_get_int64(const b_number *number)
{
int64_t v;
b_number_get_value(number, B_NUMBER_INT64, &v);
return v;
}
static inline float b_number_get_float32(const b_number *number)
{
float v;
b_number_get_value(number, B_NUMBER_FLOAT32, &v);
return v;
}
static inline double b_number_get_float64(const b_number *number)
{
double v;
b_number_get_value(number, B_NUMBER_FLOAT64, &v);
return v;
}
static inline char b_number_get_char(const b_number *number)
{
char v;
b_number_get_value(number, B_NUMBER_CHAR, &v);
return v;
}
static inline short b_number_get_short(const b_number *number)
{
short v;
b_number_get_value(number, B_NUMBER_SHORT, &v);
return v;
}
static inline int b_number_get_int(const b_number *number)
{
int v;
b_number_get_value(number, B_NUMBER_INT, &v);
return v;
}
static inline long b_number_get_long(const b_number *number)
{
long v;
b_number_get_value(number, B_NUMBER_LONG, &v);
return v;
}
static inline long long b_number_get_longlong(const b_number *number)
{
long long v;
b_number_get_value(number, B_NUMBER_LONGLONG, &v);
return v;
}
static inline float b_number_get_float(const b_number *number)
{
float v;
b_number_get_value(number, B_NUMBER_FLOAT, &v);
return v;
}
static inline double b_number_get_double(const b_number *number)
{
double v;
b_number_get_value(number, B_NUMBER_DOUBLE, &v);
return v;
}
static inline size_t b_number_get_size_t(const b_number *number)
{
size_t v;
b_number_get_value(number, B_NUMBER_SIZE_T, &v);
return v;
}
BLUE_API bool b_number_is_integer(const b_number *number);
BLUE_API bool b_number_is_float(const b_number *number);
BLUE_API size_t b_number_data_size(const b_number *number);
#endif

View File

@@ -0,0 +1,40 @@
#ifndef BLUELIB_DSREF_H_
#define BLUELIB_DSREF_H_
#include <blue/ds/type.h>
#define B_DSREF(p) ((b_dsref *)(p))
#define B_TYPEOF(object) ((struct b_dsref *)(object)->ob_type)
#define B_TYPEID(object) (b_typeid(B_DSREF(object)))
#define B_RV(p) (b_make_rvalue(B_DSREF(p)))
#define B_RVT(t, p) ((t *)(b_make_rvalue(B_DSREF(p))))
#define B_DSREF_IS(object, type) (B_TYPEID(object) == B_DSREF_TYPE_##type)
struct b_string;
struct b_stream;
typedef enum b_comparison_result {
B_LESS = -1,
B_EQUAL = 0,
B_GREATER = 1,
} b_comparison_result_t;
typedef struct b_dsref {
unsigned int ob_ref;
const struct b_dsref_type *ob_type;
} b_dsref;
BLUE_API b_dsref *b_make_rvalue(b_dsref *obj);
BLUE_API b_dsref *b_retain(b_dsref *obj);
BLUE_API void b_release(b_dsref *obj);
BLUE_API void b_to_string(b_dsref *obj, struct b_stream *out);
BLUE_API b_dsref_type_id b_typeid(const b_dsref *obj);
BLUE_API b_comparison_result_t b_compare(const b_dsref *a, const b_dsref *b);
#endif

View File

@@ -0,0 +1,83 @@
#ifndef BLUELIB_STRING_H_
#define BLUELIB_STRING_H_
#include <blue/core/status.h>
#include <blue/ds/object.h>
#include <blue/ds/type.h>
#include <ctype.h>
struct b_stream;
#define B_STRING(p) ((b_string *)(p))
#define B_CSTR(s) (b_string_create_from_cstr(s))
#define B_RV_CSTR(s) (B_RV(b_string_create_from_cstr(s)))
typedef struct b_string b_string;
typedef enum b_strlen_flags {
B_STRLEN_NORMAL = 0,
B_STRLEN_IGNORE_ESC = 0x01u,
B_STRLEN_IGNORE_MOD = 0x02u,
} b_strlen_flags;
BLUE_API b_string *b_string_create(void);
BLUE_API b_string *b_string_create_from_cstr(const char *s);
BLUE_API b_string *b_string_create_from_c(char c, size_t count);
BLUE_API b_string *b_string_duplicate(const b_string *str);
static inline b_string *b_string_retain(b_string *str)
{
return B_STRING(b_retain(B_DSREF(str)));
}
static inline void b_string_release(b_string *str)
{
b_release(B_DSREF(str));
}
BLUE_API char *b_string_steal(b_string *str);
BLUE_API b_status b_string_reserve(b_string *str, size_t capacity);
BLUE_API b_status b_string_replace(
b_string *str, size_t start, size_t length, const char *new_data);
BLUE_API b_status b_string_replace_all(b_string *str, const char *new_data);
BLUE_API b_status b_string_remove(b_string *str, size_t start, size_t length);
BLUE_API b_status b_string_transform(b_string *str, int (*transformer)(int));
static inline b_status b_string_toupper(b_string *str)
{
return b_string_transform(str, toupper);
}
static inline b_status b_string_tolower(b_string *str)
{
return b_string_transform(str, tolower);
}
BLUE_API b_status b_string_open_stream(b_string *str, struct b_stream **out);
BLUE_API void b_string_append_s(b_string *dest, const b_string *src);
BLUE_API void b_string_append_cstr(b_string *dest, const char *src);
BLUE_API void b_string_append_cstrf(b_string *dest, const char *format, ...);
BLUE_API void b_string_prepend_cstr(b_string *dest, const char *src);
BLUE_API void b_string_prepend_cstrf(b_string *dest, const char *format, ...);
BLUE_API void b_string_insert_s(b_string *dest, const b_string *src, size_t at);
BLUE_API void b_string_insert_cstr(b_string *dest, const char *src, size_t at);
BLUE_API void b_string_insert_cstrn(
b_string *dest, const char *src, size_t len, size_t at);
BLUE_API void b_string_insert_cstrf(
b_string *dest, size_t at, const char *format, ...);
BLUE_API void b_string_clear(b_string *str);
BLUE_API size_t b_string_get_size(const b_string *str, b_strlen_flags flags);
BLUE_API size_t b_string_get_capacity(const b_string *str);
BLUE_API char b_string_front(const b_string *str);
BLUE_API char b_string_back(const b_string *str);
BLUE_API void b_string_pop_back(b_string *str);
BLUE_API const char *b_string_ptr(const b_string *str);
BLUE_API b_string *b_string_substr(const b_string *str, size_t start, size_t len);
BLUE_API char *b_strdup(const char *s);
BLUE_API size_t b_strlen(const char *s, b_strlen_flags flags);
BLUE_API uint64_t b_cstr_hash(const char *s);
#endif

72
ds/include/blue/ds/tree.h Normal file
View File

@@ -0,0 +1,72 @@
#ifndef BLUELIB_TREE_H_
#define BLUELIB_TREE_H_
#include <blue/core/misc.h>
#include <blue/core/queue.h>
#include <blue/ds/string.h>
#define B_TREE(p) ((b_tree *)(p))
#define B_TREE_NODE_INIT ((b_tree_node){0})
#define B_TREE_CONTAINER(t, m, v) \
((void *)((v) ? (uintptr_t)(v) - (offsetof(t, m)) : 0))
typedef struct b_tree b_tree;
#define b_tree_node_foreach(it, node) \
for (int z__b_unique_name() = b_tree_iterator_begin_at_node(node, it); \
(it)->node != NULL; b_tree_iterator_next(it))
#define b_tree_node_foreach_recursive(it, node) \
for (int z__b_unique_name() \
= b_tree_iterator_begin_at_node_recursive(node, it); \
(it)->node != NULL; b_tree_iterator_next(it))
#define b_tree_foreach(it, tree) \
for (int z__b_unique_name() = b_tree_iterator_begin(tree, it); \
(it)->node != NULL; b_tree_iterator_next(it))
typedef struct b_tree_node {
struct b_tree_node *__p01, *__p02, *__p03;
struct b_queue_entry __q01;
// struct b_tree_node *parent;
// struct b_tree_node *first_child, *next_sibling;
} b_tree_node;
typedef struct b_tree_iterator {
b_iterator _base;
size_t i, depth;
b_tree_node *node;
unsigned char _f01;
} b_tree_iterator;
BLUE_API b_tree *b_tree_create(void);
static inline b_tree *b_tree_retain(b_tree *tree)
{
return B_TREE(b_retain(B_DSREF(tree)));
}
static inline void b_tree_release(b_tree *tree)
{
b_release(B_DSREF(tree));
}
BLUE_API void b_tree_set_root(b_tree *tree, struct b_tree_node *node);
BLUE_API void b_tree_node_add_child(b_tree_node *parent, b_tree_node *child);
BLUE_API void b_tree_node_add_sibling(b_tree_node *node, b_tree_node *to_add);
BLUE_API b_tree_node *b_tree_node_get_child(b_tree_node *node, size_t at);
BLUE_API b_tree_node *b_tree_node_get_parent(b_tree_node *node);
BLUE_API int b_tree_iterator_begin(b_tree *tree, b_tree_iterator *it);
BLUE_API int b_tree_iterator_begin_at_node(b_tree_node *node, b_tree_iterator *it);
BLUE_API int b_tree_iterator_begin_at_node_recursive(
b_tree_node *node, b_tree_iterator *it);
BLUE_API bool b_tree_iterator_next(b_tree_iterator *it);
BLUE_API b_status b_tree_iterator_erase(b_tree_iterator *it);
BLUE_API bool b_tree_iterator_is_valid(const b_tree_iterator *it);
#endif

53
ds/include/blue/ds/type.h Normal file
View File

@@ -0,0 +1,53 @@
#ifndef BLUELIB_TYPE_H_
#define BLUELIB_TYPE_H_
#include <blue/core/queue.h>
#include <blue/core/status.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define B_NPOS ((size_t)INTPTR_MAX)
struct b_dsref;
struct b_stream;
typedef uintptr_t b_dsref_type_id;
typedef enum b_fundamental_type_id {
B_DSREF_TYPE_NONE = 0,
B_DSREF_TYPE_ANY,
B_DSREF_TYPE_LIST,
B_DSREF_TYPE_ARRAY,
B_DSREF_TYPE_BUFFER,
B_DSREF_TYPE_DICT,
B_DSREF_TYPE_ERROR,
B_DSREF_TYPE_HASHMAP,
B_DSREF_TYPE_NUMBER,
B_DSREF_TYPE_STRING,
B_DSREF_TYPE_TREE,
B_DSREF_TYPE_UUID,
B_DSREF_TYPE_PATH,
B_DSREF_TYPE_FILE,
B_DSREF_TYPE_DIRECTORY,
} b_fundamental_type_id;
typedef enum b_dsref_type_flags {
B_DSREF_FUNDAMENTAL = 0x01u,
} b_dsref_type_flags;
typedef struct b_dsref_type {
b_dsref_type_flags t_flags;
char t_name[64];
size_t t_instance_size;
b_dsref_type_id t_id;
b_queue_entry t_entry;
void (*t_init)(struct b_dsref *);
void (*t_release)(struct b_dsref *);
void (*t_to_string)(struct b_dsref *, struct b_stream *);
} b_dsref_type;
BLUE_API b_status b_dsref_type_register(b_dsref_type *type);
BLUE_API struct b_dsref *b_dsref_type_instantiate(const b_dsref_type *type);
#endif

52
ds/include/blue/ds/uuid.h Normal file
View File

@@ -0,0 +1,52 @@
#ifndef BLUELIB_UUID_H_
#define BLUELIB_UUID_H_
#include <blue/core/status.h>
#include <blue/ds/object.h>
#include <blue/ds/type.h>
#define B_UUID(p) ((b_uuid *)(p))
#define B_UUID_NBYTES 16
#define B_UUID_STRING_MAX 37
struct b_string;
struct b_stringstream;
typedef struct b_uuid b_uuid;
typedef struct b_uuid_bytes {
unsigned char uuid_bytes[B_UUID_NBYTES];
} b_uuid_bytes;
BLUE_API b_uuid *b_uuid_create(void);
BLUE_API b_uuid *b_uuid_create_from_bytes(
unsigned char u00, unsigned char u01, unsigned char u02,
unsigned char u03, unsigned char u04, unsigned char u05,
unsigned char u06, unsigned char u07, unsigned char u08,
unsigned char u09, unsigned char u10, unsigned char u11, unsigned char u12,
unsigned char u13, unsigned char u14, unsigned char u15);
BLUE_API b_uuid *b_uuid_create_from_bytev(const unsigned char bytes[B_UUID_NBYTES]);
BLUE_API b_uuid *b_uuid_create_from_uuid_bytes(const b_uuid_bytes *bytes);
BLUE_API b_uuid *b_uuid_create_from_string(const struct b_string *string);
BLUE_API b_uuid *b_uuid_create_from_cstr(const char *s);
static inline b_uuid *b_uuid_retain(b_uuid *uuid)
{
return B_UUID(b_retain(B_DSREF(uuid)));
}
static inline void b_uuid_release(b_uuid *uuid)
{
b_release(B_DSREF(uuid));
}
BLUE_API b_status b_uuid_to_string(const b_uuid *uuid, struct b_string *out);
BLUE_API b_status b_uuid_to_cstr(const b_uuid *uuid, char out[B_UUID_STRING_MAX]);
BLUE_API b_status b_uuid_to_stringstream(
const b_uuid *uuid, struct b_stringstream *out);
BLUE_API void b_uuid_get_bytes(
const b_uuid *uuid, unsigned char bytes[B_UUID_NBYTES]);
BLUE_API void b_uuid_get_uuid_bytes(const b_uuid *uuid, b_uuid_bytes *bytes);
BLUE_API b_uuid_bytes *b_uuid_ptr(b_uuid *uuid);
#endif

342
ds/list.c Normal file
View File

@@ -0,0 +1,342 @@
#include "list.h"
#include <blue/ds/list.h>
#include <stdlib.h>
#include <string.h>
static void list_release(struct b_dsref *obj);
static struct b_dsref_type list_type = {
.t_name = "corelib::list",
.t_flags = B_DSREF_FUNDAMENTAL,
.t_id = B_DSREF_TYPE_LIST,
.t_instance_size = sizeof(struct b_list),
.t_release = list_release,
};
struct b_list *b_list_create(void)
{
struct b_list *list
= (struct b_list *)b_dsref_type_instantiate(&list_type);
if (!list) {
return NULL;
}
return list;
}
bool b_list_empty(struct b_list *q)
{
return q->l_len == 0;
}
void *b_list_first_item(const struct b_list *q)
{
struct b_queue_entry *entry = b_queue_first(&q->l_queue);
if (!entry) {
return NULL;
}
struct b_list_entry *list_entry
= b_unbox(struct b_list_entry, entry, e_entry);
return list_entry->e_data;
}
void *b_list_last_item(const struct b_list *q)
{
struct b_queue_entry *entry = b_queue_last(&q->l_queue);
if (!entry) {
return NULL;
}
struct b_list_entry *list_entry
= b_unbox(struct b_list_entry, entry, e_entry);
return list_entry->e_data;
}
struct b_list_entry *b_list_first_entry(const struct b_list *q)
{
struct b_queue_entry *entry = b_queue_first(&q->l_queue);
if (!entry) {
return NULL;
}
struct b_list_entry *list_entry
= b_unbox(struct b_list_entry, entry, e_entry);
return list_entry;
}
struct b_list_entry *b_list_last_entry(const struct b_list *q)
{
struct b_queue_entry *entry = b_queue_last(&q->l_queue);
if (!entry) {
return NULL;
}
struct b_list_entry *list_entry
= b_unbox(struct b_list_entry, entry, e_entry);
return list_entry;
}
struct b_list_entry *b_list_next(const struct b_list_entry *entry)
{
if (!entry) {
return NULL;
}
struct b_queue_entry *next = b_queue_next(&entry->e_entry);
if (!next) {
return NULL;
}
return b_unbox(struct b_list_entry, next, e_entry);
}
struct b_list_entry *b_list_prev(const struct b_list_entry *entry)
{
if (!entry) {
return NULL;
}
struct b_queue_entry *next = b_queue_prev(&entry->e_entry);
if (!next) {
return NULL;
}
return b_unbox(struct b_list_entry, next, e_entry);
}
size_t b_list_length(const struct b_list *q)
{
return q->l_len;
}
static struct b_list_entry *make_entry(void *item)
{
struct b_list_entry *entry = malloc(sizeof *entry);
if (!entry) {
return NULL;
}
memset(entry, 0x0, sizeof *entry);
entry->e_data = item;
return entry;
}
struct b_list_entry *b_list_insert_before(
struct b_list *q, void *ptr, struct b_list_entry *before)
{
struct b_list_entry *entry = make_entry(ptr);
if (!entry) {
return NULL;
}
b_queue_insert_before(&q->l_queue, &entry->e_entry, &before->e_entry);
q->l_len++;
return entry;
}
struct b_list_entry *b_list_insert_after(
struct b_list *q, void *ptr, struct b_list_entry *after)
{
struct b_list_entry *entry = make_entry(ptr);
if (!entry) {
return NULL;
}
b_queue_insert_after(&q->l_queue, &entry->e_entry, &after->e_entry);
q->l_len++;
return entry;
}
struct b_list_entry *b_list_push_front(struct b_list *q, void *ptr)
{
struct b_list_entry *entry = make_entry(ptr);
if (!entry) {
return NULL;
}
b_queue_push_front(&q->l_queue, &entry->e_entry);
q->l_len++;
return entry;
}
struct b_list_entry *b_list_push_back(struct b_list *q, void *ptr)
{
struct b_list_entry *entry = make_entry(ptr);
if (!entry) {
return NULL;
}
b_queue_push_back(&q->l_queue, &entry->e_entry);
q->l_len++;
return entry;
}
void *b_list_pop_front(struct b_list *q)
{
struct b_queue_entry *entry = b_queue_pop_front(&q->l_queue);
if (!entry) {
return NULL;
}
struct b_list_entry *list_entry
= b_unbox(struct b_list_entry, entry, e_entry);
void *item = list_entry->e_data;
free(list_entry);
q->l_len--;
return item;
}
void *b_list_pop_back(struct b_list *q)
{
struct b_queue_entry *entry = b_queue_pop_back(&q->l_queue);
if (!entry) {
return NULL;
}
struct b_list_entry *list_entry
= b_unbox(struct b_list_entry, entry, e_entry);
void *item = list_entry->e_data;
free(list_entry);
q->l_len--;
return item;
}
static struct b_list_entry *find_item(struct b_list *list, void *item)
{
struct b_queue_iterator it;
b_queue_foreach (&it, &list->l_queue) {
struct b_list_entry *entry
= b_unbox(struct b_list_entry, it.entry, e_entry);
if (entry->e_data == item) {
return entry;
}
}
return NULL;
}
b_status b_list_delete_item(struct b_list *q, void *ptr)
{
struct b_list_entry *entry = find_item(q, ptr);
if (!entry) {
return B_ERR_NO_ENTRY;
}
b_queue_delete(&q->l_queue, &entry->e_entry);
q->l_len--;
free(entry);
return B_SUCCESS;
}
b_status b_list_delete_entry(struct b_list *q, struct b_list_entry *entry)
{
b_queue_delete(&q->l_queue, &entry->e_entry);
q->l_len--;
free(entry);
return B_SUCCESS;
}
void b_list_delete_all(struct b_list *q)
{
struct b_queue_iterator it;
b_queue_iterator_begin(&q->l_queue, &it);
while (b_queue_iterator_is_valid(&it)) {
struct b_list_entry *entry
= b_unbox(struct b_list_entry, it.entry, e_entry);
b_queue_iterator_erase(&it);
free(entry);
}
q->l_len = 0;
}
int b_list_iterator_begin(const struct b_list *q, struct b_list_iterator *it)
{
b_queue_iterator_begin(&q->l_queue, &it->_base);
it->_q = q;
it->i = 0;
it->entry = b_unbox(struct b_list_entry, it->_base.entry, e_entry);
if (it->entry) {
it->item = it->entry->e_data;
}
return 0;
}
bool b_list_iterator_next(struct b_list_iterator *it)
{
bool ok = b_queue_iterator_next(&it->_base);
if (!ok) {
it->entry = NULL;
it->item = NULL;
return false;
}
it->i++;
it->entry = b_unbox(struct b_list_entry, it->_base.entry, e_entry);
if (it->entry) {
it->item = it->entry->e_data;
}
return it->entry != NULL;
}
b_status b_list_iterator_erase(struct b_list_iterator *it)
{
if (!it->entry) {
return B_ERR_OUT_OF_BOUNDS;
}
b_queue_iterator_erase(&it->_base);
free(it->entry);
it->entry = b_unbox(struct b_list_entry, it->_base.entry, e_entry);
if (it->entry) {
it->item = it->entry->e_data;
}
return B_SUCCESS;
}
bool b_list_iterator_is_valid(const struct b_list_iterator *it)
{
return it->entry != NULL;
}
void *b_list_entry_value(const struct b_list_entry *entry)
{
return entry ? entry->e_data : NULL;
}
static void list_release(struct b_dsref *obj)
{
struct b_list *list = B_LIST(obj);
b_list_delete_all(list);
}

19
ds/list.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef _BLUELIB_LIST_H_
#define _BLUELIB_LIST_H_
#include "object.h"
#include <blue/core/queue.h>
struct b_list {
struct b_dsref l_base;
struct b_queue l_queue;
size_t l_len;
};
struct b_list_entry {
struct b_queue_entry e_entry;
void *e_data;
};
#endif

1681
ds/number.c Normal file

File diff suppressed because it is too large Load Diff

29
ds/number.h Normal file
View File

@@ -0,0 +1,29 @@
#ifndef _BLUELIB_NUMBER_H_
#define _BLUELIB_NUMBER_H_
#include "object.h"
#include <blue/ds/number.h>
struct b_number {
struct b_dsref n_base;
b_number_type n_type;
union {
int8_t v_int8;
int16_t v_int16;
int32_t v_int32;
int64_t v_int64;
float v_float32;
double v_float64;
char v_char;
short v_short;
int v_int;
long v_long;
long long v_longlong;
float v_float;
double v_double;
size_t v_size_t;
} n_value;
};
#endif

66
ds/object.c Normal file
View File

@@ -0,0 +1,66 @@
#include "object.h"
#include <blue/core/stream.h>
#include <blue/ds/object.h>
#include <blue/ds/string.h>
#include <blue/ds/type.h>
#include <stdio.h>
#include <stdlib.h>
void b_dsref_init(struct b_dsref *obj, struct b_dsref_type *type)
{
obj->ob_ref = 1;
obj->ob_type = type;
}
struct b_dsref *b_make_rvalue(struct b_dsref *obj)
{
obj->ob_ref = 0;
return obj;
}
struct b_dsref *b_retain(struct b_dsref *obj)
{
obj->ob_ref++;
return obj;
}
void b_release(struct b_dsref *obj)
{
if (obj->ob_ref > 1) {
obj->ob_ref--;
return;
}
obj->ob_ref = 0;
if (obj->ob_type && obj->ob_type->t_release) {
obj->ob_type->t_release(obj);
}
free(obj);
}
void b_to_string(struct b_dsref *obj, struct b_stream *out)
{
if (obj->ob_type->t_to_string) {
obj->ob_type->t_to_string(obj, out);
return;
}
const char *name = "corelib::object";
if (obj->ob_type) {
name = obj->ob_type->t_name;
}
b_stream_write_fmt(out, NULL, "<%s@%p>", name, obj);
}
b_dsref_type_id b_typeid(const struct b_dsref *obj)
{
if (obj->ob_type->t_flags & B_DSREF_FUNDAMENTAL) {
return obj->ob_type->t_id;
}
return (b_dsref_type_id)obj->ob_type;
}

6
ds/object.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef _BLUELIB_DSREF_H_
#define _BLUELIB_DSREF_H_
#include <blue/ds/object.h>
#endif

683
ds/string.c Normal file
View File

@@ -0,0 +1,683 @@
#include "string.h"
#include <blue/core/stream.h>
#include <blue/core/stringstream.h>
#include <blue/ds/string.h>
#include <blue/ds/type.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void string_release(struct b_dsref *obj);
static void string_to_string(struct b_dsref *obj, struct b_stream *out);
static struct b_dsref_type string_type = {
.t_name = "corelib::string",
.t_flags = B_DSREF_FUNDAMENTAL,
.t_id = B_DSREF_TYPE_STRING,
.t_instance_size = sizeof(struct b_string),
.t_release = string_release,
.t_to_string = string_to_string,
};
struct b_string *b_string_create(void)
{
struct b_string *str
= (struct b_string *)b_dsref_type_instantiate(&string_type);
if (!str) {
return NULL;
}
str->s_len = 0;
str->s_max = STRING_INLINE_CAPACITY;
return str;
}
static bool string_is_inline(const struct b_string *str)
{
/* strings cannot go below STRING_INLINE_CAPACITY capacity */
return str->s_max == STRING_INLINE_CAPACITY;
}
static char *string_ptr(struct b_string *str)
{
if (string_is_inline(str)) {
return str->s_data.d_inline;
}
return str->s_data.d_external;
}
static int string_make_inline(struct b_string *str)
{
char *buffer = string_ptr(str);
memcpy(str->s_data.d_inline, buffer, sizeof str->s_data.d_inline);
str->s_data.d_inline[sizeof str->s_data.d_inline - 1] = '\0';
str->s_max = STRING_INLINE_CAPACITY;
if (str->s_len >= str->s_max) {
str->s_len = str->s_max;
}
free(buffer);
return 0;
}
static int string_resize_large(struct b_string *str, size_t capacity)
{
char *buffer = string_ptr(str);
char *new_buffer = realloc(buffer, capacity + 1);
if (!new_buffer) {
return -1;
}
str->s_max = capacity;
str->s_data.d_external = new_buffer;
return 0;
}
static int string_make_large(struct b_string *str, size_t capacity)
{
const char *old_buffer = string_ptr(str);
char *buffer = malloc(capacity + 1);
if (!buffer) {
return -1;
}
memcpy(buffer, old_buffer, sizeof str->s_data.d_inline);
buffer[str->s_len] = '\0';
str->s_max = capacity;
str->s_data.d_external = buffer;
return 0;
}
static int string_change_capacity(struct b_string *str, size_t capacity)
{
size_t old_capacity = str->s_max;
if (capacity < STRING_INLINE_CAPACITY) {
capacity = STRING_INLINE_CAPACITY;
}
bool was_inline = string_is_inline(str);
bool is_now_inline = capacity == STRING_INLINE_CAPACITY;
if (capacity == old_capacity) {
/* this also handles the case where the old and new capacity both fit into the inline buffer. */
return 0;
}
if (!was_inline && is_now_inline) {
/* string was large, is now small enough to fit inline. */
return string_make_inline(str);
}
if (!was_inline) {
/* string was large, and is still large. */
return string_resize_large(str, capacity);
}
if (!is_now_inline) {
/* string was inline, and now large enough to require a buffer. */
return string_make_large(str, capacity);
}
/* nothing to do */
return 0;
}
struct b_string *b_string_create_from_cstr(const char *s)
{
struct b_string *str = b_string_create();
if (!str) {
return NULL;
}
if (!s) {
return str;
}
str->s_len = strlen(s);
string_change_capacity(str, str->s_len);
char *dest = string_ptr(str);
memcpy(dest, s, str->s_len);
dest[str->s_len] = 0;
return str;
}
struct b_string *b_string_create_from_c(char c, size_t count)
{
struct b_string *str = b_string_create();
if (!str) {
return NULL;
}
string_change_capacity(str, count);
char *s = string_ptr(str);
for (size_t i = 0; i < count; i++) {
s[i] = c;
}
str->s_len = count;
return str;
}
struct b_string *b_string_duplicate(const struct b_string *str)
{
struct b_string *new_str = b_string_create();
if (!str) {
return NULL;
}
string_change_capacity(new_str, str->s_len);
const char *src = b_string_ptr(str);
char *dst = string_ptr(new_str);
memcpy(dst, src, str->s_len);
new_str->s_len = str->s_len;
return new_str;
}
char *b_string_steal(struct b_string *str)
{
char *dest = NULL;
char *src = string_ptr(str);
if (string_is_inline(str)) {
dest = b_strdup(src);
src[0] = 0;
} else {
dest = src;
str->s_data.d_external = NULL;
str->s_max = STRING_INLINE_CAPACITY;
}
str->s_len = 0;
return dest;
}
b_status b_string_reserve(struct b_string *str, size_t capacity)
{
if (str->s_max >= capacity) {
return B_SUCCESS;
}
int err = string_change_capacity(str, capacity);
return err == 0 ? B_SUCCESS : B_ERR_NO_MEMORY;
}
b_status b_string_replace(
struct b_string *str, size_t start, size_t length, const char *new_data)
{
b_status status = B_SUCCESS;
size_t new_data_len = strlen(new_data);
if (start >= str->s_len) {
return B_ERR_INVALID_ARGUMENT;
}
if (start + length >= str->s_len) {
length = str->s_len - start;
}
size_t new_str_len = str->s_len - length + new_data_len;
if (new_str_len > str->s_max) {
status = b_string_reserve(str, new_str_len);
}
if (!B_OK(status)) {
return status;
}
char *s = string_ptr(str);
char *substitution_start = s + start;
char *excess_src = s + start + length;
size_t excess_length = str->s_len - start - length;
char *excess_dest = substitution_start + new_data_len;
memmove(excess_dest, excess_src, excess_length);
memmove(substitution_start, new_data, new_data_len);
s[new_str_len] = '\0';
str->s_len = new_str_len;
return B_SUCCESS;
}
b_status b_string_replace_all(b_string *str, const char *new_data)
{
size_t new_len = strlen(new_data);
b_string_reserve(str, new_len);
char *dest = (char *)b_string_ptr(str);
memcpy(dest, new_data, new_len);
dest[new_len] = '\0';
str->s_len = new_len;
return B_SUCCESS;
}
b_status b_string_remove(b_string *str, size_t start, size_t length)
{
b_status status = B_SUCCESS;
if (start >= str->s_len) {
return B_ERR_INVALID_ARGUMENT;
}
if (start + length >= str->s_len) {
length = str->s_len - start;
}
size_t new_str_len = str->s_len - length;
char *s = string_ptr(str);
char *removal_start = s + start;
char *excess_src = s + start + length;
size_t excess_length = str->s_len - start - length;
memmove(removal_start, excess_src, excess_length);
s[new_str_len] = '\0';
str->s_len = new_str_len;
return B_SUCCESS;
}
b_status b_string_transform(b_string *str, int (*transformer)(int))
{
char *s = string_ptr(str);
for (size_t i = 0; i < str->s_len; i++) {
int c = transformer(s[i]);
if (c != 0) {
s[i] = c;
}
}
return B_SUCCESS;
}
static enum b_status stream_close(struct b_stream *stream)
{
struct b_string *str = stream->s_ptr;
b_string_release(str);
return B_SUCCESS;
}
static enum b_status stream_getc(struct b_stream *stream, int *out)
{
struct b_string *str = stream->s_ptr;
if (stream->s_cursor >= str->s_len) {
return B_ERR_NO_DATA;
}
char *s = string_ptr(str);
*out = s[stream->s_cursor];
stream->s_cursor++;
return B_SUCCESS;
}
static enum b_status stream_read(
struct b_stream *stream, unsigned char *buf, size_t count, size_t *nr_read)
{
struct b_string *str = stream->s_ptr;
if (stream->s_cursor >= str->s_len) {
*nr_read = 0;
return B_SUCCESS;
}
size_t available = str->s_len - stream->s_cursor;
size_t to_read = b_min(size_t, count, available);
char *s = string_ptr(str) + stream->s_cursor;
memcpy(buf, s, to_read);
*nr_read = to_read;
return B_SUCCESS;
}
static enum b_status stream_write(
struct b_stream *stream, const unsigned char *buf, size_t count,
size_t *nr_written)
{
struct b_string *str = stream->s_ptr;
enum b_status status = B_SUCCESS;
if (stream->s_cursor + count > str->s_max) {
status = b_string_reserve(str, stream->s_cursor + count);
}
if (!B_OK(status)) {
return status;
}
char *s = string_ptr(str) + stream->s_cursor;
memcpy(s, buf, count);
s[str->s_max] = '\0';
stream->s_cursor += count;
str->s_len = b_max(size_t, str->s_len, stream->s_cursor + count);
*nr_written = count;
return B_SUCCESS;
}
static enum b_status stream_seek(
struct b_stream *stream, long long offset, b_stream_seek_origin origin)
{
struct b_string *str = stream->s_ptr;
size_t abs_offset;
switch (origin) {
case B_STREAM_SEEK_START:
abs_offset = offset;
break;
case B_STREAM_SEEK_CURRENT:
abs_offset = stream->s_cursor + offset;
break;
case B_STREAM_SEEK_END:
abs_offset = str->s_len + offset;
break;
default:
return B_ERR_INVALID_ARGUMENT;
}
stream->s_cursor = abs_offset;
return B_SUCCESS;
}
static enum b_status stream_reserve(struct b_stream *stream, size_t len)
{
struct b_string *str = stream->s_ptr;
size_t new_capacity = str->s_len + len;
return b_string_reserve(str, new_capacity);
}
enum b_status b_string_open_stream(struct b_string *str, struct b_stream **out)
{
struct b_stream *stream = malloc(sizeof *stream);
if (!stream) {
return B_ERR_NO_MEMORY;
}
memset(stream, 0x0, sizeof *stream);
stream->s_mode |= B_STREAM_READ | B_STREAM_WRITE;
stream->s_ptr = b_string_retain(str);
stream->s_close = stream_close;
stream->s_getc = stream_getc;
stream->s_read = stream_read;
stream->s_write = stream_write;
stream->s_seek = stream_seek;
stream->s_reserve = stream_reserve;
*out = stream;
return B_SUCCESS;
}
static void string_insert(
struct b_string *dest, const char *src, size_t len, size_t at)
{
if (at >= dest->s_len) {
at = dest->s_len;
}
size_t new_size = dest->s_len + len;
if (dest->s_max < new_size) {
string_change_capacity(dest, new_size);
}
char *dest_buf = string_ptr(dest);
char *from = dest_buf + at;
char *to = dest_buf + at + len;
memmove(to, from, dest->s_len - at);
memcpy(from, src, len);
dest_buf[new_size] = '\0';
dest->s_len = new_size;
}
static void string_insertf(
struct b_string *dest, size_t at, const char *format, va_list arg)
{
char buf[1024];
size_t len = vsnprintf(buf, sizeof buf, format, arg);
string_insert(dest, buf, len, at);
}
void b_string_insert_s(struct b_string *dest, const struct b_string *src, size_t at)
{
string_insert(dest, b_string_ptr(src), src->s_len, at);
}
void b_string_insert_cstr(struct b_string *dest, const char *src, size_t at)
{
string_insert(dest, src, strlen(src), at);
}
void b_string_insert_cstrf(struct b_string *dest, size_t at, const char *format, ...)
{
va_list arg;
va_start(arg, format);
string_insertf(dest, at, format, arg);
va_end(arg);
}
void b_string_insert_cstrn(b_string *dest, const char *src, size_t len, size_t at)
{
string_insert(dest, src, len, at);
}
void b_string_append_s(struct b_string *dest, const struct b_string *src)
{
b_string_insert_s(dest, src, SIZE_MAX);
}
void b_string_append_cstr(struct b_string *dest, const char *src)
{
b_string_insert_cstr(dest, src, SIZE_MAX);
}
void b_string_append_cstrf(struct b_string *dest, const char *format, ...)
{
va_list arg;
va_start(arg, format);
string_insertf(dest, SIZE_MAX, format, arg);
va_end(arg);
}
void b_string_prepend_s(struct b_string *dest, const struct b_string *src)
{
b_string_insert_s(dest, src, 0);
}
void b_string_prepend_cstr(struct b_string *dest, const char *src)
{
b_string_insert_cstr(dest, src, 0);
}
void b_string_prepend_cstrf(struct b_string *dest, const char *format, ...)
{
va_list arg;
va_start(arg, format);
string_insertf(dest, 0, format, arg);
va_end(arg);
}
void b_string_clear(struct b_string *str)
{
if (str->s_len == 0) {
return;
}
char *s = string_ptr(str);
*s = '\0';
str->s_len = 0;
}
size_t b_string_get_size(const struct b_string *str, b_strlen_flags flags)
{
if (flags != B_STRLEN_NORMAL) {
return b_strlen(b_string_ptr(str), flags);
}
return str->s_len;
}
size_t b_string_get_capacity(const struct b_string *str)
{
return str->s_max;
}
char b_string_front(const struct b_string *str)
{
if (str->s_len == 0) {
return 0;
}
const char *s = b_string_ptr(str);
return s[0];
}
char b_string_back(const struct b_string *str)
{
if (str->s_len == 0) {
return 0;
}
const char *s = b_string_ptr(str);
return s[str->s_len - 1];
}
void b_string_pop_back(struct b_string *str)
{
if (str->s_len == 0) {
return;
}
char *s = string_ptr(str);
s[str->s_len - 1] = '\0';
str->s_len--;
}
const char *b_string_ptr(const struct b_string *str)
{
if (string_is_inline(str)) {
return str->s_data.d_inline;
}
return str->s_data.d_external;
}
struct b_string *b_string_substr(const struct b_string *str, size_t start, size_t len)
{
if (start > b_string_get_size(str, B_STRLEN_NORMAL)) {
return NULL;
}
if (start + len > b_string_get_size(str, B_STRLEN_NORMAL)) {
len = b_string_get_size(str, B_STRLEN_NORMAL) - start;
}
struct b_string *newstr = b_string_create();
b_string_reserve(newstr, len);
const char *src = b_string_ptr(str) + start;
char *dest = string_ptr(newstr);
memcpy(dest, src, len);
newstr->s_len = len;
return newstr;
}
static void string_release(struct b_dsref *obj)
{
struct b_string *str = B_STRING(obj);
if (!string_is_inline(str)) {
free(string_ptr(str));
}
}
static void string_to_string(struct b_dsref *obj, struct b_stream *out)
{
b_string *str = B_STRING(obj);
b_stream_write_fmt(out, NULL, "%s", b_string_ptr(str));
}
char *b_strdup(const char *s)
{
size_t len = strlen(s);
char *p = malloc(len + 1);
if (!p) {
return NULL;
}
memcpy(p, s, len);
p[len] = '\0';
return p;
}
size_t b_strlen(const char *s, b_strlen_flags flags)
{
if (!(flags & (B_STRLEN_IGNORE_ESC | B_STRLEN_IGNORE_MOD))) {
return strlen(s);
}
size_t out = 0;
for (size_t i = 0; s[i]; i++) {
if (s[i] == '\033' && (flags & B_STRLEN_IGNORE_ESC)) {
while (!isalpha(s[i]) && s[i]) {
i++;
}
continue;
}
if (s[i] == '[' && (flags & B_STRLEN_IGNORE_MOD)) {
i++;
if (s[i] == '[') {
out++;
continue;
}
while (s[i] != ']' && s[i]) {
i++;
}
continue;
}
out++;
}
return out;
}
b_dsref_type_id b_string_type_id(void)
{
return (b_dsref_type_id)&string_type;
}

21
ds/string.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef _BLUELIB_STRING_H_
#define _BLUELIB_STRING_H_
#include "object.h"
/* maximum length of string that can be stored inline, not including null-terminator */
#define STRING_INLINE_CAPACITY 15
struct b_string {
struct b_dsref s_base;
/* length of string, not including null-terminator */
unsigned int s_len;
/* maximum length of string storable in the currently-allocated buffer, not including null terminator */
unsigned int s_max;
union {
char d_inline[STRING_INLINE_CAPACITY + 1];
char *d_external;
} s_data;
};
#endif

300
ds/tree.c Normal file
View File

@@ -0,0 +1,300 @@
#include "tree.h"
#include <blue/ds/object.h>
#include <blue/ds/tree.h>
#include <blue/ds/type.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)
static struct b_dsref_type tree_type = {
.t_name = "corelib::tree",
.t_flags = B_DSREF_FUNDAMENTAL,
.t_id = B_DSREF_TYPE_TREE,
.t_instance_size = sizeof(struct b_tree),
};
struct b_tree *b_tree_create(void)
{
struct b_tree *tree
= (struct b_tree *)b_dsref_type_instantiate(&tree_type);
if (!tree) {
return NULL;
}
return tree;
}
void b_tree_set_root(struct b_tree *tree, struct b_tree_node *node)
{
tree->t_root = node;
}
void b_tree_node_add_child(struct b_tree_node *parent, struct b_tree_node *child)
{
if (NODE_PARENT(child)) {
return;
}
NODE_PARENT(child) = parent;
if (!NODE_FIRST_CHILD(parent)) {
NODE_FIRST_CHILD(parent) = child;
return;
}
struct b_tree_node *cur = NODE_FIRST_CHILD(parent);
while (NODE_NEXT_SIBLING(cur)) {
cur = NODE_NEXT_SIBLING(cur);
}
NODE_NEXT_SIBLING(cur) = child;
}
void b_tree_node_add_sibling(struct b_tree_node *node, struct b_tree_node *to_add)
{
if (NODE_PARENT(to_add) || !NODE_PARENT(node)) {
return;
}
b_tree_node_add_child(NODE_PARENT(node), to_add);
}
struct b_tree_node *b_tree_node_get_child(struct b_tree_node *node, size_t at)
{
size_t i = 0;
struct b_tree_node *cur = NODE_FIRST_CHILD(node);
while (i < at) {
if (!cur) {
return NULL;
}
cur = NODE_NEXT_SIBLING(cur);
i++;
}
return cur;
}
static bool tree_iterator_next(struct b_iterator *it)
{
return b_tree_iterator_next((struct b_tree_iterator *)it);
}
static b_status tree_iterator_erase(struct b_iterator *it)
{
return b_tree_iterator_erase((struct b_tree_iterator *)it);
}
static bool tree_iterator_is_valid(const struct b_iterator *it)
{
return b_tree_iterator_is_valid((const struct b_tree_iterator *)it);
}
struct b_tree_node *b_tree_node_get_parent(struct b_tree_node *node)
{
return NODE_PARENT(node);
}
int b_tree_iterator_begin(struct b_tree *tree, b_tree_iterator *it)
{
return b_tree_iterator_begin_at_node_recursive(tree->t_root, it);
}
static b_iterator_ops it_ops = {
.it_next = tree_iterator_next,
.it_erase = tree_iterator_erase,
.it_close = NULL,
.it_is_valid = tree_iterator_is_valid,
};
int b_tree_iterator_begin_at_node(struct b_tree_node *node, b_tree_iterator *it)
{
it->node = NODE_FIRST_CHILD(node);
it->i = 0;
it->depth = 0;
it->_base.it_ops = &it_ops;
ITERATOR_UNSET_RECURSIVE(it);
return 0;
}
int b_tree_iterator_begin_at_node_recursive(
struct b_tree_node *node, b_tree_iterator *it)
{
it->node = node;
it->i = 0;
it->depth = 0;
it->_base.it_ops = &it_ops;
ITERATOR_SET_RECURSIVE(it);
return 0;
}
static const struct b_tree_node *next_node(
const struct b_tree_node *node, bool recursive, int *depth_diff)
{
if (!node) {
return NULL;
}
if (!recursive) {
node = NODE_NEXT_SIBLING(node);
return node;
}
int d = 0;
struct b_tree_node *next = NODE_FIRST_CHILD(node);
if (next) {
d = 1;
*depth_diff = d;
return next;
}
const struct b_tree_node *n = node;
next = NODE_NEXT_SIBLING(n);
while (!next) {
n = NODE_PARENT(n);
if (!n) {
break;
}
d--;
next = NODE_NEXT_SIBLING(n);
}
*depth_diff = d;
return next;
}
bool b_tree_iterator_next(struct b_tree_iterator *it)
{
int depth_diff = 0;
const struct b_tree_node *next
= next_node(it->node, ITERATOR_IS_RECURSIVE(it), &depth_diff);
if (next) {
it->depth += depth_diff;
it->i++;
} else {
it->depth = 0;
it->i = 0;
}
it->node = (struct b_tree_node *)next;
return it->node != NULL;
}
static void remove_node(struct b_tree_node *node)
{
struct b_tree_node *parent = NODE_PARENT(node);
if (!parent) {
return;
}
struct b_tree_node *n0 = NULL, *n1 = NULL;
n0 = NODE_FIRST_CHILD(parent);
while (n0) {
if (n0 == node) {
break;
}
n1 = n0;
n0 = NODE_NEXT_SIBLING(n0);
}
if (!n0) {
return;
}
if (n1) {
NODE_NEXT_SIBLING(n1) = NODE_NEXT_SIBLING(n0);
} else {
NODE_FIRST_CHILD(parent) = NODE_NEXT_SIBLING(n0);
}
NODE_PARENT(n0) = NODE_NEXT_SIBLING(n0) = NULL;
}
static void reparent_children(
struct b_tree_node *old_parent, struct b_tree_node *new_parent)
{
struct b_tree_node *last = NODE_FIRST_CHILD(new_parent);
while (last && NODE_NEXT_SIBLING(last)) {
last = NODE_NEXT_SIBLING(last);
}
struct b_tree_node *cur = NODE_FIRST_CHILD(old_parent);
while (cur) {
struct b_tree_node *next = NODE_NEXT_SIBLING(cur);
NODE_PARENT(cur) = new_parent;
NODE_NEXT_SIBLING(cur) = NULL;
if (last) {
NODE_NEXT_SIBLING(last) = cur;
} else {
NODE_FIRST_CHILD(new_parent) = cur;
}
last = cur;
cur = next;
}
}
b_status b_tree_iterator_erase(struct b_tree_iterator *it)
{
if (!it->node) {
return B_ERR_OUT_OF_BOUNDS;
}
struct b_tree_node *parent = NODE_PARENT(it->node);
if (!parent) {
return B_ERR_NOT_SUPPORTED;
}
int d = 0;
struct b_tree_node *n = it->node;
struct b_tree_node *next = NODE_NEXT_SIBLING(n);
if (!next) {
next = NODE_FIRST_CHILD(n);
}
while (!next) {
n = NODE_PARENT(n);
if (!n) {
break;
}
d--;
next = NODE_NEXT_SIBLING(n);
}
remove_node(it->node);
reparent_children(it->node, parent);
return B_SUCCESS;
}
bool b_tree_iterator_is_valid(const struct b_tree_iterator *it)
{
return it->node != NULL;
}
b_dsref_type_id b_tree_type_id(void)
{
return (b_dsref_type_id)&tree_type;
}

14
ds/tree.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef _B_TREE_H_
#define _B_TREE_H_
#include "../object.h"
#include <blue/core/queue.h>
#include <blue/ds/tree.h>
struct b_tree {
struct b_dsref t_base;
struct b_tree_node *t_root;
};
#endif

29
ds/type.c Normal file
View File

@@ -0,0 +1,29 @@
#include "object.h"
#include <blue/core/queue.h>
#include <blue/ds/type.h>
#include <stdlib.h>
#include <string.h>
struct b_dsref *b_dsref_type_instantiate(const b_dsref_type *type)
{
if (!type || type->t_instance_size < sizeof(struct b_dsref)) {
return NULL;
}
struct b_dsref *out = malloc(type->t_instance_size);
if (!out) {
return NULL;
}
memset(out, 0x0, type->t_instance_size);
out->ob_ref = 1;
out->ob_type = type;
if (type->t_init) {
type->t_init(out);
}
return out;
}

198
ds/uuid.c Normal file
View File

@@ -0,0 +1,198 @@
#include "uuid.h"
#include <blue/core/stringstream.h>
#include <blue/ds/string.h>
#include <blue/ds/type.h>
#include <blue/ds/uuid.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static struct b_dsref_type uuid_type = {
.t_name = "corelib::uuid",
.t_flags = B_DSREF_FUNDAMENTAL,
.t_id = B_DSREF_TYPE_UUID,
.t_instance_size = sizeof(struct b_uuid),
};
struct b_uuid *b_uuid_create(void)
{
struct b_uuid *out
= (struct b_uuid *)b_dsref_type_instantiate(&uuid_type);
if (!out) {
return NULL;
}
return out;
}
struct b_uuid *b_uuid_create_from_bytes(
unsigned char u00, unsigned char u01, unsigned char u02,
unsigned char u03, unsigned char u04, unsigned char u05,
unsigned char u06, unsigned char u07, unsigned char u08,
unsigned char u09, unsigned char u10, unsigned char u11,
unsigned char u12, unsigned char u13, unsigned char u14, unsigned char u15)
{
struct b_uuid *uuid = b_uuid_create();
if (!uuid) {
return NULL;
}
uuid->uuid_bytes.uuid_bytes[0] = u00;
uuid->uuid_bytes.uuid_bytes[1] = u01;
uuid->uuid_bytes.uuid_bytes[2] = u02;
uuid->uuid_bytes.uuid_bytes[3] = u03;
uuid->uuid_bytes.uuid_bytes[4] = u04;
uuid->uuid_bytes.uuid_bytes[5] = u05;
uuid->uuid_bytes.uuid_bytes[6] = u06;
uuid->uuid_bytes.uuid_bytes[7] = u07;
uuid->uuid_bytes.uuid_bytes[8] = u08;
uuid->uuid_bytes.uuid_bytes[9] = u09;
uuid->uuid_bytes.uuid_bytes[10] = u10;
uuid->uuid_bytes.uuid_bytes[11] = u11;
uuid->uuid_bytes.uuid_bytes[12] = u12;
uuid->uuid_bytes.uuid_bytes[13] = u13;
uuid->uuid_bytes.uuid_bytes[14] = u14;
uuid->uuid_bytes.uuid_bytes[15] = u15;
return uuid;
}
struct b_uuid *b_uuid_create_from_bytev(const unsigned char bytes[B_UUID_NBYTES])
{
struct b_uuid *uuid = b_uuid_create();
if (!uuid) {
return NULL;
}
memcpy(uuid->uuid_bytes.uuid_bytes, bytes, B_UUID_NBYTES);
return uuid;
}
struct b_uuid *b_uuid_create_from_uuid_bytes(const struct b_uuid_bytes *bytes)
{
return b_uuid_create_from_bytev(bytes->uuid_bytes);
}
struct b_uuid *b_uuid_create_from_string(const struct b_string *string)
{
return b_uuid_create_from_cstr(b_string_ptr(string));
}
struct b_uuid *b_uuid_create_from_cstr(const char *str)
{
struct b_uuid_bytes bytes;
bool valid = true;
bool is_guid = false;
if (*str == '{') {
is_guid = true;
str++;
}
size_t i, byte = 0;
for (i = 0; str[i] && byte < B_UUID_NBYTES;) {
if (i == 8 || i == 13 || i == 18 || i == 23) {
if (str[i] != '-') {
valid = false;
break;
}
i++;
continue;
}
char n[3];
n[0] = str[i];
n[1] = str[i + 1];
n[2] = '\0';
if (!isxdigit(n[0]) || !isxdigit(n[1])) {
valid = false;
break;
}
char *p;
unsigned long v = strtoul(n, &p, 16);
bytes.uuid_bytes[byte] = v;
byte++;
i += 2;
}
if (str[i] == '}') {
if (is_guid) {
i++;
} else {
valid = false;
}
}
if (str[i] != '\0' || byte != B_UUID_NBYTES) {
valid = false;
}
if (!valid) {
return NULL;
}
return b_uuid_create_from_uuid_bytes(&bytes);
}
b_status b_uuid_to_string(const struct b_uuid *uuid, struct b_string *out)
{
char str[B_UUID_STRING_MAX];
b_uuid_to_cstr(uuid, str);
b_string_append_cstr(out, str);
return B_SUCCESS;
}
b_status b_uuid_to_cstr(const struct b_uuid *uuid, char out[B_UUID_STRING_MAX])
{
snprintf(
out, B_UUID_STRING_MAX,
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%"
"02x%02x",
uuid->uuid_bytes.uuid_bytes[0], uuid->uuid_bytes.uuid_bytes[1],
uuid->uuid_bytes.uuid_bytes[2], uuid->uuid_bytes.uuid_bytes[3],
uuid->uuid_bytes.uuid_bytes[4], uuid->uuid_bytes.uuid_bytes[5],
uuid->uuid_bytes.uuid_bytes[6], uuid->uuid_bytes.uuid_bytes[7],
uuid->uuid_bytes.uuid_bytes[8], uuid->uuid_bytes.uuid_bytes[9],
uuid->uuid_bytes.uuid_bytes[10], uuid->uuid_bytes.uuid_bytes[11],
uuid->uuid_bytes.uuid_bytes[12], uuid->uuid_bytes.uuid_bytes[13],
uuid->uuid_bytes.uuid_bytes[14], uuid->uuid_bytes.uuid_bytes[15]);
return B_SUCCESS;
}
b_status b_uuid_to_stringstream(
const struct b_uuid *uuid, struct b_stringstream *out)
{
char str[B_UUID_STRING_MAX];
b_uuid_to_cstr(uuid, str);
b_stringstream_add(out, str);
return B_SUCCESS;
}
void b_uuid_get_bytes(const struct b_uuid *uuid, unsigned char bytes[B_UUID_NBYTES])
{
memcpy(bytes, uuid->uuid_bytes.uuid_bytes, B_UUID_NBYTES);
}
void b_uuid_get_uuid_bytes(const struct b_uuid *uuid, struct b_uuid_bytes *bytes)
{
memcpy(bytes, &uuid->uuid_bytes, sizeof *bytes);
}
struct b_uuid_bytes *b_uuid_ptr(struct b_uuid *uuid)
{
return &uuid->uuid_bytes;
}
b_dsref_type_id b_uuid_type_id(void)
{
return (b_dsref_type_id)&uuid_type;
}

11
ds/uuid.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef _BLUELIB_UUID_H_
#define _BLUELIB_UUID_H_
#include <blue/ds/uuid.h>
struct b_uuid {
struct b_dsref u_base;
struct b_uuid_bytes uuid_bytes;
};
#endif