add object module from corelib

This commit is contained in:
2024-10-24 19:24:54 +01:00
parent 7eb0fc5581
commit fa6ebe6a84
38 changed files with 5606 additions and 24 deletions

3
object/CMakeLists.txt Normal file
View File

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

337
object/array.c Normal file
View File

@@ -0,0 +1,337 @@
#include "array.h"
#include <blue/core/iterator.h>
#include <blue/object/array.h>
#include <blue/object/type.h>
#include <stdlib.h>
#include <string.h>
static void array_release(struct b_object *obj);
static struct b_object_type array_type = {
.t_flags = B_OBJECT_FUNDAMENTAL,
.t_id = B_OBJECT_TYPE_ARRAY,
.t_name = "corelib::array",
.t_instance_size = sizeof(struct b_array),
.t_release = array_release,
};
struct b_array *b_array_create(void)
{
struct b_array *array
= (struct b_array *)b_object_type_instantiate(&array_type);
if (!array) {
return NULL;
}
return array;
}
struct b_array *b_array_create_with_values(
struct b_object *const *values, size_t nr_values)
{
struct b_array *array = b_array_create();
if (!array) {
return NULL;
}
size_t real_nr_values = 0;
for (size_t i = 0; i < nr_values; i++) {
if (values[i]) {
real_nr_values++;
}
}
array->ar_len = real_nr_values;
array->ar_cap = real_nr_values;
array->ar_data = calloc(real_nr_values, sizeof(struct b_object *));
if (!array->ar_data) {
b_array_release(array);
return NULL;
}
size_t index = 0;
for (size_t i = 0; i < nr_values; i++) {
array->ar_data[index++] = b_retain(values[i]);
}
return array;
}
static b_status resize_array(struct b_array *array, size_t new_capacity)
{
if (array->ar_cap < new_capacity) {
void *new_data = realloc(
array->ar_data, new_capacity * sizeof(struct b_object *));
if (!new_data) {
return B_ERR_NO_MEMORY;
}
array->ar_data = new_data;
} else {
for (size_t i = new_capacity; i < array->ar_len; i++) {
b_release(array->ar_data[i]);
}
void *new_data = realloc(
array->ar_data, new_capacity * sizeof(struct b_object *));
if (!new_data) {
return B_ERR_NO_MEMORY;
}
array->ar_data = new_data;
}
array->ar_cap = new_capacity;
if (array->ar_len > new_capacity) {
array->ar_len = new_capacity;
}
return B_SUCCESS;
}
b_status b_array_append(struct b_array *array, struct b_object *value)
{
return b_array_insert(array, value, B_NPOS);
}
b_status b_array_prepend(struct b_array *array, struct b_object *value)
{
return b_array_insert(array, value, 0);
}
b_status b_array_insert(struct b_array *array, struct b_object *value, size_t at)
{
if (at == B_NPOS) {
at = array->ar_len;
}
if (at > array->ar_len) {
return B_ERR_OUT_OF_BOUNDS;
}
b_status status = B_SUCCESS;
if (array->ar_len + 1 > array->ar_cap) {
status = resize_array(array, array->ar_cap + 8);
if (status != B_SUCCESS) {
return status;
}
}
struct b_object **src = array->ar_data + at;
struct b_object **dest = src + 1;
size_t move_len = (array->ar_len - at) * sizeof(struct b_object *);
memmove(dest, src, move_len);
array->ar_data[at] = b_retain(value);
array->ar_len++;
return B_SUCCESS;
}
b_status b_array_remove(struct b_array *array, size_t at)
{
if (at >= array->ar_len) {
return B_ERR_OUT_OF_BOUNDS;
}
struct b_object **src = array->ar_data + at;
struct b_object **dest = src + 1;
size_t move_len = array->ar_len * sizeof(struct b_object *);
b_release(array->ar_data[at]);
memmove(dest, src, move_len);
array->ar_len--;
return B_SUCCESS;
}
b_status b_array_remove_front(struct b_array *array)
{
return b_array_remove(array, 0);
}
b_status b_array_remove_back(struct b_array *array)
{
return b_array_remove(array, array->ar_len - 1);
}
struct b_object *b_array_pop(b_array *array, size_t at)
{
if (at >= array->ar_len) {
return NULL;
}
struct b_object **src = array->ar_data + at;
struct b_object **dest = src + 1;
size_t move_len = array->ar_len * sizeof(struct b_object *);
struct b_object *out = array->ar_data[at];
memmove(dest, src, move_len);
array->ar_len--;
return out;
}
struct b_object *b_array_pop_front(struct b_array *array)
{
return b_array_pop(array, 0);
}
struct b_object *b_array_pop_back(struct b_array *array)
{
return b_array_pop(array, array->ar_len - 1);
}
struct b_object *b_array_at(const struct b_array *array, size_t at)
{
if (at >= array->ar_len) {
return NULL;
}
return array->ar_data[at];
}
struct b_object *b_array_get(struct b_array *array, size_t at)
{
if (at >= array->ar_len) {
return NULL;
}
return b_retain(array->ar_data[at]);
}
size_t b_array_size(const struct b_array *array)
{
return array->ar_len;
}
size_t b_array_capacity(const struct b_array *array)
{
return array->ar_cap;
}
void array_release(struct b_object *obj)
{
struct b_array *array = B_ARRAY(obj);
if (array->ar_data) {
for (size_t i = 0; i < array->ar_len; i++) {
b_release(array->ar_data[i]);
}
free(array->ar_data);
array->ar_data = NULL;
}
}
void b_array_clear(struct b_array *array)
{
while (array->ar_len) {
b_array_remove_back(array);
}
}
static bool array_iterator_next(struct b_iterator *it)
{
return b_array_iterator_next((struct b_array_iterator *)it);
}
static b_status array_iterator_erase(struct b_iterator *it)
{
return b_array_iterator_erase((struct b_array_iterator *)it);
}
static bool array_iterator_is_valid(const struct b_iterator *it)
{
return b_array_iterator_is_valid((const struct b_array_iterator *)it);
}
static b_iterator_ops it_ops = {
.it_next = array_iterator_next,
.it_close = NULL,
.it_erase = array_iterator_erase,
.it_is_valid = array_iterator_is_valid,
};
int b_array_iterator_begin(struct b_array *array, struct b_array_iterator *it)
{
it->_a = array;
it->i = 0;
it->_base.it_ops = &it_ops;
if (array->ar_len > 0) {
it->value = array->ar_data[0];
} else {
it->value = NULL;
}
return 0;
}
bool b_array_iterator_next(struct b_array_iterator *it)
{
struct b_array *array = it->_a;
if (it->value == NULL || it->i >= array->ar_len) {
return false;
}
it->i++;
if (it->i >= array->ar_len) {
it->value = NULL;
} else {
it->value = array->ar_data[it->i];
}
return it->value != NULL;
}
b_status b_array_iterator_erase(struct b_array_iterator *it)
{
struct b_array *array = it->_a;
if (it->i >= array->ar_len) {
return B_ERR_OUT_OF_BOUNDS;
}
if (array->ar_data[it->i] != it->value) {
return B_ERR_BAD_STATE;
}
b_array_remove(array, it->i);
if (it->i < array->ar_len) {
it->value = array->ar_data[it->i];
} else {
it->value = NULL;
}
return B_SUCCESS;
}
bool b_array_iterator_is_valid(const struct b_array_iterator *it)
{
struct b_array *array = it->_a;
if (it->i >= array->ar_len) {
return false;
}
if (array->ar_data[it->i] != it->value) {
return false;
}
return it->value != NULL;
}
b_object_type_id b_array_type_id(void)
{
return (b_object_type_id)&array_type;
}

