diff --git a/fx/include/fx/value-type.h b/fx/include/fx/value-type.h index 17895d2..93e3be6 100644 --- a/fx/include/fx/value-type.h +++ b/fx/include/fx/value-type.h @@ -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 diff --git a/fx/include/fx/value.h b/fx/include/fx/value.h index 210617e..cb19216 100644 --- a/fx/include/fx/value.h +++ b/fx/include/fx/value.h @@ -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 diff --git a/fx/value-type.c b/fx/value-type.c index 54940f6..e346988 100644 --- a/fx/value-type.c +++ b/fx/value-type.c @@ -1,7 +1,12 @@ +#include #include 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) diff --git a/fx/value.c b/fx/value.c index c76859b..378ff0f 100644 --- a/fx/value.c +++ b/fx/value.c @@ -1,24 +1,47 @@ #include +#include +#include #include #include +#include +#include #include #include #include +#include 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) { + 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); } -void fx_value_set_double(fx_value *v, double d) +bool fx_value_is_set(const fx_value *v) { + return v->v_type != NULL; } -void fx_value_set_static_cstr(fx_value *v, const char *cstr) +bool fx_value_is_type(const fx_value *v, fx_type_id type) { -} - -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) { + 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_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); - } - } - - return 0; -} - -uintptr_t fx_value_get_uint(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; -} - -double fx_value_get_double(const fx_value *v) -{ - if (v->v_type.t_primitive == FX_VALUE_TYPE_DOUBLE) { - 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_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 (!fx_type_is_value_type(v->v_type)) { - return v->v_object; + if (!in->v_type) { + return FX_SUCCESS; } - return NULL; + 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)) { + *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)