/** * 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; }
/** * 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; }