15
object/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_object ar_base;
/* number of items in array */
unsigned int ar_len;
/* maximum number of items that can currently be stored in array */
unsigned int ar_cap;
struct b_object **ar_data;
};
#endif

167
object/bitmap.c Normal file
View File

@@ -0,0 +1,167 @@
#include <string.h>
#include <blue/object/bitmap.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 += __builtin_popcountl(map[i]);
}
if (set_bits > nbits) {
set_bits = nbits;
}
return set_bits;
}
unsigned int b_bitmap_count_clear(const b_bitmap_word *map, unsigned long nbits)
{
unsigned long words = B_BITMAP_WORDS(nbits);
unsigned int clear_bits = 0;
for (unsigned long i = 0; i < words; i++) {
clear_bits += __builtin_popcountl(~map[i]);
}
if (clear_bits > nbits) {
clear_bits = nbits;
}
return clear_bits;
}
unsigned int b_bitmap_highest_set(const b_bitmap_word *map, unsigned long nbits)
{
unsigned long words = B_BITMAP_WORDS(nbits);
unsigned long bit_index = 0;
b_bitmap_word last_word = 0;
unsigned long i;
for (i = 0; i < words; i++) {
if (map[i] != 0x00) {
last_word = map[i];
bit_index = i * Z__B_BITS_PER_WORD;
}
}
if (last_word == 0x00) {
return B_BITMAP_NPOS;
}
return bit_index + (Z__B_BITS_PER_WORD - __builtin_ctzl(last_word) - 1);
}
unsigned int b_bitmap_highest_clear(const b_bitmap_word *map, unsigned long nbits)
{
unsigned long words = B_BITMAP_WORDS(nbits);
unsigned long bit_index = 0;
b_bitmap_word last_word = ~(b_bitmap_word)0;
for (unsigned long i = 0; i < words; i++) {
if (map[i] != (~(unsigned long)0)) {
last_word = map[i];
bit_index = i * Z__B_BITS_PER_WORD;
}
}
if (last_word == ~(unsigned long)0) {
return B_BITMAP_NPOS;
}
if (last_word == 0) {
return bit_index + Z__B_BITS_PER_WORD - 1;
}
return bit_index + (Z__B_BITS_PER_WORD - __builtin_ctzl(~last_word)) - 1;
}
unsigned int b_bitmap_lowest_set(const b_bitmap_word *map, unsigned long nbits)
{
unsigned long words = B_BITMAP_WORDS(nbits);
unsigned long bit_index = 0;
b_bitmap_word last_word = 0;
unsigned long i;
for (i = 0; i < words; i++) {
if (map[i] != 0x00) {
last_word = map[i];
bit_index = i * Z__B_BITS_PER_WORD;
break;
}
}
if (last_word == 0x00) {
return B_BITMAP_NPOS;
}
return bit_index + __builtin_clzl(last_word);
}
unsigned int b_bitmap_lowest_clear(const b_bitmap_word *map, unsigned long nbits)
{
unsigned long words = B_BITMAP_WORDS(nbits);
unsigned long bit_index = 0;
b_bitmap_word last_word = 0;
unsigned long i;
for (i = 0; i < words; i++) {
if (map[i] != (~(unsigned long)0)) {
last_word = map[i];
bit_index = i * Z__B_BITS_PER_WORD;
break;
}
}
if (last_word == 0) {
return bit_index;
}
if (last_word == (~(b_bitmap_word)0)) {
return B_BITMAP_NPOS;
}
return bit_index + __builtin_clzl(~last_word);
}

472
object/dict.c Normal file
View File

