Exemple #1
0
/**
 * Put an object into table.
 *
 * @param tbl       qhasharr_t container pointer.
 * @param key       key string
 * @param value     value object data
 * @param size      size of value
 *
 * @return true if successful, otherwise returns false
 * @retval errno will be set in error condition.
 *  - ENOBUFS   : Table doesn't have enough space to store the object.
 *  - EINVAL    : Invalid argument.
 *  - EFAULT    : Unexpected error. Data structure is not constant.
*/
bool qhasharr_put(qhasharr_t *tbl, const char *key, size_t key_size, const void *value, size_t val_size)
{
    if (NULL == tbl || NULL == key || NULL == value)
    {
        errno = EINVAL;
        return false;
    }

    qhasharr_slot_t *_tbl_slots = NULL;
    qhasharr_init(tbl, &_tbl_slots);
    
    if (tbl->maxslots == 0)
    {
        return false;  
    }
    // check full
    if (tbl->usedslots >= tbl->maxslots)
    {
        errno = ENOBUFS;
        return false;
    }

    // get hash integer
    unsigned int hash = qhashmurmur3_32(key, key_size) % tbl->maxslots;

    // check, is slot empty
    if (_tbl_slots[hash].count == 0)   // empty slot
    {
        // put data
        if (_put_data(tbl, hash, hash, key, key_size, value, val_size, 1) == false)
        {
            return false;
        }
    }
    else if (_tbl_slots[hash].count > 0)     // same key or hash collision
    {
        // check same key;
        int idx = _get_idx(tbl, key, key_size, hash);
        if (idx >= 0)   // same key
        {
            // remove and recall
            if (!qhasharr_remove(tbl, key, key_size))
                return false;
            return qhasharr_put(tbl, key, key_size, value, val_size);
        }
        else     // no same key, just hash collision
        {
            // find empty slot
            int idx = _find_empty(tbl, hash);
            if (idx < 0)
            {
                errno = ENOBUFS;
                return false;
            }

            // put data. -1 is used for collision resolution (idx != hash);
            if (_put_data(tbl, idx, hash, key, key_size, value, val_size, -1) == false)
            {
                return false;
            }

            // increase counter from leading slot
            _tbl_slots[hash].count++;

            //      key, idx, hash, tbl->usedslots);
        }
    }
    else
    {
        // in case of -1 or -2, move it. -1 used for collision resolution,
        // -2 used for oversized value data.

        // find empty slot
        int idx = _find_empty(tbl, hash + 1);
        if (idx < 0)
        {
            errno = ENOBUFS;
            return false;
        }

        // move dup slot to empty
        _copy_slot(tbl, idx, hash);

        _remove_slot(tbl, hash);

        // in case of -2, adjust link of mother
        if (_tbl_slots[idx].count == -2)
        {
            _tbl_slots[ _tbl_slots[idx].hash ].link = idx;
            if (_tbl_slots[idx].link != -1)
            {
                _tbl_slots[ _tbl_slots[idx].link ].hash = idx;
            }
        }
        else if (_tbl_slots[idx].count == -1)
        {
            if (_tbl_slots[idx].link != -1)
            {
                _tbl_slots[ _tbl_slots[idx].link ].hash = idx;
            }
        }

        // store data
        if (_put_data(tbl, hash, hash, key, key_size, value, val_size, 1) == false)
        {
            return false;
        }
    }

    return true;
}
Exemple #2
0
/**
 * qhasharr->put(): Put an object into this table.
 *
 * @param tbl       qhasharr_t container pointer.
 * @param key       key string
 * @param value     value object data
 * @param size      size of value
 *
 * @return true if successful, otherwise returns false
 * @retval errno will be set in error condition.
 *  - ENOBUFS   : Table doesn't have enough space to store the object.
 *  - EINVAL    : Invalid argument.
 *  - EFAULT    : Unexpected error. Data structure is not constant.
*/
static bool put(qhasharr_t *tbl, const char *key, const void *value,
                size_t size)
{
    if (key == NULL || value == NULL) {
        errno = EINVAL;
        return false;
    }

    // check full
    if (tbl->usedslots >= tbl->maxslots) {
        DEBUG("hasharr: put %s - FULL", key);
        errno = ENOBUFS;
        return false;
    }

    // get hash integer
    unsigned int hash = qhashmurmur3_32(key, strlen(key)) % tbl->maxslots;

    // check, is slot empty
    if (tbl->slots[hash].count == 0) { // empty slot
        // put data
        if (_put_data(tbl, hash, hash, key, value, size, 1) == false) {
            DEBUG("hasharr: FAILED put(new) %s", key);
            return false;
        }
        DEBUG("hasharr: put(new) %s (idx=%d,hash=%u,tot=%d)",
              key, hash, hash, tbl->usedslots);
    } else if (tbl->slots[hash].count > 0) { // same key or hash collision
        // check same key;
        int idx = _get_idx(tbl, key, hash);
        if (idx >= 0) { // same key
            // remove and recall
            remove_(tbl, key);
            return put(tbl, key, value, size);
        } else { // no same key, just hash collision
            // find empty slot
            int idx = _find_empty(tbl, hash);
            if (idx < 0) {
                errno = ENOBUFS;
                return false;
            }

            // put data. -1 is used for collision resolution (idx != hash);
            if (_put_data(tbl, idx, hash, key, value, size, -1) == false) {
                DEBUG("hasharr: FAILED put(col) %s", key);
                return false;
            }

            // increase counter from leading slot
            tbl->slots[hash].count++;

            DEBUG("hasharr: put(col) %s (idx=%d,hash=%u,tot=%d)",
                  key, idx, hash, tbl->usedslots);
        }
    } else {
        // in case of -1 or -2, move it. -1 used for collision resolution,
        // -2 used for oversized value data.

        // find empty slot
        int idx = _find_empty(tbl, hash + 1);
        if (idx < 0) {
            errno = ENOBUFS;
            return false;
        }

        // move dup slot to empty
        _copy_slot(tbl, idx, hash);
        _remove_slot(tbl, hash);

        // in case of -2, adjust link of mother
        if (tbl->slots[idx].count == -2) {
            tbl->slots[ tbl->slots[idx].hash ].link = idx;
            if (tbl->slots[idx].link != -1) {
                tbl->slots[ tbl->slots[idx].link ].hash = idx;
            }
        }

        // store data
        if (_put_data(tbl, hash, hash, key, value, size, 1) == false) {
            DEBUG("hasharr: FAILED put(swp) %s", key);
            return false;
        }

        DEBUG("hasharr: put(swp) %s (idx=%u,hash=%u,tot=%d)",
              key, hash, hash, tbl->usedslots);
    }

    return true;
}