mirror of
https://github.com/janet-lang/janet
synced 2026-10-18 13:32:27 +00:00
Add bitwise key check to skip janet_equals calls (#1894)
* Add bitwise key check to skip janet_equals calls * Skip janet_equals for identity-comparing keys Since symbols, keywords, non-0 numbers, bools, tables, buffers, arrays, funcs and fibers are only equal by identity, we now fail them all if the bitwise check fails instead of passing them to `janet_equals`, so lookups only call `janet_equals` for strings, tuples, structs, abstract values and 0 * Skip traversal in janet_equals for non tuples and structs --------- Co-authored-by: Alex Alejandre <alex@alexalejandre.com>
This commit is contained in:
+2
-2
@@ -53,10 +53,10 @@ const JanetKV *janet_struct_find(const JanetKV *st, Janet key) {
|
||||
int32_t index = janet_maphash(cap, janet_hash(key));
|
||||
int32_t i;
|
||||
for (i = index; i < cap; i++)
|
||||
if (janet_checktype(st[i].key, JANET_NIL) || janet_equals(st[i].key, key))
|
||||
if (janet_checktype(st[i].key, JANET_NIL) || janet_key_equals(st[i].key, key))
|
||||
return st + i;
|
||||
for (i = 0; i < index; i++)
|
||||
if (janet_checktype(st[i].key, JANET_NIL) || janet_equals(st[i].key, key))
|
||||
if (janet_checktype(st[i].key, JANET_NIL) || janet_key_equals(st[i].key, key))
|
||||
return st + i;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+2
-2
@@ -302,7 +302,7 @@ const JanetKV *janet_dict_find(const JanetKV *buckets, int32_t cap, Janet key) {
|
||||
} else if (NULL == first_bucket) {
|
||||
first_bucket = kv;
|
||||
}
|
||||
} else if (janet_equals(kv->key, key)) {
|
||||
} else if (janet_key_equals(kv->key, key)) {
|
||||
return buckets + i;
|
||||
}
|
||||
}
|
||||
@@ -315,7 +315,7 @@ const JanetKV *janet_dict_find(const JanetKV *buckets, int32_t cap, Janet key) {
|
||||
} else if (NULL == first_bucket) {
|
||||
first_bucket = kv;
|
||||
}
|
||||
} else if (janet_equals(kv->key, key)) {
|
||||
} else if (janet_key_equals(kv->key, key)) {
|
||||
return buckets + i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,32 @@ uint32_t janet_hash_mix(uint32_t input, uint32_t more);
|
||||
|
||||
#define janet_maphash(cap, hash) ((uint32_t)(hash) & (cap - 1))
|
||||
|
||||
/* janet_bitwise_same is true when x and y are the same type and bits,
|
||||
* guarded for the nanboxed implementation */
|
||||
#if defined(JANET_NANBOX_64) || defined(JANET_NANBOX_32)
|
||||
#define janet_bitwise_same(x, y) (janet_u64(x) == janet_u64(y))
|
||||
#else
|
||||
#define janet_bitwise_same(x, y) ((x).type == (y).type && janet_u64(x) == janet_u64(y))
|
||||
#endif
|
||||
|
||||
/* Compare a stored key with a lookup key. Most types are equal only when bitwise identical, so
|
||||
* janet_equals only runs for zero (since 0.0 and -0.0 are equal), strings, tuples, structs and abstract
|
||||
* types. NaN is never stored as a key, so we skip it. */
|
||||
static inline int janet_key_equals(Janet stored, Janet key) {
|
||||
if (janet_bitwise_same(stored, key)) return 1;
|
||||
switch (janet_type(key)) {
|
||||
case JANET_NUMBER:
|
||||
return janet_unwrap_number(key) == 0 && janet_equals(stored, key);
|
||||
case JANET_STRING:
|
||||
case JANET_TUPLE:
|
||||
case JANET_STRUCT:
|
||||
case JANET_ABSTRACT:
|
||||
return janet_equals(stored, key);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int janet_valid_utf8(const uint8_t *str, int32_t len);
|
||||
|
||||
int janet_is_symbol_char(uint8_t c);
|
||||
|
||||
+22
-18
@@ -246,27 +246,27 @@ static int janet_compare_abstract(JanetAbstract xx, JanetAbstract yy) {
|
||||
return xt->compare(xx, yy);
|
||||
}
|
||||
|
||||
int janet_equals(Janet x, Janet y) {
|
||||
/* Compare two values of the same type that are not tuples or structs */
|
||||
static int janet_equals_leaf(Janet x, Janet y) {
|
||||
switch (janet_type(x)) {
|
||||
case JANET_NUMBER:
|
||||
return janet_unwrap_number(x) == janet_unwrap_number(y);
|
||||
case JANET_STRING:
|
||||
return janet_string_equal(janet_unwrap_string(x), janet_unwrap_string(y));
|
||||
case JANET_ABSTRACT:
|
||||
return !janet_compare_abstract(janet_unwrap_abstract(x), janet_unwrap_abstract(y));
|
||||
default:
|
||||
return janet_bitwise_same(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
static int janet_equals_containers(Janet x, Janet y) {
|
||||
janet_vm.traversal = janet_vm.traversal_base;
|
||||
do {
|
||||
if (janet_type(x) != janet_type(y)) return 0;
|
||||
switch (janet_type(x)) {
|
||||
case JANET_NIL:
|
||||
break;
|
||||
case JANET_BOOLEAN:
|
||||
if (janet_unwrap_boolean(x) != janet_unwrap_boolean(y)) return 0;
|
||||
break;
|
||||
case JANET_NUMBER:
|
||||
if (janet_unwrap_number(x) != janet_unwrap_number(y)) return 0;
|
||||
break;
|
||||
case JANET_STRING:
|
||||
if (!janet_string_equal(janet_unwrap_string(x), janet_unwrap_string(y))) return 0;
|
||||
break;
|
||||
case JANET_ABSTRACT:
|
||||
if (janet_compare_abstract(janet_unwrap_abstract(x), janet_unwrap_abstract(y))) return 0;
|
||||
break;
|
||||
default:
|
||||
if (janet_unwrap_pointer(x) != janet_unwrap_pointer(y)) return 0;
|
||||
if (!janet_equals_leaf(x, y)) return 0;
|
||||
break;
|
||||
case JANET_TUPLE: {
|
||||
const Janet *t1 = janet_unwrap_tuple(x);
|
||||
@@ -278,7 +278,6 @@ int janet_equals(Janet x, Janet y) {
|
||||
push_traversal_node(janet_tuple_head(t1), janet_tuple_head(t2), 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case JANET_STRUCT: {
|
||||
const JanetKV *s1 = janet_unwrap_struct(x);
|
||||
const JanetKV *s2 = janet_unwrap_struct(y);
|
||||
@@ -290,12 +289,17 @@ int janet_equals(Janet x, Janet y) {
|
||||
push_traversal_node(janet_struct_head(s1), janet_struct_head(s2), 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (!traversal_next(&x, &y));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int janet_equals(Janet x, Janet y) {
|
||||
if (janet_type(x) != janet_type(y)) return 0;
|
||||
if (janet_checktypes(x, JANET_TFLAG_TUPLE | JANET_TFLAG_STRUCT)) return janet_equals_containers(x, y);
|
||||
return janet_equals_leaf(x, y);
|
||||
}
|
||||
|
||||
static uint64_t murmur64(uint64_t h) {
|
||||
h ^= h >> 33;
|
||||
h *= 0xff51afd7ed558ccdUL;
|
||||
|
||||
Reference in New Issue
Block a user