@@ -0,0 +1,472 @@
#include "dict.h"
#include <blue/core/status.h>
#include <blue/core/stringstream.h>
#include <blue/object/dict.h>
#include <blue/object/string.h>
#include <blue/object/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_object *obj);
static void dict_to_string(struct b_object *obj, struct b_stringstream *out);
static struct b_object_type dict_type = {
.t_name = "corelib::dict",
.t_flags = B_OBJECT_FUNDAMENTAL,
.t_id = B_OBJECT_TYPE_DICT,
.t_instance_size = sizeof(struct b_dict),
.t_release = dict_release,
.t_to_string = dict_to_string,
};
struct b_dict *b_dict_create(void)
{
struct b_dict *dict
= (struct b_dict *)b_object_type_instantiate(&dict_type);
if (!dict) {
return NULL;
}
return dict;
}
struct b_dict *b_dict_create_with_items(const b_dict_item *items)
{
struct b_dict *dict = b_dict_create();
if (!dict) {
return NULL;
}
for (size_t i = 0; items[i].key; i++) {
b_dict_put(dict, items[i].key, items[i].value);
}
return dict;
}
static B_BTREE_DEFINE_SIMPLE_GET(
struct b_dict_bucket, uint64_t, bk_node, bk_hash,
get_bucket) static B_BTREE_DEFINE_SIMPLE_INSERT(struct b_dict_bucket, bk_node, bk_hash, put_bucket)
static struct b_dict_bucket *create_bucket(void)
{
struct b_dict_bucket *bucket = malloc(sizeof *bucket);
if (!bucket) {
return NULL;
}
memset(bucket, 0x0, sizeof *bucket);
return bucket;
}
static struct b_dict_bucket_item *create_bucket_item(void)
{
struct b_dict_bucket_item *item = malloc(sizeof *item);
if (!item) {
return NULL;
}
memset(item, 0x0, sizeof *item);
return item;
}
b_status b_dict_put(struct b_dict *dict, const char *key, b_object *value)
{
uint64_t hash = b_cstr_hash(key);
struct b_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
if (!bucket) {
bucket = create_bucket();
if (!bucket) {
return B_ERR_NO_MEMORY;
}
bucket->bk_hash = hash;
put_bucket(&dict->d_buckets, bucket);
}
struct b_dict_bucket_item *item = create_bucket_item();
if (!item) {
return B_ERR_NO_MEMORY;
}
item->bi_str = b_strdup(key);
item->bi_value = b_retain(value);
b_queue_push_back(&bucket->bk_items, &item->bi_entry);
return B_SUCCESS;
}
b_object *b_dict_at(const struct b_dict *dict, const char *key)
{
uint64_t hash = b_cstr_hash(key);
struct b_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
if (!bucket) {
return NULL;
}
b_queue_iterator it;
b_queue_foreach (&it, &bucket->bk_items) {
struct b_dict_bucket_item *item
= b_unbox(struct b_dict_bucket_item, it.entry, bi_entry);
if (!strcmp(item->bi_str, key)) {
return item->bi_value;
}
}
return NULL;
}
b_object *b_dict_get(struct b_dict *dict, const char *key)
{
b_object *value = b_dict_at(dict, key);
if (value) {
b_retain(value);
}
return value;
}
bool b_dict_has_key(const struct b_dict *dict, const char *key)
{
return b_dict_at(dict, key) != NULL;
}
size_t b_dict_get_size(const struct b_dict *dict)
{
size_t count = 0;
b_btree_iterator it1;
b_queue_iterator it2;
b_btree_foreach (&it1, &dict->d_buckets) {
struct b_dict_bucket *bucket
= b_unbox(struct b_dict_bucket, it1.node, bk_node);
b_queue_foreach (&it2, &bucket->bk_items) {
count++;
}
}
return count;
}
bool b_dict_is_empty(const b_dict *dict)
{
b_btree_node *first_node = b_btree_first(&dict->d_buckets);
struct b_dict_bucket *first_bucket
= b_unbox(struct b_dict_bucket, first_node, bk_node);
if (!first_bucket) {
return true;
}
b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items);
struct b_dict_bucket_item *first_item
= b_unbox(struct b_dict_bucket_item, first_entry, bi_entry);
if (!first_item) {
return true;
}
return false;
}
static void dict_to_string(struct b_object *obj, struct b_stringstream *out)
{
struct b_dict *dict = B_DICT(obj);
if (b_dict_is_empty(dict)) {
b_stringstream_add(out, "{}");
return;
}
b_stringstream_add(out, "{\n");
b_stringstream_push_indent(out, 1);
size_t len = b_dict_get_size(dict);
b_dict_iterator it;
b_dict_foreach(&it, dict)
{
b_stringstream_addf(out, "%s: ", it.key);
b_to_string(it.value, out);
if (it.i < len - 1) {
b_stringstream_add(out, ",");
}
b_stringstream_add(out, "\n");
}
b_stringstream_pop_indent(out);
b_stringstream_add(out, "}");
}
static bool dict_iterator_next(struct b_iterator *it)
{
return b_dict_iterator_next((struct b_dict_iterator *)it);
}
static b_status dict_iterator_erase(struct b_iterator *it)
{
return b_dict_iterator_erase((struct b_dict_iterator *)it);
}
static bool dict_iterator_is_valid(const struct b_iterator *it)
{
return b_dict_iterator_is_valid((struct b_dict_iterator *)it);
}
static struct b_iterator_ops it_ops
= {.it_next = dict_iterator_next,
.it_close = NULL,
.it_erase = dict_iterator_erase,
.it_is_valid = dict_iterator_is_valid};
int b_dict_iterator_begin(struct b_dict *dict, b_dict_iterator *it)
{
it->_base.it_ops = &it_ops;
it->i = 0;
if (b_dict_is_empty(dict)) {
it->key = NULL;
it->value = NULL;
return -1;
}
b_btree_node *first_node = b_btree_first(&dict->d_buckets);
struct b_dict_bucket *first_bucket
= b_unbox(struct b_dict_bucket, first_node, bk_node);
if (!first_bucket) {
it->key = NULL;
it->value = NULL;
return -1;
}
b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items);
struct b_dict_bucket_item *first_item
= b_unbox(struct b_dict_bucket_item, first_entry, bi_entry);
if (!first_item) {
it->key = NULL;
it->value = NULL;
return -1;
}
it->key = first_item->bi_str;
it->value = first_item->bi_value;
it->_d = dict;
it->_cbn = first_node;
it->_cqe = first_entry;
return 0;
}
static bool get_next_node(
struct b_btree_node *cur_node, struct b_queue_entry *cur_entry,
struct b_btree_node **out_next_node, struct b_queue_entry **out_next_entry)
{
struct b_dict_bucket *cur_bucket
= b_unbox(struct b_dict_bucket, cur_node, bk_node);
if (!cur_bucket) {
return false;
}
struct b_dict_bucket_item *cur_item
= b_unbox(struct b_dict_bucket_item, cur_entry, bi_entry);
if (!cur_item) {
return false;
}
struct b_btree_node *next_node = cur_node;
struct b_queue_entry *next_entry = b_queue_next(cur_entry);
if (!next_entry) {
next_node = b_btree_next(cur_node);
if (!next_node) {
return false;
}
struct b_dict_bucket *next_bucket
= b_unbox(struct b_dict_bucket, next_node, bk_node);
if (!next_bucket) {
return false;
}
next_entry = b_queue_first(&next_bucket->bk_items);
if (!next_entry) {
return false;
}
}
struct b_dict_bucket_item *next_item
= b_unbox(struct b_dict_bucket_item, next_entry, bi_entry);
if (!next_item) {
return false;
}
*out_next_node = next_node;
*out_next_entry = next_entry;
return true;
}
bool b_dict_iterator_next(b_dict_iterator *it)
{
struct b_btree_node *next_node;
struct b_queue_entry *next_entry;
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
it->key = NULL;
it->value = NULL;
return -1;
}
struct b_dict_bucket_item *next_item
= b_unbox(struct b_dict_bucket_item, next_entry, bi_entry);
if (!next_item) {
it->key = NULL;
it->value = NULL;
return -1;
}
it->i++;
it->key = next_item->bi_str;
it->value = next_item->bi_value;
it->_cbn = next_node;
it->_cqe = next_entry;
return 0;
}
static b_status delete_item(
struct b_dict *dict, struct b_dict_bucket *bucket,
struct b_dict_bucket_item *item)
{
b_queue_delete(&bucket->bk_items, &item->bi_entry);
free(item);
if (b_queue_empty(&bucket->bk_items)) {
b_btree_delete(&dict->d_buckets, &bucket->bk_node);
free(bucket);
}
return B_SUCCESS;
}
b_status b_dict_iterator_erase(struct b_dict_iterator *it)
{
if ((it->key || it->value) && !(it->_cbn && it->_cqe)) {
return B_ERR_BAD_STATE;
}
if (!it->key || !it->_cqe) {
return B_ERR_OUT_OF_BOUNDS;
}
struct b_btree_node *next_node;
struct b_queue_entry *next_entry;
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
it->key = NULL;
it->value = NULL;
return false;
}
struct b_dict_bucket *cur_bucket
= b_unbox(struct b_dict_bucket, it->_cbn, bk_node);
struct b_dict_bucket_item *cur_item
= b_unbox(struct b_dict_bucket_item, it->_cqe, bi_entry);
struct b_dict_bucket_item *next_item
= b_unbox(struct b_dict_bucket_item, next_entry, bi_entry);
b_status status = delete_item(it->_d, cur_bucket, cur_item);
if (B_ERR(status)) {
return status;
}
if (next_item) {
it->key = next_item->bi_str;
it->value = next_item->bi_value;
it->_cbn = next_node;
it->_cqe = next_entry;
} else {
it->key = NULL;
it->value = NULL;
it->_cbn = NULL;
it->_cqe = NULL;
}
return B_SUCCESS;
}
bool b_dict_iterator_is_valid(const struct b_dict_iterator *it)
{
return it->key != NULL;
}
static void dict_release(struct b_object *obj)
{
struct b_dict *dict = B_DICT(obj);
b_btree_iterator tree_it;
b_btree_iterator_begin(&dict->d_buckets, &tree_it);
while (b_btree_iterator_is_valid(&tree_it)) {
struct b_dict_bucket *bucket
= b_unbox(struct b_dict_bucket, tree_it.node, bk_node);
b_btree_iterator_erase(&tree_it);
if (!bucket) {
continue;
}
b_queue_iterator bucket_it;
b_queue_iterator_begin(&bucket->bk_items, &bucket_it);
while (b_queue_iterator_is_valid(&bucket_it)) {
struct b_dict_bucket_item *item = b_unbox(
struct b_dict_bucket_item, bucket_it.entry,
bi_entry);
b_queue_iterator_erase(&bucket_it);
if (!item) {
continue;
}
free(item->bi_str);
b_release(item->bi_value);
free(item);
}
free(bucket);
}
#if 0
b_dict_iterator it;
b_dict_iterator_begin(dict, &it);
while (b_dict_iterator_is_valid(&it)) {
b_dict_iterator_erase(&it);
}
#endif
}
b_object_type_id b_dict_type_id(void)
{
return (b_object_type_id)&dict_type;
}

