aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/hashtab.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/hashtab.c')
-rw-r--r--src/nvim/hashtab.c33
1 files changed, 22 insertions, 11 deletions
diff --git a/src/nvim/hashtab.c b/src/nvim/hashtab.c
index 1ebac603c2..851e70caca 100644
--- a/src/nvim/hashtab.c
+++ b/src/nvim/hashtab.c
@@ -30,6 +30,7 @@
#include "nvim/hashtab.h"
#include "nvim/memory.h"
#include "nvim/message.h"
+#include "nvim/types.h"
#include "nvim/vim.h"
// Magic value for algorithm that walks through the array.
@@ -87,7 +88,7 @@ void hash_clear_all(hashtab_T *ht, unsigned int off)
/// is changed in any way.
hashitem_T *hash_find(const hashtab_T *const ht, const char *const key)
{
- return hash_lookup(ht, key, strlen(key), hash_hash((char_u *)key));
+ return hash_lookup(ht, key, strlen(key), hash_hash(key));
}
/// Like hash_find, but key is not NUL-terminated
@@ -140,7 +141,7 @@ hashitem_T *hash_lookup(const hashtab_T *const ht, const char *const key, const
if (hi->hi_key == HI_KEY_REMOVED) {
freeitem = hi;
} else if ((hi->hi_hash == hash)
- && (STRNCMP(hi->hi_key, key, key_len) == 0)
+ && (strncmp(hi->hi_key, key, key_len) == 0)
&& hi->hi_key[key_len] == NUL) {
return hi;
}
@@ -166,7 +167,7 @@ hashitem_T *hash_lookup(const hashtab_T *const ht, const char *const key, const
if ((hi->hi_hash == hash)
&& (hi->hi_key != HI_KEY_REMOVED)
- && (STRNCMP(hi->hi_key, key, key_len) == 0)
+ && (strncmp(hi->hi_key, key, key_len) == 0)
&& hi->hi_key[key_len] == NUL) {
return hi;
}
@@ -201,10 +202,10 @@ void hash_debug_results(void)
///
/// @return OK if success.
/// FAIL if key already present
-int hash_add(hashtab_T *ht, char_u *key)
+int hash_add(hashtab_T *ht, char *key)
{
hash_T hash = hash_hash(key);
- hashitem_T *hi = hash_lookup(ht, (const char *)key, STRLEN(key), hash);
+ hashitem_T *hi = hash_lookup(ht, key, strlen(key), hash);
if (!HASHITEM_EMPTY(hi)) {
internal_error("hash_add()");
return FAIL;
@@ -220,9 +221,10 @@ int hash_add(hashtab_T *ht, char_u *key)
/// @param key Pointer to the key for the new item. The key has to be contained
/// in the new item (@see hashitem_T). Must not be NULL.
/// @param hash The precomputed hash value for the key.
-void hash_add_item(hashtab_T *ht, hashitem_T *hi, char_u *key, hash_T hash)
+void hash_add_item(hashtab_T *ht, hashitem_T *hi, char *key, hash_T hash)
{
ht->ht_used++;
+ ht->ht_changed++;
if (hi->hi_key == NULL) {
ht->ht_filled++;
}
@@ -242,6 +244,7 @@ void hash_add_item(hashtab_T *ht, hashitem_T *hi, char_u *key, hash_T hash)
void hash_remove(hashtab_T *ht, hashitem_T *hi)
{
ht->ht_used--;
+ ht->ht_changed++;
hi->hi_key = HI_KEY_REMOVED;
hash_may_resize(ht, 0);
}
@@ -290,6 +293,7 @@ static void hash_may_resize(hashtab_T *ht, size_t minitems)
#endif // ifdef HT_DEBUG
size_t minsize;
+ const size_t oldsize = ht->ht_mask + 1;
if (minitems == 0) {
// Return quickly for small tables with at least two NULL items.
// items are required for the lookup to decide a key isn't there.
@@ -302,7 +306,6 @@ static void hash_may_resize(hashtab_T *ht, size_t minitems)
// removed items, so that they get cleaned up).
// Shrink the array when it's less than 1/5 full. When growing it is
// at least 1/4 full (avoids repeated grow-shrink operations)
- size_t oldsize = ht->ht_mask + 1;
if ((ht->ht_filled * 3 < oldsize * 2) && (ht->ht_used > oldsize / 5)) {
return;
}
@@ -333,6 +336,13 @@ static void hash_may_resize(hashtab_T *ht, size_t minitems)
}
bool newarray_is_small = newsize == HT_INIT_SIZE;
+
+ if (!newarray_is_small && newsize == oldsize && ht->ht_filled * 3 < oldsize * 2) {
+ // The hashtab is already at the desired size, and there are not too
+ // many removed items, bail out.
+ return;
+ }
+
bool keep_smallarray = newarray_is_small
&& ht->ht_array == ht->ht_smallarray;
@@ -384,6 +394,7 @@ static void hash_may_resize(hashtab_T *ht, size_t minitems)
ht->ht_array = newarray;
ht->ht_mask = newmask;
ht->ht_filled = ht->ht_used;
+ ht->ht_changed++;
}
#define HASH_CYCLE_BODY(hash, p) \
@@ -395,9 +406,9 @@ static void hash_may_resize(hashtab_T *ht, size_t minitems)
/// run a script that uses hashtables a lot. Vim will then print statistics
/// when exiting. Try that with the current hash algorithm and yours. The
/// lower the percentage the better.
-hash_T hash_hash(const char_u *key)
+hash_T hash_hash(const char *key)
{
- hash_T hash = *key;
+ hash_T hash = (uint8_t)(*key);
if (hash == 0) {
return (hash_T)0;
@@ -405,7 +416,7 @@ hash_T hash_hash(const char_u *key)
// A simplistic algorithm that appears to do very well.
// Suggested by George Reilly.
- const uint8_t *p = key + 1;
+ const uint8_t *p = (uint8_t *)key + 1;
while (*p != NUL) {
HASH_CYCLE_BODY(hash, p);
}
@@ -449,5 +460,5 @@ hash_T hash_hash_len(const char *key, const size_t len)
const char_u *_hash_key_removed(void)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- return HI_KEY_REMOVED;
+ return (char_u *)HI_KEY_REMOVED;
}