Repository: numpy/numpy
File: numpy/_core/src/common/npy_hashtable.c (C)

Code before:
    }
#else
    assert(b->prev == NULL);
    PyMem_Free(b);
#endif
    PyMem_Free(tb);
}


static int
_resize_if_necessary(PyArrayIdentityHash *tb)
{
#ifdef Py_GIL_DISABLED
    assert(PyMutex_IsLocked(&tb->mutex));
#endif
    struct buckets *old_buckets = tb->buckets;
    int key_len = tb->key_len;
    npy_intp new_size = 0, prev_size = old_buckets->size;
    assert(prev_size > 0);

    if ((old_buckets->nelem + 1) * 2 > prev_size) {
        /* Double in size */
        new_size = prev_size * 2;
    }

    if (new_size == 0) {
        /* No resize necessary */
        return 0;
    }

    npy_intp alloc_size;
    if (npy_mul_sizes_with_overflow(&alloc_size, new_size, key_len + 1)) {
        return -1;
    }
    struct buckets *new_buckets = (struct buckets *)PyMem_Calloc(
        1, sizeof(struct buckets) + alloc_size * sizeof(PyObject *));
    if (new_buckets == NULL) {
        PyErr_NoMemory();
        return -1;
    }
    new_buckets->size = new_size;
    new_buckets->nelem = 0;
    for (npy_intp i = 0; i < prev_size; i++) {
        PyObject **item = &old_buckets->array[i * (key_len + 1)];
        if (item[0] != NULL) {
            PyObject **tb_item = find_item_buckets(new_buckets, key_len, item + 1, NULL);
            memcpy(tb_item+1, item+1, key_len * sizeof(PyObject *));
            new_buckets->nelem++;
            tb_item[0] = item[0];
        }
    }

Review comment (suggestion):
The condition here on `new_size == 0` is a bit confusing to me. I think it would be easier to understand as:

```
if ((old_buckets->nelem + 1) * 2 <= old_buckets->size) {
    /* No resize necessary if load factor is not more than 0.5 */
    return 0;
}

/* Double in size */
npy_intp new_size = old_buckets->size * 2;
...
```

Code after:
    }
#else
    assert(b->prev == NULL);
    PyMem_Free(b);
#endif
    PyMem_Free(tb);
}


static int
_resize_if_necessary(PyArrayIdentityHash *tb)
{
#ifdef Py_GIL_DISABLED
    assert(PyMutex_IsLocked(&tb->mutex));
#endif
    struct buckets *old_buckets = tb->buckets;
    int key_len = tb->key_len;
    npy_intp prev_size = old_buckets->size;
    assert(prev_size > 0);

    if ((old_buckets->nelem + 1) * 2 <= old_buckets->size) {
        /* No resize necessary if load factor is not more than 0.5 */
        return 0;
    }

    /* Double in size */
    npy_intp new_size = old_buckets->size * 2;

    npy_intp alloc_size;
    if (npy_mul_sizes_with_overflow(&alloc_size, new_size, key_len + 1)) {
        return -1;
    }
    struct buckets *new_buckets = (struct buckets *)PyMem_Calloc(
        1, sizeof(struct buckets) + alloc_size * sizeof(PyObject *));
    if (new_buckets == NULL) {
        PyErr_NoMemory();
        return -1;
    }
    new_buckets->size = new_size;
    new_buckets->nelem = 0;
    for (npy_intp i = 0; i < prev_size; i++) {
        PyObject **item = &old_buckets->array[i * (key_len + 1)];
        if (item[0] != NULL) {
            PyObject **tb_item = find_item_buckets(new_buckets, key_len, item + 1, NULL);
            memcpy(tb_item+1, item+1, key_len * sizeof(PyObject *));
            new_buckets->nelem++;
            tb_item[0] = item[0];
        }
    }
#ifdef Py_GIL_DISABLED
    new_buckets->prev = old_buckets;