26
object/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_object *bi_value;
};
struct b_dict_bucket {
b_btree_node bk_node;
uint64_t bk_hash;
b_queue bk_items;
};
struct b_dict {
struct b_object d_base;
b_btree d_buckets;
};
#endif

434
object/hashmap.c Normal file
View File

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

25
object/hashmap.h Normal file
View File

@@ -0,0 +1,25 @@
#ifndef _B_HASHMAP_H_
#define _B_HASHMAP_H_
#include <blue/core/btree.h>
#include <blue/core/queue.h>
#include <blue/object/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_object h_base;
struct b_btree h_buckets;
};
#endif

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

View File

@@ -0,0 +1,34 @@
#ifndef BLUELIB_BITMAP_H_
#define BLUELIB_BITMAP_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)]
extern void b_bitmap_zero(b_bitmap_word *map, unsigned long nbits);
extern void b_bitmap_fill(b_bitmap_word *map, unsigned long nbits);
extern void b_bitmap_set(b_bitmap_word *map, unsigned long bit);
extern void b_bitmap_clear(b_bitmap_word *map, unsigned long bit);
extern bool b_bitmap_check(const b_bitmap_word *map, unsigned long bit);
extern unsigned int b_bitmap_count_set(const b_bitmap_word *map, unsigned long nbits);
extern unsigned int b_bitmap_count_clear(const b_bitmap_word *map, unsigned long nbits);
extern unsigned int b_bitmap_highest_set(const b_bitmap_word *map, unsigned long nbits);
extern unsigned int b_bitmap_highest_clear(const b_bitmap_word *map, unsigned long nbits);
extern unsigned int b_bitmap_lowest_set(const b_bitmap_word *map, unsigned long nbits);
extern unsigned int b_bitmap_lowest_clear(const b_bitmap_word *map, unsigned long nbits);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,33 @@
#ifndef BLUELIB_BUFFER_H_
#define BLUELIB_BUFFER_H_
#include <blue/object/type.h>
#include <blue/object/object.h>
#include <blue/object/status.h>
#include <stddef.h>
#define B_BUFFER(p) ((b_buffer *)(p))
typedef struct b_buffer b_buffer;
extern b_buffer *b_buffer_create(size_t item_sz);
extern b_buffer *b_buffer_create_from_bytes(const void *p, size_t len);
extern b_buffer *b_buffer_create_from_array(const void *p, size_t item_sz, size_t len);
static inline b_buffer *b_buffer_retain(b_buffer *buf) { return B_BUFFER(b_retain(B_OBJECT(buf))); }
static inline void b_buffer_release(b_buffer *buf) { b_release(B_OBJECT(buf)); }
extern void *b_buffer_steal(b_buffer *buf);
extern b_status b_buffer_reserve(b_buffer *buf, size_t capacity);
extern b_status b_buffer_append(b_buffer *dest, const void *p, size_t count);
extern b_status b_buffer_prepend(b_buffer *dest, const void *p, size_t count);
extern b_status b_buffer_insert(b_buffer *dest, const void *p, size_t count, size_t at);
extern b_status b_buffer_clear(b_buffer *str);
extern size_t b_buffer_get_size(const b_buffer *str);
extern size_t b_buffer_get_item_size(const b_buffer *str);
extern size_t b_buffer_get_capacity(const b_buffer *str);
extern void *b_buffer_ptr(const b_buffer *str);
#endif

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/object/object.h>
#include <blue/object/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_object *value;
b_dict *_d;
b_btree_node *_cbn;
b_queue_entry *_cqe;
} b_dict_iterator;
typedef struct b_dict_item {
const char *key;
b_object *value;
} b_dict_item;
extern b_dict *b_dict_create(void);
extern b_dict *b_dict_create_with_items(const b_dict_item *items);
static inline b_dict *b_dict_retain(b_dict *dict)
{
return B_DICT(b_retain(B_OBJECT(dict)));
}
static inline void b_dict_release(b_dict *dict)
{
b_release(B_OBJECT(dict));
}
extern b_status b_dict_put(b_dict *dict, const char *key, b_object *value);
extern b_object *b_dict_at(const b_dict *dict, const char *key);
extern b_object *b_dict_get(b_dict *dict, const char *key);
extern bool b_dict_has_key(const b_dict *dict, const char *key);
extern size_t b_dict_get_size(const b_dict *dict);
extern bool b_dict_is_empty(const b_dict *dict);
extern int b_dict_iterator_begin(b_dict *dict, b_dict_iterator *it);
extern bool b_dict_iterator_next(b_dict_iterator *it);
extern b_status b_dict_iterator_erase(b_dict_iterator *it);
extern bool b_dict_iterator_is_valid(const b_dict_iterator *it);
#endif

View File

