fx: implement wchar and wstr value types

This commit is contained in:
2026-05-25 17:23:32 +01:00
parent 13332145c2
commit 0f1dfc0b07
4 changed files with 820 additions and 242 deletions
+3
View File
@@ -33,6 +33,8 @@ enum {
__FX_VALUE_TYPE_FLOAT,
__FX_VALUE_TYPE_DOUBLE,
__FX_VALUE_TYPE_WCHAR,
__FX_VALUE_TYPE_WSTR,
__FX_VALUE_TYPE_CSTR,
__FX_VALUE_TYPE_POINTER,
};
@@ -49,5 +51,6 @@ FX_DECLS_END;
FX_API fx_type_id fx_value_type_get_type(void);
FX_API bool fx_type_is_value_type(fx_type_id ty);
FX_API unsigned int __fx_type_get_value_type(fx_type_id ty);
FX_API size_t __fx_value_type_get_size(unsigned int ty);
#endif
+100 -32
View File
@@ -34,13 +34,15 @@
#define FX_UINT(v) __FX_VALUE_CREATE(UINT, v_uint, v)
#define FX_LONG(v) __FX_VALUE_CREATE(LONG, v_long, v)
#define FX_ULONG(v) __FX_VALUE_CREATE(ULONG, v_ulong, v)
#define FX_LONGLONG(v) __FX_VALUE_CREATE(LONGLONG, v_int, v)
#define FX_ULONGLONG(v) __FX_VALUE_CREATE(ULONGLONG, v_uint, v)
#define FX_LONGLONG(v) __FX_VALUE_CREATE(LONGLONG, v_longlong, v)
#define FX_ULONGLONG(v) __FX_VALUE_CREATE(ULONGLONG, v_ulonglong, v)
#define FX_SIZE(v) __FX_VALUE_CREATE(SIZE, v_size, v)
#define FX_FLOAT(v) __FX_VALUE_CREATE(FLOAT, v_float, v)
#define FX_DOUBLE(v) __FX_VALUE_CREATE(DOUBLE, v_double, v)
#define FX_WCHAR(v) __FX_VALUE_CREATE(WCHAR, v_wchar, v)
#define FX_WSTR(v) __FX_VALUE_CREATE(WSTR, v_wstr, v)
#define FX_CSTR(v) __FX_VALUE_CREATE(CSTR, v_cstr, v)
#define FX_POINTER(v) __FX_VALUE_CREATE(POINTER, v_pointer, v)
#define FX_VALUE_OBJECT(v) \
@@ -79,6 +81,8 @@ typedef struct fx_value {
float v_float;
double v_double;
fx_wchar v_wchar;
const fx_wchar *v_wstr;
const char *v_cstr;
void *v_pointer;
fx_object *v_object;
@@ -87,41 +91,105 @@ typedef struct fx_value {
FX_API void fx_value_init(fx_value *v, fx_type_id type);
FX_API void fx_value_copy(fx_value *dst, fx_value *src);
FX_API void fx_value_copy_array(fx_value *dst, fx_value *src, size_t count);
static inline bool fx_value_is_type(const fx_value *value, fx_type_id ty)
{
return fx_type_id_compare(value->v_type, ty) == 0;
}
FX_API void fx_value_copy(fx_value *dst, const fx_value *src);
FX_API fx_value fx_value_copy_return(const fx_value src);
FX_API fx_value fx_value_ref_copy_return(const fx_value *src);
FX_API void fx_value_copy_array(
fx_value *dst,
const fx_value *src,
size_t count);
FX_API void fx_value_unset(fx_value *v);
FX_API void fx_value_unset_array(fx_value *v, size_t length);
FX_API void fx_value_set_bool(fx_value *v, bool b);
FX_API void fx_value_set_int(fx_value *v, intptr_t i);
FX_API void fx_value_set_uint(fx_value *v, uintptr_t u);
FX_API void fx_value_set_double(fx_value *v, double d);
FX_API void fx_value_set_static_cstr(fx_value *v, const char *cstr);
FX_API void fx_value_set_pointer(fx_value *v, void *p);
FX_API void fx_value_set_object(fx_value *v, fx_object *obj);
FX_API fx_status fx_value_hash(const fx_value *v, uint64_t *out_hash);
FX_API int fx_value_compare(const fx_value *left, const fx_value *right);
FX_API bool fx_value_is_bool(const fx_value *v);
FX_API bool fx_value_is_int(const fx_value *v);
FX_API bool fx_value_is_uint(const fx_value *v);
FX_API bool fx_value_is_double(const fx_value *v);
FX_API bool fx_value_is_string(const fx_value *v);
FX_API bool fx_value_is_pointer(const fx_value *v);
FX_API bool fx_value_is_object(const fx_value *v, fx_type_id type);
FX_API fx_status fx_value_to_string(
const fx_value *v,
FX_TYPE_FWDREF(fx_stream) * out,
const char *format);
FX_API bool fx_value_get_bool(const fx_value *v);
FX_API intptr_t fx_value_get_int(const fx_value *v);
FX_API uintptr_t fx_value_get_uint(const fx_value *v);
FX_API double fx_value_get_double(const fx_value *v);
FX_API const char *fx_value_get_cstr(const fx_value *v);
FX_API void *fx_value_get_pointer(fx_value *v);
FX_API const void *fx_value_get_pointer_c(const fx_value *v);
FX_API fx_object *fx_value_get_object(fx_value *v);
FX_API const fx_object *fx_value_get_object_c(const fx_value *v);
FX_API bool fx_value_is_set(const fx_value *v);
FX_API bool fx_value_is_type(const fx_value *v, fx_type_id type);
FX_API fx_status
fx_value_change_type(fx_value *in, fx_value *out, fx_type_id convert_to);
FX_API fx_type_id
fx_value_get_common_type(const fx_value *a, const fx_value *b);
FX_API fx_status
fx_value_add(const fx_value *left, const fx_value *right, fx_value *out);
FX_API fx_status
fx_value_subtract(const fx_value *left, const fx_value *right, fx_value *out);
FX_API fx_status
fx_value_multiply(const fx_value *left, const fx_value *right, fx_value *out);
FX_API fx_status
fx_value_divide(const fx_value *left, const fx_value *right, fx_value *out);
FX_API fx_status fx_value_increment(fx_value *value);
FX_API fx_status fx_value_decrement(fx_value *value);
FX_API fx_status fx_value_add_in_place(fx_value *left, const fx_value *right);
FX_API fx_status
fx_value_subtract_in_place(fx_value *left, const fx_value *right);
FX_API fx_status
fx_value_multiply_in_place(fx_value *left, const fx_value *right);
FX_API fx_status
fx_value_divide_in_place(fx_value *left, const fx_value *right);
FX_API fx_status fx_value_set_bool(fx_value *v, bool value);
FX_API fx_status fx_value_set_i16(fx_value *v, i16 value);
FX_API fx_status fx_value_set_u16(fx_value *v, u16 value);
FX_API fx_status fx_value_set_i32(fx_value *v, i32 value);
FX_API fx_status fx_value_set_u32(fx_value *v, u32 value);
FX_API fx_status fx_value_set_i64(fx_value *v, i64 value);
FX_API fx_status fx_value_set_u64(fx_value *v, u64 value);
FX_API fx_status fx_value_set_iptr(fx_value *v, iptr value);
FX_API fx_status fx_value_set_uptr(fx_value *v, uptr value);
FX_API fx_status fx_value_set_sbyte(fx_value *v, sbyte value);
FX_API fx_status fx_value_set_byte(fx_value *v, byte value);
FX_API fx_status fx_value_set_short(fx_value *v, short value);
FX_API fx_status fx_value_set_ushort(fx_value *v, unsigned short value);
FX_API fx_status fx_value_set_int(fx_value *v, int value);
FX_API fx_status fx_value_set_uint(fx_value *v, unsigned int value);
FX_API fx_status fx_value_set_long(fx_value *v, long value);
FX_API fx_status fx_value_set_ulong(fx_value *v, unsigned long value);
FX_API fx_status fx_value_set_longlong(fx_value *v, long long value);
FX_API fx_status fx_value_set_ulonglong(fx_value *v, unsigned long long value);
FX_API fx_status fx_value_set_size(fx_value *v, size_t value);
FX_API fx_status fx_value_set_float(fx_value *v, float value);
FX_API fx_status fx_value_set_double(fx_value *v, double value);
FX_API fx_status fx_value_set_cstr(fx_value *v, const char *value);
FX_API fx_status fx_value_set_wchar(fx_value *v, fx_wchar value);
FX_API fx_status fx_value_set_wstr(fx_value *v, const fx_wchar *value);
FX_API fx_status fx_value_set_pointer(fx_value *v, void *value);
FX_API fx_status fx_value_set_object(fx_value *v, fx_object *value);
FX_API fx_status fx_value_get_bool(const fx_value *v, bool *out);
FX_API fx_status fx_value_get_i16(const fx_value *v, i16 *out);
FX_API fx_status fx_value_get_u16(const fx_value *v, u16 *out);
FX_API fx_status fx_value_get_i32(const fx_value *v, i32 *out);
FX_API fx_status fx_value_get_u32(const fx_value *v, u32 *out);
FX_API fx_status fx_value_get_i64(const fx_value *v, i64 *out);
FX_API fx_status fx_value_get_u64(const fx_value *v, u64 *out);
FX_API fx_status fx_value_get_iptr(const fx_value *v, iptr *out);
FX_API fx_status fx_value_get_uptr(const fx_value *v, uptr *out);
FX_API fx_status fx_value_get_sbyte(const fx_value *v, sbyte *out);
FX_API fx_status fx_value_get_byte(const fx_value *v, byte *out);
FX_API fx_status fx_value_get_short(const fx_value *v, short *out);
FX_API fx_status fx_value_get_ushort(const fx_value *v, unsigned short *out);
FX_API fx_status fx_value_get_int(const fx_value *v, int *out);
FX_API fx_status fx_value_get_uint(const fx_value *v, unsigned int *out);
FX_API fx_status fx_value_get_long(const fx_value *v, long *out);
FX_API fx_status fx_value_get_ulong(const fx_value *v, unsigned long *out);
FX_API fx_status fx_value_get_longlong(const fx_value *v, long long *out);
FX_API fx_status
fx_value_get_ulonglong(const fx_value *v, unsigned long long *out);
FX_API fx_status fx_value_get_size(const fx_value *v, size_t *out);
FX_API fx_status fx_value_get_float(const fx_value *v, float *out);
FX_API fx_status fx_value_get_double(const fx_value *v, double *out);
FX_API fx_status fx_value_get_cstr(const fx_value *v, const char **out);
FX_API fx_status fx_value_get_wchar(const fx_value *v, fx_wchar *out);
FX_API fx_status fx_value_get_wstr(const fx_value *v, const fx_wchar **out);
FX_API fx_status fx_value_get_pointer(const fx_value *v, void **out);
FX_API fx_status fx_value_get_object(const fx_value *v, fx_object **out);
#endif
+64
View File
@@ -1,7 +1,12 @@
#include <fx/int-primitives.h>
#include <fx/value-type.h>
bool fx_type_is_value_type(fx_type_id ty)
{
if (!ty) {
return false;
}
return ty->a.p00 == __FX_VALUE_TYPE_BASEID;
}
@@ -14,6 +19,65 @@ unsigned int __fx_type_get_value_type(fx_type_id ty)
return ty->a.p01;
}
size_t __fx_value_type_get_size(unsigned int ty)
{
switch (ty) {
case __FX_VALUE_TYPE_BOOL:
return sizeof(bool);
case __FX_VALUE_TYPE_I16:
return sizeof(i16);
case __FX_VALUE_TYPE_U16:
return sizeof(u16);
case __FX_VALUE_TYPE_I32:
return sizeof(i32);
case __FX_VALUE_TYPE_U32:
return sizeof(u32);
case __FX_VALUE_TYPE_I64:
return sizeof(i64);
case __FX_VALUE_TYPE_U64:
return sizeof(u64);
case __FX_VALUE_TYPE_IPTR:
return sizeof(iptr);
case __FX_VALUE_TYPE_UPTR:
return sizeof(uptr);
case __FX_VALUE_TYPE_SBYTE:
return sizeof(sbyte);
case __FX_VALUE_TYPE_BYTE:
return sizeof(byte);
case __FX_VALUE_TYPE_SHORT:
return sizeof(short);
case __FX_VALUE_TYPE_USHORT:
return sizeof(unsigned short);
case __FX_VALUE_TYPE_INT:
return sizeof(int);
case __FX_VALUE_TYPE_UINT:
return sizeof(unsigned int);
case __FX_VALUE_TYPE_LONG:
return sizeof(long);
case __FX_VALUE_TYPE_ULONG:
return sizeof(unsigned long);
case __FX_VALUE_TYPE_LONGLONG:
return sizeof(long long);
case __FX_VALUE_TYPE_ULONGLONG:
return sizeof(unsigned long long);
case __FX_VALUE_TYPE_SIZE:
return sizeof(size_t);
case __FX_VALUE_TYPE_FLOAT:
return sizeof(float);
case __FX_VALUE_TYPE_DOUBLE:
return sizeof(double);
case __FX_VALUE_TYPE_CSTR:
return sizeof(const char *);
case __FX_VALUE_TYPE_POINTER:
return sizeof(void *);
default:
return 0;
}
}
/*** CLASS DEFINITION *********************************************************/
FX_TYPE_CLASS_BEGIN(fx_value_type)
+651 -208
View File
@@ -1,24 +1,47 @@
#include <fx/bool.h>
#include <fx/comparable.h>
#include <fx/convertible.h>
#include <fx/float.h>
#include <fx/int.h>
#include <fx/operable.h>
#include <fx/reflection/type.h>
#include <fx/string.h>
#include <fx/value-type.h>
#include <fx/value.h>
#include <fx/wstr.h>
void fx_value_init(fx_value *v, fx_type_id type)
{
}
void fx_value_copy(fx_value *dst, fx_value *src)
void fx_value_copy(fx_value *dst, const fx_value *src)
{
memcpy(dst, src, sizeof *dst);
if (!fx_type_is_value_type(dst->v_type)) {
if (dst->v_type && !fx_type_is_value_type(dst->v_type)) {
fx_object_ref(dst->v_object);
}
}
void fx_value_copy_array(fx_value *dst, fx_value *src, size_t count)
fx_value fx_value_copy_return(const fx_value src)
{
fx_value result;
fx_value_copy(&result, &src);
return result;
}
fx_value fx_value_ref_copy_return(const fx_value *src)
{
if (!src) {
return FX_VALUE_EMPTY;
}
fx_value result;
fx_value_copy(&result, src);
return result;
}
void fx_value_copy_array(fx_value *dst, const fx_value *src, size_t count)
{
for (size_t i = 0; i < count; i++) {
fx_value_copy(dst + i, src + i);
@@ -27,11 +50,13 @@ void fx_value_copy_array(fx_value *dst, fx_value *src, size_t count)
void fx_value_unset(fx_value *v)
{
#if 0
if (v->v_type.t_primitive > __FX_VALUE_TYPE_OBJECT_BOUNDARY) {
if (!v->v_type) {
return;
}
if (!fx_type_is_value_type(v->v_type)) {
fx_object_unref(v->v_object);
}
#endif
memset(v, 0x0, sizeof *v);
}
@@ -43,232 +68,650 @@ void fx_value_unset_array(fx_value *v, size_t count)
}
}
void fx_value_set_bool(fx_value *v, bool b)
fx_status fx_value_to_string(
const fx_value *v,
fx_stream *out,
const char *format)
{
if (!v->v_type) {
return FX_SUCCESS;
}
void *c = fx_class_get(v->v_type);
if (!c) {
return FX_ERR_NOT_SUPPORTED;
}
fx_object_class *object = fx_class_get_interface(c, FX_TYPE_OBJECT);
if (object && object->to_string) {
return object->to_string(v, out, format);
}
const fx_type *ty = fx_type_get_by_id(v->v_type);
if (ty) {
fx_stream_write_fmt(out, NULL, "%s", fx_type_get_name(ty));
return FX_SUCCESS;
}
return FX_ERR_NOT_SUPPORTED;
}
void fx_value_set_int(fx_value *v, intptr_t i)
fx_status fx_value_hash(const fx_value *v, uint64_t *out_hash)
{
void *c = fx_class_get(v->v_type);
if (!c) {
return FX_ERR_NOT_SUPPORTED;
}
fx_object_class *object = fx_class_get_interface(c, FX_TYPE_OBJECT);
if (!object || !object->hash) {
return FX_ERR_NOT_SUPPORTED;
}
return object->hash(v, out_hash);
}
void fx_value_set_uint(fx_value *v, uintptr_t u)
int fx_value_compare(const fx_value *left, const fx_value *right)
{
}
void fx_value_set_double(fx_value *v, double d)
{
}
void fx_value_set_static_cstr(fx_value *v, const char *cstr)
{
}
void fx_value_set_pointer(fx_value *v, void *p)
{
}
void fx_value_set_object(fx_value *v, fx_object *obj)
{
}
#if 0
bool fx_value_is_bool(const fx_value *v)
{
if (v->v_type.t_primitive == FX_VALUE_TYPE_BOOL) {
return true;
}
if (v->v_type.t_primitive > __FX_VALUE_TYPE_OBJECT_BOUNDARY) {
if (fx_type_id_compare(v->v_type.t_object, FX_TYPE_BOOL)) {
return true;
}
}
return false;
}
bool fx_value_is_int(const fx_value *v)
{
if (v->v_type.t_primitive == FX_VALUE_TYPE_INT) {
return true;
}
if (v->v_type.t_primitive > __FX_VALUE_TYPE_OBJECT_BOUNDARY) {
if (fx_type_id_compare(v->v_type.t_object, FX_TYPE_INT)) {
return true;
}
}
return false;
}
bool fx_value_is_uint(const fx_value *v)
{
if (v->v_type.t_primitive == FX_VALUE_TYPE_UINT) {
return true;
}
if (v->v_type.t_primitive > __FX_VALUE_TYPE_OBJECT_BOUNDARY) {
if (fx_type_id_compare(v->v_type.t_object, FX_TYPE_UINT)) {
return true;
}
}
return false;
}
bool fx_value_is_double(const fx_value *v)
{
if (v->v_type.t_primitive == FX_VALUE_TYPE_DOUBLE) {
return true;
}
if (v->v_type.t_primitive > __FX_VALUE_TYPE_OBJECT_BOUNDARY) {
if (fx_type_id_compare(v->v_type.t_object, FX_TYPE_DOUBLE)) {
return true;
}
}
return false;
}
bool fx_value_is_string(const fx_value *v)
{
if (v->v_type.t_primitive == FX_VALUE_TYPE_CSTR) {
return true;
}
if (v->v_type.t_primitive > __FX_VALUE_TYPE_OBJECT_BOUNDARY) {
if (fx_type_id_compare(v->v_type.t_object, FX_TYPE_STRING)) {
return true;
}
}
return false;
}
bool fx_value_is_pointer(const fx_value *v)
{
return (v->v_type.t_primitive == FX_VALUE_TYPE_POINTER);
}
bool fx_value_is_object(const fx_value *v, fx_type_id type)
{
if (v->v_type.t_primitive > __FX_VALUE_TYPE_OBJECT_BOUNDARY) {
if (fx_type_id_compare(v->v_type.t_object, type)) {
return true;
}
}
return false;
}
bool fx_value_get_bool(const fx_value *v)
{
if (v->v_type.t_primitive == FX_VALUE_TYPE_BOOL) {
return v->v_bool;
}
if (v->v_type.t_primitive > __FX_VALUE_TYPE_OBJECT_BOUNDARY) {
if (fx_type_id_compare(v->v_type.t_object, FX_TYPE_BOOL)) {
return fx_bool_get_value(v->v_object);
}
}
return false;
}
intptr_t fx_value_get_int(const fx_value *v)
{
if (v->v_type.t_primitive == FX_VALUE_TYPE_INT) {
return v->v_int;
}
if (v->v_type.t_primitive > __FX_VALUE_TYPE_OBJECT_BOUNDARY) {
if (fx_type_id_compare(v->v_type.t_object, FX_TYPE_INT)) {
return fx_int_get_value(v->v_object);
}
}
if (!left->v_type && !right->v_type) {
return 0;
}
if (!left->v_type || !right->v_type) {
return -1;
}
void *c = fx_class_get(left->v_type);
if (!c) {
return FX_ERR_NOT_SUPPORTED;
}
fx_comparable_class *comparable = fx_class_get_interface(
c,
FX_TYPE_COMPARABLE);
if (!comparable || !comparable->c_compare) {
return FX_ERR_NOT_SUPPORTED;
}
return comparable->c_compare(left, right);
}
uintptr_t fx_value_get_uint(const fx_value *v)
bool fx_value_is_set(const fx_value *v)
{
if (v->v_type.t_primitive == FX_VALUE_TYPE_UINT) {
return v->v_uint;
}
if (v->v_type.t_primitive > __FX_VALUE_TYPE_OBJECT_BOUNDARY) {
if (fx_type_id_compare(v->v_type.t_object, FX_TYPE_UINT)) {
return fx_uint_get_value(v->v_object);
}
}
return 0;
return v->v_type != NULL;
}
double fx_value_get_double(const fx_value *v)
bool fx_value_is_type(const fx_value *v, fx_type_id type)
{
if (v->v_type.t_primitive == FX_VALUE_TYPE_DOUBLE) {
return v->v_uint;
if (fx_type_id_compare(v->v_type, type) == 0) {
return true;
}
if (v->v_type.t_primitive > __FX_VALUE_TYPE_OBJECT_BOUNDARY) {
if (fx_type_id_compare(v->v_type.t_object, FX_TYPE_DOUBLE)) {
return fx_double_get_value(v->v_object);
}
}
return 0;
}
#endif
const char *fx_value_get_cstr(const fx_value *v)
{
if (v->v_type == FX_TYPE_CSTR) {
return v->v_cstr;
}
if (v->v_type == FX_TYPE_STRING) {
return fx_string_get_cstr(v->v_object);
}
return NULL;
}
void *fx_value_get_pointer(fx_value *v)
{
if (__fx_type_get_value_type(v->v_type) == __FX_VALUE_TYPE_POINTER) {
return v->v_pointer;
}
return NULL;
}
const void *fx_value_get_pointer_c(const fx_value *v)
{
if (__fx_type_get_value_type(v->v_type) == __FX_VALUE_TYPE_POINTER) {
return v->v_pointer;
}
return NULL;
}
fx_object *fx_value_get_object(fx_value *v)
{
if (!fx_type_is_value_type(v->v_type)) {
return v->v_object;
return fx_object_is_type(v->v_object, type);
}
return NULL;
return false;
}
const fx_object *fx_value_get_object_c(const fx_value *v)
static fx_status value_change_string(fx_value *in, fx_value *out)
{
if (!in->v_type) {
return FX_SUCCESS;
}
void *c = fx_class_get(in->v_type);
if (!c) {
return FX_ERR_NOT_SUPPORTED;
}
fx_object_class *object = fx_class_get_interface(c, FX_TYPE_OBJECT);
if (!object || !object->to_string) {
return FX_ERR_NOT_SUPPORTED;
}
fx_stringstream *strm = fx_stringstream_create();
if (!strm) {
return FX_ERR_NO_MEMORY;
}
fx_status status = object->to_string(in, strm, NULL);
if (!FX_OK(status)) {
fx_stringstream_unref(strm);
return status;
}
fx_string *result = fx_string_create_from_cstr(
fx_stringstream_ptr(strm));
fx_stringstream_unref(strm);
if (!result) {
return FX_ERR_NO_MEMORY;
}
*out = FX_VALUE_OBJECT(result);
return FX_SUCCESS;
}
fx_status fx_value_change_type(
fx_value *in,
fx_value *out,
fx_type_id convert_to)
{
if (fx_value_is_type(in, convert_to)) {
fx_value_copy(out, in);
return FX_SUCCESS;
}
if (fx_type_id_compare(convert_to, FX_TYPE_STRING) == 0) {
return value_change_string(in, out);
}
void *c = fx_class_get(in->v_type);
if (!c) {
return FX_ERR_NOT_SUPPORTED;
}
fx_convertible_class *convertible = fx_class_get_interface(
c,
FX_TYPE_CONVERTIBLE);
if (!convertible) {
return FX_ERR_NOT_SUPPORTED;
}
if (!fx_type_is_value_type(convert_to)) {
if (convertible->c_to_object) {
return convertible->c_to_object(in, out, convert_to);
}
return FX_ERR_NOT_SUPPORTED;
}
unsigned int value_type = __fx_type_get_value_type(convert_to);
fx_status status = FX_SUCCESS;
switch (value_type) {
case __FX_VALUE_TYPE_BOOL:
status = convertible->c_to_bool
? convertible->c_to_bool(in, &out->v_bool)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_I16:
status = convertible->c_to_i16
? convertible->c_to_i16(in, &out->v_i16)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_U16:
status = convertible->c_to_u16
? convertible->c_to_u16(in, &out->v_u16)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_I32:
status = convertible->c_to_i32
? convertible->c_to_i32(in, &out->v_i32)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_U32:
status = convertible->c_to_u32
? convertible->c_to_u32(in, &out->v_u32)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_I64:
status = convertible->c_to_i64
? convertible->c_to_i64(in, &out->v_i64)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_U64:
status = convertible->c_to_u64
? convertible->c_to_u64(in, &out->v_u64)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_IPTR:
status = convertible->c_to_iptr
? convertible->c_to_iptr(in, &out->v_iptr)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_UPTR:
status = convertible->c_to_uptr
? convertible->c_to_uptr(in, &out->v_uptr)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_SBYTE:
status = convertible->c_to_sbyte
? convertible->c_to_sbyte(in, &out->v_sbyte)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_BYTE:
status = convertible->c_to_byte
? convertible->c_to_byte(in, &out->v_byte)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_SHORT:
status = convertible->c_to_short
? convertible->c_to_short(in, &out->v_short)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_USHORT:
status = convertible->c_to_ushort
? convertible->c_to_ushort(in, &out->v_ushort)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_INT:
status = convertible->c_to_int
? convertible->c_to_int(in, &out->v_int)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_UINT:
status = convertible->c_to_uint
? convertible->c_to_uint(in, &out->v_uint)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_LONG:
status = convertible->c_to_long
? convertible->c_to_long(in, &out->v_long)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_ULONG:
status = convertible->c_to_ulong
? convertible->c_to_ulong(in, &out->v_ulong)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_LONGLONG:
status = convertible->c_to_longlong
? convertible->c_to_longlong(
in,
&out->v_longlong)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_ULONGLONG:
status = convertible->c_to_ulonglong
? convertible->c_to_ulonglong(
in,
&out->v_ulonglong)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_SIZE:
status = convertible->c_to_size
? convertible->c_to_size(in, &out->v_size)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_FLOAT:
status = convertible->c_to_float
? convertible->c_to_float(in, &out->v_float)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_DOUBLE:
status = convertible->c_to_double
? convertible->c_to_double(in, &out->v_double)
: FX_ERR_NOT_SUPPORTED;
break;
case __FX_VALUE_TYPE_CSTR:
status = convertible->c_to_cstr
? convertible->c_to_cstr(in, &out->v_cstr)
: FX_ERR_NOT_SUPPORTED;
break;
default:
return FX_ERR_NOT_SUPPORTED;
}
if (FX_OK(status)) {
out->v_type = convert_to;
}
return status;
}
#define VALUE_GETTER(c_type_name, fx_type_name, type_id) \
fx_status fx_value_get_##fx_type_name( \
const fx_value *v, \
c_type_name *out) \
{ \
if (fx_type_id_compare(v->v_type, type_id) == 0) { \
*out = v->v_##fx_type_name; \
return FX_SUCCESS; \
} \
\
void *c = fx_class_get(v->v_type); \
if (!c) { \
return FX_ERR_NOT_SUPPORTED; \
} \
\
fx_convertible_class *convertible = fx_class_get_interface( \
c, \
FX_TYPE_CONVERTIBLE); \
if (!convertible) { \
return FX_ERR_NOT_SUPPORTED; \
} \
\
c_type_name result; \
fx_status status = convertible->c_to_##fx_type_name( \
v, \
&result); \
if (!FX_OK(status)) { \
return status; \
} \
\
*out = result; \
return FX_SUCCESS; \
}
#define VALUE_SETTER(c_type_name, fx_type_name, type_id) \
fx_status fx_value_set_##fx_type_name(fx_value *v, c_type_name value) \
{ \
fx_value_unset(v); \
v->v_type = type_id; \
v->v_##fx_type_name = value; \
return FX_SUCCESS; \
}
VALUE_GETTER(bool, bool, FX_TYPE_BOOL)
VALUE_GETTER(i16, i16, FX_TYPE_I16)
VALUE_GETTER(u16, u16, FX_TYPE_U16)
VALUE_GETTER(i32, i32, FX_TYPE_I32)
VALUE_GETTER(u32, u32, FX_TYPE_U32)
VALUE_GETTER(i64, i64, FX_TYPE_I64)
VALUE_GETTER(u64, u64, FX_TYPE_U64)
VALUE_GETTER(iptr, iptr, FX_TYPE_IPTR)
VALUE_GETTER(uptr, uptr, FX_TYPE_UPTR)
VALUE_GETTER(sbyte, sbyte, FX_TYPE_SBYTE)
VALUE_GETTER(byte, byte, FX_TYPE_BYTE)
VALUE_GETTER(short, short, FX_TYPE_SHORT)
VALUE_GETTER(unsigned short, ushort, FX_TYPE_USHORT)
VALUE_GETTER(int, int, FX_TYPE_INT)
VALUE_GETTER(unsigned int, uint, FX_TYPE_UINT)
VALUE_GETTER(long, long, FX_TYPE_LONG)
VALUE_GETTER(unsigned long, ulong, FX_TYPE_ULONG)
VALUE_GETTER(long long, longlong, FX_TYPE_LONGLONG)
VALUE_GETTER(unsigned long long, ulonglong, FX_TYPE_ULONGLONG)
VALUE_GETTER(size_t, size, FX_TYPE_SIZE)
VALUE_GETTER(float, float, FX_TYPE_FLOAT)
VALUE_GETTER(double, double, FX_TYPE_DOUBLE)
VALUE_GETTER(fx_wchar, wchar, FX_TYPE_WCHAR)
VALUE_GETTER(const fx_wchar *, wstr, FX_TYPE_WSTR)
VALUE_SETTER(bool, bool, FX_TYPE_BOOL)
VALUE_SETTER(i16, i16, FX_TYPE_I16)
VALUE_SETTER(u16, u16, FX_TYPE_U16)
VALUE_SETTER(i32, i32, FX_TYPE_I32)
VALUE_SETTER(u32, u32, FX_TYPE_U32)
VALUE_SETTER(i64, i64, FX_TYPE_I64)
VALUE_SETTER(u64, u64, FX_TYPE_U64)
VALUE_SETTER(iptr, iptr, FX_TYPE_IPTR)
VALUE_SETTER(uptr, uptr, FX_TYPE_UPTR)
VALUE_SETTER(sbyte, sbyte, FX_TYPE_SBYTE)
VALUE_SETTER(byte, byte, FX_TYPE_BYTE)
VALUE_SETTER(short, short, FX_TYPE_SHORT)
VALUE_SETTER(unsigned short, ushort, FX_TYPE_USHORT)
VALUE_SETTER(int, int, FX_TYPE_INT)
VALUE_SETTER(unsigned int, uint, FX_TYPE_UINT)
VALUE_SETTER(long, long, FX_TYPE_LONG)
VALUE_SETTER(unsigned long, ulong, FX_TYPE_ULONG)
VALUE_SETTER(long long, longlong, FX_TYPE_LONGLONG)
VALUE_SETTER(unsigned long long, ulonglong, FX_TYPE_ULONGLONG)
VALUE_SETTER(size_t, size, FX_TYPE_SIZE)
VALUE_SETTER(float, float, FX_TYPE_FLOAT)
VALUE_SETTER(double, double, FX_TYPE_DOUBLE)
VALUE_SETTER(fx_wchar, wchar, FX_TYPE_WCHAR)
fx_status fx_value_get_cstr(const fx_value *v, const char **out)
{
if (fx_type_id_compare(v->v_type, FX_TYPE_CSTR) == 0) {
*out = v->v_cstr;
return FX_SUCCESS;
}
if (fx_type_id_compare(v->v_type, FX_TYPE_STRING) == 0) {
*out = fx_string_get_cstr(v->v_object);
return FX_SUCCESS;
}
*out = NULL;
return FX_ERR_NOT_SUPPORTED;
}
fx_status fx_value_get_pointer(const fx_value *v, void **out)
{
if (fx_type_id_compare(v->v_type, FX_TYPE_POINTER) == 0) {
*out = v->v_pointer;
return FX_SUCCESS;
}
*out = NULL;
return FX_ERR_NOT_SUPPORTED;
}
fx_status fx_value_get_object(const fx_value *v, fx_object **out)
{
if (!v || !v->v_type) {
*out = NULL;
return FX_SUCCESS;
}
if (!fx_type_is_value_type(v->v_type)) {
return v->v_object;
*out = v->v_object;
return FX_SUCCESS;
}
*out = NULL;
return FX_ERR_NOT_SUPPORTED;
}
static bool is_integral_type(unsigned int type)
{
switch (type) {
case __FX_VALUE_TYPE_BOOL:
case __FX_VALUE_TYPE_I16:
case __FX_VALUE_TYPE_U16:
case __FX_VALUE_TYPE_I32:
case __FX_VALUE_TYPE_U32:
case __FX_VALUE_TYPE_I64:
case __FX_VALUE_TYPE_U64:
case __FX_VALUE_TYPE_IPTR:
case __FX_VALUE_TYPE_UPTR:
case __FX_VALUE_TYPE_SBYTE:
case __FX_VALUE_TYPE_BYTE:
case __FX_VALUE_TYPE_SHORT:
case __FX_VALUE_TYPE_USHORT:
case __FX_VALUE_TYPE_INT:
case __FX_VALUE_TYPE_UINT:
case __FX_VALUE_TYPE_LONG:
case __FX_VALUE_TYPE_ULONG:
case __FX_VALUE_TYPE_LONGLONG:
case __FX_VALUE_TYPE_ULONGLONG:
case __FX_VALUE_TYPE_SIZE:
return true;
default:
return false;
}
}
static bool is_signed_type(unsigned int type)
{
switch (type) {
case __FX_VALUE_TYPE_I16:
case __FX_VALUE_TYPE_I32:
case __FX_VALUE_TYPE_I64:
case __FX_VALUE_TYPE_IPTR:
case __FX_VALUE_TYPE_SBYTE:
case __FX_VALUE_TYPE_SHORT:
case __FX_VALUE_TYPE_INT:
case __FX_VALUE_TYPE_LONG:
case __FX_VALUE_TYPE_LONGLONG:
return true;
default:
return false;
}
}
static bool is_float_type(unsigned int type)
{
switch (type) {
case __FX_VALUE_TYPE_FLOAT:
case __FX_VALUE_TYPE_DOUBLE:
return true;
default:
return false;
}
}
static bool is_negative(unsigned int type, const fx_value *v)
{
switch (type) {
case __FX_VALUE_TYPE_I16:
return v->v_i16 < 0;
case __FX_VALUE_TYPE_I32:
return v->v_i32 < 0;
case __FX_VALUE_TYPE_I64:
return v->v_i64 < 0;
case __FX_VALUE_TYPE_IPTR:
return v->v_iptr < 0;
case __FX_VALUE_TYPE_SBYTE:
return v->v_sbyte < 0;
case __FX_VALUE_TYPE_SHORT:
return v->v_short < 0;
case __FX_VALUE_TYPE_INT:
return v->v_int < 0;
case __FX_VALUE_TYPE_LONG:
return v->v_long < 0;
case __FX_VALUE_TYPE_LONGLONG:
return v->v_longlong < 0;
default:
return false;
}
}
FX_API fx_type_id fx_value_get_common_type(const fx_value *a, const fx_value *b)
{
unsigned int a_type = __fx_type_get_value_type(a->v_type);
unsigned int b_type = __fx_type_get_value_type(b->v_type);
if (fx_type_id_compare(a->v_type, FX_TYPE_STRING) == 0
&& b_type == __FX_VALUE_TYPE_CSTR) {
return FX_TYPE_STRING;
}
if (fx_type_id_compare(b->v_type, FX_TYPE_STRING) == 0
&& a_type == __FX_VALUE_TYPE_CSTR) {
return FX_TYPE_STRING;
}
if (!fx_type_is_value_type(a->v_type)
|| !fx_type_is_value_type(b->v_type)) {
if (fx_type_id_compare(a->v_type, b->v_type) == 0) {
return a->v_type;
}
return NULL;
}
if (a_type == b_type) {
return a->v_type;
}
if (is_float_type(a_type) && is_float_type(b_type)) {
return a_type == b_type ? a->v_type : FX_TYPE_DOUBLE;
}
if (!is_integral_type(a_type) || !is_integral_type(b_type)) {
if (a_type == __FX_VALUE_TYPE_CSTR) {
return FX_TYPE_STRING;
}
return a->v_type;
}
size_t a_size = __fx_value_type_get_size(a_type);
size_t b_size = __fx_value_type_get_size(b_type);
bool a_signed = is_signed_type(a_type);
bool b_signed = is_signed_type(b_type);
if ((!a_signed && !b_signed) || (a_signed && b_signed)) {
return a_size > b_size ? a->v_type : b->v_type;
}
bool a_negative = is_negative(a_type, a);
bool b_negative = is_negative(b_type, b);
if ((!a_negative && !b_negative) || (a_negative && b_negative)) {
return a_size > b_size ? a->v_type : b->v_type;
}
/* TODO if value is too large for i64, return double instead */
return FX_TYPE_I64;
}
#define BINARY_OP(name) \
fx_status fx_value_##name( \
const fx_value *left, \
const fx_value *right, \
fx_value *out) \
{ \
if (fx_type_id_compare(left->v_type, right->v_type) != 0) { \
return FX_ERR_NOT_SUPPORTED; \
} \
\
void *c = fx_class_get(left->v_type); \
if (!c) { \
return FX_ERR_NOT_SUPPORTED; \
} \
\
fx_operable_class *operable = fx_class_get_interface( \
c, \
FX_TYPE_OPERABLE); \
if (!operable || !operable->op_##name) { \
return FX_ERR_NOT_SUPPORTED; \
} \
\
return operable->op_##name(left, right, out); \
}
#define PREFIX_OP(name) \
fx_status fx_value_##name(fx_value *value) \
{ \
void *c = fx_class_get(value->v_type); \
if (!c) { \
return FX_ERR_NOT_SUPPORTED; \
} \
\
fx_operable_class *operable = fx_class_get_interface( \
c, \
FX_TYPE_OPERABLE); \
if (!operable || !operable->op_##name) { \
return FX_ERR_NOT_SUPPORTED; \
} \
\
return operable->op_##name(value); \
}
#define IN_PLACE_OP(name) \
fx_status fx_value_##name(fx_value *left, const fx_value *right) \
{ \
if (fx_type_id_compare(left->v_type, right->v_type) != 0) { \
return FX_ERR_NOT_SUPPORTED; \
} \
\
void *c = fx_class_get(left->v_type); \
if (!c) { \
return FX_ERR_NOT_SUPPORTED; \
} \
\
fx_operable_class *operable = fx_class_get_interface( \
c, \
FX_TYPE_OPERABLE); \
if (!operable || !operable->op_##name) { \
return FX_ERR_NOT_SUPPORTED; \
} \
\
return operable->op_##name(left, right); \
}
BINARY_OP(add)
BINARY_OP(subtract)
BINARY_OP(multiply)
BINARY_OP(divide)
PREFIX_OP(increment)
PREFIX_OP(decrement)
IN_PLACE_OP(add_in_place)
IN_PLACE_OP(subtract_in_place)
IN_PLACE_OP(multiply_in_place)
IN_PLACE_OP(divide_in_place)