Merge branch 'main' into feature/new-object-system

This commit is contained in:
2025-10-15 11:13:00 +01:00
227 changed files with 8252 additions and 2129 deletions

View File

@@ -8,7 +8,7 @@
#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 void array_to_string(const struct b_dsref *obj, struct b_stream *out);
static struct b_dsref_type array_type = {
.t_flags = B_DSREF_FUNDAMENTAL,
@@ -221,7 +221,7 @@ 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)
static void array_to_string(const struct b_dsref *obj, struct b_stream *out)
{
struct b_array *array = B_ARRAY(obj);

488
ds/datetime.c Normal file
View File

@@ -0,0 +1,488 @@
#include "datetime.h"
#include <blue/core/stream.h>
#include <blue/ds/datetime.h>
#include <blue/ds/string.h>
static void datetime_to_string(const struct b_dsref *obj, struct b_stream *out);
static struct b_dsref_type datetime_type = {
.t_name = "corelib::datetime",
.t_flags = B_DSREF_FUNDAMENTAL,
.t_id = B_DSREF_TYPE_DATETIME,
.t_instance_size = sizeof(struct b_datetime),
.t_to_string = datetime_to_string,
};
struct b_datetime *b_datetime_create(void)
{
return (struct b_datetime *)b_dsref_type_instantiate(&datetime_type);
}
static bool is_leap_year(const struct b_datetime *dt)
{
if ((dt->dt_year % 400) == 0) {
return true;
}
if ((dt->dt_year % 4) == 0 && (dt->dt_year % 100) != 0) {
return true;
}
return false;
}
static bool is_year_valid(const struct b_datetime *dt)
{
return dt->dt_year >= 0;
}
static bool is_month_valid(const struct b_datetime *dt)
{
return dt->dt_month >= 1 && dt->dt_month <= 12;
}
static bool is_day_valid(const struct b_datetime *dt)
{
if (dt->dt_day < 1) {
return false;
}
switch (dt->dt_month) {
case 2:
return dt->dt_day <= (is_leap_year(dt) ? 29 : 28);
case 4:
case 6:
case 9:
case 11:
return dt->dt_day <= 30;
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
return dt->dt_day <= 31;
default:
return false;
}
}
static bool is_time_valid(const struct b_datetime *dt)
{
if (!(dt->dt_hour >= 0 && dt->dt_hour <= 23)) {
return false;
}
if (!(dt->dt_min >= 0 && dt->dt_min <= 59)) {
return false;
}
if (!(dt->dt_sec >= 0 && dt->dt_sec <= 60)) {
return false;
}
return true;
}
static bool is_zone_valid(const struct b_datetime *dt)
{
if (!(dt->dt_zone_offset_hour >= 0 && dt->dt_zone_offset_hour <= 23)) {
return false;
}
if (!(dt->dt_zone_offset_minute >= 0 && dt->dt_zone_offset_minute <= 59)) {
return false;
}
return true;
}
static bool validate(const struct b_datetime *dt)
{
if (dt->dt_has_date) {
if (!is_year_valid(dt)) {
return false;
}
if (!is_month_valid(dt)) {
return false;
}
if (!is_day_valid(dt)) {
return false;
}
}
if (dt->dt_has_time) {
if (!is_time_valid(dt)) {
return false;
}
if (!is_zone_valid(dt)) {
return false;
}
}
return true;
}
struct b_datetime *parse_rfc3339(const char *s)
{
struct b_datetime *dt = b_datetime_create();
if (!dt) {
return NULL;
}
size_t len = strlen(s);
size_t i = 0, c = 0;
bool has_date = false, has_time = false;
dt->dt_localtime = true;
if (len >= 10 && s[4] == '-' && s[7] == '-') {
has_date = true;
}
if (len >= 8 && s[2] == ':' && s[5] == ':') {
has_time = true;
}
if (len >= 19 && s[4] == '-' && s[7] == '-'
&& (s[10] == 'T' || s[10] == 't' || s[10] == ' ') && s[13] == ':'
&& s[16] == ':') {
has_date = true;
has_time = true;
}
if (!has_date && !has_time) {
goto fail;
}
if (has_date) {
for (c = 0; c < 4; c++, i++) {
if (!isdigit(s[i])) {
goto fail;
}
dt->dt_year *= 10;
dt->dt_year += (s[i] - '0');
}
if (s[i++] != '-') {
goto fail;
}
for (c = 0; c < 2; c++, i++) {
if (!isdigit(s[i])) {
goto fail;
}
dt->dt_month *= 10;
dt->dt_month += (s[i] - '0');
}
if (s[i++] != '-' || dt->dt_month > 12) {
goto fail;
}
for (c = 0; c < 2; c++, i++) {
if (!isdigit(s[i])) {
goto fail;
}
dt->dt_day *= 10;
dt->dt_day += (s[i] - '0');
}
if (dt->dt_day > 31) {
goto fail;
}
}
if ((s[i] == 'T' || s[i] == 't' || s[i] == ' ') && !has_time) {
goto fail;
}
if (has_date && has_time) {
if (s[i] != 'T' && s[i] != 't' && s[i] != ' ') {
goto fail;
}
i++;
}
if (has_time) {
for (c = 0; c < 2; c++, i++) {
if (!isdigit(s[i])) {
goto fail;
}
dt->dt_hour *= 10;
dt->dt_hour += (s[i] - '0');
}
if (s[i++] != ':') {
goto fail;
}
for (c = 0; c < 2; c++, i++) {
if (!isdigit(s[i])) {
goto fail;
}
dt->dt_min *= 10;
dt->dt_min += (s[i] - '0');
}
if (s[i++] != ':') {
goto fail;
}
for (c = 0; c < 2; c++, i++) {
if (!isdigit(s[i])) {
goto fail;
}
dt->dt_sec *= 10;
dt->dt_sec += (s[i] - '0');
}
if (s[i] == '.') {
i++;
for (c = 0; s[i]; c++, i++) {
if (!isdigit(s[i])) {
break;
}
dt->dt_msec *= 10;
dt->dt_msec += (s[i] - '0');
}
if (c == 0) {
goto fail;
}
}
if (s[i] == '+' || s[i] == '-') {
dt->dt_localtime = false;
dt->dt_zone_offset_negative = s[i] == '-';
i++;
for (c = 0; c < 2; c++, i++) {
if (!isdigit(s[i])) {
goto fail;
}
dt->dt_zone_offset_hour *= 10;
dt->dt_zone_offset_hour += (s[i] - '0');
}
if (s[i++] != ':') {
goto fail;
}
for (c = 0; c < 2; c++, i++) {
if (!isdigit(s[i])) {
goto fail;
}
dt->dt_zone_offset_minute *= 10;
dt->dt_zone_offset_minute += (s[i] - '0');
}
} else if (s[i] == 'Z' || s[i] == 'z') {
dt->dt_localtime = false;
i++;
}
}
if (s[i] != 0) {
goto fail;
}
dt->dt_has_date = has_date;
dt->dt_has_time = has_time;
return dt;
fail:
b_datetime_release(dt);
return NULL;
}
struct b_datetime *b_datetime_parse(enum b_datetime_format format, const char *s)
{
struct b_datetime *dt = NULL;
switch (format) {
case B_DATETIME_FORMAT_RFC3339:
dt = parse_rfc3339(s);
break;
default:
return NULL;
}
if (!dt) {
return NULL;
}
if (!validate(dt)) {
b_datetime_release(dt);
return NULL;
}
return dt;
}
enum b_status encode_rfc3339(const struct b_datetime *dt, struct b_stream *out)
{
if (dt->dt_has_date) {
b_stream_write_fmt(
out, NULL, "%04ld-%02ld-%02ld", dt->dt_year,
dt->dt_month, dt->dt_day);
}
if (dt->dt_has_date && dt->dt_has_time) {
b_stream_write_char(out, 'T');
}
if (dt->dt_has_time) {
b_stream_write_fmt(
out, NULL, "%02ld:%02ld:%02ld", dt->dt_hour, dt->dt_min,
dt->dt_sec);
if (dt->dt_msec > 0) {
b_stream_write_fmt(out, NULL, ".%04ld", dt->dt_msec);
}
if (!dt->dt_localtime) {
if (dt->dt_zone_offset_hour == 0
&& dt->dt_zone_offset_minute == 0) {
b_stream_write_char(out, 'Z');
} else {
b_stream_write_fmt(
out, NULL, "%c%02ld:%02ld",
dt->dt_zone_offset_negative ? '-' : '+',
dt->dt_zone_offset_hour,
dt->dt_zone_offset_minute);
}
}
}
return B_SUCCESS;
}
void b_datetime_to_string(
const b_datetime *dt, b_datetime_format format, struct b_string *dest)
{
struct b_stream *out;
b_string_open_stream(dest, &out);
switch (format) {
case B_DATETIME_FORMAT_RFC3339:
encode_rfc3339(dt, out);
break;
default:
break;
}
b_stream_close(out);
}
bool b_datetime_is_localtime(const b_datetime *dt)
{
return dt->dt_localtime;
}
bool b_datetime_has_date(const b_datetime *dt)
{
return dt->dt_has_date;
}
bool b_datetime_has_time(const b_datetime *dt)
{
return dt->dt_has_time;
}
long b_datetime_year(const b_datetime *dt)
{
return dt->dt_year;
}
long b_datetime_month(const b_datetime *dt)
{
return dt->dt_month;
}
long b_datetime_day(const b_datetime *dt)
{
return dt->dt_day;
}
long b_datetime_hour(const b_datetime *dt)
{
return dt->dt_hour;
}
long b_datetime_minute(const b_datetime *dt)
{
return dt->dt_min;
}
long b_datetime_second(const b_datetime *dt)
{
return dt->dt_sec;
}
long b_datetime_subsecond(const b_datetime *dt)
{
return dt->dt_msec;
}
bool b_datetime_zone_offset_is_negative(const b_datetime *dt)
{
return dt->dt_zone_offset_negative;
}
long b_datetime_zone_offset_hour(const b_datetime *dt)
{
return dt->dt_zone_offset_hour;
}
long b_datetime_zone_offset_minute(const b_datetime *dt)
{
return dt->dt_zone_offset_minute;
}
static void datetime_to_string(const struct b_dsref *obj, struct b_stream *out)
{
struct b_datetime *dt = B_DATETIME(obj);
if (dt->dt_has_date) {
b_stream_write_fmt(
out, NULL, "%04ld-%02ld-%02ld", dt->dt_year,
dt->dt_month, dt->dt_day);
}
if (dt->dt_has_date && dt->dt_has_time) {
b_stream_write_char(out, ' ');
}
if (dt->dt_has_time) {
b_stream_write_fmt(
out, NULL, "%02ld:%02ld:%02ld", dt->dt_hour, dt->dt_min,
dt->dt_sec);
if (dt->dt_msec > 0) {
b_stream_write_fmt(out, NULL, ".%04ld", dt->dt_msec);
}
if (!dt->dt_localtime) {
b_stream_write_fmt(
out, NULL, " %c%02ld:%02ld",
dt->dt_zone_offset_negative ? '-' : '+',
dt->dt_zone_offset_hour,
dt->dt_zone_offset_minute);
}
}
}

17
ds/datetime.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef _BLUELIB_DATETIME_H_
#define _BLUELIB_DATETIME_H_
#include "object.h"
struct b_datetime {
struct b_dsref dt_base;
unsigned int dt_year, dt_month, dt_day;
unsigned short dt_hour, dt_min, dt_sec;
unsigned int dt_msec;
bool dt_has_date, dt_has_time, dt_localtime;
unsigned short dt_zone_offset_hour, dt_zone_offset_minute;
bool dt_zone_offset_negative;
};
#endif

View File

@@ -24,7 +24,7 @@ uint64_t b_cstr_hash(const char *s)
}
static void dict_release(struct b_dsref *obj);
static void dict_to_string(struct b_dsref *obj, struct b_stream *out);
static void dict_to_string(const struct b_dsref *obj, struct b_stream *out);
static struct b_dsref_type dict_type = {
.t_name = "corelib::dict",
@@ -105,7 +105,35 @@ b_status b_dict_put(struct b_dict *dict, const char *key, b_dsref *value)
return B_ERR_NO_MEMORY;
}
item->bi_str = b_strdup(key);
item->bi_str = b_string_create_from_cstr(key);
item->bi_value = b_retain(value);
b_queue_push_back(&bucket->bk_items, &item->bi_entry);
return B_SUCCESS;
}
b_status b_dict_put_sk(
struct b_dict *dict, const struct b_string *key, b_dsref *value)
{
uint64_t hash = b_string_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_string_duplicate(key);
item->bi_value = b_retain(value);
b_queue_push_back(&bucket->bk_items, &item->bi_entry);
@@ -126,7 +154,28 @@ b_dsref *b_dict_at(const struct b_dict *dict, const char *key)
struct b_dict_bucket_item *item
= b_unbox(struct b_dict_bucket_item, it.entry, bi_entry);
if (!strcmp(item->bi_str, key)) {
if (!strcmp(b_string_ptr(item->bi_str), key)) {
return item->bi_value;
}
}
return NULL;
}
b_dsref *b_dict_at_sk(const struct b_dict *dict, const struct b_string *key)
{
uint64_t hash = b_string_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 (b_string_compare(item->bi_str, key)) {
return item->bi_value;
}
}
@@ -144,11 +193,26 @@ b_dsref *b_dict_get(struct b_dict *dict, const char *key)
return value;
}
b_dsref *b_dict_get_sk(struct b_dict *dict, const struct b_string *key)
{
b_dsref *value = b_dict_at_sk(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;
}
bool b_dict_has_skey(const struct b_dict *dict, const struct b_string *key)
{
return b_dict_at_sk(dict, key) != NULL;
}
size_t b_dict_get_size(const struct b_dict *dict)
{
size_t count = 0;
@@ -186,7 +250,7 @@ bool b_dict_is_empty(const b_dict *dict)
return false;
}
static void dict_to_string(struct b_dsref *obj, struct b_stream *out)
static void dict_to_string(const struct b_dsref *obj, struct b_stream *out)
{
struct b_dict *dict = B_DICT(obj);
@@ -203,7 +267,8 @@ static void dict_to_string(struct b_dsref *obj, struct b_stream *out)
b_dict_iterator it;
b_dict_foreach(&it, dict)
{
b_stream_write_fmt(out, NULL, "%s: ", it.key);
b_to_string(B_DSREF(it.key), out);
b_stream_write_string(out, ": ", NULL);
bool is_string = b_typeid(it.value) == B_DSREF_TYPE_STRING;
@@ -243,11 +308,12 @@ 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};
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)
{

View File

@@ -6,9 +6,11 @@
#include <blue/core/btree.h>
#include <blue/core/queue.h>
struct b_string;
struct b_dict_bucket_item {
b_queue_entry bi_entry;
char *bi_str;
struct b_string *bi_str;
struct b_dsref *bi_value;
};

View File

@@ -40,6 +40,45 @@ static uint64_t hash_data(const void *p, size_t size)
static void hashmap_release(struct b_dsref *obj);
static uint64_t hash_key(const struct b_hashmap_key *key)
{
if (key->key_flags & B_HASHMAP_KEY_F_INTVALUE) {
return hash_data(&key->key_data, sizeof key->key_data);
} else {
return hash_data(key->key_data, key->key_size);
}
}
static bool compare_key(
const struct b_hashmap_key *a, const struct b_hashmap_key *b)
{
const void *a_data = NULL, *b_data = NULL;
size_t a_len = 0, b_len = 0;
if (a->key_flags & B_HASHMAP_KEY_F_INTVALUE) {
a_data = &a->key_data;
a_len = sizeof a->key_data;
} else {
a_data = a->key_data;
a_len = a->key_size;
}
if (b->key_flags & B_HASHMAP_KEY_F_INTVALUE) {
b_data = &b->key_data;
b_len = sizeof b->key_data;
} else {
b_data = b->key_data;
b_len = b->key_size;
}
if (a_len != b_len) {
return false;
}
size_t cmp_len = a_len;
return memcmp(a_data, b_data, cmp_len) == 0;
}
static struct b_dsref_type hashmap_type = {
.t_name = "corelib::hashmap",
.t_flags = B_DSREF_FUNDAMENTAL,
@@ -101,7 +140,7 @@ 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);
uint64_t hash = hash_key(key);
struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
if (!bucket) {
@@ -119,12 +158,9 @@ b_status b_hashmap_put(
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;
if (compare_key(&item->bi_key, key)) {
memcpy(&item->bi_value, value, sizeof *value);
return B_SUCCESS;
}
}
@@ -144,7 +180,8 @@ b_status b_hashmap_put(
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);
uint64_t hash = hash_key(key);
struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
if (!bucket) {
return NULL;
@@ -155,11 +192,7 @@ const struct b_hashmap_value *b_hashmap_get(
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)) {
if (compare_key(&item->bi_key, key)) {
return &item->bi_value;
}
}
@@ -169,7 +202,7 @@ const struct b_hashmap_value *b_hashmap_get(
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);
uint64_t hash = hash_key(key);
struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
if (!bucket) {
return false;
@@ -180,11 +213,7 @@ bool b_hashmap_has_key(const struct b_hashmap *hashmap, const b_hashmap_key *key
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)) {
if (compare_key(&item->bi_key, key)) {
return true;
}
}

View File

@@ -0,0 +1,49 @@
#ifndef BLUELIB_DATETIME_H_
#define BLUELIB_DATETIME_H_
#include <blue/core/status.h>
#include <blue/ds/object.h>
#include <blue/ds/type.h>
#include <ctype.h>
struct b_string;
#define B_DATETIME(p) ((b_datetime *)(p))
typedef struct b_datetime b_datetime;
typedef enum b_datetime_format {
B_DATETIME_FORMAT_RFC3339 = 1,
} b_datetime_format;
BLUE_API b_datetime *b_datetime_create(void);
BLUE_API b_datetime *b_datetime_parse(b_datetime_format format, const char *s);
BLUE_API void b_datetime_to_string(
const b_datetime *dt, b_datetime_format format, struct b_string *dest);
static inline b_datetime *b_datetime_retain(b_datetime *dt)
{
return B_DATETIME(b_retain(B_DSREF(dt)));
}
static inline void b_datetime_release(b_datetime *dt)
{
b_release(B_DSREF(dt));
}
BLUE_API bool b_datetime_is_localtime(const b_datetime *dt);
BLUE_API bool b_datetime_has_date(const b_datetime *dt);
BLUE_API bool b_datetime_has_time(const b_datetime *dt);
BLUE_API long b_datetime_year(const b_datetime *dt);
BLUE_API long b_datetime_month(const b_datetime *dt);
BLUE_API long b_datetime_day(const b_datetime *dt);
BLUE_API long b_datetime_hour(const b_datetime *dt);
BLUE_API long b_datetime_minute(const b_datetime *dt);
BLUE_API long b_datetime_second(const b_datetime *dt);
BLUE_API long b_datetime_subsecond(const b_datetime *dt);
BLUE_API bool b_datetime_zone_offset_is_negative(const b_datetime *dt);
BLUE_API long b_datetime_zone_offset_hour(const b_datetime *dt);
BLUE_API long b_datetime_zone_offset_minute(const b_datetime *dt);
#endif

View File

@@ -8,16 +8,12 @@
#include <blue/ds/object.h>
#include <blue/ds/type.h>
#define B_DICT(p) ((b_dict *)(p))
struct b_string;
#define B_DICT_ITEM(k, v) \
{ \
.key = (k), .value = (v) \
}
#define B_DICT_ITEM_END \
{ \
.key = NULL, .value = NULL \
}
#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); \
@@ -28,7 +24,7 @@ typedef struct b_dict b_dict;
typedef struct b_dict_iterator {
b_iterator _base;
size_t i;
const char *key;
const struct b_string *key;
b_dsref *value;
b_dict *_d;
@@ -54,10 +50,15 @@ static inline void b_dict_release(b_dict *dict)
}
BLUE_API b_status b_dict_put(b_dict *dict, const char *key, b_dsref *value);
BLUE_API b_status b_dict_put_sk(
b_dict *dict, const struct b_string *key, b_dsref *value);
BLUE_API b_dsref *b_dict_at(const b_dict *dict, const char *key);
BLUE_API b_dsref *b_dict_at_sk(const b_dict *dict, const struct b_string *key);
BLUE_API b_dsref *b_dict_get(b_dict *dict, const char *key);
BLUE_API b_dsref *b_dict_get_sk(b_dict *dict, const struct b_string *key);
BLUE_API bool b_dict_has_key(const b_dict *dict, const char *key);
BLUE_API bool b_dict_has_skey(const b_dict *dict, const struct b_string *key);
BLUE_API size_t b_dict_get_size(const b_dict *dict);
BLUE_API bool b_dict_is_empty(const b_dict *dict);

View File

@@ -7,27 +7,17 @@
#include <blue/core/status.h>
#include <blue/ds/object.h>
#include <blue/ds/type.h>
#include <stddef.h>
#define B_HASHMAP(p) ((b_hashmap *)(p))
#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_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) \
}
{.key = B_HASHMAP_KEY(k, ks), .value = B_HASHMAP_VALUE(v, vs)}
#define B_HASHMAP_ITEM_END \
{ \
.key = {0}, .value = { 0 } \
}
#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); \
@@ -38,7 +28,12 @@ typedef struct b_hashmap b_hashmap;
typedef void (*b_hashmap_key_destructor)(void *);
typedef void (*b_hashmap_value_destructor)(void *);
typedef enum b_hashmap_key_flags {
B_HASHMAP_KEY_F_INTVALUE = 0x01u,
} b_hashmap_key_flags;
typedef struct b_hashmap_key {
b_hashmap_key_flags key_flags;
const void *key_data;
size_t key_size;
} b_hashmap_key;

View File

@@ -237,6 +237,17 @@ static inline size_t b_number_get_size_t(const b_number *number)
BLUE_API bool b_number_is_integer(const b_number *number);
BLUE_API bool b_number_is_float(const b_number *number);
BLUE_API bool b_number_is_inf(const b_number *number);
BLUE_API bool b_number_is_inf_positive(const b_number *number);
BLUE_API bool b_number_is_inf_negative(const b_number *number);
BLUE_API bool b_number_is_nan(const b_number *number);
BLUE_API bool b_number_is_nan_positive(const b_number *number);
BLUE_API bool b_number_is_nan_negative(const b_number *number);
BLUE_API void b_number_set_inf_positive(b_number *number, bool v);
BLUE_API void b_number_set_inf_negative(b_number *number, bool v);
BLUE_API void b_number_set_nan_positive(b_number *number, bool v);
BLUE_API void b_number_set_nan_negative(b_number *number, bool v);
BLUE_API size_t b_number_data_size(const b_number *number);

View File

@@ -5,11 +5,11 @@
#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_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_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)
@@ -32,7 +32,7 @@ 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 void b_to_string(const 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);

View File

@@ -1,6 +1,8 @@
#ifndef BLUELIB_STRING_H_
#define BLUELIB_STRING_H_
#include <blue/core/encoding.h>
#include <blue/core/iterator.h>
#include <blue/core/status.h>
#include <blue/ds/object.h>
#include <blue/ds/type.h>
@@ -13,16 +15,44 @@ struct b_stream;
#define B_CSTR(s) (b_string_create_from_cstr(s))
#define B_RV_CSTR(s) (B_RV(b_string_create_from_cstr(s)))
#define b_string_foreach(it, str) \
for (int z__b_unique_name() = b_string_iterator_begin(str, it); \
b_string_iterator_is_valid(it); b_string_iterator_next(it))
typedef struct b_string b_string;
typedef struct b_string_iterator {
b_iterator _base;
int _m, _f;
b_string *_s, *_tmp;
const char **_d;
size_t _nd, _ds;
b_status status;
size_t iteration_index;
size_t byte_index;
size_t codepoint_index;
b_wchar char_value;
const char *string_value;
size_t string_length;
size_t string_codepoints;
} b_string_iterator;
typedef enum b_strlen_flags {
B_STRLEN_NORMAL = 0,
B_STRLEN_IGNORE_ESC = 0x01u,
B_STRLEN_IGNORE_MOD = 0x02u,
B_STRLEN_CODEPOINTS = 0x04u,
} b_strlen_flags;
typedef enum b_string_tokenise_flags {
B_STRING_TOK_F_NORMAL = 0x00u,
B_STRING_TOK_F_INCLUDE_EMPTY_TOKENS = 0x01u,
} b_string_tokenise_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_wstr(const b_wchar *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);
@@ -41,6 +71,7 @@ BLUE_API b_status b_string_replace(
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));
BLUE_API b_status b_string_trim(b_string *str);
static inline b_status b_string_toupper(b_string *str)
{
return b_string_transform(str, toupper);
@@ -51,22 +82,42 @@ static inline b_status b_string_tolower(b_string *str)
}
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(
BLUE_API b_status b_string_append_c(b_string *dest, char c);
BLUE_API b_status b_string_append_wc(b_string *dest, b_wchar c);
BLUE_API b_status b_string_append_s(b_string *dest, const b_string *src);
BLUE_API b_status b_string_append_cstr(b_string *dest, const char *src);
BLUE_API b_status b_string_append_wstr(b_string *dest, const b_wchar *src);
BLUE_API b_status b_string_append_cstrf(b_string *dest, const char *format, ...);
BLUE_API b_status b_string_prepend_c(b_string *dest, char c);
BLUE_API b_status b_string_prepend_wc(b_string *dest, b_wchar c);
BLUE_API b_status b_string_prepend_cstr(b_string *dest, const char *src);
BLUE_API b_status b_string_prepend_wstr(b_string *dest, const b_wchar *src);
BLUE_API b_status b_string_prepend_cstrf(b_string *dest, const char *format, ...);
BLUE_API b_status b_string_insert_c(b_string *dest, char c, size_t at);
BLUE_API b_status b_string_insert_wc(b_string *dest, b_wchar c, size_t at);
BLUE_API b_status b_string_insert_s(b_string *dest, const b_string *src, size_t at);
BLUE_API b_status b_string_insert_cstr(b_string *dest, const char *src, size_t at);
BLUE_API b_status b_string_insert_wstr(
b_string *dest, const b_wchar *src, size_t at);
BLUE_API b_status b_string_insert_cstrn(
b_string *dest, const char *src, size_t len, size_t at);
BLUE_API void b_string_insert_cstrf(
BLUE_API b_status b_string_insert_wstrn(
b_string *dest, const char *src, size_t len, size_t at);
BLUE_API b_status b_string_insert_cstrf(
b_string *dest, size_t at, const char *format, ...);
BLUE_API void b_string_clear(b_string *str);
BLUE_API b_status b_string_tokenise(
b_string *str, const char *delims[], size_t nr_delims,
b_string_tokenise_flags flags, b_string_iterator *it);
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 bool b_string_compare(const b_string *a, const b_string *b);
BLUE_API char b_string_front(const b_string *str);
BLUE_API char b_string_back(const b_string *str);
@@ -75,9 +126,16 @@ 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 int b_string_iterator_begin(const b_string *string, b_string_iterator *it);
BLUE_API bool b_string_iterator_next(b_string_iterator *it);
// BLUE_API b_status b_string_iterator_erase(b_string_iterator *it);
BLUE_API bool b_string_iterator_is_valid(const b_string_iterator *it);
BLUE_API char *b_strdup(const char *s);
BLUE_API size_t b_strlen(const char *s, b_strlen_flags flags);
BLUE_API b_wchar *b_wstrdup(const b_wchar *s);
BLUE_API size_t b_wstrlen(const b_wchar *s);
BLUE_API uint64_t b_cstr_hash(const char *s);
BLUE_API uint64_t b_string_hash(const b_string *s);
#endif

View File

@@ -30,6 +30,7 @@ typedef enum b_fundamental_type_id {
B_DSREF_TYPE_PATH,
B_DSREF_TYPE_FILE,
B_DSREF_TYPE_DIRECTORY,
B_DSREF_TYPE_DATETIME,
} b_fundamental_type_id;
typedef enum b_dsref_type_flags {
@@ -44,7 +45,7 @@ typedef struct b_dsref_type {
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 *);
void (*t_to_string)(const struct b_dsref *, struct b_stream *);
} b_dsref_type;
BLUE_API b_status b_dsref_type_register(b_dsref_type *type);

View File

@@ -10,7 +10,7 @@ typedef int (*number_converter_t)(const struct b_number *, void *);
static number_converter_t converters[B_NUMBER_TYPE_COUNT][B_NUMBER_TYPE_COUNT];
static void number_to_string(struct b_dsref *obj, struct b_stream *out);
static void number_to_string(const struct b_dsref *obj, struct b_stream *out);
static struct b_dsref_type number_type = {
.t_name = "corelib::number",
@@ -139,6 +139,408 @@ bool b_number_is_float(const struct b_number *number)
}
}
bool b_number_is_inf(const b_number *number)
{
return (number->n_flags & NUMBER_F_INF) != 0;
}
bool b_number_is_inf_positive(const b_number *number)
{
if (!(number->n_flags & NUMBER_F_INF)) {
return false;
}
switch (number->n_type) {
case B_NUMBER_INT8:
return number->n_value.v_int8 >= 0;
case B_NUMBER_INT16:
return number->n_value.v_int16 >= 0;
case B_NUMBER_INT32:
return number->n_value.v_int32 >= 0;
case B_NUMBER_INT64:
return number->n_value.v_int64 >= 0;
case B_NUMBER_FLOAT32:
return number->n_value.v_float32 >= 0;
case B_NUMBER_FLOAT64:
return number->n_value.v_float64 >= 0;
case B_NUMBER_CHAR:
return number->n_value.v_char >= 0;
case B_NUMBER_SHORT:
return number->n_value.v_short >= 0;
case B_NUMBER_INT:
return number->n_value.v_int >= 0;
case B_NUMBER_LONG:
return number->n_value.v_long >= 0;
case B_NUMBER_LONGLONG:
return number->n_value.v_longlong >= 0;
case B_NUMBER_FLOAT:
return number->n_value.v_float >= 0;
case B_NUMBER_DOUBLE:
return number->n_value.v_double >= 0;
case B_NUMBER_SIZE_T:
return number->n_value.v_size_t >= 0;
default:
return true;
}
}
bool b_number_is_inf_negative(const b_number *number)
{
if (!(number->n_flags & NUMBER_F_INF)) {
return false;
}
switch (number->n_type) {
case B_NUMBER_INT8:
return number->n_value.v_int8 < 0;
case B_NUMBER_INT16:
return number->n_value.v_int16 < 0;
case B_NUMBER_INT32:
return number->n_value.v_int32 < 0;
case B_NUMBER_INT64:
return number->n_value.v_int64 < 0;
case B_NUMBER_FLOAT32:
return number->n_value.v_float32 < 0;
case B_NUMBER_FLOAT64:
return number->n_value.v_float64 < 0;
case B_NUMBER_CHAR:
return number->n_value.v_char < 0;
case B_NUMBER_SHORT:
return number->n_value.v_short < 0;
case B_NUMBER_INT:
return number->n_value.v_int < 0;
case B_NUMBER_LONG:
return number->n_value.v_long < 0;
case B_NUMBER_LONGLONG:
return number->n_value.v_longlong < 0;
case B_NUMBER_FLOAT:
return number->n_value.v_float < 0;
case B_NUMBER_DOUBLE:
return number->n_value.v_double < 0;
case B_NUMBER_SIZE_T:
return number->n_value.v_size_t < 0;
default:
return false;
}
}
bool b_number_is_nan(const b_number *number)
{
return (number->n_flags & NUMBER_F_NAN) != 0;
}
bool b_number_is_nan_positive(const b_number *number)
{
if (!(number->n_flags & NUMBER_F_NAN)) {
return false;
}
switch (number->n_type) {
case B_NUMBER_INT8:
return number->n_value.v_int8 >= 0;
case B_NUMBER_INT16:
return number->n_value.v_int16 >= 0;
case B_NUMBER_INT32:
return number->n_value.v_int32 >= 0;
case B_NUMBER_INT64:
return number->n_value.v_int64 >= 0;
case B_NUMBER_FLOAT32:
return number->n_value.v_float32 >= 0;
case B_NUMBER_FLOAT64:
return number->n_value.v_float64 >= 0;
case B_NUMBER_CHAR:
return number->n_value.v_char >= 0;
case B_NUMBER_SHORT:
return number->n_value.v_short >= 0;
case B_NUMBER_INT:
return number->n_value.v_int >= 0;
case B_NUMBER_LONG:
return number->n_value.v_long >= 0;
case B_NUMBER_LONGLONG:
return number->n_value.v_longlong >= 0;
case B_NUMBER_FLOAT:
return number->n_value.v_float >= 0;
case B_NUMBER_DOUBLE:
return number->n_value.v_double >= 0;
case B_NUMBER_SIZE_T:
return number->n_value.v_size_t >= 0;
default:
return true;
}
}
bool b_number_is_nan_negative(const b_number *number)
{
if (!(number->n_flags & NUMBER_F_NAN)) {
return false;
}
switch (number->n_type) {
case B_NUMBER_INT8:
return number->n_value.v_int8 < 0;
case B_NUMBER_INT16:
return number->n_value.v_int16 < 0;
case B_NUMBER_INT32:
return number->n_value.v_int32 < 0;
case B_NUMBER_INT64:
return number->n_value.v_int64 < 0;
case B_NUMBER_FLOAT32:
return number->n_value.v_float32 < 0;
case B_NUMBER_FLOAT64:
return number->n_value.v_float64 < 0;
case B_NUMBER_CHAR:
return number->n_value.v_char < 0;
case B_NUMBER_SHORT:
return number->n_value.v_short < 0;
case B_NUMBER_INT:
return number->n_value.v_int < 0;
case B_NUMBER_LONG:
return number->n_value.v_long < 0;
case B_NUMBER_LONGLONG:
return number->n_value.v_longlong < 0;
case B_NUMBER_FLOAT:
return number->n_value.v_float < 0;
case B_NUMBER_DOUBLE:
return number->n_value.v_double < 0;
case B_NUMBER_SIZE_T:
return number->n_value.v_size_t < 0;
default:
return false;
}
}
void b_number_set_inf_positive(b_number *number, bool v)
{
if (!v) {
number->n_flags &= ~NUMBER_F_INF;
return;
}
number->n_flags &= ~NUMBER_F_NAN;
number->n_flags |= NUMBER_F_INF;
switch (number->n_type) {
case B_NUMBER_INT8:
number->n_value.v_int8 = 0;
break;
case B_NUMBER_INT16:
number->n_value.v_int16 = 0;
break;
case B_NUMBER_INT32:
number->n_value.v_int32 = 0;
break;
case B_NUMBER_INT64:
number->n_value.v_int64 = 0;
break;
case B_NUMBER_FLOAT32:
number->n_value.v_float32 = 0;
break;
case B_NUMBER_FLOAT64:
number->n_value.v_float64 = 0;
break;
case B_NUMBER_CHAR:
number->n_value.v_char = 0;
break;
case B_NUMBER_SHORT:
number->n_value.v_short = 0;
break;
case B_NUMBER_INT:
number->n_value.v_int = 0;
break;
case B_NUMBER_LONG:
number->n_value.v_long = 0;
break;
case B_NUMBER_LONGLONG:
number->n_value.v_longlong = 0;
break;
case B_NUMBER_FLOAT:
number->n_value.v_float = 0;
break;
case B_NUMBER_DOUBLE:
number->n_value.v_double = 0;
break;
case B_NUMBER_SIZE_T:
number->n_value.v_size_t = 0;
break;
default:
break;
}
}
void b_number_set_inf_negative(b_number *number, bool v)
{
if (!v) {
number->n_flags &= ~NUMBER_F_INF;
return;
}
number->n_flags &= ~NUMBER_F_NAN;
number->n_flags |= NUMBER_F_INF;
switch (number->n_type) {
case B_NUMBER_INT8:
number->n_value.v_int8 = -1;
break;
case B_NUMBER_INT16:
number->n_value.v_int16 = -1;
break;
case B_NUMBER_INT32:
number->n_value.v_int32 = -1;
break;
case B_NUMBER_INT64:
number->n_value.v_int64 = -1;
break;
case B_NUMBER_FLOAT32:
number->n_value.v_float32 = -1;
break;
case B_NUMBER_FLOAT64:
number->n_value.v_float64 = -1;
break;
case B_NUMBER_CHAR:
number->n_value.v_char = -1;
break;
case B_NUMBER_SHORT:
number->n_value.v_short = -1;
break;
case B_NUMBER_INT:
number->n_value.v_int = -1;
break;
case B_NUMBER_LONG:
number->n_value.v_long = -1;
break;
case B_NUMBER_LONGLONG:
number->n_value.v_longlong = -1;
break;
case B_NUMBER_FLOAT:
number->n_value.v_float = -1;
break;
case B_NUMBER_DOUBLE:
number->n_value.v_double = -1;
break;
case B_NUMBER_SIZE_T:
number->n_value.v_size_t = -1;
break;
default:
break;
}
}
void b_number_set_nan_positive(b_number *number, bool v)
{
if (!v) {
number->n_flags &= ~NUMBER_F_NAN;
return;
}
number->n_flags &= ~NUMBER_F_INF;
number->n_flags |= NUMBER_F_NAN;
switch (number->n_type) {
case B_NUMBER_INT8:
number->n_value.v_int8 = 0;
break;
case B_NUMBER_INT16:
number->n_value.v_int16 = 0;
break;
case B_NUMBER_INT32:
number->n_value.v_int32 = 0;
break;
case B_NUMBER_INT64:
number->n_value.v_int64 = 0;
break;
case B_NUMBER_FLOAT32:
number->n_value.v_float32 = 0;
break;
case B_NUMBER_FLOAT64:
number->n_value.v_float64 = 0;
break;
case B_NUMBER_CHAR:
number->n_value.v_char = 0;
break;
case B_NUMBER_SHORT:
number->n_value.v_short = 0;
break;
case B_NUMBER_INT:
number->n_value.v_int = 0;
break;
case B_NUMBER_LONG:
number->n_value.v_long = 0;
break;
case B_NUMBER_LONGLONG:
number->n_value.v_longlong = 0;
break;
case B_NUMBER_FLOAT:
number->n_value.v_float = 0;
break;
case B_NUMBER_DOUBLE:
number->n_value.v_double = 0;
break;
case B_NUMBER_SIZE_T:
number->n_value.v_size_t = 0;
break;
default:
break;
}
}
void b_number_set_nan_negative(b_number *number, bool v)
{
if (!v) {
number->n_flags &= ~NUMBER_F_NAN;
return;
}
number->n_flags &= ~NUMBER_F_INF;
number->n_flags |= NUMBER_F_NAN;
switch (number->n_type) {
case B_NUMBER_INT8:
number->n_value.v_int8 = -1;
break;
case B_NUMBER_INT16:
number->n_value.v_int16 = -1;
break;
case B_NUMBER_INT32:
number->n_value.v_int32 = -1;
break;
case B_NUMBER_INT64:
number->n_value.v_int64 = -1;
break;
case B_NUMBER_FLOAT32:
number->n_value.v_float32 = -1;
break;
case B_NUMBER_FLOAT64:
number->n_value.v_float64 = -1;
break;
case B_NUMBER_CHAR:
number->n_value.v_char = -1;
break;
case B_NUMBER_SHORT:
number->n_value.v_short = -1;
break;
case B_NUMBER_INT:
number->n_value.v_int = -1;
break;
case B_NUMBER_LONG:
number->n_value.v_long = -1;
break;
case B_NUMBER_LONGLONG:
number->n_value.v_longlong = -1;
break;
case B_NUMBER_FLOAT:
number->n_value.v_float = -1;
break;
case B_NUMBER_DOUBLE:
number->n_value.v_double = -1;
break;
case B_NUMBER_SIZE_T:
number->n_value.v_size_t = -1;
break;
default:
break;
}
}
size_t b_number_data_size(const struct b_number *number)
{
switch (number->n_type) {
@@ -175,9 +577,130 @@ size_t b_number_data_size(const struct b_number *number)
}
}
static void number_to_string(struct b_dsref *obj, struct b_stream *out)
static void print_inf(const struct b_number *n, struct b_stream *out)
{
switch (n->n_type) {
case B_NUMBER_INT8:
b_stream_write_string(out, n->n_value.v_int8 < 0 ? "-" : "", NULL);
break;
case B_NUMBER_INT16:
b_stream_write_string(out, n->n_value.v_int16 < 0 ? "-" : "", NULL);
break;
case B_NUMBER_INT32:
b_stream_write_string(out, n->n_value.v_int32 < 0 ? "-" : "", NULL);
break;
case B_NUMBER_INT64:
b_stream_write_string(out, n->n_value.v_int64 < 0 ? "-" : "", NULL);
break;
case B_NUMBER_FLOAT32:
b_stream_write_string(
out, n->n_value.v_float32 < 0 ? "-" : "", NULL);
break;
case B_NUMBER_FLOAT64:
b_stream_write_string(
out, n->n_value.v_float64 < 0 ? "-" : "", NULL);
break;
case B_NUMBER_CHAR:
b_stream_write_string(out, n->n_value.v_char < 0 ? "-" : "", NULL);
break;
case B_NUMBER_SHORT:
b_stream_write_string(out, n->n_value.v_short < 0 ? "-" : "", NULL);
break;
case B_NUMBER_INT:
b_stream_write_string(out, n->n_value.v_int < 0 ? "-" : "", NULL);
break;
case B_NUMBER_LONG:
b_stream_write_string(out, n->n_value.v_long < 0 ? "-" : "", NULL);
break;
case B_NUMBER_LONGLONG:
b_stream_write_string(
out, n->n_value.v_longlong < 0 ? "-" : "", NULL);
break;
case B_NUMBER_FLOAT:
b_stream_write_string(out, n->n_value.v_float < 0 ? "-" : "", NULL);
break;
case B_NUMBER_DOUBLE:
b_stream_write_string(out, n->n_value.v_double < 0 ? "-" : "", NULL);
break;
case B_NUMBER_SIZE_T:
b_stream_write_string(out, n->n_value.v_size_t < 0 ? "-" : "", NULL);
break;
default:
break;
}
b_stream_write_string(out, "INF", NULL);
}
static void print_nan(const struct b_number *n, struct b_stream *out)
{
switch (n->n_type) {
case B_NUMBER_INT8:
b_stream_write_string(out, n->n_value.v_int8 < 0 ? "-" : "", NULL);
break;
case B_NUMBER_INT16:
b_stream_write_string(out, n->n_value.v_int16 < 0 ? "-" : "", NULL);
break;
case B_NUMBER_INT32:
b_stream_write_string(out, n->n_value.v_int32 < 0 ? "-" : "", NULL);
break;
case B_NUMBER_INT64:
b_stream_write_string(out, n->n_value.v_int64 < 0 ? "-" : "", NULL);
break;
case B_NUMBER_FLOAT32:
b_stream_write_string(
out, n->n_value.v_float32 < 0 ? "-" : "", NULL);
break;
case B_NUMBER_FLOAT64:
b_stream_write_string(
out, n->n_value.v_float64 < 0 ? "-" : "", NULL);
break;
case B_NUMBER_CHAR:
b_stream_write_string(out, n->n_value.v_char < 0 ? "-" : "", NULL);
break;
case B_NUMBER_SHORT:
b_stream_write_string(out, n->n_value.v_short < 0 ? "-" : "", NULL);
break;
case B_NUMBER_INT:
b_stream_write_string(out, n->n_value.v_int < 0 ? "-" : "", NULL);
break;
case B_NUMBER_LONG:
b_stream_write_string(out, n->n_value.v_long < 0 ? "-" : "", NULL);
break;
case B_NUMBER_LONGLONG:
b_stream_write_string(
out, n->n_value.v_longlong < 0 ? "-" : "", NULL);
break;
case B_NUMBER_FLOAT:
b_stream_write_string(out, n->n_value.v_float < 0 ? "-" : "", NULL);
break;
case B_NUMBER_DOUBLE:
b_stream_write_string(out, n->n_value.v_double < 0 ? "-" : "", NULL);
break;
case B_NUMBER_SIZE_T:
b_stream_write_string(out, n->n_value.v_size_t < 0 ? "-" : "", NULL);
break;
default:
break;
}
b_stream_write_string(out, "NaN", NULL);
}
static void number_to_string(const struct b_dsref *obj, struct b_stream *out)
{
struct b_number *number = B_NUMBER(obj);
if (number->n_flags & NUMBER_F_INF) {
print_inf(number, out);
return;
}
if (number->n_flags & NUMBER_F_NAN) {
print_nan(number, out);
return;
}
switch (number->n_type) {
case B_NUMBER_INT8:
b_stream_write_fmt(out, NULL, "%" PRIu8, number->n_value.v_int8);

View File

@@ -5,9 +5,15 @@
#include <blue/ds/number.h>
enum b_number_flags {
NUMBER_F_INF = 0x01u,
NUMBER_F_NAN = 0x02u,
};
struct b_number {
struct b_dsref n_base;
b_number_type n_type;
enum b_number_flags n_flags;
union {
int8_t v_int8;
int16_t v_int16;

View File

@@ -41,7 +41,7 @@ void b_release(struct b_dsref *obj)
free(obj);
}
void b_to_string(struct b_dsref *obj, struct b_stream *out)
void b_to_string(const struct b_dsref *obj, struct b_stream *out)
{
if (obj->ob_type->t_to_string) {
obj->ob_type->t_to_string(obj, out);

File diff suppressed because it is too large Load Diff

View File

@@ -8,9 +8,14 @@
struct b_string {
struct b_dsref s_base;
/* length of string, not including null-terminator */
/* length of string in bytes, not including null-terminator.
* a multi-byte utf-8 codepoint will be counted as multiple bytes here */
unsigned int s_len;
/* maximum length of string storable in the currently-allocated buffer, not including null terminator */
/* length of string in codepoints, not including null-terminator.
* a multi-byte utf-8 codepoint will be counted as one codepoint here */
unsigned int s_codepoints;
/* maximum length of string storable in the currently-allocated buffer
* in bytes, not including null terminator */
unsigned int s_max;
union {
char d_inline[STRING_INLINE_CAPACITY + 1];