impotent/value.h
2025-08-31 16:22:38 +03:00

127 lines
2.6 KiB
C

#pragma once
#include<stdbool.h>
#include<stdint.h>
#include<stddef.h>
#include<ctype.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<assert.h>
#include"str.h"
#define LTAG_MASK 0xFFFF000000000000ULL
#define LTAG_NAN 0xFFF8000000000001ULL
#define LTAG_NIL 0xFFF8000000000002ULL
#define LTAG_FALSE 0xFFF8000000000003ULL
#define LTAG_TRUE 0xFFF8000000000004ULL
#define LTAG_I32 0xFFF9000000000000ULL
#define LTAG_TABLE 0xFFFA000000000000ULL
#define LTAG_USERDATA 0xFFFB000000000000ULL
#define LTAG_FUNCTION 0xFFFC000000000000ULL
#define LTAG_FLOAT 0xFFFD000000000000ULL
#define LTAG_STRING 0xFFFE000000000000ULL
typedef enum {
LT_NIL,
LT_STRING,
LT_NUMBER,
LT_INTEGER,
LT_TABLE,
LT_USERDATA,
LT_BOOLEAN,
LT_FUNCTION,
} LType;
typedef union {
double f;
uint64_t u;
} LValue;
static inline uint64_t lhash64(uint64_t val) {
val ^= (val >> 33);
val *= 0xff51afd7ed558ccdUL;
val ^= (val >> 33);
val *= 0xc4ceb9fe1a85ec53UL;
val ^= (val >> 33);
return val;
}
static inline LValue lvalue_from_double(double f) {
LValue v;
if(isnan(f)) {
// Normalize
v.u = LTAG_NAN;
} else {
v.f = f;
}
return (LValue) {.f = f};
}
static inline LValue lvalue_from_int32(int32_t i) {
return (LValue) {.u = LTAG_I32 | (uint32_t) i};
}
static inline LValue lvalue_from_bool(bool b) {
return (LValue) {.u = b ? LTAG_TRUE : LTAG_FALSE};
}
static inline LValue lvalue_from_nil() {
return (LValue) {.u = LTAG_NIL};
}
struct LTable;
static inline LValue lvalue_from_table(struct LTable *tbl) {
return (LValue) {.u = LTAG_TABLE | (uintptr_t) tbl};
}
struct LString;
static inline LValue lvalue_from_string(struct LString *str) {
return (LValue) {.u = LTAG_STRING | (uintptr_t) str};
}
struct LFunc;
static inline LValue lvalue_from_func(struct LFunc *f) {
return (LValue) {.u = LTAG_FUNCTION | (uintptr_t) f};
}
static inline int32_t lvalue_to_int32(LValue v) {
return v.u & ~LTAG_MASK;
}
static inline uint64_t lvalue_tag(LValue v) {
return v.u & LTAG_MASK;
}
static inline LValue lvalue_raw(uint64_t tag, uint64_t rawval) {
assert(rawval == (rawval & ~LTAG_MASK));
return (LValue) {.u = tag | rawval};
}
static inline uint64_t lvalue_hash(LValue lv) {
if(lvalue_tag(lv) == LTAG_STRING) {
LString *str = (LString*) (lv.u & ~LTAG_MASK);
uint64_t h = 0;
for(size_t i = 0; i < (str->length & ~7); i += 8) {
h = lhash64(h ^ *(uint64_t*) &str->data[i]);
}
uint64_t last = 0;
memcpy(&last, str->data + (str->length & ~7), str->length - (str->length & ~7));
h = lhash64(h ^ last);
return h;
}
return lhash64(lv.u);
}
bool lvalue_eq(LValue, LValue);