Commit | Line | Data |
a0d0e21e |
1 | /* hv.c |
79072805 |
2 | * |
a0d0e21e |
3 | * Copyright (c) 1991-1994, Larry Wall |
79072805 |
4 | * |
5 | * You may distribute under the terms of either the GNU General Public |
6 | * License or the Artistic License, as specified in the README file. |
7 | * |
a0d0e21e |
8 | */ |
9 | |
10 | /* |
11 | * "I sit beside the fire and think of all that I have seen." --Bilbo |
79072805 |
12 | */ |
13 | |
14 | #include "EXTERN.h" |
15 | #include "perl.h" |
16 | |
a0d0e21e |
17 | static void hsplit _((HV *hv)); |
18 | static void hfreeentries _((HV *hv)); |
79072805 |
19 | |
4633a7c4 |
20 | static HE* more_he(); |
21 | |
22 | static HE* |
23 | new_he() |
24 | { |
25 | HE* he; |
26 | if (he_root) { |
27 | he = he_root; |
fde52b5c |
28 | he_root = HeNEXT(he); |
4633a7c4 |
29 | return he; |
30 | } |
31 | return more_he(); |
32 | } |
33 | |
34 | static void |
35 | del_he(p) |
36 | HE* p; |
37 | { |
fde52b5c |
38 | HeNEXT(p) = (HE*)he_root; |
4633a7c4 |
39 | he_root = p; |
40 | } |
41 | |
42 | static HE* |
43 | more_he() |
44 | { |
45 | register HE* he; |
46 | register HE* heend; |
47 | he_root = (HE*)safemalloc(1008); |
48 | he = he_root; |
49 | heend = &he[1008 / sizeof(HE) - 1]; |
50 | while (he < heend) { |
fde52b5c |
51 | HeNEXT(he) = (HE*)(he + 1); |
4633a7c4 |
52 | he++; |
53 | } |
fde52b5c |
54 | HeNEXT(he) = 0; |
4633a7c4 |
55 | return new_he(); |
56 | } |
57 | |
fde52b5c |
58 | /* (klen == HEf_SVKEY) is special for MAGICAL hv entries, meaning key slot |
59 | * contains an SV* */ |
60 | |
79072805 |
61 | SV** |
62 | hv_fetch(hv,key,klen,lval) |
63 | HV *hv; |
64 | char *key; |
65 | U32 klen; |
66 | I32 lval; |
67 | { |
68 | register XPVHV* xhv; |
fde52b5c |
69 | register U32 hash; |
79072805 |
70 | register HE *entry; |
79072805 |
71 | SV *sv; |
79072805 |
72 | |
73 | if (!hv) |
74 | return 0; |
463ee0b2 |
75 | |
8990e307 |
76 | if (SvRMAGICAL(hv)) { |
463ee0b2 |
77 | if (mg_find((SV*)hv,'P')) { |
8990e307 |
78 | sv = sv_newmortal(); |
463ee0b2 |
79 | mg_copy((SV*)hv, sv, key, klen); |
463ee0b2 |
80 | Sv = sv; |
81 | return &Sv; |
82 | } |
83 | } |
84 | |
79072805 |
85 | xhv = (XPVHV*)SvANY(hv); |
86 | if (!xhv->xhv_array) { |
a0d0e21e |
87 | if (lval |
88 | #ifdef DYNAMIC_ENV_FETCH /* if it's an %ENV lookup, we may get it on the fly */ |
89 | || (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME)) |
90 | #endif |
91 | ) |
463ee0b2 |
92 | Newz(503,xhv->xhv_array, sizeof(HE*) * (xhv->xhv_max + 1), char); |
79072805 |
93 | else |
94 | return 0; |
95 | } |
96 | |
fde52b5c |
97 | PERL_HASH(hash, key, klen); |
79072805 |
98 | |
a0d0e21e |
99 | entry = ((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max]; |
fde52b5c |
100 | for (; entry; entry = HeNEXT(entry)) { |
101 | if (HeHASH(entry) != hash) /* strings can't be equal */ |
79072805 |
102 | continue; |
fde52b5c |
103 | if (HeKLEN(entry) != klen) |
79072805 |
104 | continue; |
fde52b5c |
105 | if (bcmp(HeKEY(entry),key,klen)) /* is this it? */ |
79072805 |
106 | continue; |
fde52b5c |
107 | return &HeVAL(entry); |
79072805 |
108 | } |
a0d0e21e |
109 | #ifdef DYNAMIC_ENV_FETCH /* %ENV lookup? If so, try to fetch the value now */ |
110 | if (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME)) { |
111 | char *gotenv; |
112 | |
113 | gotenv = my_getenv(key); |
114 | if (gotenv != NULL) { |
115 | sv = newSVpv(gotenv,strlen(gotenv)); |
116 | return hv_store(hv,key,klen,sv,hash); |
117 | } |
118 | } |
119 | #endif |
79072805 |
120 | if (lval) { /* gonna assign to this, so it better be there */ |
121 | sv = NEWSV(61,0); |
122 | return hv_store(hv,key,klen,sv,hash); |
123 | } |
124 | return 0; |
125 | } |
126 | |
fde52b5c |
127 | /* returns a HE * structure with the all fields set */ |
128 | /* note that hent_val will be a mortal sv for MAGICAL hashes */ |
129 | HE * |
130 | hv_fetch_ent(hv,keysv,lval,hash) |
131 | HV *hv; |
132 | SV *keysv; |
133 | I32 lval; |
134 | register U32 hash; |
135 | { |
136 | register XPVHV* xhv; |
137 | register char *key; |
138 | STRLEN klen; |
139 | register HE *entry; |
140 | SV *sv; |
141 | |
142 | if (!hv) |
143 | return 0; |
144 | |
145 | xhv = (XPVHV*)SvANY(hv); |
146 | |
147 | if (SvRMAGICAL(hv) && mg_find((SV*)hv,'P')) { |
148 | if (!(entry = xhv->xhv_eiter)) { |
149 | xhv->xhv_eiter = entry = new_he(); /* only one HE per MAGICAL hash */ |
150 | Zero(entry, 1, HE); |
151 | HeKLEN(entry) = HEf_SVKEY; /* hent_key is holding an SV* */ |
152 | } |
153 | else if ((sv = HeSVKEY(entry))) |
154 | SvREFCNT_dec(sv); |
155 | sv = sv_newmortal(); |
156 | mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY); |
157 | HeVAL(entry) = sv; |
158 | HeKEY(entry) = (char*)SvREFCNT_inc(keysv); |
159 | return entry; |
160 | } |
161 | |
162 | key = SvPV(keysv, klen); |
163 | |
164 | if (!hash) |
165 | PERL_HASH(hash, key, klen); |
166 | |
167 | if (!xhv->xhv_array) { |
168 | if (lval |
169 | #ifdef DYNAMIC_ENV_FETCH /* if it's an %ENV lookup, we may get it on the fly */ |
170 | || (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME)) |
171 | #endif |
172 | ) |
173 | Newz(503,xhv->xhv_array, sizeof(HE*) * (xhv->xhv_max + 1), char); |
174 | else |
175 | return 0; |
176 | } |
177 | |
178 | entry = ((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max]; |
179 | for (; entry; entry = HeNEXT(entry)) { |
180 | if (HeHASH(entry) != hash) /* strings can't be equal */ |
181 | continue; |
182 | if (HeKLEN(entry) != klen) |
183 | continue; |
184 | if (bcmp(HeKEY(entry),key,klen)) /* is this it? */ |
185 | continue; |
186 | return entry; |
187 | } |
188 | #ifdef DYNAMIC_ENV_FETCH /* %ENV lookup? If so, try to fetch the value now */ |
189 | if (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME)) { |
190 | char *gotenv; |
191 | |
192 | gotenv = my_getenv(key); |
193 | if (gotenv != NULL) { |
194 | sv = newSVpv(gotenv,strlen(gotenv)); |
195 | return hv_store_ent(hv,keysv,sv,hash); |
196 | } |
197 | } |
198 | #endif |
199 | if (lval) { /* gonna assign to this, so it better be there */ |
200 | sv = NEWSV(61,0); |
201 | return hv_store_ent(hv,keysv,sv,hash); |
202 | } |
203 | return 0; |
204 | } |
205 | |
79072805 |
206 | SV** |
207 | hv_store(hv,key,klen,val,hash) |
208 | HV *hv; |
209 | char *key; |
210 | U32 klen; |
211 | SV *val; |
93a17b20 |
212 | register U32 hash; |
79072805 |
213 | { |
214 | register XPVHV* xhv; |
79072805 |
215 | register I32 i; |
216 | register HE *entry; |
217 | register HE **oentry; |
79072805 |
218 | |
219 | if (!hv) |
220 | return 0; |
221 | |
222 | xhv = (XPVHV*)SvANY(hv); |
463ee0b2 |
223 | if (SvMAGICAL(hv)) { |
463ee0b2 |
224 | mg_copy((SV*)hv, val, key, klen); |
a0d0e21e |
225 | #ifndef OVERLOAD |
463ee0b2 |
226 | if (!xhv->xhv_array) |
227 | return 0; |
a0d0e21e |
228 | #else |
229 | if (!xhv->xhv_array && (SvMAGIC(hv)->mg_type != 'A' |
230 | || SvMAGIC(hv)->mg_moremagic)) |
231 | return 0; |
232 | #endif /* OVERLOAD */ |
463ee0b2 |
233 | } |
fde52b5c |
234 | if (!hash) |
235 | PERL_HASH(hash, key, klen); |
236 | |
237 | if (!xhv->xhv_array) |
238 | Newz(505, xhv->xhv_array, sizeof(HE**) * (xhv->xhv_max + 1), char); |
239 | |
240 | oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max]; |
241 | i = 1; |
242 | |
243 | for (entry = *oentry; entry; i=0, entry = HeNEXT(entry)) { |
244 | if (HeHASH(entry) != hash) /* strings can't be equal */ |
245 | continue; |
246 | if (HeKLEN(entry) != klen) |
247 | continue; |
248 | if (bcmp(HeKEY(entry),key,klen)) /* is this it? */ |
249 | continue; |
250 | SvREFCNT_dec(HeVAL(entry)); |
251 | HeVAL(entry) = val; |
252 | return &HeVAL(entry); |
253 | } |
254 | |
255 | entry = new_he(); |
256 | HeKLEN(entry) = klen; |
257 | if (HvSHAREKEYS(hv)) |
258 | HeKEY(entry) = sharepvn(key, klen, hash); |
259 | else /* gotta do the real thing */ |
260 | HeKEY(entry) = savepvn(key,klen); |
261 | HeVAL(entry) = val; |
262 | HeHASH(entry) = hash; |
263 | HeNEXT(entry) = *oentry; |
264 | *oentry = entry; |
265 | |
266 | xhv->xhv_keys++; |
267 | if (i) { /* initial entry? */ |
268 | ++xhv->xhv_fill; |
269 | if (xhv->xhv_keys > xhv->xhv_max) |
270 | hsplit(hv); |
79072805 |
271 | } |
272 | |
fde52b5c |
273 | return &HeVAL(entry); |
274 | } |
275 | |
276 | HE * |
277 | hv_store_ent(hv,keysv,val,hash) |
278 | HV *hv; |
279 | SV *keysv; |
280 | SV *val; |
281 | register U32 hash; |
282 | { |
283 | register XPVHV* xhv; |
284 | register char *key; |
285 | STRLEN klen; |
286 | register I32 i; |
287 | register HE *entry; |
288 | register HE **oentry; |
289 | |
290 | if (!hv) |
291 | return 0; |
292 | |
293 | xhv = (XPVHV*)SvANY(hv); |
294 | if (SvMAGICAL(hv)) { |
295 | mg_copy((SV*)hv, val, (char*)keysv, HEf_SVKEY); |
296 | #ifndef OVERLOAD |
297 | if (!xhv->xhv_array) |
298 | return Nullhe; |
299 | #else |
300 | if (!xhv->xhv_array && (SvMAGIC(hv)->mg_type != 'A' |
301 | || SvMAGIC(hv)->mg_moremagic)) |
302 | return Nullhe; |
303 | #endif /* OVERLOAD */ |
304 | } |
305 | |
306 | key = SvPV(keysv, klen); |
307 | |
308 | if (!hash) |
309 | PERL_HASH(hash, key, klen); |
310 | |
79072805 |
311 | if (!xhv->xhv_array) |
463ee0b2 |
312 | Newz(505, xhv->xhv_array, sizeof(HE**) * (xhv->xhv_max + 1), char); |
79072805 |
313 | |
a0d0e21e |
314 | oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max]; |
79072805 |
315 | i = 1; |
316 | |
fde52b5c |
317 | for (entry = *oentry; entry; i=0, entry = HeNEXT(entry)) { |
318 | if (HeHASH(entry) != hash) /* strings can't be equal */ |
79072805 |
319 | continue; |
fde52b5c |
320 | if (HeKLEN(entry) != klen) |
79072805 |
321 | continue; |
fde52b5c |
322 | if (bcmp(HeKEY(entry),key,klen)) /* is this it? */ |
79072805 |
323 | continue; |
fde52b5c |
324 | SvREFCNT_dec(HeVAL(entry)); |
325 | HeVAL(entry) = val; |
326 | return entry; |
79072805 |
327 | } |
79072805 |
328 | |
4633a7c4 |
329 | entry = new_he(); |
fde52b5c |
330 | HeKLEN(entry) = klen; |
331 | if (HvSHAREKEYS(hv)) |
332 | HeKEY(entry) = sharepvn(key, klen, hash); |
333 | else /* gotta do the real thing */ |
334 | HeKEY(entry) = savepvn(key,klen); |
335 | HeVAL(entry) = val; |
336 | HeHASH(entry) = hash; |
337 | HeNEXT(entry) = *oentry; |
79072805 |
338 | *oentry = entry; |
339 | |
463ee0b2 |
340 | xhv->xhv_keys++; |
79072805 |
341 | if (i) { /* initial entry? */ |
463ee0b2 |
342 | ++xhv->xhv_fill; |
343 | if (xhv->xhv_keys > xhv->xhv_max) |
79072805 |
344 | hsplit(hv); |
345 | } |
79072805 |
346 | |
fde52b5c |
347 | return entry; |
79072805 |
348 | } |
349 | |
350 | SV * |
748a9306 |
351 | hv_delete(hv,key,klen,flags) |
79072805 |
352 | HV *hv; |
353 | char *key; |
354 | U32 klen; |
748a9306 |
355 | I32 flags; |
79072805 |
356 | { |
357 | register XPVHV* xhv; |
79072805 |
358 | register I32 i; |
fde52b5c |
359 | register U32 hash; |
79072805 |
360 | register HE *entry; |
361 | register HE **oentry; |
362 | SV *sv; |
79072805 |
363 | |
364 | if (!hv) |
365 | return Nullsv; |
8990e307 |
366 | if (SvRMAGICAL(hv)) { |
463ee0b2 |
367 | sv = *hv_fetch(hv, key, klen, TRUE); |
368 | mg_clear(sv); |
fde52b5c |
369 | if (mg_find(sv, 's')) { |
370 | return Nullsv; /* %SIG elements cannot be deleted */ |
371 | } |
a0d0e21e |
372 | if (mg_find(sv, 'p')) { |
373 | sv_unmagic(sv, 'p'); /* No longer an element */ |
374 | return sv; |
375 | } |
463ee0b2 |
376 | } |
79072805 |
377 | xhv = (XPVHV*)SvANY(hv); |
378 | if (!xhv->xhv_array) |
379 | return Nullsv; |
fde52b5c |
380 | |
381 | PERL_HASH(hash, key, klen); |
79072805 |
382 | |
a0d0e21e |
383 | oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max]; |
79072805 |
384 | entry = *oentry; |
385 | i = 1; |
fde52b5c |
386 | for (; entry; i=0, oentry = &HeNEXT(entry), entry = *oentry) { |
387 | if (HeHASH(entry) != hash) /* strings can't be equal */ |
79072805 |
388 | continue; |
fde52b5c |
389 | if (HeKLEN(entry) != klen) |
79072805 |
390 | continue; |
fde52b5c |
391 | if (bcmp(HeKEY(entry),key,klen)) /* is this it? */ |
79072805 |
392 | continue; |
fde52b5c |
393 | *oentry = HeNEXT(entry); |
79072805 |
394 | if (i && !*oentry) |
395 | xhv->xhv_fill--; |
748a9306 |
396 | if (flags & G_DISCARD) |
397 | sv = Nullsv; |
398 | else |
fde52b5c |
399 | sv = sv_mortalcopy(HeVAL(entry)); |
a0d0e21e |
400 | if (entry == xhv->xhv_eiter) |
fde52b5c |
401 | HeKLEN(entry) = HEf_LAZYDEL; |
a0d0e21e |
402 | else |
fde52b5c |
403 | he_free(entry, HvSHAREKEYS(hv)); |
404 | --xhv->xhv_keys; |
405 | return sv; |
406 | } |
407 | return Nullsv; |
408 | } |
409 | |
410 | SV * |
411 | hv_delete_ent(hv,keysv,flags,hash) |
412 | HV *hv; |
413 | SV *keysv; |
414 | I32 flags; |
415 | U32 hash; |
416 | { |
417 | register XPVHV* xhv; |
418 | register I32 i; |
419 | register char *key; |
420 | STRLEN klen; |
421 | register HE *entry; |
422 | register HE **oentry; |
423 | SV *sv; |
424 | |
425 | if (!hv) |
426 | return Nullsv; |
427 | if (SvRMAGICAL(hv)) { |
428 | entry = hv_fetch_ent(hv, keysv, TRUE, hash); |
429 | sv = HeVAL(entry); |
430 | mg_clear(sv); |
431 | if (mg_find(sv, 'p')) { |
432 | sv_unmagic(sv, 'p'); /* No longer an element */ |
433 | return sv; |
434 | } |
435 | } |
436 | xhv = (XPVHV*)SvANY(hv); |
437 | if (!xhv->xhv_array) |
438 | return Nullsv; |
439 | |
440 | key = SvPV(keysv, klen); |
441 | |
442 | if (!hash) |
443 | PERL_HASH(hash, key, klen); |
444 | |
445 | oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max]; |
446 | entry = *oentry; |
447 | i = 1; |
448 | for (; entry; i=0, oentry = &HeNEXT(entry), entry = *oentry) { |
449 | if (HeHASH(entry) != hash) /* strings can't be equal */ |
450 | continue; |
451 | if (HeKLEN(entry) != klen) |
452 | continue; |
453 | if (bcmp(HeKEY(entry),key,klen)) /* is this it? */ |
454 | continue; |
455 | *oentry = HeNEXT(entry); |
456 | if (i && !*oentry) |
457 | xhv->xhv_fill--; |
458 | if (flags & G_DISCARD) |
459 | sv = Nullsv; |
460 | else |
461 | sv = sv_mortalcopy(HeVAL(entry)); |
462 | if (entry == xhv->xhv_eiter) |
463 | HeKLEN(entry) = HEf_LAZYDEL; |
464 | else |
465 | he_free(entry, HvSHAREKEYS(hv)); |
463ee0b2 |
466 | --xhv->xhv_keys; |
79072805 |
467 | return sv; |
468 | } |
79072805 |
469 | return Nullsv; |
79072805 |
470 | } |
471 | |
a0d0e21e |
472 | bool |
473 | hv_exists(hv,key,klen) |
474 | HV *hv; |
475 | char *key; |
476 | U32 klen; |
477 | { |
478 | register XPVHV* xhv; |
fde52b5c |
479 | register U32 hash; |
a0d0e21e |
480 | register HE *entry; |
481 | SV *sv; |
482 | |
483 | if (!hv) |
484 | return 0; |
485 | |
486 | if (SvRMAGICAL(hv)) { |
487 | if (mg_find((SV*)hv,'P')) { |
488 | sv = sv_newmortal(); |
489 | mg_copy((SV*)hv, sv, key, klen); |
490 | magic_existspack(sv, mg_find(sv, 'p')); |
491 | return SvTRUE(sv); |
492 | } |
493 | } |
494 | |
495 | xhv = (XPVHV*)SvANY(hv); |
496 | if (!xhv->xhv_array) |
497 | return 0; |
498 | |
fde52b5c |
499 | PERL_HASH(hash, key, klen); |
a0d0e21e |
500 | |
501 | entry = ((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max]; |
fde52b5c |
502 | for (; entry; entry = HeNEXT(entry)) { |
503 | if (HeHASH(entry) != hash) /* strings can't be equal */ |
a0d0e21e |
504 | continue; |
fde52b5c |
505 | if (HeKLEN(entry) != klen) |
a0d0e21e |
506 | continue; |
fde52b5c |
507 | if (bcmp(HeKEY(entry),key,klen)) /* is this it? */ |
508 | continue; |
509 | return TRUE; |
510 | } |
511 | return FALSE; |
512 | } |
513 | |
514 | |
515 | bool |
516 | hv_exists_ent(hv,keysv,hash) |
517 | HV *hv; |
518 | SV *keysv; |
519 | U32 hash; |
520 | { |
521 | register XPVHV* xhv; |
522 | register char *key; |
523 | STRLEN klen; |
524 | register HE *entry; |
525 | SV *sv; |
526 | |
527 | if (!hv) |
528 | return 0; |
529 | |
530 | if (SvRMAGICAL(hv)) { |
531 | if (mg_find((SV*)hv,'P')) { |
532 | sv = sv_newmortal(); |
533 | mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY); |
534 | magic_existspack(sv, mg_find(sv, 'p')); |
535 | return SvTRUE(sv); |
536 | } |
537 | } |
538 | |
539 | xhv = (XPVHV*)SvANY(hv); |
540 | if (!xhv->xhv_array) |
541 | return 0; |
542 | |
543 | key = SvPV(keysv, klen); |
544 | if (!hash) |
545 | PERL_HASH(hash, key, klen); |
546 | |
547 | entry = ((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max]; |
548 | for (; entry; entry = HeNEXT(entry)) { |
549 | if (HeHASH(entry) != hash) /* strings can't be equal */ |
550 | continue; |
551 | if (HeKLEN(entry) != klen) |
552 | continue; |
553 | if (bcmp(HeKEY(entry),key,klen)) /* is this it? */ |
a0d0e21e |
554 | continue; |
555 | return TRUE; |
556 | } |
557 | return FALSE; |
558 | } |
559 | |
79072805 |
560 | static void |
561 | hsplit(hv) |
562 | HV *hv; |
563 | { |
564 | register XPVHV* xhv = (XPVHV*)SvANY(hv); |
a0d0e21e |
565 | I32 oldsize = (I32) xhv->xhv_max + 1; /* sic(k) */ |
79072805 |
566 | register I32 newsize = oldsize * 2; |
567 | register I32 i; |
568 | register HE **a; |
569 | register HE **b; |
570 | register HE *entry; |
571 | register HE **oentry; |
c07a80fd |
572 | #ifndef STRANGE_MALLOC |
4633a7c4 |
573 | I32 tmp; |
c07a80fd |
574 | #endif |
79072805 |
575 | |
463ee0b2 |
576 | a = (HE**)xhv->xhv_array; |
79072805 |
577 | nomemok = TRUE; |
4633a7c4 |
578 | #ifdef STRANGE_MALLOC |
79072805 |
579 | Renew(a, newsize, HE*); |
4633a7c4 |
580 | #else |
581 | i = newsize * sizeof(HE*); |
582 | #define MALLOC_OVERHEAD 16 |
583 | tmp = MALLOC_OVERHEAD; |
584 | while (tmp - MALLOC_OVERHEAD < i) |
585 | tmp += tmp; |
586 | tmp -= MALLOC_OVERHEAD; |
587 | tmp /= sizeof(HE*); |
588 | assert(tmp >= newsize); |
589 | New(2,a, tmp, HE*); |
590 | Copy(xhv->xhv_array, a, oldsize, HE*); |
c07a80fd |
591 | if (oldsize >= 64 && !nice_chunk) { |
592 | nice_chunk = (char*)xhv->xhv_array; |
593 | nice_chunk_size = oldsize * sizeof(HE*) * 2 - MALLOC_OVERHEAD; |
4633a7c4 |
594 | } |
595 | else |
596 | Safefree(xhv->xhv_array); |
597 | #endif |
598 | |
79072805 |
599 | nomemok = FALSE; |
79072805 |
600 | Zero(&a[oldsize], oldsize, HE*); /* zero 2nd half*/ |
601 | xhv->xhv_max = --newsize; |
463ee0b2 |
602 | xhv->xhv_array = (char*)a; |
79072805 |
603 | |
604 | for (i=0; i<oldsize; i++,a++) { |
605 | if (!*a) /* non-existent */ |
606 | continue; |
607 | b = a+oldsize; |
608 | for (oentry = a, entry = *a; entry; entry = *oentry) { |
fde52b5c |
609 | if ((HeHASH(entry) & newsize) != i) { |
610 | *oentry = HeNEXT(entry); |
611 | HeNEXT(entry) = *b; |
79072805 |
612 | if (!*b) |
613 | xhv->xhv_fill++; |
614 | *b = entry; |
615 | continue; |
616 | } |
617 | else |
fde52b5c |
618 | oentry = &HeNEXT(entry); |
79072805 |
619 | } |
620 | if (!*a) /* everything moved */ |
621 | xhv->xhv_fill--; |
622 | } |
623 | } |
624 | |
625 | HV * |
463ee0b2 |
626 | newHV() |
79072805 |
627 | { |
628 | register HV *hv; |
629 | register XPVHV* xhv; |
630 | |
a0d0e21e |
631 | hv = (HV*)NEWSV(502,0); |
632 | sv_upgrade((SV *)hv, SVt_PVHV); |
79072805 |
633 | xhv = (XPVHV*)SvANY(hv); |
634 | SvPOK_off(hv); |
635 | SvNOK_off(hv); |
fde52b5c |
636 | #ifndef NODEFAULT_SHAREKEYS |
637 | HvSHAREKEYS_on(hv); /* key-sharing on by default */ |
638 | #endif |
463ee0b2 |
639 | xhv->xhv_max = 7; /* start with 8 buckets */ |
79072805 |
640 | xhv->xhv_fill = 0; |
641 | xhv->xhv_pmroot = 0; |
79072805 |
642 | (void)hv_iterinit(hv); /* so each() will start off right */ |
643 | return hv; |
644 | } |
645 | |
646 | void |
fde52b5c |
647 | he_free(hent, shared) |
79072805 |
648 | register HE *hent; |
fde52b5c |
649 | I32 shared; |
79072805 |
650 | { |
651 | if (!hent) |
652 | return; |
fde52b5c |
653 | SvREFCNT_dec(HeVAL(hent)); |
654 | if (HeKLEN(hent) == HEf_SVKEY) |
655 | SvREFCNT_dec((SV*)HeKEY(hent)); |
656 | else if (shared) |
657 | unsharepvn(HeKEY(hent), HeKLEN(hent), HeHASH(hent)); |
658 | else |
659 | Safefree(HeKEY(hent)); |
4633a7c4 |
660 | del_he(hent); |
79072805 |
661 | } |
662 | |
663 | void |
fde52b5c |
664 | he_delayfree(hent, shared) |
79072805 |
665 | register HE *hent; |
fde52b5c |
666 | I32 shared; |
79072805 |
667 | { |
668 | if (!hent) |
669 | return; |
fde52b5c |
670 | sv_2mortal(HeVAL(hent)); /* free between statements */ |
671 | if (HeKLEN(hent) == HEf_SVKEY) |
672 | sv_2mortal((SV*)HeKEY(hent)); |
673 | else if (shared) |
674 | unsharepvn(HeKEY(hent), HeKLEN(hent), HeHASH(hent)); |
675 | else |
676 | Safefree(HeKEY(hent)); |
4633a7c4 |
677 | del_he(hent); |
79072805 |
678 | } |
679 | |
680 | void |
463ee0b2 |
681 | hv_clear(hv) |
79072805 |
682 | HV *hv; |
79072805 |
683 | { |
684 | register XPVHV* xhv; |
685 | if (!hv) |
686 | return; |
687 | xhv = (XPVHV*)SvANY(hv); |
463ee0b2 |
688 | hfreeentries(hv); |
79072805 |
689 | xhv->xhv_fill = 0; |
a0d0e21e |
690 | xhv->xhv_keys = 0; |
79072805 |
691 | if (xhv->xhv_array) |
463ee0b2 |
692 | (void)memzero(xhv->xhv_array, (xhv->xhv_max + 1) * sizeof(HE*)); |
a0d0e21e |
693 | |
694 | if (SvRMAGICAL(hv)) |
695 | mg_clear((SV*)hv); |
79072805 |
696 | } |
697 | |
698 | static void |
463ee0b2 |
699 | hfreeentries(hv) |
79072805 |
700 | HV *hv; |
79072805 |
701 | { |
a0d0e21e |
702 | register HE **array; |
79072805 |
703 | register HE *hent; |
704 | register HE *ohent = Null(HE*); |
a0d0e21e |
705 | I32 riter; |
706 | I32 max; |
fde52b5c |
707 | I32 shared; |
79072805 |
708 | |
709 | if (!hv) |
710 | return; |
a0d0e21e |
711 | if (!HvARRAY(hv)) |
79072805 |
712 | return; |
a0d0e21e |
713 | |
714 | riter = 0; |
715 | max = HvMAX(hv); |
716 | array = HvARRAY(hv); |
717 | hent = array[0]; |
fde52b5c |
718 | shared = HvSHAREKEYS(hv); |
a0d0e21e |
719 | for (;;) { |
720 | if (hent) { |
721 | ohent = hent; |
fde52b5c |
722 | hent = HeNEXT(hent); |
723 | he_free(ohent, shared); |
a0d0e21e |
724 | } |
725 | if (!hent) { |
726 | if (++riter > max) |
727 | break; |
728 | hent = array[riter]; |
729 | } |
79072805 |
730 | } |
a0d0e21e |
731 | (void)hv_iterinit(hv); |
79072805 |
732 | } |
733 | |
734 | void |
463ee0b2 |
735 | hv_undef(hv) |
79072805 |
736 | HV *hv; |
79072805 |
737 | { |
738 | register XPVHV* xhv; |
739 | if (!hv) |
740 | return; |
741 | xhv = (XPVHV*)SvANY(hv); |
463ee0b2 |
742 | hfreeentries(hv); |
79072805 |
743 | Safefree(xhv->xhv_array); |
85e6fe83 |
744 | if (HvNAME(hv)) { |
745 | Safefree(HvNAME(hv)); |
746 | HvNAME(hv) = 0; |
747 | } |
79072805 |
748 | xhv->xhv_array = 0; |
463ee0b2 |
749 | xhv->xhv_max = 7; /* it's a normal associative array */ |
79072805 |
750 | xhv->xhv_fill = 0; |
a0d0e21e |
751 | xhv->xhv_keys = 0; |
752 | |
753 | if (SvRMAGICAL(hv)) |
754 | mg_clear((SV*)hv); |
79072805 |
755 | } |
756 | |
79072805 |
757 | I32 |
758 | hv_iterinit(hv) |
759 | HV *hv; |
760 | { |
761 | register XPVHV* xhv = (XPVHV*)SvANY(hv); |
a0d0e21e |
762 | HE *entry = xhv->xhv_eiter; |
fde52b5c |
763 | if (entry && HeKLEN(entry) == HEf_LAZYDEL) /* was deleted earlier? */ |
764 | he_free(entry, HvSHAREKEYS(hv)); |
79072805 |
765 | xhv->xhv_riter = -1; |
766 | xhv->xhv_eiter = Null(HE*); |
767 | return xhv->xhv_fill; |
768 | } |
769 | |
770 | HE * |
771 | hv_iternext(hv) |
772 | HV *hv; |
773 | { |
774 | register XPVHV* xhv; |
775 | register HE *entry; |
a0d0e21e |
776 | HE *oldentry; |
463ee0b2 |
777 | MAGIC* mg; |
79072805 |
778 | |
779 | if (!hv) |
463ee0b2 |
780 | croak("Bad associative array"); |
79072805 |
781 | xhv = (XPVHV*)SvANY(hv); |
a0d0e21e |
782 | oldentry = entry = xhv->xhv_eiter; |
463ee0b2 |
783 | |
8990e307 |
784 | if (SvRMAGICAL(hv) && (mg = mg_find((SV*)hv,'P'))) { |
785 | SV *key = sv_newmortal(); |
fde52b5c |
786 | if (entry) |
787 | sv_setsv(key, HeSVKEY_force(entry)); |
a0d0e21e |
788 | else { |
fde52b5c |
789 | xhv->xhv_eiter = entry = new_he(); /* only one HE per MAGICAL hash */ |
4633a7c4 |
790 | Zero(entry, 1, HE); |
fde52b5c |
791 | HeKLEN(entry) = HEf_SVKEY; |
a0d0e21e |
792 | } |
793 | magic_nextpack((SV*) hv,mg,key); |
463ee0b2 |
794 | if (SvOK(key)) { |
fde52b5c |
795 | SvREFCNT_dec(HeSVKEY(entry)); |
796 | HeKEY(entry) = (char*)SvREFCNT_inc(key); |
797 | return entry; /* beware, hent_val is not set */ |
463ee0b2 |
798 | } |
fde52b5c |
799 | if (HeVAL(entry)) |
800 | SvREFCNT_dec(HeVAL(entry)); |
4633a7c4 |
801 | del_he(entry); |
463ee0b2 |
802 | xhv->xhv_eiter = Null(HE*); |
803 | return Null(HE*); |
79072805 |
804 | } |
463ee0b2 |
805 | |
79072805 |
806 | if (!xhv->xhv_array) |
4633a7c4 |
807 | Newz(506,xhv->xhv_array, sizeof(HE*) * (xhv->xhv_max + 1), char); |
fde52b5c |
808 | if (entry) |
809 | entry = HeNEXT(entry); |
810 | while (!entry) { |
811 | ++xhv->xhv_riter; |
812 | if (xhv->xhv_riter > xhv->xhv_max) { |
813 | xhv->xhv_riter = -1; |
814 | break; |
79072805 |
815 | } |
fde52b5c |
816 | entry = ((HE**)xhv->xhv_array)[xhv->xhv_riter]; |
817 | } |
79072805 |
818 | |
fde52b5c |
819 | if (oldentry && HeKLEN(oldentry) == HEf_LAZYDEL) /* was deleted earlier? */ |
820 | he_free(oldentry, HvSHAREKEYS(hv)); |
a0d0e21e |
821 | |
79072805 |
822 | xhv->xhv_eiter = entry; |
823 | return entry; |
824 | } |
825 | |
826 | char * |
827 | hv_iterkey(entry,retlen) |
828 | register HE *entry; |
829 | I32 *retlen; |
830 | { |
fde52b5c |
831 | if (HeKLEN(entry) == HEf_SVKEY) { |
832 | return SvPV((SV*)HeKEY(entry), *(STRLEN*)retlen); |
833 | } |
834 | else { |
835 | *retlen = HeKLEN(entry); |
836 | return HeKEY(entry); |
837 | } |
838 | } |
839 | |
840 | /* unlike hv_iterval(), this always returns a mortal copy of the key */ |
841 | SV * |
842 | hv_iterkeysv(entry) |
843 | register HE *entry; |
844 | { |
845 | if (HeKLEN(entry) == HEf_SVKEY) |
846 | return sv_mortalcopy((SV*)HeKEY(entry)); |
847 | else |
848 | return sv_2mortal(newSVpv((HeKLEN(entry) ? HeKEY(entry) : ""), |
849 | HeKLEN(entry))); |
79072805 |
850 | } |
851 | |
852 | SV * |
853 | hv_iterval(hv,entry) |
854 | HV *hv; |
855 | register HE *entry; |
856 | { |
8990e307 |
857 | if (SvRMAGICAL(hv)) { |
463ee0b2 |
858 | if (mg_find((SV*)hv,'P')) { |
8990e307 |
859 | SV* sv = sv_newmortal(); |
fde52b5c |
860 | mg_copy((SV*)hv, sv, HeKEY(entry), HeKLEN(entry)); |
463ee0b2 |
861 | return sv; |
862 | } |
79072805 |
863 | } |
fde52b5c |
864 | return HeVAL(entry); |
79072805 |
865 | } |
866 | |
a0d0e21e |
867 | SV * |
868 | hv_iternextsv(hv, key, retlen) |
869 | HV *hv; |
870 | char **key; |
871 | I32 *retlen; |
872 | { |
873 | HE *he; |
874 | if ( (he = hv_iternext(hv)) == NULL) |
875 | return NULL; |
876 | *key = hv_iterkey(he, retlen); |
877 | return hv_iterval(hv, he); |
878 | } |
879 | |
79072805 |
880 | void |
881 | hv_magic(hv, gv, how) |
882 | HV* hv; |
883 | GV* gv; |
a0d0e21e |
884 | int how; |
79072805 |
885 | { |
a0d0e21e |
886 | sv_magic((SV*)hv, (SV*)gv, how, Nullch, 0); |
79072805 |
887 | } |
fde52b5c |
888 | |
889 | /* get a (constant) string ptr from the global string table |
890 | * string will get added if it is not already there. |
891 | * len and hash must both be valid for str. |
892 | */ |
893 | char * |
894 | sharepvn(str, len, hash) |
895 | char *str; |
896 | I32 len; |
897 | register U32 hash; |
898 | { |
899 | register XPVHV* xhv; |
900 | register HE *entry; |
901 | register HE **oentry; |
902 | register I32 i = 1; |
903 | I32 found = 0; |
904 | |
905 | /* what follows is the moral equivalent of: |
906 | |
907 | if (!(Svp = hv_fetch(strtab, str, len, FALSE))) |
908 | hv_store(strtab, str, len, Nullsv, hash); |
909 | */ |
910 | xhv = (XPVHV*)SvANY(strtab); |
911 | /* assert(xhv_array != 0) */ |
912 | oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max]; |
913 | for (entry = *oentry; entry; i=0, entry = HeNEXT(entry)) { |
914 | if (HeHASH(entry) != hash) /* strings can't be equal */ |
915 | continue; |
916 | if (HeKLEN(entry) != len) |
917 | continue; |
918 | if (bcmp(HeKEY(entry),str,len)) /* is this it? */ |
919 | continue; |
920 | found = 1; |
921 | break; |
922 | } |
923 | if (!found) { |
924 | entry = new_he(); |
925 | HeKLEN(entry) = len; |
926 | HeKEY(entry) = savepvn(str,len); |
927 | HeVAL(entry) = Nullsv; |
928 | HeHASH(entry) = hash; |
929 | HeNEXT(entry) = *oentry; |
930 | *oentry = entry; |
931 | xhv->xhv_keys++; |
932 | if (i) { /* initial entry? */ |
933 | ++xhv->xhv_fill; |
934 | if (xhv->xhv_keys > xhv->xhv_max) |
935 | hsplit(strtab); |
936 | } |
937 | } |
938 | |
939 | ++HeVAL(entry); /* use value slot as REFCNT */ |
940 | return HeKEY(entry); |
941 | } |
942 | |
943 | /* possibly free a shared string if no one has access to it |
944 | * len and hash must both be valid for str. |
945 | */ |
946 | void |
947 | unsharepvn(str, len, hash) |
948 | char *str; |
949 | I32 len; |
950 | register U32 hash; |
951 | { |
952 | register XPVHV* xhv; |
953 | register HE *entry; |
954 | register HE **oentry; |
955 | register I32 i = 1; |
956 | I32 found = 0; |
957 | |
958 | /* what follows is the moral equivalent of: |
959 | if ((Svp = hv_fetch(strtab, tmpsv, FALSE, hash))) { |
960 | if (--*Svp == Nullsv) |
961 | hv_delete(strtab, str, len, G_DISCARD, hash); |
962 | } */ |
963 | xhv = (XPVHV*)SvANY(strtab); |
964 | /* assert(xhv_array != 0) */ |
965 | oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max]; |
966 | for (entry = *oentry; entry; i=0, oentry = &HeNEXT(entry), entry = *oentry) { |
967 | if (HeHASH(entry) != hash) /* strings can't be equal */ |
968 | continue; |
969 | if (HeKLEN(entry) != len) |
970 | continue; |
971 | if (bcmp(HeKEY(entry),str,len)) /* is this it? */ |
972 | continue; |
973 | found = 1; |
974 | if (--HeVAL(entry) == Nullsv) { |
975 | *oentry = HeNEXT(entry); |
976 | if (i && !*oentry) |
977 | xhv->xhv_fill--; |
978 | Safefree(HeKEY(entry)); |
979 | del_he(entry); |
980 | --xhv->xhv_keys; |
981 | } |
982 | break; |
983 | } |
984 | |
985 | if (!found) |
986 | warn("Attempt to free non-existent shared string"); |
987 | } |
988 | |