Scripting: Move equality into type implementation

This commit is contained in:
Vicki Pfau 2021-08-29 20:57:54 -07:00
parent 16563fe4d2
commit 8818bf4048
3 changed files with 314 additions and 16 deletions

View File

@ -213,6 +213,7 @@ struct mScriptType {
void (*alloc)(struct mScriptValue*);
void (*free)(struct mScriptValue*);
uint32_t (*hash)(const struct mScriptValue*);
bool (*equal)(const struct mScriptValue*, const struct mScriptValue*);
};
struct mScriptValue {

View File

@ -171,6 +171,235 @@ M_TEST_DEFINE(coerceFromFloat) {
mScriptFrameDeinit(&frame);
}
M_TEST_DEFINE(s32Equality) {
struct mScriptValue s32A;
struct mScriptValue s32B;
struct mScriptValue u32;
struct mScriptValue f32;
s32A = mSCRIPT_MAKE_S32(0);
s32B = mSCRIPT_MAKE_S32(0);
assert_true(s32A.type->equal(&s32A, &s32B));
s32B = mSCRIPT_MAKE_S32(1);
assert_false(s32A.type->equal(&s32A, &s32B));
s32A = mSCRIPT_MAKE_S32(1);
assert_true(s32A.type->equal(&s32A, &s32B));
s32B = mSCRIPT_MAKE_S32(-1);
assert_false(s32A.type->equal(&s32A, &s32B));
s32A = mSCRIPT_MAKE_S32(-1);
assert_true(s32A.type->equal(&s32A, &s32B));
s32A = mSCRIPT_MAKE_S32(0);
u32 = mSCRIPT_MAKE_U32(0);
assert_true(s32A.type->equal(&s32A, &u32));
s32A = mSCRIPT_MAKE_S32(1);
u32 = mSCRIPT_MAKE_U32(1);
assert_true(s32A.type->equal(&s32A, &u32));
s32A = mSCRIPT_MAKE_S32(0);
u32 = mSCRIPT_MAKE_U32(1);
assert_false(s32A.type->equal(&s32A, &u32));
s32A = mSCRIPT_MAKE_S32(1);
u32 = mSCRIPT_MAKE_U32(0);
assert_false(s32A.type->equal(&s32A, &u32));
s32A = mSCRIPT_MAKE_S32(0x7FFFFFFF);
u32 = mSCRIPT_MAKE_U32(0x7FFFFFFF);
assert_true(s32A.type->equal(&s32A, &u32));
s32A = mSCRIPT_MAKE_S32(0xFFFFFFFF);
u32 = mSCRIPT_MAKE_U32(0xFFFFFFFF);
assert_false(s32A.type->equal(&s32A, &u32));
s32A = mSCRIPT_MAKE_S32(0x80000000);
u32 = mSCRIPT_MAKE_U32(0x80000000);
assert_false(s32A.type->equal(&s32A, &u32));
s32A = mSCRIPT_MAKE_S32(0);
f32 = mSCRIPT_MAKE_F32(0);
assert_true(s32A.type->equal(&s32A, &f32));
s32A = mSCRIPT_MAKE_S32(1);
f32 = mSCRIPT_MAKE_F32(1);
assert_true(s32A.type->equal(&s32A, &f32));
s32A = mSCRIPT_MAKE_S32(0);
f32 = mSCRIPT_MAKE_F32(1);
assert_false(s32A.type->equal(&s32A, &f32));
s32A = mSCRIPT_MAKE_S32(1);
f32 = mSCRIPT_MAKE_F32(0);
assert_false(s32A.type->equal(&s32A, &f32));
s32A = mSCRIPT_MAKE_S32(-1);
f32 = mSCRIPT_MAKE_F32(-1);
assert_true(s32A.type->equal(&s32A, &f32));
s32A = mSCRIPT_MAKE_S32(0);
f32 = mSCRIPT_MAKE_F32(-1);
assert_false(s32A.type->equal(&s32A, &f32));
s32A = mSCRIPT_MAKE_S32(-1);
f32 = mSCRIPT_MAKE_F32(0);
assert_false(s32A.type->equal(&s32A, &f32));
}
M_TEST_DEFINE(u32Equality) {
struct mScriptValue u32A;
struct mScriptValue u32B;
struct mScriptValue s32;
struct mScriptValue f32;
u32A = mSCRIPT_MAKE_U32(0);
u32B = mSCRIPT_MAKE_U32(0);
assert_true(u32A.type->equal(&u32A, &u32B));
u32B = mSCRIPT_MAKE_U32(1);
assert_false(u32A.type->equal(&u32A, &u32B));
u32A = mSCRIPT_MAKE_U32(1);
assert_true(u32A.type->equal(&u32A, &u32B));
u32B = mSCRIPT_MAKE_U32(0x80000000U);
assert_false(u32A.type->equal(&u32A, &u32B));
u32A = mSCRIPT_MAKE_U32(0x80000000U);
assert_true(u32A.type->equal(&u32A, &u32B));
u32A = mSCRIPT_MAKE_U32(0);
s32 = mSCRIPT_MAKE_S32(0);
assert_true(u32A.type->equal(&u32A, &s32));
u32A = mSCRIPT_MAKE_U32(1);
s32 = mSCRIPT_MAKE_S32(1);
assert_true(u32A.type->equal(&u32A, &s32));
u32A = mSCRIPT_MAKE_U32(0);
s32 = mSCRIPT_MAKE_S32(1);
assert_false(u32A.type->equal(&u32A, &s32));
u32A = mSCRIPT_MAKE_U32(1);
s32 = mSCRIPT_MAKE_S32(0);
assert_false(u32A.type->equal(&u32A, &s32));
u32A = mSCRIPT_MAKE_U32(0x7FFFFFFF);
s32 = mSCRIPT_MAKE_S32(0x7FFFFFFF);
assert_true(u32A.type->equal(&u32A, &s32));
u32A = mSCRIPT_MAKE_U32(0xFFFFFFFF);
s32 = mSCRIPT_MAKE_S32(0xFFFFFFFF);
assert_false(u32A.type->equal(&u32A, &s32));
u32A = mSCRIPT_MAKE_U32(0x80000000);
s32 = mSCRIPT_MAKE_S32(0x80000000);
assert_false(u32A.type->equal(&u32A, &s32));
u32A = mSCRIPT_MAKE_U32(0);
f32 = mSCRIPT_MAKE_F32(0);
assert_true(u32A.type->equal(&u32A, &f32));
u32A = mSCRIPT_MAKE_U32(1);
f32 = mSCRIPT_MAKE_F32(1);
assert_true(u32A.type->equal(&u32A, &f32));
u32A = mSCRIPT_MAKE_U32(0);
f32 = mSCRIPT_MAKE_F32(1);
assert_false(u32A.type->equal(&u32A, &f32));
u32A = mSCRIPT_MAKE_U32(1);
f32 = mSCRIPT_MAKE_F32(0);
assert_false(u32A.type->equal(&u32A, &f32));
u32A = mSCRIPT_MAKE_U32(0x80000000);
f32 = mSCRIPT_MAKE_F32(0x80000000);
assert_true(u32A.type->equal(&u32A, &f32));
u32A = mSCRIPT_MAKE_U32(0);
f32 = mSCRIPT_MAKE_F32(0x80000000);
assert_false(u32A.type->equal(&u32A, &f32));
u32A = mSCRIPT_MAKE_U32(0x80000000);
f32 = mSCRIPT_MAKE_F32(0);
assert_false(u32A.type->equal(&u32A, &f32));
}
M_TEST_DEFINE(f32Equality) {
struct mScriptValue f32A;
struct mScriptValue f32B;
struct mScriptValue s32;
struct mScriptValue u32;
f32A = mSCRIPT_MAKE_F32(0);
f32B = mSCRIPT_MAKE_F32(0);
assert_true(f32A.type->equal(&f32A, &f32B));
f32B = mSCRIPT_MAKE_F32(1);
assert_false(f32A.type->equal(&f32A, &f32B));
f32A = mSCRIPT_MAKE_F32(1);
assert_true(f32A.type->equal(&f32A, &f32B));
f32B = mSCRIPT_MAKE_F32(1.1);
assert_false(f32A.type->equal(&f32A, &f32B));
f32A = mSCRIPT_MAKE_F32(1.1);
assert_true(f32A.type->equal(&f32A, &f32B));
f32A = mSCRIPT_MAKE_F32(0);
s32 = mSCRIPT_MAKE_S32(0);
assert_true(f32A.type->equal(&f32A, &s32));
f32A = mSCRIPT_MAKE_F32(1);
s32 = mSCRIPT_MAKE_S32(1);
assert_true(f32A.type->equal(&f32A, &s32));
f32A = mSCRIPT_MAKE_F32(0);
s32 = mSCRIPT_MAKE_S32(1);
assert_false(f32A.type->equal(&f32A, &s32));
f32A = mSCRIPT_MAKE_F32(1);
s32 = mSCRIPT_MAKE_S32(0);
assert_false(f32A.type->equal(&f32A, &s32));
f32A = mSCRIPT_MAKE_F32(1.1);
s32 = mSCRIPT_MAKE_S32(1);
assert_false(f32A.type->equal(&f32A, &s32));
f32A = mSCRIPT_MAKE_F32(0x40000000);
s32 = mSCRIPT_MAKE_S32(0x40000000);
assert_true(f32A.type->equal(&f32A, &s32));
f32A = mSCRIPT_MAKE_F32(0);
u32 = mSCRIPT_MAKE_U32(0);
assert_true(f32A.type->equal(&f32A, &u32));
f32A = mSCRIPT_MAKE_F32(1);
u32 = mSCRIPT_MAKE_U32(1);
assert_true(f32A.type->equal(&f32A, &u32));
f32A = mSCRIPT_MAKE_F32(0);
u32 = mSCRIPT_MAKE_U32(1);
assert_false(f32A.type->equal(&f32A, &u32));
f32A = mSCRIPT_MAKE_F32(1);
u32 = mSCRIPT_MAKE_U32(0);
assert_false(f32A.type->equal(&f32A, &u32));
f32A = mSCRIPT_MAKE_F32(1.1);
u32 = mSCRIPT_MAKE_U32(1);
assert_false(f32A.type->equal(&f32A, &u32));
f32A = mSCRIPT_MAKE_F32(0x40000000);
u32 = mSCRIPT_MAKE_U32(0x40000000);
assert_true(f32A.type->equal(&f32A, &u32));
}
M_TEST_DEFINE(hashTableBasic) {
struct mScriptValue* table = mScriptValueAlloc(mSCRIPT_TYPE_MS_TABLE);
assert_non_null(table);
@ -213,4 +442,7 @@ M_TEST_SUITE_DEFINE(mScript,
cmocka_unit_test(wrongArgType),
cmocka_unit_test(coerceToFloat),
cmocka_unit_test(coerceFromFloat),
cmocka_unit_test(s32Equality),
cmocka_unit_test(u32Equality),
cmocka_unit_test(f32Equality),
cmocka_unit_test(hashTableBasic))

View File

@ -18,6 +18,11 @@ static bool _valEqual(const void* a, const void* b);
static void* _valRef(void*);
static void _valDeref(void*);
static bool _typeEqual(const struct mScriptValue*, const struct mScriptValue*);
static bool _s32Equal(const struct mScriptValue*, const struct mScriptValue*);
static bool _u32Equal(const struct mScriptValue*, const struct mScriptValue*);
static bool _f32Equal(const struct mScriptValue*, const struct mScriptValue*);
const struct mScriptType mSTVoid = {
.base = mSCRIPT_TYPE_VOID,
.size = 0,
@ -25,6 +30,7 @@ const struct mScriptType mSTVoid = {
.alloc = NULL,
.free = NULL,
.hash = NULL,
.equal = _typeEqual,
};
const struct mScriptType mSTSInt32 = {
@ -34,6 +40,7 @@ const struct mScriptType mSTSInt32 = {
.alloc = NULL,
.free = NULL,
.hash = _hashScalar,
.equal = _s32Equal,
};
const struct mScriptType mSTUInt32 = {
@ -43,6 +50,7 @@ const struct mScriptType mSTUInt32 = {
.alloc = NULL,
.free = NULL,
.hash = _hashScalar,
.equal = _u32Equal,
};
const struct mScriptType mSTFloat32 = {
@ -52,6 +60,7 @@ const struct mScriptType mSTFloat32 = {
.alloc = NULL,
.free = NULL,
.hash = NULL,
.equal = _f32Equal,
};
const struct mScriptType mSTTable = {
@ -113,22 +122,7 @@ uint32_t _valHash(const void* val, size_t len, uint32_t seed) {
bool _valEqual(const void* a, const void* b) {
const struct mScriptValue* valueA = a;
const struct mScriptValue* valueB = b;
// TODO: Move equality into type
if (valueA->type != valueB->type) {
return false;
}
switch (valueA->type->base) {
case mSCRIPT_TYPE_VOID:
return true;
case mSCRIPT_TYPE_SINT:
return valueA->value.s32 == valueB->value.s32;
case mSCRIPT_TYPE_UINT:
return valueA->value.u32 == valueB->value.u32;
case mSCRIPT_TYPE_FLOAT:
return valueA->value.f32 == valueB->value.f32;
default:
return valueA->value.opaque == valueB->value.opaque;
}
return valueA->type->equal(valueA, valueB);
}
void* _valRef(void* val) {
@ -140,6 +134,77 @@ void _valDeref(void* val) {
mScriptValueDeref(val);
}
bool _typeEqual(const struct mScriptValue* a, const struct mScriptValue* b) {
return a->type == b->type;
}
bool _s32Equal(const struct mScriptValue* a, const struct mScriptValue* b) {
int32_t val;
switch (b->type->base) {
case mSCRIPT_TYPE_SINT:
val = b->value.s32;
break;
case mSCRIPT_TYPE_UINT:
if (b->value.u32 > (uint32_t) INT_MAX) {
return false;
}
if (a->value.s32 < 0) {
return false;
}
val = b->value.u32;
break;
case mSCRIPT_TYPE_VOID:
return false;
default:
return b->type->equal && b->type->equal(b, a);
}
return a->value.s32 == val;
}
bool _u32Equal(const struct mScriptValue* a, const struct mScriptValue* b) {
uint32_t val;
switch (b->type->base) {
case mSCRIPT_TYPE_SINT:
if (b->value.s32 < 0) {
return false;
}
if (a->value.u32 > (uint32_t) INT_MAX) {
return false;
}
val = b->value.s32;
break;
case mSCRIPT_TYPE_UINT:
val = b->value.u32;
break;
case mSCRIPT_TYPE_VOID:
return false;
default:
return b->type->equal && b->type->equal(b, a);
}
return a->value.u32 == val;
}
bool _f32Equal(const struct mScriptValue* a, const struct mScriptValue* b) {
float val;
switch (b->type->base) {
case mSCRIPT_TYPE_SINT:
val = b->value.s32;
break;
case mSCRIPT_TYPE_UINT:
val = b->value.u32;
break;
case mSCRIPT_TYPE_FLOAT:
val = b->value.f32;
break;
case mSCRIPT_TYPE_VOID:
return false;
default:
return b->type->equal && b->type->equal(b, a);
}
return a->value.f32 == val;
}
struct mScriptValue* mScriptValueAlloc(const struct mScriptType* type) {
// TODO: Use an arena instead of just the generic heap
struct mScriptValue* val = malloc(sizeof(*val));