@@ -0,0 +1,92 @@
#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/object/object.h>
#include <blue/object/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 = {}, .value = {} \
}
#define b_hashmap_foreach(it, hashmap) \
for (int z__b_unique_name() = b_hashmap_iterator_begin(hashmap, it); \
(it)->key != NULL; b_hashmap_iterator_next(it))
typedef struct b_hashmap b_hashmap;
typedef struct b_hashmap_key {
const void *key_data;
size_t key_size;
bool key_owned;
} b_hashmap_key;
typedef struct b_hashmap_value {
void *value_data;
size_t value_size;
bool value_owned;
} b_hashmap_value;
typedef struct b_hashmap_item {
b_hashmap_key key;
b_hashmap_value value;
} b_hashmap_item;
typedef struct b_hashmap_iterator {
b_iterator _base;
size_t i;
const b_hashmap_key *key;
const b_hashmap_value *value;
b_hashmap *_h;
b_btree_node *_cbn;
b_queue_entry *_cqe;
} b_hashmap_iterator;
extern b_hashmap *b_hashmap_create(void);
extern b_hashmap *b_hashmap_create_with_items(const b_hashmap_item *items);
static inline b_hashmap *b_hashmap_retain(b_hashmap *hashmap)
{
return B_HASHMAP(b_retain(B_OBJECT(hashmap)));
}
static inline void b_hashmap_release(b_hashmap *hashmap)
{
b_release(B_OBJECT(hashmap));
}
extern b_status b_hashmap_put(
b_hashmap *hashmap, const b_hashmap_key *key, const b_hashmap_value *value);
extern const b_hashmap_value *b_hashmap_get(
const b_hashmap *hashmap, const b_hashmap_key *key);
extern bool b_hashmap_has_key(const b_hashmap *hashmap, const b_hashmap_key *key);
extern size_t b_hashmap_get_size(const b_hashmap *hashmap);
extern bool b_hashmap_is_empty(const b_hashmap *hashmap);
extern int b_hashmap_iterator_begin(b_hashmap *hashmap, b_hashmap_iterator *it);
extern bool b_hashmap_iterator_next(b_hashmap_iterator *it);
extern b_status b_hashmap_iterator_erase(b_hashmap_iterator *it);
extern bool b_hashmap_iterator_is_valid(const b_hashmap_iterator *it);
#endif

View File

@@ -0,0 +1,285 @@
#ifndef BLUELIB_NUMBER_H
#define BLUELIB_NUMBER_H
#include <blue/object/object.h>
#include <blue/object/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;
typedef struct {
union {
unsigned char i_bytes[sizeof(uint16_t)];
int16_t i_val;
uint16_t i_uval;
};
} b_i16;
typedef struct {
union {
unsigned char i_bytes[sizeof(uint32_t)];
int32_t i_val;
uint32_t i_uval;
};
} b_i32;
typedef struct {
union {
unsigned char i_bytes[sizeof(uint64_t)];
int64_t i_val;
uint64_t i_uval;
};
} b_i64;
extern b_number *b_number_create(b_number_type type, void *value_ptr);
static inline b_number *b_number_retain(b_number *number)
{
return B_NUMBER(b_retain(B_OBJECT(number)));
}
static inline void b_number_release(b_number *number)
{
b_release(B_OBJECT(number));
}
static inline b_number *b_number_create_int8(int8_t value)
{
return b_number_create(B_NUMBER_INT8, &value);
}
static inline b_number *b_number_create_int16(int16_t value)
{
return b_number_create(B_NUMBER_INT16, &value);
}
static inline b_number *b_number_create_int32(int32_t value)
{
return b_number_create(B_NUMBER_INT32, &value);
}
static inline b_number *b_number_create_int64(int64_t value)
{
return b_number_create(B_NUMBER_INT64, &value);
}
static inline b_number *b_number_create_float32(float value)
{
return b_number_create(B_NUMBER_FLOAT32, &value);
}
static inline b_number *b_number_create_float64(double value)
{
return b_number_create(B_NUMBER_FLOAT64, &value);
}
static inline b_number *b_number_create_char(char value)
{
return b_number_create(B_NUMBER_CHAR, &value);
}
static inline b_number *b_number_create_short(short value)
{
return b_number_create(B_NUMBER_SHORT, &value);
}
static inline b_number *b_number_create_int(int value)
{
return b_number_create(B_NUMBER_INT, &value);
}
static inline b_number *b_number_create_long(long value)
{
return b_number_create(B_NUMBER_LONG, &value);
}
static inline b_number *b_number_create_longlong(long long value)
{
return b_number_create(B_NUMBER_LONGLONG, &value);
}
static inline b_number *b_number_create_float(float value)
{
return b_number_create(B_NUMBER_FLOAT, &value);
}
static inline b_number *b_number_create_double(double value)
{
return b_number_create(B_NUMBER_DOUBLE, &value);
}
static inline b_number *b_number_create_size_t(size_t value)
{
return b_number_create(B_NUMBER_SIZE_T, &value);
}
extern b_number_type b_number_get_type(const b_number *number);
extern int b_number_get_value(
const b_number *number, b_number_type type, void *value_ptr);
static inline int8_t b_number_get_int8(const b_number *number)
{
int8_t v;
b_number_get_value(number, B_NUMBER_INT8, &v);
return v;
}
static inline int16_t b_number_get_int16(const b_number *number)
{
int16_t v;
b_number_get_value(number, B_NUMBER_INT16, &v);
return v;
}
static inline int32_t b_number_get_int32(const b_number *number)
{
int32_t v;
b_number_get_value(number, B_NUMBER_INT32, &v);
return v;
}
static inline int64_t b_number_get_int64(const b_number *number)
{
int64_t v;
b_number_get_value(number, B_NUMBER_INT64, &v);
return v;
}
static inline float b_number_get_float32(const b_number *number)
{
float v;
b_number_get_value(number, B_NUMBER_FLOAT32, &v);
return v;
}
static inline double b_number_get_float64(const b_number *number)
{
double v;
b_number_get_value(number, B_NUMBER_FLOAT64, &v);
return v;
}
static inline char b_number_get_char(const b_number *number)
{
char v;
b_number_get_value(number, B_NUMBER_CHAR, &v);
return v;
}
static inline short b_number_get_short(const b_number *number)
{
short v;
b_number_get_value(number, B_NUMBER_SHORT, &v);
return v;
}
static inline int b_number_get_int(const b_number *number)
{
int v;
b_number_get_value(number, B_NUMBER_INT, &v);
return v;
}
static inline long b_number_get_long(const b_number *number)
{
long v;
b_number_get_value(number, B_NUMBER_LONG, &v);
return v;
}
static inline long long b_number_get_longlong(const b_number *number)
{
long long v;
b_number_get_value(number, B_NUMBER_LONGLONG, &v);
return v;
}
static inline float b_number_get_float(const b_number *number)
{
float v;
b_number_get_value(number, B_NUMBER_FLOAT, &v);
return v;
}
static inline double b_number_get_double(const b_number *number)
{
double v;
b_number_get_value(number, B_NUMBER_DOUBLE, &v);
return v;
}
static inline size_t b_number_get_size_t(const b_number *number)
{
size_t v;
b_number_get_value(number, B_NUMBER_SIZE_T, &v);
return v;
}
extern bool b_number_is_integer(const b_number *number);
extern bool b_number_is_float(const b_number *number);
extern size_t b_number_data_size(const b_number *number);
extern b_i16 b_i16_htob(uint16_t v);
extern b_i16 b_i16_htos(uint16_t v);
extern uint16_t b_i16_btoh(b_i16 v);
extern uint16_t b_i16_stoh(b_i16 v);
extern b_i32 b_i32_htob(uint32_t v);
extern b_i32 b_i32_htos(uint32_t v);
extern uint32_t b_i32_btoh(b_i32 v);
extern uint32_t b_i32_stoh(b_i32 v);
extern b_i64 b_i64_htob(uint64_t v);
extern b_i64 b_i64_htos(uint64_t v);
extern uint64_t b_i64_btoh(b_i64 v);
extern uint64_t b_i64_stoh(b_i64 v);
#endif

