mirror of
https://github.com/janet-lang/janet
synced 2026-10-14 03:31:40 +00:00
Decide once per lookup if janet_equals needed (#1903)
As key types can't change during lookup, we only need to check them once. The check is now inlined in util.h, so structs and tables can use the same implementation. (Structs had a simpler copy of the table implementation before, now they just ignore the table specific parts as they lack deleted buckets) Co-authored-by: Alex Alejandre <alex@alexalejandre.com>
This commit is contained in:
+3
-13
@@ -46,19 +46,9 @@ JanetKV *janet_struct_begin(int32_t count) {
|
||||
return st;
|
||||
}
|
||||
|
||||
/* Find an item in a struct without looking for prototypes. Should be similar to janet_dict_find, but
|
||||
* specialized to structs (slightly more compact). */
|
||||
const JanetKV *janet_struct_find(const JanetKV *st, Janet key) {
|
||||
int32_t cap = janet_struct_capacity(st);
|
||||
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_key_equals(st[i].key, key))
|
||||
return st + i;
|
||||
for (i = 0; i < index; i++)
|
||||
if (janet_checktype(st[i].key, JANET_NIL) || janet_key_equals(st[i].key, key))
|
||||
return st + i;
|
||||
return NULL;
|
||||
/* Find an item in a struct without looking for prototypes. */
|
||||
const JanetKV *janet_struct_find(const JanetKV *st, Janet key) {
|
||||
return janet_dict_find(st, janet_struct_capacity(st), key);
|
||||
}
|
||||
|
||||
/* Put a kv pair into a struct that has not yet been fully constructed.
|
||||
|
||||
+2
-2
@@ -216,8 +216,8 @@ void janet_table_put(JanetTable *t, Janet key, Janet value) {
|
||||
} else {
|
||||
if (NULL == bucket || 2 * (t->count + t->deleted + 1) > t->capacity) {
|
||||
janet_table_rehash(t, janet_tablen(2 * t->count + 2));
|
||||
bucket = janet_table_find(t, key);
|
||||
}
|
||||
bucket = janet_table_find(t, key);
|
||||
if (janet_checktype(bucket->value, JANET_BOOLEAN))
|
||||
--t->deleted;
|
||||
bucket->key = key;
|
||||
@@ -235,8 +235,8 @@ static void janet_table_put_no_overwrite(JanetTable *t, Janet key, Janet value)
|
||||
return;
|
||||
if (NULL == bucket || 2 * (t->count + t->deleted + 1) > t->capacity) {
|
||||
janet_table_rehash(t, janet_tablen(2 * t->count + 2));
|
||||
bucket = janet_table_find(t, key);
|
||||
}
|
||||
bucket = janet_table_find(t, key);
|
||||
if (janet_checktype(bucket->value, JANET_BOOLEAN))
|
||||
--t->deleted;
|
||||
bucket->key = key;
|
||||
|
||||
+5
-5
@@ -287,9 +287,9 @@ void safe_memcpy(void *dest, const void *src, size_t len) {
|
||||
memcpy(dest, src, len);
|
||||
}
|
||||
|
||||
/* Helper to find a value in a Janet struct or table. Returns the bucket
|
||||
* containing the key, or the first empty bucket if there is no such key. */
|
||||
const JanetKV *janet_dict_find(const JanetKV *buckets, int32_t cap, Janet key) {
|
||||
/* Helper to find a value in a Janet struct or table like janet_dict_find, for keys
|
||||
* equaling stored key that is not bitwise identical to it. */
|
||||
const JanetKV *janet_dict_find_deep(const JanetKV *buckets, int32_t cap, Janet key) {
|
||||
int32_t index = janet_maphash(cap, janet_hash(key));
|
||||
int32_t i;
|
||||
const JanetKV *first_bucket = NULL;
|
||||
@@ -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_key_equals(kv->key, key)) {
|
||||
} else if (janet_bitwise_same(kv->key, key) || janet_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_key_equals(kv->key, key)) {
|
||||
} else if (janet_bitwise_same(kv->key, key) || janet_equals(kv->key, key)) {
|
||||
return buckets + i;
|
||||
}
|
||||
}
|
||||
|
||||
+32
-19
@@ -77,24 +77,6 @@ uint32_t janet_hash_mix(uint32_t input, uint32_t more);
|
||||
#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);
|
||||
@@ -113,7 +95,38 @@ void safe_memcpy(void *dest, const void *src, size_t len);
|
||||
|
||||
void janet_buffer_push_types(JanetBuffer *buffer, int types);
|
||||
|
||||
const JanetKV *janet_dict_find(const JanetKV *buckets, int32_t cap, Janet key);
|
||||
const JanetKV *janet_dict_find_deep(const JanetKV *buckets, int32_t cap, Janet key);
|
||||
|
||||
/* Helper to find a value in a Janet struct or table. Returns the bucket
|
||||
* containing the key, or the first empty bucket if there is no such key.
|
||||
* Most types are equal only when bitwise identical, so we can probe them
|
||||
* without calling janet_equals. Zero (since 0.0 and -0.0 are equal), strings,
|
||||
* tuples, structs and abstract types go to janet_dict_find_deep, nil too
|
||||
* as it's bitwise identical to an empty bucket's key. NaN is never
|
||||
* stored as a key. */
|
||||
static inline const JanetKV *janet_dict_find(const JanetKV *buckets, int32_t cap, Janet key) {
|
||||
int32_t hash;
|
||||
if (janet_checktype(key, JANET_KEYWORD) || janet_checktype(key, JANET_SYMBOL)) {
|
||||
hash = janet_string_hash(janet_unwrap_string(key));
|
||||
} else if (janet_checktypes(key, JANET_TFLAG_NIL | JANET_TFLAG_STRING | JANET_TFLAG_TUPLE | JANET_TFLAG_STRUCT | JANET_TFLAG_ABSTRACT) ||
|
||||
(janet_checktype(key, JANET_NUMBER) && janet_unwrap_number(key) == 0)) {
|
||||
return janet_dict_find_deep(buckets, cap, key);
|
||||
} else {
|
||||
hash = janet_hash(key);
|
||||
}
|
||||
uint32_t mask = (uint32_t) cap - 1;
|
||||
uint32_t i = (uint32_t) hash & mask;
|
||||
const JanetKV *first_bucket = NULL;
|
||||
for (int32_t n = 0; n < cap; n++, i = (i + 1) & mask) {
|
||||
const JanetKV *kv = buckets + i;
|
||||
if (janet_bitwise_same(kv->key, key)) return kv;
|
||||
if (janet_checktype(kv->key, JANET_NIL)) {
|
||||
if (janet_checktype(kv->value, JANET_NIL)) return kv;
|
||||
if (NULL == first_bucket) first_bucket = kv;
|
||||
}
|
||||
}
|
||||
return first_bucket;
|
||||
}
|
||||
|
||||
void janet_memempty(JanetKV *mem, int32_t count);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user