object: number: add support for positive/negative infinite and NaN values

This commit is contained in:
2025-09-22 10:52:02 +01:00
parent be47176524
commit 15cb225533
3 changed files with 540 additions and 0 deletions

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_integer(const b_number *number);
BLUE_API bool b_number_is_float(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); BLUE_API size_t b_number_data_size(const b_number *number);

View File

@@ -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) size_t b_number_data_size(const struct b_number *number)
{ {
switch (number->n_type) { switch (number->n_type) {
@@ -175,9 +577,130 @@ size_t b_number_data_size(const struct b_number *number)
} }
} }
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_object *obj, struct b_stream *out) static void number_to_string(const struct b_object *obj, struct b_stream *out)
{ {
struct b_number *number = B_NUMBER(obj); 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) { switch (number->n_type) {
case B_NUMBER_INT8: case B_NUMBER_INT8:
b_stream_write_fmt(out, NULL, "%" PRIu8, number->n_value.v_int8); b_stream_write_fmt(out, NULL, "%" PRIu8, number->n_value.v_int8);

View File

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