No OOM in hash_may_resize() and hash_add_item()

hash_add() can still return FAIL if the key already exists.
This commit is contained in:
Felipe Oliveira Carvalho
2014-05-28 18:24:23 -03:00
parent 6f29364632
commit 48fc1602be
3 changed files with 14 additions and 30 deletions

View File

@@ -5781,7 +5781,7 @@ static dict_T *dict_copy(dict_T *orig, int deep, int copyID)
/* /*
* Add item "item" to Dictionary "d". * Add item "item" to Dictionary "d".
* Returns FAIL when out of memory and when key already exists. * Returns FAIL when key already exists.
*/ */
int dict_add(dict_T *d, dictitem_T *item) int dict_add(dict_T *d, dictitem_T *item)
{ {
@@ -5815,7 +5815,7 @@ int dict_add_nr_str(dict_T *d, char *key, long nr, char_u *str)
/* /*
* Add a list entry to dictionary "d". * Add a list entry to dictionary "d".
* Returns FAIL when out of memory and when key already exists. * Returns FAIL when key already exists.
*/ */
int dict_add_list(dict_T *d, char *key, list_T *list) int dict_add_list(dict_T *d, char *key, list_T *list)
{ {

View File

@@ -171,7 +171,7 @@ void hash_debug_results(void)
/// in the new item (@see hashitem_T). Must not be NULL. /// in the new item (@see hashitem_T). Must not be NULL.
/// ///
/// @return OK if success. /// @return OK if success.
/// FAIL if key already present, or out of memory. /// FAIL if key already present
int hash_add(hashtab_T *ht, char_u *key) int hash_add(hashtab_T *ht, char_u *key)
{ {
hash_T hash = hash_hash(key); hash_T hash = hash_hash(key);
@@ -180,7 +180,8 @@ int hash_add(hashtab_T *ht, char_u *key)
EMSG2(_(e_intern2), "hash_add()"); EMSG2(_(e_intern2), "hash_add()");
return FAIL; return FAIL;
} }
return hash_add_item(ht, hi, key, hash); hash_add_item(ht, hi, key, hash);
return OK;
} }
/// Add item "hi" for key "key" to hashtable "ht". /// Add item "hi" for key "key" to hashtable "ht".
@@ -190,16 +191,8 @@ 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 /// @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. /// in the new item (@see hashitem_T). Must not be NULL.
/// @param hash The precomputed hash value for the key. /// @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)
/// @return OK if success.
/// FAIL if out of memory.
int hash_add_item(hashtab_T *ht, hashitem_T *hi, char_u *key, hash_T hash)
{ {
// If resizing failed before and it fails again we can't add an item.
if (ht->ht_error && (hash_may_resize(ht, 0) == FAIL)) {
return FAIL;
}
ht->ht_used++; ht->ht_used++;
if (hi->hi_key == NULL) { if (hi->hi_key == NULL) {
ht->ht_filled++; ht->ht_filled++;
@@ -208,7 +201,7 @@ int hash_add_item(hashtab_T *ht, hashitem_T *hi, char_u *key, hash_T hash)
hi->hi_hash = hash; hi->hi_hash = hash;
// When the space gets low may resize the array. // When the space gets low may resize the array.
return hash_may_resize(ht, 0); hash_may_resize(ht, 0);
} }
/// Remove item "hi" from hashtable "ht". /// Remove item "hi" from hashtable "ht".
@@ -250,14 +243,11 @@ void hash_unlock(hashtab_T *ht)
/// - Shrink when too much empty space. /// - Shrink when too much empty space.
/// - Grow when not enough empty space. /// - Grow when not enough empty space.
/// If non-zero, passed minitems will be used. /// If non-zero, passed minitems will be used.
/// static void hash_may_resize(hashtab_T *ht, size_t minitems)
/// @return OK if success.
/// FAIL if out of memory.
static int hash_may_resize(hashtab_T *ht, size_t minitems)
{ {
// 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;
} }
#ifdef HT_DEBUG #ifdef HT_DEBUG
@@ -276,7 +266,7 @@ static int hash_may_resize(hashtab_T *ht, size_t minitems)
// 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.
if ((ht->ht_filled < HT_INIT_SIZE - 1) if ((ht->ht_filled < HT_INIT_SIZE - 1)
&& (ht->ht_array == ht->ht_smallarray)) { && (ht->ht_array == ht->ht_smallarray)) {
return OK; return;
} }
// Grow or refill the array when it's more than 2/3 full (including // Grow or refill the array when it's more than 2/3 full (including
@@ -285,7 +275,7 @@ static int hash_may_resize(hashtab_T *ht, size_t minitems)
// at least 1/4 full (avoids repeated grow-shrink operations) // at least 1/4 full (avoids repeated grow-shrink operations)
size_t oldsize = ht->ht_mask + 1; size_t 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;
} }
if (ht->ht_used > 1000) { if (ht->ht_used > 1000) {
@@ -309,10 +299,8 @@ static int hash_may_resize(hashtab_T *ht, size_t minitems)
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;
if (newsize == 0) { // assert newsize didn't overflow
// overflow assert(newsize != 0);
return FAIL;
}
} }
bool newarray_is_small = newsize == HT_INIT_SIZE; bool newarray_is_small = newsize == HT_INIT_SIZE;
@@ -364,9 +352,6 @@ static int hash_may_resize(hashtab_T *ht, size_t minitems)
ht->ht_array = newarray; ht->ht_array = newarray;
ht->ht_mask = newmask; ht->ht_mask = newmask;
ht->ht_filled = ht->ht_used; ht->ht_filled = ht->ht_used;
ht->ht_error = false;
return OK;
} }
/// Get the hash number for a key. /// Get the hash number for a key.

View File

@@ -59,8 +59,6 @@ typedef struct hashtable_S {
size_t ht_used; /// number of items used size_t ht_used; /// number of items used
size_t ht_filled; /// number of items used or removed size_t ht_filled; /// number of items used or removed
int ht_locked; /// counter for hash_lock() int ht_locked; /// counter for hash_lock()
bool ht_error; /// when set growing failed, can't add more
/// items before growing works
hashitem_T *ht_array; /// points to the array, allocated when it's hashitem_T *ht_array; /// points to the array, allocated when it's
/// not "ht_smallarray" /// not "ht_smallarray"
hashitem_T ht_smallarray[HT_INIT_SIZE]; /// initial array hashitem_T ht_smallarray[HT_INIT_SIZE]; /// initial array
@@ -69,4 +67,5 @@ typedef struct hashtable_S {
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "hashtab.h.generated.h" # include "hashtab.h.generated.h"
#endif #endif
#endif // NVIM_HASHTAB_H #endif // NVIM_HASHTAB_H