View File

@@ -0,0 +1,38 @@
#ifndef BLUELIB_OBJECT_H_
#define BLUELIB_OBJECT_H_
#include <blue/object/type.h>
#define B_OBJECT(p) ((b_object *)(p))
#define B_TYPEOF(object) ((struct b_object *)(object)->ob_type)
#define B_TYPEID(object) (b_typeid(B_OBJECT(object)))
#define B_RV(p) (b_make_rvalue(B_OBJECT(p)))
#define B_RVT(t, p) ((t *)(b_make_rvalue(B_OBJECT(p))))
struct b_string;
struct b_stringstream;
typedef enum b_comparison_result {
B_LESS = -1,
B_EQUAL = 0,
B_GREATER = 1,
} b_comparison_result_t;
typedef struct b_object {
unsigned int ob_ref;
const struct b_object_type *ob_type;
} b_object;
extern b_object *b_make_rvalue(b_object *obj);
extern b_object *b_retain(b_object *obj);
extern void b_release(b_object *obj);
extern void b_to_string(b_object *obj, struct b_stringstream *out);
extern b_object_type_id b_typeid(const b_object *obj);
extern b_comparison_result_t b_compare(const b_object *a, const b_object *b);
#endif

View File

@@ -0,0 +1,77 @@
#ifndef BLUELIB_STRING_H_
#define BLUELIB_STRING_H_
#include <blue/core/status.h>
#include <blue/object/object.h>
#include <blue/object/type.h>
#define B_STRING(p) ((b_string *)(p))
#define B_CSTR(s) (b_string_create_from_cstr(s))
#define B_RV_CSTR(s) (B_RV(b_string_create_from_cstr(s)))
typedef struct b_string b_string;
typedef enum b_strlen_flags {
B_STRLEN_NORMAL = 0,
B_STRLEN_IGNORE_ESC = 0x01u,
} b_strlen_flags;
typedef struct b_strv_builder {
char *strv_buf;
size_t strv_len;
size_t strv_max;
unsigned char strv_alloc;
} b_strv_builder;
extern b_string *b_string_create(void);
extern b_string *b_string_create_from_cstr(const char *s);
extern b_string *b_string_create_from_c(char c, size_t count);
static inline b_string *b_string_retain(b_string *str)
{
return B_STRING(b_retain(B_OBJECT(str)));
}
static inline void b_string_release(b_string *str)
{
b_release(B_OBJECT(str));
}
extern char *b_string_steal(b_string *str);
extern b_status b_string_reserve(b_string *str, size_t capacity);
extern void b_string_append_s(b_string *dest, const b_string *src);
extern void b_string_append_cstr(b_string *dest, const char *src);
extern void b_string_append_cstrf(b_string *dest, const char *format, ...);
extern void b_string_prepend_s(b_string *dest, const b_string *src);
extern void b_string_prepend_cstr(b_string *dest, const char *src);
extern void b_string_prepend_cstrf(b_string *dest, const char *format, ...);
extern void b_string_insert_s(b_string *dest, const b_string *src, size_t at);
extern void b_string_insert_cstr(b_string *dest, const char *src, size_t at);
extern void b_string_insert_cstrn(
b_string *dest, const char *src, size_t len, size_t at);
extern void b_string_insert_cstrf(
b_string *dest, size_t at, const char *format, ...);
extern void b_string_clear(b_string *str);
extern size_t b_string_get_size(const b_string *str, b_strlen_flags flags);
extern size_t b_string_get_capacity(const b_string *str);
extern const char *b_string_ptr(const b_string *str);
extern void b_strv_builder_begin(b_strv_builder *strv, char *buf, size_t max);
extern void b_strv_builder_begin_dynamic(b_strv_builder *strv);
extern b_status b_strv_builder_add(b_strv_builder *strv, const char *str);
extern b_status b_strv_builder_addf(b_strv_builder *strv, const char *format, ...);
extern b_status b_strv_builder_addv(b_strv_builder *strv, const char **strs);
extern b_status b_strv_builder_addvl(
b_strv_builder *strv, const char **strs, size_t count);
extern b_status b_strv_builder_add_many(b_strv_builder *strv, ...);
extern char *b_strv_builder_end(b_strv_builder *strv);
extern char *b_strdup(const char *s);
extern size_t b_strlen(const char *s, b_strlen_flags flags);
extern uint64_t b_cstr_hash(const char *s);
#endif

View File

@@ -0,0 +1,25 @@
#ifndef BLUELIB_STRING_FORMATTER_H
#define BLUELIB_STRING_FORMATTER_H
#include <blue/object/string.h>
#include <stdarg.h>
typedef struct b_stringstream b_stringstream;
extern b_stringstream *b_stringstream_create(void);
extern b_string *b_stringstream_end(b_stringstream *f);
extern void b_stringstream_destroy(b_stringstream *f);
extern const b_string *b_stringstream_str(b_stringstream *f);
extern const char *b_stringstream_cstr(b_stringstream *f);
extern void b_stringstream_clear(b_stringstream *f);
extern void b_stringstream_push_indent(b_stringstream *f, int indent);
extern void b_stringstream_push_indent_abs(b_stringstream *f, int indent);
extern void b_stringstream_pop_indent(b_stringstream *f);
extern void b_stringstream_add(b_stringstream *f, const char *s);
extern void b_stringstream_addf(b_stringstream *f, const char *format, ...);
extern void b_stringstream_addvf(b_stringstream *f, const char *format, va_list arg);
extern void b_stringstream_add_str(b_stringstream *f, const b_string *str);
#endif

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

View File

@@ -0,0 +1,51 @@
#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_object;
struct b_stringstream;
typedef uintptr_t b_object_type_id;
typedef enum b_fundamental_type_id {
B_OBJECT_TYPE_NONE = 0,
B_OBJECT_TYPE_ANY,
B_OBJECT_TYPE_ARRAY,
B_OBJECT_TYPE_BUFFER,
B_OBJECT_TYPE_DICT,
B_OBJECT_TYPE_ERROR,
B_OBJECT_TYPE_HASHMAP,
B_OBJECT_TYPE_NUMBER,
B_OBJECT_TYPE_STRING,
B_OBJECT_TYPE_TREE,
B_OBJECT_TYPE_UUID,
B_OBJECT_TYPE_FILE,
B_OBJECT_TYPE_DIRECTORY,
} b_fundamental_type_id;
typedef enum b_object_type_flags {
B_OBJECT_FUNDAMENTAL = 0x01u,
} b_object_type_flags;
typedef struct b_object_type {
b_object_type_flags t_flags;
char t_name[64];
size_t t_instance_size;
b_object_type_id t_id;
b_queue_entry t_entry;
void (*t_init)(struct b_object *);
void (*t_release)(struct b_object *);
void (*t_to_string)(struct b_object *, struct b_stringstream *);
} b_object_type;
extern b_status b_object_type_register(b_object_type *type);
extern struct b_object *b_object_type_instantiate(const b_object_type *type);
#endif

