static bool remove_slot(qhasharr_t *tbl, int idx) { qhasharr_slot_t *tblslots = get_slots(tbl); assert(tblslots[idx].count != 0); tblslots[idx].count = 0; return true; }
/** * 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; }
void* tss::get() const { tss_slots* slots = get_slots(false); if (!slots) return 0; if (m_slot >= slots->size()) return 0; return (*slots)[m_slot]; }
static int get_idx(qhasharr_t *tbl, const void *name, size_t namesize, uint32_t hash) { qhasharr_data_t *tbldata = tbl->data; qhasharr_slot_t *tblslots = get_slots(tbl); if (tblslots[hash].count > 0) { int count, idx; for (count = 0, idx = hash; count < tblslots[hash].count;) { if (tblslots[idx].hash == hash && (tblslots[idx].count > 0 || tblslots[idx].count == COLLISION_MARK)) { // same hash count++; // is same key? // first check key length if (namesize == tblslots[idx].data.pair.namesize) { if (namesize <= Q_HASHARR_NAMESIZE) { // original key is stored if (!memcmp(name, tblslots[idx].data.pair.name, namesize)) { return idx; } } else { // key is truncated, compare MD5 also. unsigned char namemd5[16]; qhashmd5(name, namesize, namemd5); if (!memcmp(name, tblslots[idx].data.pair.name, Q_HASHARR_NAMESIZE) && !memcmp(namemd5, tblslots[idx].data.pair.namemd5, 16)) { return idx; } } } } // increase idx idx++; if (idx >= tbldata->maxslots) idx = 0; // check loop if (idx == hash) break; continue; } } return -1; }
static int dialog_loadgame_load(gg_widget_t *widget, gg_widget_t *emitter, void *data, void *extra_data) { int slot = saveload_selected; if (get_slots() & (1 << slot)) { set_pgn_slot(slot); set_set_loading(TRUE); gg_dialog_close(); gg_dialog_close(); } return 1; }
static bool copy_slot(qhasharr_t *tbl, int idx1, int idx2) { qhasharr_slot_t *tblslots = get_slots(tbl); if (tblslots[idx1].count != 0 || tblslots[idx2].count == 0) { errno = EFAULT; return false; } memcpy((void *) (&tblslots[idx1]), (void *) (&tblslots[idx2]), sizeof(qhasharr_slot_t)); return true; }
static void *get_data(qhasharr_t *tbl, int idx, size_t *size) { if (idx < 0) { errno = ENOENT; return NULL; } qhasharr_slot_t *tblslots = get_slots(tbl); int newidx; size_t datasize; for (newidx = idx, datasize = 0;; newidx = tblslots[newidx].link) { datasize += tblslots[newidx].datasize; if (tblslots[newidx].link == -1) break; } void *data, *dp; if ((data = malloc(datasize)) == NULL) { errno = ENOMEM; return NULL; } for (newidx = idx, dp = data;; newidx = tblslots[newidx].link) { if (tblslots[newidx].count == EXTBLOCK_MARK) { // extended data block memcpy(dp, (void *) tblslots[newidx].data.ext.data, tblslots[newidx].datasize); } else { // key/value pair data block memcpy(dp, (void *) tblslots[newidx].data.pair.data, tblslots[newidx].datasize); } dp += tblslots[newidx].datasize; if (tblslots[newidx].link == -1) break; } if (size != NULL) *size = datasize; #ifdef QHASHARR_TIMESTAMP time(&tblslots[idx].timestamp); #endif return data; }
/** * qhasharr->clear(): Clears this table so that it contains no keys. * * @param tbl qhasharr_t container pointer. * * @return true if successful, otherwise returns false. */ void qhasharr_clear(qhasharr_t *tbl) { if (tbl == NULL) { errno = EINVAL; return; } qhasharr_data_t *tbldata = tbl->data; qhasharr_slot_t *tblslots = get_slots(tbl); if (tbldata->usedslots == 0) return; tbldata->usedslots = 0; tbldata->num = 0; // clear memory memset((void *) tblslots, '\0', (tbldata->maxslots * sizeof(qhasharr_slot_t))); }
/** * qhasharr->getnext(): Get next element. * * @param tbl qhasharr_t container pointer. * @param idx index pointer * * @return key name string if successful, otherwise(end of table) returns NULL * @retval errno will be set in error condition. * - ENOENT : No next element. * - EINVAL : Invald argument. * - ENOMEM : Memory allocation failed. * * @code * int idx = 0; * qhasharr_obj_t obj; * while(tbl->getnext(tbl, &obj, &idx) == true) { * printf("NAMESIZE=%zu, DATASIZE=%zu\n", * obj.namesize, obj.datasize); * free(obj.name); // key name * free(obj.data); // value data * } * @endcode * * @note * Please be aware a key name will be returned with truncated length * because key name gets truncated if it doesn't fit into slot size, * Q_HASHARR_NAMESIZE. */ bool qhasharr_getnext(qhasharr_t *tbl, qhasharr_obj_t *obj, int *idx) { if (tbl == NULL || obj == NULL || idx == NULL) { errno = EINVAL; return NULL; } qhasharr_data_t *tbldata = tbl->data; qhasharr_slot_t *tblslots = get_slots(tbl); for (; *idx < tbldata->maxslots; (*idx)++) { if (tblslots[*idx].count == 0 || tblslots[*idx].count == EXTBLOCK_MARK) { continue; } size_t namesize = tblslots[*idx].data.pair.namesize; if (namesize > Q_HASHARR_NAMESIZE) namesize = Q_HASHARR_NAMESIZE; obj->name = malloc(namesize + 1); if (obj->name == NULL) { errno = ENOMEM; return false; } memcpy(obj->name, tblslots[*idx].data.pair.name, namesize); memcpy(obj->name + namesize, "", 1); // for truncated case obj->namesize = namesize; obj->data = get_data(tbl, *idx, &obj->datasize); if (obj->data == NULL) { free(obj->name); errno = ENOMEM; return false; } *idx += 1; return true; } errno = ENOENT; return false; }
void tss::set(void* value) { tss_slots* slots = get_slots(true); if (!slots) throw boost::thread_resource_error(); if (m_slot >= slots->size()) { try { slots->resize(m_slot + 1); } catch (...) { throw boost::thread_resource_error(); } } (*slots)[m_slot] = value; }
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; }
// find empty slot : return empty slow number, otherwise returns -1. static int find_avail(qhasharr_t *tbl, int startidx) { qhasharr_data_t *tbldata = tbl->data; qhasharr_slot_t *tblslots = get_slots(tbl); if (startidx >= tbldata->maxslots) startidx = 0; int idx = startidx; while (true) { if (tblslots[idx].count == 0) return idx; idx++; if (idx >= tbldata->maxslots) idx = 0; if (idx == startidx) break; } return -1; }
/** * qhasharr->getts_by_obj(): Get an timestamp of object by key object from * this table * * @param tbl qhasharr_t container pointer. * @param name key data * @param namesize size of key * @param ts if not NULL, timestamp of object will be stored * * @return malloced object pointer if successful, otherwise(not found) * returns NULL * @retval errno will be set in error condition. * - ENOENT : No such key found. * - EINVAL : Invalid argument. * * @note * timestamp must be pre-allocated. */ bool qhasharr_getts_by_obj(qhasharr_t *tbl, const void *name, size_t namesize, time_t *ts) { if (tbl == NULL || name == NULL || namesize == 0) { errno = EINVAL; return false; } qhasharr_data_t *tbldata = tbl->data; // get hash integer uint32_t hash = qhashmurmur3_32(name, namesize) % tbldata->maxslots; int idx = get_idx(tbl, name, namesize, hash); if (idx < 0) { errno = ENOENT; return false; } if (ts) { qhasharr_slot_t *tblslots = get_slots(tbl); *ts = tblslots[idx].timestamp; } return true; }
int main(int argc, char **argv) { pid_t id; pid_t childs[ANZAHL_JOBS]; int i = 0; int slot = 0; int delay = 0; char command[32] = ""; /* array initialisieren */ for (i=0; i<ANZAHL_JOBS; ++i) childs[i] = 0; while (1) { printf("Nr, Wartezeit und Befehl eingeben: "); if ((i = scanf("%d, %d, %31s", &slot, &delay, command)) < 2) { fprintf(stderr, "Usage: %s <slot>, <delay>, <command>\n", argv[0]); exit(EXIT_FAILURE); } /* zombies terminieren */ get_zombies(childs); /* check for correct input */ if ((i == 2 && delay != -1 ) || slot > 9) { fprintf(stderr, "Usage: %s <slot>, <delay>, <command>\n", argv[0]); exit(EXIT_FAILURE); } /* job loeschen */ else if (i == 2) { /* job vorhanden? */ if (childs[slot] != 0) { kill(childs[slot], 9); childs[slot] = 0; } else { printf("Slot %d schon frei.\n", slot); continue; } } /* job hinzufuegen */ else if (i == 3) { if (childs[slot] != 0) { printf("Slot %d belegt.\n", slot); continue; } /* job anlegen */ id = fork(); /* fork fehlgeschlagen */ if (id == -1) { perror("fork failed"); exit(EXIT_FAILURE); } /* child-prozess */ else if (id == 0) { sleep(delay); printf("Child: %d\n", getpid()); /* command ausfuehren */ if (execlp(command, command, NULL) == -1) { perror("execlp"); exit(EXIT_FAILURE); } exit(0); } /* parent-prozess */ else if (id > 0) { printf("Parent: %d erzeugt.\n", id); childs[slot] = id; get_zombies(childs); get_slots(childs); } } } return 0; }
static int _mwrite_one(Stream_t *Dir, char *argname, char *shortname, write_data_callback *cb, void *arg, ClashHandling_t *ch) { char longname[VBUFSIZE]; const char *dstname; dos_name_t dosname; int expanded; struct scan_state scan; clash_action ret; doscp_t *cp = GET_DOSCONVERT(Dir); expanded = 0; if(isSpecial(argname)) { fprintf(stderr, "Cannot create entry named . or ..\n"); return -1; } if(ch->name_converter == dos_name) { if(shortname) stripspaces(shortname); if(argname) stripspaces(argname); } if(shortname){ convert_to_shortname(cp, ch, shortname, &dosname); if(ch->use_longname & 1){ /* short name mangled, treat it as a long name */ argname = shortname; shortname = 0; } } if (argname[0] && (argname[1] == ':')) { /* Skip drive letter */ dstname = argname + 2; } else { dstname = argname; } /* Copy original argument dstname to working value longname */ strncpy(longname, dstname, VBUFSIZE-1); if(shortname) { ch->use_longname = convert_to_shortname(cp, ch, shortname, &dosname); if(strcmp(shortname, longname)) ch->use_longname |= 1; } else { ch->use_longname = convert_to_shortname(cp, ch, longname, &dosname); } ch->action[0] = ch->namematch_default[0]; ch->action[1] = ch->namematch_default[1]; while (1) { switch((ret=get_slots(Dir, &dosname, longname, &scan, ch))){ case NAMEMATCH_ERROR: return -1; /* Non-file-specific error, * quit */ case NAMEMATCH_SKIP: return -1; /* Skip file (user request or * error) */ case NAMEMATCH_PRENAME: ch->use_longname = convert_to_shortname(cp, ch, longname, &dosname); continue; case NAMEMATCH_RENAME: continue; /* Renamed file, loop again */ case NAMEMATCH_GREW: /* No collision, and not enough slots. * Try to grow the directory */ if (expanded) { /* Already tried this * once, no good */ fprintf(stderr, "%s: No directory slots\n", progname); return -1; } expanded = 1; if (dir_grow(Dir, scan.max_entry)) return -1; continue; case NAMEMATCH_OVERWRITE: case NAMEMATCH_SUCCESS: return write_slots(Dir, &dosname, longname, &scan, cb, arg, ch->use_longname); default: fprintf(stderr, "Internal error: clash_action=%d\n", ret); return -1; } } }
/** * 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; }
gg_dialog_t *dialog_saveload_create(gg_dialog_t *parent, int saving) { gg_widget_t *dialog; gg_widget_t *rootvbox = gg_vbox_create(0); gg_widget_t *vbox = gg_vbox_create(0); gg_widget_t *hbox = gg_vbox_create(0); gg_widget_t *hboxtemp; gg_widget_t *widget; char temp[80]; char whiteis[80], blackis[80]; int i=0,j=0; int padding=0; change_saving=saving; if ( !changing_slot ) saveload_selected=0; /*DBG_LOG( "dialog opened with saveselected of %i", saveload_selected );*/ /* Right side.. */ if (!changing_slot) { #ifdef _arch_dreamcast dc_restore_savegames(); #endif for ( i=0; i<SAVEGAME_SLOTS; i++ ) load_save_xml( i ); } if ( get_slots() & (1 << saveload_selected) ) { gg_widget_t *board_box = gg_vbox_create(0); sprintf( temp, "Saved: %s", get_time_save(saveload_selected) ); widget = gg_label_create(temp); gg_container_append(GG_CONTAINER(vbox), widget); switch ( get_config_save(saveload_selected)->player[WHITE] ) { case PLAYER_ENGINE: sprintf( whiteis, "CPU" ); break; case PLAYER_UI: sprintf( whiteis, "Human" ); break; default: /* Whoops */ sprintf( whiteis, "Oh no.." ); break; } switch ( get_config_save(saveload_selected)->player[BLACK] ) { case PLAYER_ENGINE: sprintf( blackis, "CPU" ); break; case PLAYER_UI: sprintf( blackis, "Human" ); break; default: /* Whoops */ sprintf( blackis, "Oh no.." ); break; } sprintf( temp, "%s vs %s", whiteis, blackis ); widget = gg_label_create(temp); gg_container_append(GG_CONTAINER(vbox), widget); sprintf( temp, "Difficulty: %s", get_config_save(saveload_selected)->difficulty ? "Normal" : "Easy" ); widget = gg_label_create(temp); gg_container_append(GG_CONTAINER(vbox), widget); sprintf( temp, "Level: %i", get_config_save(saveload_selected)->cpu_level ); widget = gg_label_create(temp); gg_container_append(GG_CONTAINER(vbox), widget); widget = gg_label_create(" "); gg_container_append(GG_CONTAINER(vbox), widget); /* create board.. */ for ( i=7; i>=0; i-- ) { gg_widget_t *hboxtemp2; gg_colour_t col_white = { 1.0f, 1.0f, 1.0f, 1.0f }; /*gg_colour_t col_grey = { 0.3f, 0.3f, 0.3f, 1.0f };*/ hboxtemp = gg_hbox_create(0); hboxtemp2 = gg_hbox_create(0); gg_set_requested_size(hboxtemp2, 20, 20); gg_container_append(GG_CONTAINER(hboxtemp), hboxtemp2); for ( j=0; j<8; j++ ) { gg_colour_t col_green = {0.5, 0.6, 0.5, 1.0}; gg_colour_t col_yellow = {0.8, 0.7, 0.4, 1.0}; gg_colour_t front, *back; int square = get_saved_board(saveload_selected)->square[i * 8 + j]; sprintf(temp, "%c", xmlsquaretofont(square)); widget = gg_label_create( temp ); gg_set_requested_size(widget, 20, 20); gg_align_set_alignment(GG_ALIGN(widget), 0.5, 0.5); if (COLOUR(square) == WHITE) front = col_white; else front = *get_col(COL_BLACK); if ((i + j) % 2 == 0) back = &col_green; else back = &col_yellow; /* FIXME Hack to turn off shadow */ front.a = 2.0f; gg_label_set_colour(GG_LABEL(widget), &front, back); gg_container_append(GG_CONTAINER(hboxtemp), widget); } gg_container_append(GG_CONTAINER(board_box), hboxtemp); } gg_container_append(GG_CONTAINER(vbox), board_box); } else { sprintf( temp, "Empty slot" ); widget = gg_label_create(temp); gg_container_append(GG_CONTAINER(vbox), widget); for ( i=0; i<12; i++ ) { widget = gg_label_create(" "); gg_container_append(GG_CONTAINER(vbox), widget); } } gg_set_requested_size(vbox, 201, 0); gg_container_append(GG_CONTAINER(hbox), gg_frame_create(vbox)); /* left side */ vbox = gg_vbox_create(0); /* padding.. */ for ( i=0; i<padding; i++ ) { widget = gg_label_create(" "); gg_container_append(GG_CONTAINER(vbox), widget); } widget = gg_option_create(); for ( i=0; i<SAVEGAME_SLOTS; i++ ) { sprintf( temp, "Save slot: %i", i+1 ); gg_option_append_label(GG_OPTION(widget), temp, 0.5f, 0.0f); } gg_widget_subscribe_signal_name(widget, widget->id, "option_changed", dialog_saveload_change, widget); gg_container_append(GG_CONTAINER(vbox), widget); if ( changing_slot ) gg_option_set_selected(GG_OPTION(widget), saveload_selected); if ( saving ) { widget = gg_action_create_with_label("Save Game", 0.5f, 0.0f); gg_widget_subscribe_signal_name(widget, widget->id, "action_pressed", dialog_savegame_save, vbox); } else { widget = gg_action_create_with_label("Load Game", 0.5f, 0.0f); gg_widget_subscribe_signal_name(widget, widget->id, "action_pressed", dialog_loadgame_load, vbox); } gg_container_append(GG_CONTAINER(vbox), widget); widget = gg_action_create_with_label("Cancel", 0.5f, 0.0f); gg_widget_subscribe_signal_name(widget, widget->id, "action_pressed", dialog_close_cb, NULL); gg_container_append(GG_CONTAINER(vbox), widget); /*for ( i=0; i<SAVEGAME_SLOTS; i++ ) { sprintf( temp, "%i: ", i ); widget = gg_action_create_with_label(temp, 0.0f, 0.0f); gg_action_set_callback(GG_ACTION(widget), dialog_saveload_change, vbox); gg_container_append(GG_CONTAINER(vbox), widget); }*/ gg_container_append(GG_CONTAINER(hbox), vbox ); if ( changing_slot ) gg_vbox_set_selected(vbox, padding ); /* Dialog stuff */ gg_container_append(GG_CONTAINER(rootvbox), hbox); dialog = gg_dialog_create(rootvbox, NULL, parent, GG_DIALOG_AUTOHIDE_PARENT); if ( saving ) gg_dialog_set_style(GG_DIALOG(dialog), get_ingame_style()); else gg_dialog_set_style(GG_DIALOG(dialog), get_menu_style()); return GG_DIALOG(dialog); }
/** * qhasharr->debug(): Print hash table for debugging purpose * * @param tbl qhasharr_t container pointer. * @param out output stream * * @return true if successful, otherwise returns false * @retval errno will be set in error condition. * - EIO : Invalid output stream. */ bool qhasharr_debug(qhasharr_t *tbl, FILE *out) { if (tbl == NULL) { errno = EINVAL; return false; } if (out == NULL) { errno = EIO; return false; } qhasharr_slot_t *tblslots = get_slots(tbl); int idx = 0; qhasharr_obj_t obj; while (tbl->getnext(tbl, &obj, &idx) == true) { uint16_t namesize = tblslots[idx - 1].data.pair.namesize; _q_textout(out, obj.name, obj.namesize, MAX_HUMANOUT); fprintf(out, "%s(%d)=", (namesize > Q_HASHARR_NAMESIZE) ? "..." : "", namesize); _q_textout(out, obj.data, obj.datasize, MAX_HUMANOUT); fprintf(out, " (%zu)\n", obj.datasize); free(obj.name); free(obj.data); } #ifdef BUILD_DEBUG qhasharr_data_t *tbldata = tbl->data; fprintf(out, "%d elements (slot %d used/%d total)\n", tbldata->num, tbldata->usedslots, tbldata->maxslots); for (idx = 0; idx < tbldata->maxslots; idx++) { if (tblslots[idx].count == 0) continue; fprintf(out, "slot=%d,type=", idx); if (tblslots[idx].count == EXTBLOCK_MARK) { fprintf(out, "EXTEND"); fprintf(out, ",prev=%d", tblslots[idx].hash); fprintf(out, ",next=%d", tblslots[idx].link); fprintf(out, ",datasize=%d", tblslots[idx].datasize); fprintf(out, ",data="); _q_textout(out, tblslots[idx].data.ext.data, tblslots[idx].datasize, MAX_HUMANOUT); } else { fprintf(out, "%s", (tblslots[idx].count == COLLISION_MARK)?"COLISN":"NORMAL"); fprintf(out, ",next=%d", tblslots[idx].link); fprintf(out, ",count=%d", tblslots[idx].count); fprintf(out, ",hash=%u", tblslots[idx].hash); fprintf(out, ",namesize=%d", tblslots[idx].data.pair.namesize); fprintf(out, ",datasize=%d", tblslots[idx].datasize); fprintf(out, ",name="); _q_textout(out, tblslots[idx].data.pair.name, (tblslots[idx].data.pair.namesize>Q_HASHARR_NAMESIZE) ? Q_HASHARR_NAMESIZE : tblslots[idx].data.pair.namesize, MAX_HUMANOUT); fprintf(out, ",data="); _q_textout(out, tblslots[idx].data.pair.data, tblslots[idx].datasize, MAX_HUMANOUT); } fprintf(out, "\n"); } #endif return true; }
static bool put_data(qhasharr_t *tbl, int idx, uint32_t hash, const void *name, size_t namesize, const void *data, size_t datasize, int count) { qhasharr_data_t *tbldata = tbl->data; qhasharr_slot_t *tblslots = get_slots(tbl); assert(tblslots[idx].count == 0); unsigned char namemd5[16]; qhashmd5(name, namesize, namemd5); // store name tblslots[idx].count = count; tblslots[idx].hash = hash; memcpy(tblslots[idx].data.pair.name, name, (namesize < Q_HASHARR_NAMESIZE) ? namesize : Q_HASHARR_NAMESIZE); memcpy((char *) tblslots[idx].data.pair.namemd5, (char *) namemd5, 16); tblslots[idx].data.pair.namesize = namesize; tblslots[idx].link = -1; // store data int newidx; size_t savesize; for (newidx = idx, savesize = 0; savesize < datasize;) { if (savesize > 0) { // find next empty slot int tmpidx = find_avail(tbl, newidx + 1); if (tmpidx < 0) { remove_data(tbl, idx); errno = ENOBUFS; return false; } // clear & set memset((void *) (&tblslots[tmpidx]), '\0', sizeof(qhasharr_slot_t)); tblslots[tmpidx].count = EXTBLOCK_MARK; // extended data block tblslots[tmpidx].hash = newidx; // previous link tblslots[tmpidx].link = -1; // end block mark tblslots[tmpidx].datasize = 0; tblslots[newidx].link = tmpidx; // link chain newidx = tmpidx; } // copy data size_t copysize = datasize - savesize; if (tblslots[newidx].count == EXTBLOCK_MARK) { // extended value if (copysize > sizeof(struct Q_HASHARR_SLOT_EXT)) { copysize = sizeof(struct Q_HASHARR_SLOT_EXT); } memcpy(tblslots[newidx].data.ext.data, data + savesize, copysize); } else { // first slot if (copysize > Q_HASHARR_DATASIZE) { copysize = Q_HASHARR_DATASIZE; } memcpy(tblslots[newidx].data.pair.data, data + savesize, copysize); // increase stored key counter tbldata->num++; } tblslots[newidx].datasize = copysize; savesize += copysize; // increase used slot counter tbldata->usedslots++; } #ifdef QHASHARR_TIMESTAMP time(&tblslots[idx].timestamp); #endif return true; }