mirror of
https://github.com/CPunch/Cosmo.git
synced 2025-11-06 23:50:19 +00:00
added support for NaN boxing (8 byte CValues!)
This commit is contained in:
98
src/cvalue.h
98
src/cvalue.h
@@ -4,10 +4,10 @@
|
||||
#include "cosmo.h"
|
||||
|
||||
typedef enum {
|
||||
COSMO_TNIL,
|
||||
COSMO_TNUMBER, // number has to be 0 because NaN box
|
||||
COSMO_TBOOLEAN,
|
||||
COSMO_TNUMBER,
|
||||
COSMO_TOBJ
|
||||
COSMO_TOBJ,
|
||||
COSMO_TNIL,
|
||||
} CosmoType;
|
||||
|
||||
typedef double cosmo_Number;
|
||||
@@ -15,6 +15,57 @@ typedef double cosmo_Number;
|
||||
/*
|
||||
holds primitive cosmo types
|
||||
*/
|
||||
|
||||
#ifdef NAN_BOXXED
|
||||
/*
|
||||
NaN box, this is great for performance on x86_64 or ARM64 architectures. If you don't know how this works please reference these
|
||||
two articles:
|
||||
|
||||
https://leonardschuetz.ch/blog/nan-boxing/ and https://piotrduperas.com/posts/nan-boxing/
|
||||
|
||||
both are great resources :)
|
||||
|
||||
TL;DR: we can store payloads in the NaN value in the IEEE 754 standard.
|
||||
*/
|
||||
typedef union CValue {
|
||||
uint64_t data;
|
||||
cosmo_Number num;
|
||||
} CValue;
|
||||
|
||||
#define MASK_SIGN_BIT ((uint64_t)1 << 63)
|
||||
#define MASK_TYPE ((uint64_t)0xf)
|
||||
#define MASK_PAYLOAD ((uint64_t)0xfffffffffff0)
|
||||
|
||||
#define MAKE_PAYLOAD(x) ((uint64_t)(x) << 4)
|
||||
|
||||
// The bits that must be set to indicate a quiet NaN.
|
||||
#define MASK_QUIETNAN ((uint64_t)0x7ffc000000000000)
|
||||
|
||||
// sadly this requires a bit more than a simple macro :(
|
||||
static inline CosmoType GET_TYPE(CValue val) {
|
||||
// it's not not a number (its a number)
|
||||
if ((((val.data) & MASK_QUIETNAN) != MASK_QUIETNAN))
|
||||
return COSMO_TNUMBER;
|
||||
|
||||
if ((((val.data) & (MASK_QUIETNAN | MASK_SIGN_BIT)) == (MASK_QUIETNAN | MASK_SIGN_BIT)))
|
||||
return COSMO_TOBJ;
|
||||
|
||||
return (val.data & MASK_TYPE);
|
||||
}
|
||||
|
||||
#define cosmoV_newNumber(x) ((CValue){.num = x})
|
||||
#define cosmoV_newObj(x) ((CValue){.data = MASK_SIGN_BIT | MASK_QUIETNAN | (uint64_t)(uintptr_t)(x)})
|
||||
#define cosmoV_newBoolean(x) ((CValue){.data = MASK_QUIETNAN | MAKE_PAYLOAD(x) | COSMO_TBOOLEAN})
|
||||
#define cosmoV_newNil() ((CValue){.data = MASK_QUIETNAN | COSMO_TNIL})
|
||||
|
||||
#define cosmoV_readNumber(x) ((x).num)
|
||||
#define cosmoV_readBoolean(x) ((bool)((x).data & MASK_PAYLOAD))
|
||||
#define cosmoV_readObj(x) (((CObj*)(uintptr_t)(((x).data) & ~(MASK_SIGN_BIT | MASK_QUIETNAN))))
|
||||
|
||||
#else
|
||||
/*
|
||||
Tagged union, this is the best platform independent solution
|
||||
*/
|
||||
typedef struct CValue {
|
||||
CosmoType type;
|
||||
union {
|
||||
@@ -23,6 +74,29 @@ typedef struct CValue {
|
||||
CObj *obj;
|
||||
} val;
|
||||
} CValue;
|
||||
|
||||
#define GET_TYPE(x) ((x).type)
|
||||
|
||||
// create CValues
|
||||
|
||||
#define cosmoV_newNumber(x) ((CValue){COSMO_TNUMBER, {.num = (x)}})
|
||||
#define cosmoV_newBoolean(x) ((CValue){COSMO_TBOOLEAN, {.b = (x)}})
|
||||
#define cosmoV_newObj(x) ((CValue){COSMO_TOBJ, {.obj = (CObj*)(x)}})
|
||||
#define cosmoV_newNil() ((CValue){COSMO_TNIL, {.num = 0}})
|
||||
|
||||
// read CValues
|
||||
|
||||
#define cosmoV_readNumber(x) ((cosmo_Number)(x).val.num)
|
||||
#define cosmoV_readBoolean(x) ((bool)(x).val.b)
|
||||
#define cosmoV_readObj(x) ((CObj*)(x).val.obj)
|
||||
|
||||
#endif
|
||||
|
||||
#define IS_NUMBER(x) (GET_TYPE(x) == COSMO_TNUMBER)
|
||||
#define IS_BOOLEAN(x) (GET_TYPE(x) == COSMO_TBOOLEAN)
|
||||
#define IS_NIL(x) (GET_TYPE(x) == COSMO_TNIL)
|
||||
#define IS_OBJ(x) (GET_TYPE(x) == COSMO_TOBJ)
|
||||
|
||||
typedef CValue* StkPtr;
|
||||
|
||||
typedef struct CValueArray {
|
||||
@@ -40,22 +114,4 @@ COSMO_API bool cosmoV_equal(CValue valA, CValue valB);
|
||||
COSMO_API CObjString *cosmoV_toString(CState *state, CValue val);
|
||||
COSMO_API const char *cosmoV_typeStr(CValue val); // return constant char array for corresponding type
|
||||
|
||||
#define IS_NUMBER(x) (x.type == COSMO_TNUMBER)
|
||||
#define IS_BOOLEAN(x) (x.type == COSMO_TBOOLEAN)
|
||||
#define IS_NIL(x) (x.type == COSMO_TNIL)
|
||||
#define IS_OBJ(x) (x.type == COSMO_TOBJ)
|
||||
|
||||
// create CValues
|
||||
|
||||
#define cosmoV_newNumber(x) ((CValue){COSMO_TNUMBER, {.num = x}})
|
||||
#define cosmoV_newBoolean(x) ((CValue){COSMO_TBOOLEAN, {.b = x}})
|
||||
#define cosmoV_newObj(x) ((CValue){COSMO_TOBJ, {.obj = (CObj*)x}})
|
||||
#define cosmoV_newNil() ((CValue){COSMO_TNIL, {.num = 0}})
|
||||
|
||||
// read CValues
|
||||
|
||||
#define cosmoV_readNumber(x) ((cosmo_Number)x.val.num)
|
||||
#define cosmoV_readBoolean(x) ((bool)x.val.b)
|
||||
#define cosmoV_readObj(x) ((CObj*)x.val.obj)
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user