|
93 | 93 | REBSER *blk = Make_Block(size*2);
|
94 | 94 | REBSER *ser = 0;
|
95 | 95 |
|
96 |
| - ser = Make_Hash_Array(size); |
| 96 | + // Use hashing only when there is more then MIN_DICT keys. |
| 97 | + if (size > MIN_DICT) ser = Make_Hash_Array(size); |
97 | 98 |
|
98 | 99 | blk->series = ser;
|
99 | 100 |
|
|
124 | 125 | REBCNT n;
|
125 | 126 | REBVAL *val;
|
126 | 127 |
|
| 128 | + if (!hser) { |
| 129 | + // If there are no hashes for the keys, use plain linear search... |
| 130 | + hash = Find_Block_Key(series, key, wide, cased); |
| 131 | + if (hash == NOT_FOUND) { |
| 132 | + if (mode > 1) { |
| 133 | + // Append new value the target series: |
| 134 | + Append_Series(series, (REBYTE*)key, wide); |
| 135 | + } |
| 136 | + return -1; |
| 137 | + } |
| 138 | + return hash; |
| 139 | + } |
| 140 | + |
127 | 141 | // Compute hash for value:
|
128 | 142 | len = hser->tail;
|
129 | 143 | hash = Hash_Value(key, len);
|
|
214 | 228 | ** and val is SET, create the entry and store the key and
|
215 | 229 | ** val.
|
216 | 230 | **
|
217 |
| -** RETURNS: the index to the VALUE or zero if there is none. |
| 231 | +** RETURNS: the index to the VALUE or NOT_FOUND if there is none. |
218 | 232 | **
|
219 | 233 | ***********************************************************************/
|
220 | 234 | {
|
221 | 235 | REBSER *hser = series->series; // can be null
|
222 |
| - REBCNT *hashes; |
| 236 | + REBCNT *hashes = NULL; |
223 | 237 | REBCNT hash;
|
224 | 238 | REBCNT n;
|
225 | 239 | REBVAL *set;
|
226 | 240 |
|
227 |
| - if (IS_NONE(key) || hser == NULL) return 0; |
| 241 | + if (IS_NONE(key)) return NOT_FOUND; |
| 242 | + |
| 243 | + // We may not be large enough yet for the hash table to |
| 244 | + // be worthwhile, so just do a linear search: |
| 245 | + if (!hser) { |
| 246 | + if (series->tail <= MIN_DICT * 2) { |
| 247 | + hash = Find_Block_Key(series, key, 2, cased); |
| 248 | + if (hash != NOT_FOUND) { |
| 249 | + hash++; // position of the value |
| 250 | + // Key already exists so update the value, if needed... |
| 251 | + if (val) { |
| 252 | + set = BLK_SKIP(series, hash); |
| 253 | + *set = *val; |
| 254 | + } |
| 255 | + // Return |
| 256 | + return hash; |
| 257 | + } |
| 258 | + if (!val) return NOT_FOUND; |
| 259 | + hash /= 2; |
| 260 | + goto new_entry; |
| 261 | + } |
228 | 262 |
|
| 263 | + // Add hash table: |
| 264 | + //Print("hash added %d", series->tail); |
| 265 | + series->series = hser = Make_Hash_Array(series->tail); |
| 266 | + Rehash_Hash(series); |
| 267 | + } |
229 | 268 | // Get hash table, expand it if needed:
|
230 | 269 | if (series->tail > hser->tail/2) {
|
231 | 270 | Expand_Hash(hser); // modifies size value
|
|
237 | 276 | n = hashes[hash];
|
238 | 277 |
|
239 | 278 | // Just a GET of value:
|
240 |
| - if (!val) return n; |
| 279 | + if (!val) return ((n-1)*2)+1; |
241 | 280 |
|
242 | 281 | // Must set the value:
|
243 | 282 | if (n) { // re-set it:
|
244 |
| - set = BLK_SKIP(series, ((n-1)*2)); // find the key |
245 |
| - VAL_CLR_OPT(set++, OPTS_HIDE); // clear HIDE flag in case it was removed key; change to value position |
246 |
| - *set = *val; // set the value |
247 |
| - return n; |
| 283 | + n = (n-1)*2; // index of the key |
| 284 | + set = BLK_SKIP(series, n); // find the key |
| 285 | + VAL_CLR_OPT(set++, OPTS_HIDE); // clear HIDE flag in case it was removed key; change to value position |
| 286 | + *set = *val; // set the value |
| 287 | + return n+1; // index of the value |
248 | 288 | }
|
249 |
| - |
| 289 | +new_entry: |
250 | 290 | // Create new entry:
|
251 | 291 | #ifndef DO_NOT_NORMALIZE_MAP_KEYS
|
252 | 292 | // append key
|
|
275 | 315 | #endif
|
276 | 316 | // append value
|
277 | 317 | Append_Val(series, val); // no Copy_Series_Value(val) on strings
|
278 |
| - |
279 |
| - return (hashes[hash] = series->tail/2); |
| 318 | + if (hashes) hashes[hash] = series->tail / 2; // Hash index is not a real index position of the value! |
| 319 | + return series->tail; // Index of the new value. |
280 | 320 | }
|
281 | 321 |
|
282 | 322 |
|
|
320 | 360 |
|
321 | 361 | n = Find_Entry(VAL_SERIES(data), pvs->select, val, FALSE);
|
322 | 362 |
|
323 |
| - if (!n) return PE_NONE; |
| 363 | + if (n == NOT_FOUND) return PE_NONE; |
324 | 364 |
|
325 |
| - pvs->value = VAL_BLK_SKIP(data, ((n-1)*2)+1); |
| 365 | + pvs->value = VAL_BLK_SKIP(data, n); |
326 | 366 | return PE_OK;
|
327 | 367 | }
|
328 | 368 |
|
|
507 | 547 | case A_SELECT:
|
508 | 548 | case A_FIND:
|
509 | 549 | n = Find_Entry(series, arg, 0, Find_Refines(ds, AM_SELECT_CASE) ? AM_FIND_CASE : 0);
|
510 |
| - if (!n) return R_NONE; |
511 |
| - *D_RET = *VAL_BLK_SKIP(val, ((n-1)*2)+((action == A_FIND)?0:1)); |
| 550 | + if (n == NOT_FOUND) return R_NONE; |
| 551 | + *D_RET = *VAL_BLK_SKIP(val, n - ((action == A_FIND)?1:0)); // `find` returns the key |
512 | 552 | break;
|
513 | 553 |
|
514 | 554 | case A_INSERT:
|
|
534 | 574 | case A_REMOVE:
|
535 | 575 | //O: throw an error if /part is used?
|
536 | 576 | n = Find_Entry(series, D_ARG(ARG_REMOVE_KEY_ARG), 0, TRUE);
|
537 |
| - if (n) { |
538 |
| - n = (n-1)*2; |
539 |
| - VAL_SET_OPT(VAL_BLK_SKIP(val, n), OPTS_HIDE); |
540 |
| - VAL_SET(VAL_BLK_SKIP(val, n+1), REB_NONE); // set value to none (so the old one may be GCed) |
| 577 | + if (n != NOT_FOUND) { |
| 578 | + VAL_SET_OPT(VAL_BLK_SKIP(val, n-1), OPTS_HIDE); // hide the key |
| 579 | + VAL_SET(VAL_BLK_SKIP(val, n), REB_NONE); // set value to none (so the old one may be GCed) |
541 | 580 | }
|
542 | 581 | return R_ARG1;
|
543 | 582 |
|
|
0 commit comments