View File

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

1681
object/number.c Normal file

File diff suppressed because it is too large Load Diff

29
object/number.h Normal file
View File

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

65
object/object.c Normal file
View File

@@ -0,0 +1,65 @@
#include "object.h"
#include <blue/object/object.h>
#include <blue/object/type.h>
#include <blue/object/string.h>
#include <blue/core/stringstream.h>
#include <stdlib.h>
#include <stdio.h>
void b_object_init(struct b_object *obj, struct b_object_type *type)
{
obj->ob_ref = 1;
obj->ob_type = type;
}
struct b_object *b_make_rvalue(struct b_object *obj)
{
obj->ob_ref = 0;
return obj;
}
struct b_object *b_retain(struct b_object *obj)
{
obj->ob_ref++;
return obj;
}
void b_release(struct b_object *obj)
{
if (obj->ob_ref > 1) {
obj->ob_ref--;
return;
}
obj->ob_ref = 0;
if (obj->ob_type && obj->ob_type->t_release) {
obj->ob_type->t_release(obj);
}
free(obj);
}
void b_to_string(struct b_object *obj, struct b_stringstream *out)
{
if (obj->ob_type->t_to_string) {
obj->ob_type->t_to_string(obj, out);
return;
}
const char *name = "corelib::object";
if (obj->ob_type) {
name = obj->ob_type->t_name;
}
b_stringstream_addf(out, "<%s@%p>", name, obj);
}
b_object_type_id b_typeid(const struct b_object *obj)
{
if (obj->ob_type->t_flags & B_OBJECT_FUNDAMENTAL) {
return obj->ob_type->t_id;
}
return (b_object_type_id)obj->ob_type;
}

6
object/object.h Normal file
View File

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

497
object/string.c Normal file
View File

