/** * qhasharr->remove_by_idx(): Remove an object from this table by index number. * * @param tbl qhasharr_t container pointer. * @param idx slot index number * * @return true if successful, otherwise(not found) returns false * @retval errno will be set in error condition. * - ENOENT : Index is not pointing a valid object. * - EINVAL : Invald argument. * - EFAULT : Unexpected error. Data structure is not constant. * * @code * int idx = 0; * qhasharr_obj_t obj; * while(tbl->getnext(tbl, &obj, &idx) == true) { * if (condition_to_remove) { * idx--; // adjust index by -1 * remove_by_idx(idx); * } * free(obj.name); * free(obj.data); * } * @endcode * * @note * This function is to remove an object in getnext() traversal loop without * knowing the object name but index value. When key names are longer than * defined size, the keys are stored with truncation with their fingerprint, * so this method provides a way to remove those keys. * getnext() returns actual index + 1(pointing next slot of current finding), * so you need to adjust it by -1 for the valid index number. And once you * remove object by this method, rewind idx by -1 before calling getnext() * because collision objects can be moved back to removed index again, so * by adjusting index by -1, getnext() can continue search from the removed * slot index again. Please refer an example code. */ bool qhasharr_remove_by_idx(qhasharr_t *tbl, int idx) { if (idx < 0) { errno = EINVAL; return false; } qhasharr_data_t *tbldata = tbl->data; qhasharr_slot_t *tblslots = get_slots(tbl); if (tblslots[idx].count == 1) { // just remove remove_data(tbl, idx); } else if (tblslots[idx].count > 1) { // leading slot and has collision // find the collision key int idx2; for (idx2 = idx + 1;; idx2++) { if (idx2 >= tbldata->maxslots) idx2 = 0; if (idx2 == idx) { errno = EFAULT; return false; } if (tblslots[idx2].count == COLLISION_MARK && tblslots[idx2].hash == tblslots[idx].hash) { break; } } // move to leading slot int backupcount = tblslots[idx].count; remove_data(tbl, idx); // remove leading data copy_slot(tbl, idx, idx2); // copy slot remove_slot(tbl, idx2); // remove moved slot tblslots[idx].count = backupcount - 1; // adjust collision counter if (tblslots[idx].link != -1) { tblslots[tblslots[idx].link].hash = idx; } } else if (tblslots[idx].count == COLLISION_MARK) { // collision key // decrease counter from leading slot if (tblslots[tblslots[idx].hash].count <= 1) { errno = EFAULT; return false; } tblslots[tblslots[idx].hash].count--; // remove data remove_data(tbl, idx); } else { errno = ENOENT; return false; } return true; }
static bool remove_data(qhasharr_t *tbl, int idx) { qhasharr_data_t *tbldata = tbl->data; qhasharr_slot_t *tblslots = get_slots(tbl); assert(tblslots[idx].count != 0); while (true) { int link = tblslots[idx].link; remove_slot(tbl, idx); tbldata->usedslots--; if (link == -1) break; idx = link; } // decrease stored key counter tbldata->num--; return true; }
// from signal_interface virtual void slot_destroyed(slot_interface& aSlot) const { remove_slot(aSlot); }
void disconnect(const Key& aKey, slot_interface& aSlot) const { remove_slot(aKey, aSlot); }
void disconnect(slot_interface& aSlot) const { remove_slot(aSlot); }
/** * qhasharr->put_by_obj(): ut an object into this table by key object. * * @param tbl qhasharr_t container pointer. * @param name key data * @param namesize size of key * @param data data * @param datasize size of data * * @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_by_obj(qhasharr_t *tbl, const void *name, size_t namesize, const void *data, size_t datasize) { if (tbl == NULL || name == NULL || namesize == 0 || data == NULL || datasize == 0) { errno = EINVAL; return false; } qhasharr_data_t *tbldata = tbl->data; qhasharr_slot_t *tblslots = get_slots(tbl); // check full if (tbldata->usedslots >= tbldata->maxslots) { errno = ENOBUFS; return false; } // get hash integer uint32_t hash = qhashmurmur3_32(name, namesize) % tbldata->maxslots; // check, is slot empty if (tblslots[hash].count == 0) { // empty slot // put data if (put_data(tbl, hash, hash, name, namesize, data, datasize, 1) == false) { return false; } } else if (tblslots[hash].count > 0) { // same key or hash collision // check same key; int idx = get_idx(tbl, name, namesize, hash); if (idx >= 0) { // same key // remove and recall qhasharr_remove_by_idx(tbl, idx); return qhasharr_put_by_obj(tbl, name, namesize, data, datasize); } else { // no same key but hash collision // find empty slot int idx = find_avail(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, name, namesize, data, datasize, COLLISION_MARK) == false) { return false; } // increase counter from leading slot tblslots[hash].count++; } } else { // collision key or extended block // find empty slot int idx = find_avail(tbl, hash + 1); if (idx < 0) { errno = ENOBUFS; return false; } // move the slot copy_slot(tbl, idx, hash); remove_slot(tbl, hash); // adjust the link chain if (tblslots[idx].link != -1) { tblslots[tblslots[idx].link].hash = idx; } if (tblslots[idx].count == EXTBLOCK_MARK) { tblslots[tblslots[idx].hash].link = idx; } // store data if (put_data(tbl, hash, hash, name, namesize, data, datasize, 1) == false) { return false; } } return true; }