object: number: add support for positive/negative infinite and NaN values
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
523
object/number.c
523
object/number.c
@@ -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 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)
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -5,9 +5,15 @@
|
||||
|
||||
#include <blue/object/number.h>
|
||||
|
||||
enum b_number_flags {
|
||||
NUMBER_F_INF = 0x01u,
|
||||
NUMBER_F_NAN = 0x02u,
|
||||
};
|
||||
|
||||
struct b_number {
|
||||
struct b_object n_base;
|
||||
b_number_type n_type;
|
||||
enum b_number_flags n_flags;
|
||||
union {
|
||||
int8_t v_int8;
|
||||
int16_t v_int16;
|
||||
|
||||
Reference in New Issue
Block a user