static bool _put_data(qhasharr_t *tbl, int idx, unsigned int hash, const char *key, size_t key_size, const void *value, size_t val_size, int count) { size_t tmp_size = 0; qhasharr_slot_t *_tbl_slots = NULL; qhasharr_init(tbl, &_tbl_slots); // check if used if (_tbl_slots[idx].count != 0) { errno = EFAULT; return false; } unsigned char keymd5[16]; qhashmd5(key, key_size, keymd5); // store key _tbl_slots[idx].count = count; _tbl_slots[idx].hash = hash; tmp_size = (key_size <= _Q_HASHARR_KEYSIZE) ? key_size : _Q_HASHARR_KEYSIZE; memcpy(_tbl_slots[idx].data.pair.key, key, tmp_size); memcpy((char *)_tbl_slots[idx].data.pair.keymd5, (char *)keymd5, 16); _tbl_slots[idx].data.pair.keylen = key_size; _tbl_slots[idx].link = -1; // store value int newidx; size_t savesize; for (newidx = idx, savesize = 0; savesize < val_size;) { if (savesize > 0) // find next empty slot { int tmpidx = _find_empty(tbl, newidx + 1); if (tmpidx < 0) { _remove_data(tbl, idx); errno = ENOBUFS; return false; } // clear & set memset((void *)(&_tbl_slots[tmpidx]), '\0', sizeof(qhasharr_slot_t)); _tbl_slots[tmpidx].count = -2; // extended data block _tbl_slots[tmpidx].hash = newidx; // prev link _tbl_slots[tmpidx].link = -1; // end block mark _tbl_slots[tmpidx].size = 0; _tbl_slots[newidx].link = tmpidx; // link chain newidx = tmpidx; } // copy data size_t copysize = val_size - savesize; if (_tbl_slots[newidx].count == -2) { // extended value //if (copysize > sizeof(struct _Q_HASHARR_SLOT_EXT)) { // copysize = sizeof(struct _Q_HASHARR_SLOT_EXT); //} if (copysize > sizeof(union _slot_data)) { copysize = sizeof(union _slot_data); } memcpy(_tbl_slots[newidx].data.ext.value, (char*)value + savesize, copysize); } else { // first slot if (copysize > _Q_HASHARR_VALUESIZE) { copysize = _Q_HASHARR_VALUESIZE; } memcpy(_tbl_slots[newidx].data.pair.value, (char*)value + savesize, copysize); // increase stored key counter tbl->num++; } _tbl_slots[newidx].size = copysize; savesize += copysize; // increase used slot counter tbl->usedslots++; } return true; }
static bool _put_data(qhasharr_t *tbl, int idx, unsigned int hash, const char *key, const void *value, size_t size, int count) { // check if used if (tbl->slots[idx].count != 0) { DEBUG("hasharr: BUG found."); errno = EFAULT; return false; } size_t keylen = strlen(key); unsigned char keymd5[16]; qhashmd5(key, keylen, keymd5); // store key tbl->slots[idx].count = count; tbl->slots[idx].hash = hash; strncpy(tbl->slots[idx].data.pair.key, key, _Q_HASHARR_KEYSIZE); memcpy((char *)tbl->slots[idx].data.pair.keymd5, (char *)keymd5, 16); tbl->slots[idx].data.pair.keylen = keylen; tbl->slots[idx].link = -1; // store value int newidx; size_t savesize; for (newidx = idx, savesize = 0; savesize < size;) { if (savesize > 0) { // find next empty slot int tmpidx = _find_empty(tbl, newidx + 1); if (tmpidx < 0) { DEBUG("hasharr: Can't expand slot for key %s.", key); _remove_data(tbl, idx); errno = ENOBUFS; return false; } // clear & set memset((void *)(&tbl->slots[tmpidx]), '\0', sizeof(qhasharr_slot_t)); tbl->slots[tmpidx].count = -2; // extended data block tbl->slots[tmpidx].hash = newidx; // prev link tbl->slots[tmpidx].link = -1; // end block mark tbl->slots[tmpidx].size = 0; tbl->slots[newidx].link = tmpidx; // link chain DEBUG("hasharr: slot %d is linked to slot %d for key %s.", tmpidx, newidx, key); newidx = tmpidx; } // copy data size_t copysize = size - savesize; if (tbl->slots[newidx].count == -2) { // extended value if (copysize > sizeof(struct _Q_HASHARR_SLOT_EXT)) { copysize = sizeof(struct _Q_HASHARR_SLOT_EXT); } memcpy(tbl->slots[newidx].data.ext.value, value + savesize, copysize); } else { // first slot if (copysize > _Q_HASHARR_VALUESIZE) { copysize = _Q_HASHARR_VALUESIZE; } memcpy(tbl->slots[newidx].data.pair.value, value + savesize, copysize); // increase stored key counter tbl->num++; } tbl->slots[newidx].size = copysize; savesize += copysize; // increase used slot counter tbl->usedslots++; } return true; }
/** * Remove an object from this table. * * @param tbl qhasharr_t container pointer. * @param key key string * * @return true if successful, otherwise(not found) returns false * @retval errno will be set in error condition. * - ENOENT : No such key found. * - EINVAL : Invald argument. * - EFAULT : Unexpected error. Data structure is not constant. */ bool qhasharr_remove(qhasharr_t *tbl, const char *key, size_t key_size) { if (NULL == tbl || NULL == key) { errno = EINVAL; return false; } qhasharr_slot_t *_tbl_slots = NULL; qhasharr_init(tbl, &_tbl_slots); if (tbl->maxslots == 0) { return false; } // get hash integer unsigned int hash = qhashmurmur3_32(key, key_size) % tbl->maxslots; int idx = _get_idx(tbl, key, key_size, hash); if (idx < 0) { errno = ENOENT; return false; } if (_tbl_slots[idx].count == 1) { // just remove _remove_data(tbl, idx); } else if (_tbl_slots[idx].count > 1) // leading slot and has dup { // find dup int idx2; for (idx2 = idx + 1; ; idx2++) { if (idx2 >= tbl->maxslots) idx2 = 0; if (idx2 == idx) { errno = EFAULT; return false; } if (_tbl_slots[idx2].count == -1 && _tbl_slots[idx2].hash == hash) { break; } } // move to leading slot int backupcount = _tbl_slots[idx].count; _remove_data(tbl, idx); // remove leading data _copy_slot(tbl, idx, idx2); // copy slot _remove_slot(tbl, idx2); // remove moved slot _tbl_slots[idx].count = backupcount - 1; // adjust collision counter if (_tbl_slots[idx].link != -1) { _tbl_slots[_tbl_slots[idx].link].hash = idx; } } else if (_tbl_slots[idx].count == -1) // in case of -1. used for collision resolution { // decrease counter from leading slot if (_tbl_slots[ _tbl_slots[idx].hash ].count <= 1) { errno = EFAULT; return false; } _tbl_slots[ _tbl_slots[idx].hash ].count--; // remove data _remove_data(tbl, idx); } else { errno = ENOENT; return false; } return true; }
/** * qhasharr->remove(): Remove an object from this table. * * @param tbl qhasharr_t container pointer. * @param key key string * * @return true if successful, otherwise(not found) returns false * @retval errno will be set in error condition. * - ENOENT : No such key found. * - EINVAL : Invald argument. * - EFAULT : Unexpected error. Data structure is not constant. */ static bool remove_(qhasharr_t *tbl, const char *key) { if (key == NULL) { errno = EINVAL; return false; } // get hash integer unsigned int hash = qhashmurmur3_32(key, strlen(key)) % tbl->maxslots; int idx = _get_idx(tbl, key, hash); if (idx < 0) { DEBUG("not found %s", key); errno = ENOENT; return false; } if (tbl->slots[idx].count == 1) { // just remove _remove_data(tbl, idx); DEBUG("hasharr: rem %s (idx=%d,tot=%d)", key, idx, tbl->usedslots); } else if (tbl->slots[idx].count > 1) { // leading slot and has dup // find dup int idx2; for (idx2 = idx + 1; ; idx2++) { if (idx2 >= tbl->maxslots) idx2 = 0; if (idx2 == idx) { DEBUG("hasharr: [BUG] failed to remove dup key %s.", key); errno = EFAULT; return false; } if (tbl->slots[idx2].count == -1 && tbl->slots[idx2].hash == hash) { break; } } // move to leading slot int backupcount = tbl->slots[idx].count; _remove_data(tbl, idx); // remove leading data _copy_slot(tbl, idx, idx2); // copy slot _remove_slot(tbl, idx2); // remove moved slot tbl->slots[idx].count = backupcount - 1; // adjust collision counter if (tbl->slots[idx].link != -1) { tbl->slots[tbl->slots[idx].link].hash = idx; } DEBUG("hasharr: rem(lead) %s (idx=%d,tot=%d)", key, idx, tbl->usedslots); } else { // in case of -1. used for collision resolution // decrease counter from leading slot if (tbl->slots[ tbl->slots[idx].hash ].count <= 1) { DEBUG("hasharr: [BUG] failed to remove %s. " "counter of leading slot mismatch.", key); errno = EFAULT; return false; } tbl->slots[ tbl->slots[idx].hash ].count--; // remove data _remove_data(tbl, idx); DEBUG("hasharr: rem(dup) %s (idx=%d,tot=%d)", key, idx, tbl->usedslots); } return true; }