mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Remove long_u: hashtab: Cleanup: Others.
hashtab.h: - Add missing includes. - Move hash_T to the top and use it to define hashtab_T. - Move hash_removed related definitions to the top, as they are used in the definition of hashtab_T. - Reformat multiline expression (start continuation with operator). - Reformat function declaration into one single line. hashtab.c: - Use C99 style variable declarations (move declarations as near to first-usage point as possible). - Simplify oldarray/newarray computation. - Simplify unneeded else branch. - Remove redundant casts.
This commit is contained in:
parent
98255c7a78
commit
4d97ae66f9
@ -18,6 +18,7 @@
|
|||||||
/// of the entries is empty to keep the lookup efficient (at the cost of extra
|
/// of the entries is empty to keep the lookup efficient (at the cost of extra
|
||||||
/// memory).
|
/// memory).
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "nvim/vim.h"
|
#include "nvim/vim.h"
|
||||||
@ -56,12 +57,8 @@ void hash_clear(hashtab_T *ht)
|
|||||||
/// @param off the offset from start of value to start of key (@see hashitem_T).
|
/// @param off the offset from start of value to start of key (@see hashitem_T).
|
||||||
void hash_clear_all(hashtab_T *ht, int off)
|
void hash_clear_all(hashtab_T *ht, int off)
|
||||||
{
|
{
|
||||||
long todo;
|
long todo = (long)ht->ht_used;
|
||||||
hashitem_T *hi;
|
for (hashitem_T *hi = ht->ht_array; todo > 0; ++hi) {
|
||||||
|
|
||||||
todo = (long)ht->ht_used;
|
|
||||||
|
|
||||||
for (hi = ht->ht_array; todo > 0; ++hi) {
|
|
||||||
if (!HASHITEM_EMPTY(hi)) {
|
if (!HASHITEM_EMPTY(hi)) {
|
||||||
free(hi->hi_key - off);
|
free(hi->hi_key - off);
|
||||||
todo--;
|
todo--;
|
||||||
@ -96,11 +93,6 @@ hashitem_T* hash_find(hashtab_T *ht, char_u *key)
|
|||||||
/// is changed in any way.
|
/// is changed in any way.
|
||||||
hashitem_T* hash_lookup(hashtab_T *ht, char_u *key, hash_T hash)
|
hashitem_T* hash_lookup(hashtab_T *ht, char_u *key, hash_T hash)
|
||||||
{
|
{
|
||||||
hash_T perturb;
|
|
||||||
hashitem_T *freeitem;
|
|
||||||
hashitem_T *hi;
|
|
||||||
unsigned idx;
|
|
||||||
|
|
||||||
#ifdef HT_DEBUG
|
#ifdef HT_DEBUG
|
||||||
hash_count_lookup++;
|
hash_count_lookup++;
|
||||||
#endif // ifdef HT_DEBUG
|
#endif // ifdef HT_DEBUG
|
||||||
@ -109,19 +101,18 @@ hashitem_T* hash_lookup(hashtab_T *ht, char_u *key, hash_T hash)
|
|||||||
// - return if there is no item at all
|
// - return if there is no item at all
|
||||||
// - skip over a removed item
|
// - skip over a removed item
|
||||||
// - return if the item matches
|
// - return if the item matches
|
||||||
idx = (unsigned)(hash & ht->ht_mask);
|
unsigned idx = (unsigned)(hash & ht->ht_mask);
|
||||||
hi = &ht->ht_array[idx];
|
hashitem_T *hi = &ht->ht_array[idx];
|
||||||
|
|
||||||
if (hi->hi_key == NULL) {
|
if (hi->hi_key == NULL) {
|
||||||
return hi;
|
return hi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hashitem_T *freeitem = NULL;
|
||||||
if (hi->hi_key == HI_KEY_REMOVED) {
|
if (hi->hi_key == HI_KEY_REMOVED) {
|
||||||
freeitem = hi;
|
freeitem = hi;
|
||||||
} else if ((hi->hi_hash == hash) && (STRCMP(hi->hi_key, key) == 0)) {
|
} else if ((hi->hi_hash == hash) && (STRCMP(hi->hi_key, key) == 0)) {
|
||||||
return hi;
|
return hi;
|
||||||
} else {
|
|
||||||
freeitem = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to search through the table to find the key. The algorithm
|
// Need to search through the table to find the key. The algorithm
|
||||||
@ -131,7 +122,7 @@ hashitem_T* hash_lookup(hashtab_T *ht, char_u *key, hash_T hash)
|
|||||||
// When we run into a NULL key it's clear that the key isn't there.
|
// When we run into a NULL key it's clear that the key isn't there.
|
||||||
// Return the first available slot found (can be a slot of a removed
|
// Return the first available slot found (can be a slot of a removed
|
||||||
// item).
|
// item).
|
||||||
for (perturb = hash;; perturb >>= PERTURB_SHIFT) {
|
for (hash_T perturb = hash;; perturb >>= PERTURB_SHIFT) {
|
||||||
#ifdef HT_DEBUG
|
#ifdef HT_DEBUG
|
||||||
// count a "miss" for hashtab lookup
|
// count a "miss" for hashtab lookup
|
||||||
hash_count_perturb++;
|
hash_count_perturb++;
|
||||||
@ -247,7 +238,7 @@ void hash_lock(hashtab_T *ht)
|
|||||||
void hash_unlock(hashtab_T *ht)
|
void hash_unlock(hashtab_T *ht)
|
||||||
{
|
{
|
||||||
ht->ht_locked--;
|
ht->ht_locked--;
|
||||||
(void)hash_may_resize(ht, 0);
|
hash_may_resize(ht, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resize hastable (new size can be given or automatically computed).
|
/// Resize hastable (new size can be given or automatically computed).
|
||||||
@ -262,16 +253,6 @@ void hash_unlock(hashtab_T *ht)
|
|||||||
/// FAIL if out of memory.
|
/// FAIL if out of memory.
|
||||||
static int hash_may_resize(hashtab_T *ht, int minitems)
|
static int hash_may_resize(hashtab_T *ht, int minitems)
|
||||||
{
|
{
|
||||||
hashitem_T temparray[HT_INIT_SIZE];
|
|
||||||
hashitem_T *oldarray, *newarray;
|
|
||||||
hashitem_T *olditem, *newitem;
|
|
||||||
unsigned newi;
|
|
||||||
int todo;
|
|
||||||
long_u oldsize, newsize;
|
|
||||||
long_u minsize;
|
|
||||||
long_u newmask;
|
|
||||||
hash_T perturb;
|
|
||||||
|
|
||||||
// Don't resize a locked table.
|
// Don't resize a locked table.
|
||||||
if (ht->ht_locked > 0) {
|
if (ht->ht_locked > 0) {
|
||||||
return OK;
|
return OK;
|
||||||
@ -287,6 +268,7 @@ static int hash_may_resize(hashtab_T *ht, int minitems)
|
|||||||
}
|
}
|
||||||
#endif // ifdef HT_DEBUG
|
#endif // ifdef HT_DEBUG
|
||||||
|
|
||||||
|
long_u minsize;
|
||||||
if (minitems == 0) {
|
if (minitems == 0) {
|
||||||
// Return quickly for small tables with at least two NULL items.
|
// Return quickly for small tables with at least two NULL items.
|
||||||
// items are required for the lookup to decide a key isn't there.
|
// items are required for the lookup to decide a key isn't there.
|
||||||
@ -299,7 +281,7 @@ static int hash_may_resize(hashtab_T *ht, int minitems)
|
|||||||
// removed items, so that they get cleaned up).
|
// removed items, so that they get cleaned up).
|
||||||
// Shrink the array when it's less than 1/5 full. When growing it is
|
// 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)
|
// at least 1/4 full (avoids repeated grow-shrink operations)
|
||||||
oldsize = ht->ht_mask + 1;
|
long_u oldsize = ht->ht_mask + 1;
|
||||||
if ((ht->ht_filled * 3 < oldsize * 2) && (ht->ht_used > oldsize / 5)) {
|
if ((ht->ht_filled * 3 < oldsize * 2) && (ht->ht_used > oldsize / 5)) {
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -321,8 +303,7 @@ static int hash_may_resize(hashtab_T *ht, int minitems)
|
|||||||
minsize = minitems * 3 / 2;
|
minsize = minitems * 3 / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
newsize = HT_INIT_SIZE;
|
long_u newsize = HT_INIT_SIZE;
|
||||||
|
|
||||||
while (newsize < minsize) {
|
while (newsize < minsize) {
|
||||||
// make sure it's always a power of 2
|
// make sure it's always a power of 2
|
||||||
newsize <<= 1;
|
newsize <<= 1;
|
||||||
@ -332,40 +313,37 @@ static int hash_may_resize(hashtab_T *ht, int minitems)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newsize == HT_INIT_SIZE) {
|
bool newarray_is_small = newsize == HT_INIT_SIZE;
|
||||||
// Use the small array inside the hashdict structure.
|
bool keep_smallarray = newarray_is_small
|
||||||
newarray = ht->ht_smallarray;
|
&& ht->ht_array == ht->ht_smallarray;
|
||||||
if (ht->ht_array == newarray) {
|
|
||||||
// Moving from ht_smallarray to ht_smallarray! Happens when there
|
// Make sure that oldarray and newarray do not overlap,
|
||||||
// are many removed items. Copy the items to be able to clean up
|
// so that copying is possible.
|
||||||
// removed items.
|
hashitem_T temparray[HT_INIT_SIZE];
|
||||||
memmove(temparray, newarray, sizeof(temparray));
|
hashitem_T *oldarray = keep_smallarray
|
||||||
oldarray = temparray;
|
? memcpy(temparray, ht->ht_smallarray, sizeof(temparray))
|
||||||
} else {
|
: ht->ht_array;
|
||||||
oldarray = ht->ht_array;
|
hashitem_T *newarray = newarray_is_small
|
||||||
}
|
? ht->ht_smallarray
|
||||||
} else {
|
: xmalloc(sizeof(hashitem_T) * newsize);
|
||||||
// Allocate an array.
|
|
||||||
newarray = xmalloc(sizeof(hashitem_T) * newsize);
|
|
||||||
oldarray = ht->ht_array;
|
|
||||||
}
|
|
||||||
memset(newarray, 0, (size_t)(sizeof(hashitem_T) * newsize));
|
memset(newarray, 0, (size_t)(sizeof(hashitem_T) * newsize));
|
||||||
|
|
||||||
// Move all the items from the old array to the new one, placing them in
|
// Move all the items from the old array to the new one, placing them in
|
||||||
// the right spot. The new array won't have any removed items, thus this
|
// the right spot. The new array won't have any removed items, thus this
|
||||||
// is also a cleanup action.
|
// is also a cleanup action.
|
||||||
newmask = newsize - 1;
|
long_u newmask = newsize - 1;
|
||||||
todo = (int)ht->ht_used;
|
int todo = (int)ht->ht_used;
|
||||||
|
|
||||||
for (olditem = oldarray; todo > 0; ++olditem) {
|
for (hashitem_T *olditem = oldarray; todo > 0; ++olditem) {
|
||||||
if (!HASHITEM_EMPTY(olditem)) {
|
if (!HASHITEM_EMPTY(olditem)) {
|
||||||
// The algorithm to find the spot to add the item is identical to
|
// The algorithm to find the spot to add the item is identical to
|
||||||
// the algorithm to find an item in hash_lookup(). But we only
|
// the algorithm to find an item in hash_lookup(). But we only
|
||||||
// need to search for a NULL key, thus it's simpler.
|
// need to search for a NULL key, thus it's simpler.
|
||||||
newi = (unsigned)(olditem->hi_hash & newmask);
|
unsigned newi = (unsigned)(olditem->hi_hash & newmask);
|
||||||
newitem = &newarray[newi];
|
hashitem_T *newitem = &newarray[newi];
|
||||||
if (newitem->hi_key != NULL) {
|
if (newitem->hi_key != NULL) {
|
||||||
for (perturb = olditem->hi_hash;; perturb >>= PERTURB_SHIFT) {
|
for (hash_T perturb = olditem->hi_hash;; perturb >>= PERTURB_SHIFT) {
|
||||||
newi = 5 * newi + perturb + 1;
|
newi = 5 * newi + perturb + 1;
|
||||||
newitem = &newarray[newi & newmask];
|
newitem = &newarray[newi & newmask];
|
||||||
if (newitem->hi_key == NULL) {
|
if (newitem->hi_key == NULL) {
|
||||||
@ -397,17 +375,16 @@ static int hash_may_resize(hashtab_T *ht, int minitems)
|
|||||||
/// lower the percentage the better.
|
/// lower the percentage the better.
|
||||||
hash_T hash_hash(char_u *key)
|
hash_T hash_hash(char_u *key)
|
||||||
{
|
{
|
||||||
hash_T hash;
|
hash_T hash = *key;
|
||||||
char_u *p;
|
|
||||||
|
|
||||||
if ((hash = *key) == 0) {
|
if (hash == 0) {
|
||||||
// Empty keys are not allowed, but we don't want to crash if we get one.
|
// Empty keys are not allowed, but we don't want to crash if we get one.
|
||||||
return (hash_T) 0;
|
return (hash_T) 0;
|
||||||
}
|
}
|
||||||
p = key + 1;
|
|
||||||
|
|
||||||
// A simplistic algorithm that appears to do very well.
|
// A simplistic algorithm that appears to do very well.
|
||||||
// Suggested by George Reilly.
|
// Suggested by George Reilly.
|
||||||
|
char_u *p = key + 1;
|
||||||
while (*p != NUL) {
|
while (*p != NUL) {
|
||||||
hash = hash * 101 + *p++;
|
hash = hash * 101 + *p++;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,17 @@
|
|||||||
#ifndef NVIM_HASHTAB_H
|
#ifndef NVIM_HASHTAB_H
|
||||||
#define NVIM_HASHTAB_H
|
#define NVIM_HASHTAB_H
|
||||||
|
|
||||||
|
#include "nvim/vim.h"
|
||||||
|
|
||||||
|
/// Type for hash number (hash calculation result).
|
||||||
|
typedef long_u hash_T;
|
||||||
|
|
||||||
|
/// The address of "hash_removed" is used as a magic number
|
||||||
|
/// for hi_key to indicate a removed item.
|
||||||
|
#define HI_KEY_REMOVED &hash_removed
|
||||||
|
#define HASHITEM_EMPTY(hi) ((hi)->hi_key == NULL \
|
||||||
|
|| (hi)->hi_key == &hash_removed)
|
||||||
|
|
||||||
/// A hastable item.
|
/// A hastable item.
|
||||||
///
|
///
|
||||||
/// Each item has a NUL terminated string key.
|
/// Each item has a NUL terminated string key.
|
||||||
@ -19,7 +30,7 @@
|
|||||||
/// This reduces the size of this item by 1/3.
|
/// This reduces the size of this item by 1/3.
|
||||||
typedef struct hashitem_S {
|
typedef struct hashitem_S {
|
||||||
/// Cached hash number for hi_key.
|
/// Cached hash number for hi_key.
|
||||||
long_u hi_hash;
|
hash_T hi_hash;
|
||||||
|
|
||||||
/// Item key.
|
/// Item key.
|
||||||
///
|
///
|
||||||
@ -30,12 +41,6 @@ typedef struct hashitem_S {
|
|||||||
char_u *hi_key;
|
char_u *hi_key;
|
||||||
} hashitem_T;
|
} hashitem_T;
|
||||||
|
|
||||||
/// The address of "hash_removed" is used as a magic number
|
|
||||||
/// for hi_key to indicate a removed item.
|
|
||||||
#define HI_KEY_REMOVED &hash_removed
|
|
||||||
#define HASHITEM_EMPTY(hi) ((hi)->hi_key == NULL || (hi)->hi_key == \
|
|
||||||
&hash_removed)
|
|
||||||
|
|
||||||
/// Initial size for a hashtable.
|
/// Initial size for a hashtable.
|
||||||
/// Our items are relatively small and growing is expensive, thus start with 16.
|
/// Our items are relatively small and growing is expensive, thus start with 16.
|
||||||
/// Must be a power of 2.
|
/// Must be a power of 2.
|
||||||
@ -60,9 +65,6 @@ typedef struct hashtable_S {
|
|||||||
hashitem_T ht_smallarray[HT_INIT_SIZE]; /// initial array
|
hashitem_T ht_smallarray[HT_INIT_SIZE]; /// initial array
|
||||||
} hashtab_T;
|
} hashtab_T;
|
||||||
|
|
||||||
/// Type for hash number (hash calculation result).
|
|
||||||
typedef long_u hash_T;
|
|
||||||
|
|
||||||
// hashtab.c
|
// hashtab.c
|
||||||
void hash_init(hashtab_T *ht);
|
void hash_init(hashtab_T *ht);
|
||||||
void hash_clear(hashtab_T *ht);
|
void hash_clear(hashtab_T *ht);
|
||||||
@ -71,8 +73,7 @@ hashitem_T *hash_find(hashtab_T *ht, char_u *key);
|
|||||||
hashitem_T *hash_lookup(hashtab_T *ht, char_u *key, hash_T hash);
|
hashitem_T *hash_lookup(hashtab_T *ht, char_u *key, hash_T hash);
|
||||||
void hash_debug_results(void);
|
void hash_debug_results(void);
|
||||||
int hash_add(hashtab_T *ht, char_u *key);
|
int hash_add(hashtab_T *ht, char_u *key);
|
||||||
int hash_add_item(hashtab_T *ht, hashitem_T *hi, char_u *key,
|
int hash_add_item(hashtab_T *ht, hashitem_T *hi, char_u *key, hash_T hash);
|
||||||
hash_T hash);
|
|
||||||
void hash_remove(hashtab_T *ht, hashitem_T *hi);
|
void hash_remove(hashtab_T *ht, hashitem_T *hi);
|
||||||
void hash_lock(hashtab_T *ht);
|
void hash_lock(hashtab_T *ht);
|
||||||
void hash_unlock(hashtab_T *ht);
|
void hash_unlock(hashtab_T *ht);
|
||||||
|
Loading…
Reference in New Issue
Block a user