@@ -0,0 +1,497 @@
#include "string.h"
#include <blue/core/stringstream.h>
#include <blue/object/string.h>
#include <blue/object/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_object *obj);
static void string_to_string(struct b_object *obj, struct b_stringstream *out);
static struct b_object_type string_type = {
.t_name = "corelib::string",
.t_flags = B_OBJECT_FUNDAMENTAL,
.t_id = B_OBJECT_TYPE_STRING,
.t_instance_size = sizeof(struct b_string),
.t_release = string_release,
.t_to_string = string_to_string,
};
struct b_string *b_string_create(void)
{
struct b_string *str
= (struct b_string *)b_object_type_instantiate(&string_type);
if (!str) {
return NULL;
}
str->s_len = 0;
str->s_max = STRING_INLINE_CAPACITY;
return str;
}
static bool string_is_inline(const struct b_string *str)
{
/* strings cannot go below STRING_INLINE_CAPACITY capacity */
return str->s_max == STRING_INLINE_CAPACITY;
}
static char *string_ptr(struct b_string *str)
{
if (string_is_inline(str)) {
return str->s_data.d_inline;
}
return str->s_data.d_external;
}
static int string_make_inline(struct b_string *str)
{
char *buffer = string_ptr(str);
memcpy(str->s_data.d_inline, buffer, sizeof str->s_data.d_inline);
str->s_data.d_inline[sizeof str->s_data.d_inline - 1] = '\0';
str->s_max = STRING_INLINE_CAPACITY;
if (str->s_len >= str->s_max) {
str->s_len = str->s_max;
}
free(buffer);
return 0;
}
static int string_resize_large(struct b_string *str, size_t capacity)
{
char *buffer = string_ptr(str);
char *new_buffer = realloc(buffer, capacity + 1);
if (!new_buffer) {
return -1;
}
str->s_max = capacity;
str->s_data.d_external = new_buffer;
return 0;
}
static int string_make_large(struct b_string *str, size_t capacity)
{
const char *old_buffer = string_ptr(str);
char *buffer = malloc(capacity + 1);
if (!buffer) {
return -1;
}
memcpy(buffer, old_buffer, sizeof str->s_data.d_inline);
buffer[str->s_len] = '\0';
str->s_max = capacity;
str->s_data.d_external = buffer;
return 0;
}
static int string_change_capacity(struct b_string *str, size_t capacity)
{
size_t old_capacity = str->s_max;
if (capacity < STRING_INLINE_CAPACITY) {
capacity = STRING_INLINE_CAPACITY;
}
bool was_inline = string_is_inline(str);
bool is_now_inline = capacity == STRING_INLINE_CAPACITY;
if (capacity == old_capacity) {
/* this also handles the case where the old and new capacity both fit into the inline buffer. */
return 0;
}
if (!was_inline && is_now_inline) {
/* string was large, is now small enough to fit inline. */
return string_make_inline(str);
}
if (!was_inline) {
/* string was large, and is still large. */
return string_resize_large(str, capacity);
}
if (!is_now_inline) {
/* string was inline, and now large enough to require a buffer. */
return string_make_large(str, capacity);
}
/* nothing to do */
return 0;
}
struct b_string *b_string_create_from_cstr(const char *s)
{
struct b_string *str = b_string_create();
if (!str) {
return NULL;
}
if (!s) {
return str;
}
str->s_len = strlen(s);
string_change_capacity(str, str->s_len);
char *dest = string_ptr(str);
memcpy(dest, s, str->s_len);
dest[str->s_len] = 0;
return str;
}
struct b_string *b_string_create_from_c(char c, size_t count)
{
struct b_string *str = b_string_create();
if (!str) {
return NULL;
}
string_change_capacity(str, count);
char *s = string_ptr(str);
for (size_t i = 0; i < count; i++) {
s[i] = c;
}
str->s_len = count;
return str;
}
char *b_string_steal(struct b_string *str)
{
char *dest = NULL;
char *src = string_ptr(str);
if (string_is_inline(str)) {
dest = b_strdup(src);
} else {
dest = src;
str->s_data.d_external = NULL;
str->s_max = 0;
}
str->s_len = 0;
return dest;
}
b_status b_string_reserve(struct b_string *str, size_t capacity)
{
if (str->s_max >= capacity) {
return B_SUCCESS;
}
int err = string_change_capacity(str, capacity);
return err == 0 ? B_SUCCESS : B_ERR_NO_MEMORY;
}
static void string_insert(
struct b_string *dest, const char *src, size_t len, size_t at)
{
if (at >= dest->s_len) {
at = dest->s_len;
}
size_t new_size = dest->s_len + len;
if (dest->s_max < new_size) {
string_change_capacity(dest, new_size);
}
char *dest_buf = string_ptr(dest);
char *from = dest_buf + at;
char *to = dest_buf + at + len;
memmove(to, from, dest->s_len - at);
memcpy(from, src, len);
dest_buf[new_size] = '\0';
dest->s_len = new_size;
}
static void string_insertf(
struct b_string *dest, size_t at, const char *format, va_list arg)
{
char buf[1024];
size_t len = vsnprintf(buf, sizeof buf, format, arg);
string_insert(dest, buf, len, at);
}
void b_string_insert_s(struct b_string *dest, const struct b_string *src, size_t at)
{
string_insert(dest, b_string_ptr(src), src->s_len, at);
}
void b_string_insert_cstr(struct b_string *dest, const char *src, size_t at)
{
string_insert(dest, src, strlen(src), at);
}
void b_string_insert_cstrf(struct b_string *dest, size_t at, const char *format, ...)
{
va_list arg;
va_start(arg, format);
string_insertf(dest, at, format, arg);
va_end(arg);
}
void b_string_insert_cstrn(b_string *dest, const char *src, size_t len, size_t at)
{
string_insert(dest, src, len, at);
}
void b_string_append_s(struct b_string *dest, const struct b_string *src)
{
b_string_insert_s(dest, src, SIZE_MAX);
}
void b_string_append_cstr(struct b_string *dest, const char *src)
{
b_string_insert_cstr(dest, src, SIZE_MAX);
}
void b_string_append_cstrf(struct b_string *dest, const char *format, ...)
{
va_list arg;
va_start(arg, format);
string_insertf(dest, SIZE_MAX, format, arg);
va_end(arg);
}
void b_string_prepend_s(struct b_string *dest, const struct b_string *src)
{
b_string_insert_s(dest, src, 0);
}
void b_string_prepend_cstr(struct b_string *dest, const char *src)
{
b_string_insert_cstr(dest, src, 0);
}
void b_string_prepend_cstrf(struct b_string *dest, const char *format, ...)
{
va_list arg;
va_start(arg, format);
string_insertf(dest, 0, format, arg);
va_end(arg);
}
void b_string_clear(struct b_string *str)
{
if (str->s_len == 0) {
return;
}
char *s = string_ptr(str);
*s = '\0';
str->s_len = 0;
}
size_t b_string_get_size(const struct b_string *str, b_strlen_flags flags)
{
if (flags != B_STRLEN_NORMAL) {
return b_strlen(b_string_ptr(str), flags);
}
return str->s_len;
}
size_t b_string_get_capacity(const struct b_string *str)
{
return str->s_max;
}
const char *b_string_ptr(const struct b_string *str)
{
if (string_is_inline(str)) {
return str->s_data.d_inline;
}
return str->s_data.d_external;
}
static void string_release(struct b_object *obj)
{
struct b_string *str = B_STRING(obj);
if (!string_is_inline(str)) {
free(string_ptr(str));
}
}
static void string_to_string(struct b_object *obj, struct b_stringstream *out)
{
b_string *str = B_STRING(obj);
b_stringstream_add(out, b_string_ptr(str));
}
void b_strv_builder_begin(b_strv_builder *strv, char *buf, size_t max)
{
strv->strv_buf = buf;
strv->strv_max = max;
strv->strv_len = 0;
strv->strv_alloc = 0;
}
void b_strv_builder_begin_dynamic(b_strv_builder *strv)
{
strv->strv_buf = NULL;
strv->strv_max = 0;
strv->strv_len = 0;
strv->strv_alloc = 1;
}
static b_status strv_builder_push_string(
b_strv_builder *strv, const char *s, size_t len)
{
if (strv->strv_len + len >= strv->strv_max && strv->strv_alloc == 1) {
char *new_buf = realloc(strv->strv_buf, strv->strv_len + len + 1);
if (!new_buf) {
return B_ERR_NO_MEMORY;
}
strv->strv_buf = new_buf;
strv->strv_max = strv->strv_len + len + 1;
}
for (size_t i = 0; i < len; i++) {
if (strv->strv_len < strv->strv_max) {
strv->strv_buf[strv->strv_len++] = s[i];
strv->strv_buf[strv->strv_len] = 0;
}
}
return B_SUCCESS;
}
b_status b_strv_builder_add(struct b_strv_builder *strv, const char *str)
{
return strv_builder_push_string(strv, str, strlen(str));
}
b_status b_strv_builder_addf(struct b_strv_builder *strv, const char *format, ...)
{
char str[1024];
va_list arg;
va_start(arg, format);
size_t len = vsnprintf(str, sizeof str, format, arg);
va_end(arg);
return strv_builder_push_string(strv, str, len);
}
b_status b_strv_builder_addv(b_strv_builder *strv, const char **strs)
{
for (size_t i = 0; strs[i]; i++) {
size_t len = strlen(strs[i]);
b_status status = strv_builder_push_string(strv, strs[i], len);
if (B_ERR(status)) {
return status;
}
}
return B_SUCCESS;
}
b_status b_strv_builder_addvl(b_strv_builder *strv, const char **strs, size_t count)
{
for (size_t i = 0; i < count; i++) {
if (!strs[i]) {
continue;
}
size_t len = strlen(strs[i]);
b_status status = strv_builder_push_string(strv, strs[i], len);
if (B_ERR(status)) {
return status;
}
}
return B_SUCCESS;
}
b_status b_strv_builder_add_many(b_strv_builder *strv, ...)
{
va_list arg;
va_start(arg, strv);
while (1) {
const char *s = va_arg(arg, const char *);
if (!s) {
return B_SUCCESS;
}
size_t len = strlen(s);
b_status status = strv_builder_push_string(strv, s, len);
if (B_ERR(status)) {
return status;
}
}
return B_SUCCESS;
}
char *b_strv_builder_end(b_strv_builder *strv)
{
char *out = strv->strv_buf;
strv->strv_alloc = 0;
strv->strv_len = 0;
strv->strv_max = 0;
strv->strv_buf = NULL;
return out;
}
char *b_strdup(const char *s)
{
size_t len = strlen(s);
char *p = malloc(len + 1);
if (!p) {
return NULL;
}
memcpy(p, s, len);
p[len] = '\0';
return p;
}
size_t b_strlen(const char *s, b_strlen_flags flags)
{
if (!(flags & B_STRLEN_IGNORE_ESC)) {
return strlen(s);
}
size_t out = 0;
bool esc = false;
for (size_t i = 0; s[i]; i++) {
if (s[i] == '\033') {
esc = true;
}
if (!esc) {
out++;
}
if (isalpha(s[i])) {
esc = false;
}
}
return out;
}
b_object_type_id b_string_type_id(void)
{
return (b_object_type_id)&string_type;
}

21
object/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_object s_base;
/* length of string, not including null-terminator */
unsigned int s_len;
/* maximum length of string storable in the currently-allocated buffer, not including null terminator */
unsigned int s_max;
union {
char d_inline[STRING_INLINE_CAPACITY + 1];
char *d_external;
} s_data;
};
#endif

300
object/tree.c Normal file
View File

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

14
object/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/object/tree.h>
struct b_tree {
struct b_object t_base;
struct b_tree_node *t_root;
};
#endif

29
object/type.c Normal file
View File

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

187
object/uuid.c Normal file
View File

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

11
object/uuid.h Normal file
View File

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