1 /* Copyright (C) 1989, 1996, 1997, 1998, 1999, 2000 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: idict.c,v 1.12 2004/08/19 19:33:09 stefan Exp $ */
18 /* Dictionary implementation */
19 #include "math_.h" /* for frexp */
20 #include "string_.h" /* for strlen */
21 #include "ghost.h"
22 #include "gxalloc.h" /* for accessing masks */
23 #include "ierrors.h"
24 #include "imemory.h"
25 #include "idebug.h" /* for debug_print_name */
26 #include "inamedef.h"
27 #include "iname.h"
28 #include "ipacked.h"
29 #include "isave.h" /* for value cache in names */
30 #include "store.h"
31 #include "idict.h" /* interface definition */
32 #include "idictdef.h"
33 #include "iutil.h"
34 #include "ivmspace.h" /* for store check */
35
36 /*
37 * Dictionaries per se aren't supposed to know anything about the
38 * dictionary stack, let alone the interpreter's dictionary stack.
39 * Unfortunately, there is are two design couplings between them:
40 * dictionary stacks cache some of the elements of their top dictionary
41 * (requiring updating when that dictionary grows or is unpacked),
42 * and names may cache a pointer to their definition (requiring a
43 * check whether a dictionary appears on the dictionary stack).
44 * Therefore, we need iddstack.h here.
45 * We'd really like to fix this, but we don't see how.
46 */
47 #include "iddstack.h"
48
49 /*
50 * Define the size of the largest valid dictionary.
51 * This is limited by the size field of the keys and values refs,
52 * and by the enumeration interface, which requires the size to
53 * fit in an int. As it happens, max_array_size will always be
54 * smaller than max_int.
55 */
56 const uint dict_max_size = max_array_size - 1;
57
58 /* Define whether dictionaries are packed by default. */
59 bool dict_default_pack = true;
60
61 /*
62 * Define the check for whether we can set the 1-element cache.
63 * We only set the cache if we aren't inside a save.
64 * This way, we never have to undo setting the cache.
65 */
66 #define CAN_SET_PVALUE_CACHE(pds, pdref, mem)\
67 (pds && dstack_dict_is_permanent(pds, pdref) && !ref_saving_in(mem))
68
69 /* Forward references */
70 private int dict_create_contents(uint size, const ref * pdref, bool pack);
71
72 /* Debugging statistics */
73 #ifdef DEBUG
74 struct stats_dict_s {
75 long lookups; /* total lookups */
76 long probe1; /* successful lookups on only 1 probe */
77 long probe2; /* successful lookups on 2 probes */
78 } stats_dict;
79
80 /* Wrapper for dict_find */
81 int real_dict_find(const ref * pdref, const ref * key, ref ** ppvalue);
82 int
dict_find(const ref * pdref,const ref * pkey,ref ** ppvalue)83 dict_find(const ref * pdref, const ref * pkey, ref ** ppvalue)
84 {
85 dict *pdict = pdref->value.pdict;
86 int code = real_dict_find(pdref, pkey, ppvalue);
87
88 stats_dict.lookups++;
89 if (r_has_type(pkey, t_name) && dict_is_packed(pdict)) {
90 uint nidx = name_index(dict_mem(pdict), pkey);
91 uint hash =
92 dict_hash_mod(dict_name_index_hash(nidx), npairs(pdict)) + 1;
93
94 if (pdict->keys.value.packed[hash] ==
95 pt_tag(pt_literal_name) + nidx
96 )
97 stats_dict.probe1++;
98 else if (pdict->keys.value.packed[hash - 1] ==
99 pt_tag(pt_literal_name) + nidx
100 )
101 stats_dict.probe2++;
102 }
103 /* Do the cheap flag test before the expensive remainder test. */
104 if (gs_debug_c('d') && !(stats_dict.lookups % 1000))
105 dlprintf3("[d]lookups=%ld probe1=%ld probe2=%ld\n",
106 stats_dict.lookups, stats_dict.probe1, stats_dict.probe2);
107 return code;
108 }
109 #define dict_find real_dict_find
110 #endif
111
112 /* Round up the size of a dictionary. Return 0 if too large. */
113 uint
dict_round_size_small(uint rsize)114 dict_round_size_small(uint rsize)
115 {
116 return (rsize > dict_max_size ? 0 : rsize);
117 }
118 uint
dict_round_size_large(uint rsize)119 dict_round_size_large(uint rsize)
120 { /* Round up to a power of 2 if not huge. */
121 /* If the addition overflows, the new rsize will be zero, */
122 /* which will (correctly) be interpreted as a limitcheck. */
123 if (rsize > dict_max_non_huge)
124 return (rsize > dict_max_size ? 0 : rsize);
125 while (rsize & (rsize - 1))
126 rsize = (rsize | (rsize - 1)) + 1;
127 return (rsize <= dict_max_size ? rsize : dict_max_non_huge);
128 }
129
130 /* Create a dictionary using the given allocator. */
131 int
dict_alloc(gs_ref_memory_t * mem,uint size,ref * pdref)132 dict_alloc(gs_ref_memory_t * mem, uint size, ref * pdref)
133 {
134 ref arr;
135 int code =
136 gs_alloc_ref_array(mem, &arr, a_all, sizeof(dict) / sizeof(ref),
137 "dict_alloc");
138 dict *pdict;
139 ref dref;
140
141 if (code < 0)
142 return code;
143 pdict = (dict *) arr.value.refs;
144 make_tav(&dref, t_dictionary,
145 r_space(&arr) | imemory_new_mask(mem) | a_all,
146 pdict, pdict);
147 make_struct(&pdict->memory, avm_foreign, mem);
148 code = dict_create_contents(size, &dref, dict_default_pack);
149 if (code < 0) {
150 gs_free_ref_array(mem, &arr, "dict_alloc");
151 return code;
152 }
153 *pdref = dref;
154 return 0;
155 }
156 /* Create unpacked keys for a dictionary. */
157 /* The keys are allocated using the same allocator as the dictionary. */
158 private int
dict_create_unpacked_keys(uint asize,const ref * pdref)159 dict_create_unpacked_keys(uint asize, const ref * pdref)
160 {
161 dict *pdict = pdref->value.pdict;
162 gs_ref_memory_t *mem = dict_memory(pdict);
163 int code;
164
165 code = gs_alloc_ref_array(mem, &pdict->keys, a_all, asize,
166 "dict_create_unpacked_keys");
167 if (code >= 0) {
168 uint new_mask = imemory_new_mask(mem);
169 ref *kp = pdict->keys.value.refs;
170
171 r_set_attrs(&pdict->keys, new_mask);
172 refset_null_new(kp, asize, new_mask);
173 r_set_attrs(kp, a_executable); /* wraparound entry */
174 }
175 return code;
176 }
177 /* Create the contents (keys and values) of a newly allocated dictionary. */
178 /* Allocate in the current VM space, which is assumed to be the same as */
179 /* the VM space where the dictionary is allocated. */
180 private int
dict_create_contents(uint size,const ref * pdref,bool pack)181 dict_create_contents(uint size, const ref * pdref, bool pack)
182 {
183 dict *pdict = pdref->value.pdict;
184 gs_ref_memory_t *mem = dict_memory(pdict);
185 uint new_mask = imemory_new_mask(mem);
186 uint asize = dict_round_size((size == 0 ? 1 : size));
187 int code;
188 register uint i;
189
190 if (asize == 0 || asize > max_array_size - 1) /* too large */
191 return_error(e_limitcheck);
192 asize++; /* allow room for wraparound entry */
193 code = gs_alloc_ref_array(mem, &pdict->values, a_all, asize,
194 "dict_create_contents(values)");
195 if (code < 0)
196 return code;
197 r_set_attrs(&pdict->values, new_mask);
198 refset_null_new(pdict->values.value.refs, asize, new_mask);
199 if (pack) {
200 uint ksize = (asize + packed_per_ref - 1) / packed_per_ref;
201 ref arr;
202 ref_packed *pkp;
203 ref_packed *pzp;
204
205 code = gs_alloc_ref_array(mem, &arr, a_all, ksize,
206 "dict_create_contents(packed keys)");
207 if (code < 0)
208 return code;
209 pkp = (ref_packed *) arr.value.refs;
210 make_tasv(&pdict->keys, t_shortarray,
211 r_space(&arr) | a_all | new_mask,
212 asize, packed, pkp);
213 for (pzp = pkp, i = 0; i < asize || i % packed_per_ref; pzp++, i++)
214 *pzp = packed_key_empty;
215 *pkp = packed_key_deleted; /* wraparound entry */
216 } else { /* not packed */
217 int code = dict_create_unpacked_keys(asize, pdref);
218
219 if (code < 0)
220 return code;
221 }
222 make_tav(&pdict->count, t_integer, new_mask, intval, 0);
223 make_tav(&pdict->maxlength, t_integer, new_mask, intval, size);
224 return 0;
225 }
226
227 /*
228 * Ensure that a dictionary uses the unpacked representation for keys.
229 * We can't just use dict_resize, because the values slots mustn't move.
230 */
231 int
dict_unpack(ref * pdref,dict_stack_t * pds)232 dict_unpack(ref * pdref, dict_stack_t *pds)
233 {
234 dict *pdict = pdref->value.pdict;
235
236 if (!dict_is_packed(pdict))
237 return 0; /* nothing to do */
238 {
239 gs_ref_memory_t *mem = dict_memory(pdict);
240 uint count = nslots(pdict);
241 const ref_packed *okp = pdict->keys.value.packed;
242 ref old_keys;
243 int code;
244 ref *nkp;
245
246 old_keys = pdict->keys;
247 if (ref_must_save_in(mem, &old_keys))
248 ref_do_save_in(mem, pdref, &pdict->keys, "dict_unpack(keys)");
249 code = dict_create_unpacked_keys(count, pdref);
250 if (code < 0)
251 return code;
252 for (nkp = pdict->keys.value.refs; count--; okp++, nkp++)
253 if (r_packed_is_name(okp)) {
254 packed_get((const gs_memory_t *)mem, okp, nkp);
255 ref_mark_new_in(mem, nkp);
256 } else if (*okp == packed_key_deleted)
257 r_set_attrs(nkp, a_executable);
258 if (!ref_must_save_in(mem, &old_keys))
259 gs_free_ref_array(mem, &old_keys, "dict_unpack(old keys)");
260 if (pds)
261 dstack_set_top(pds); /* just in case */
262 }
263 return 0;
264 }
265
266 /*
267 * Look up a key in a dictionary. Store a pointer to the value slot
268 * where found, or to the (value) slot for inserting.
269 * Return 1 if found, 0 if not and there is room for a new entry,
270 * or e_dictfull if the dictionary is full and the key is missing.
271 * The caller is responsible for ensuring key is not a null.
272 */
273 int
dict_find(const ref * pdref,const ref * pkey,ref ** ppvalue)274 dict_find(const ref * pdref, const ref * pkey,
275 ref ** ppvalue /* result is stored here */ )
276 {
277 dict *pdict = pdref->value.pdict;
278 uint size = npairs(pdict);
279 register int etype;
280 uint nidx;
281 ref_packed kpack;
282 uint hash;
283 int ktype;
284 const gs_memory_t *mem = dict_mem(pdict);
285
286 /* Compute hash. The only types we bother with are strings, */
287 /* names, and (unlikely, but worth checking for) integers. */
288 switch (r_type(pkey)) {
289 case t_name:
290 nidx = name_index(mem, pkey);
291 nh:
292 hash = dict_name_index_hash(nidx);
293 kpack = packed_name_key(nidx);
294 ktype = t_name;
295 break;
296 case t_string: /* convert to a name first */
297 {
298 ref nref;
299 int code;
300
301 if (!r_has_attr(pkey, a_read))
302 return_error(e_invalidaccess);
303 code = name_ref(mem, pkey->value.bytes, r_size(pkey), &nref, 1);
304 if (code < 0)
305 return code;
306 nidx = name_index(mem, &nref);
307 }
308 goto nh;
309 case t_real:
310 /*
311 * Make sure that equal reals and integers hash the same.
312 */
313 {
314 int expt, i;
315 double mant = frexp(pkey->value.realval, &expt);
316 /*
317 * The value is mant * 2^expt, where 0.5 <= mant < 1,
318 * or else expt == mant == 0.
319 */
320
321 if (expt < sizeof(long) * 8 || pkey->value.realval == min_long)
322 i = (int)pkey->value.realval;
323 else
324 i = (int)(mant * min_long); /* MSVC 6.00.8168.0 cannot compile this */
325 hash = (uint)i * 30503; /* with -O2 as a single expression */
326 }
327 goto ih;
328 case t_integer:
329 hash = (uint)pkey->value.intval * 30503;
330 ih:
331 kpack = packed_key_impossible;
332 ktype = -1;
333 nidx = 0; /* only to pacify gcc */
334 break;
335 case t_null: /* not allowed as a key */
336 return_error(e_typecheck);
337 default:
338 hash = r_btype(pkey) * 99; /* yech */
339 kpack = packed_key_impossible;
340 ktype = -1;
341 nidx = 0; /* only to pacify gcc */
342 }
343 /* Search the dictionary */
344 if (dict_is_packed(pdict)) {
345 const ref_packed *pslot = 0;
346
347 packed_search_1(*ppvalue = packed_search_value_pointer,
348 return 1,
349 if (pslot == 0) pslot = kp, goto miss);
350 packed_search_2(*ppvalue = packed_search_value_pointer,
351 return 1,
352 if (pslot == 0) pslot = kp, goto miss);
353 /*
354 * Double wraparound, dict is full.
355 * Note that even if there was an empty slot (pslot != 0),
356 * we must return dictfull if length = maxlength.
357 */
358 if (pslot == 0 || d_length(pdict) == d_maxlength(pdict))
359 return_error(e_dictfull);
360 *ppvalue = pdict->values.value.refs + (pslot - kbot);
361 return 0;
362 miss: /* Key is missing, not double wrap. See above re dictfull. */
363 if (d_length(pdict) == d_maxlength(pdict))
364 return_error(e_dictfull);
365 if (pslot == 0)
366 pslot = kp;
367 *ppvalue = pdict->values.value.refs + (pslot - kbot);
368 return 0;
369 } else {
370 ref *kbot = pdict->keys.value.refs;
371 register ref *kp;
372 ref *pslot = 0;
373 int wrap = 0;
374
375 for (kp = kbot + dict_hash_mod(hash, size) + 2;;) {
376 --kp;
377 if ((etype = r_type(kp)) == ktype) { /* Fast comparison if both keys are names */
378 if (name_index(mem, kp) == nidx) {
379 *ppvalue = pdict->values.value.refs + (kp - kbot);
380 return 1;
381 }
382 } else if (etype == t_null) { /* Empty, deleted, or wraparound. */
383 /* Figure out which. */
384 if (kp == kbot) { /* wrap */
385 if (wrap++) { /* wrapped twice */
386 if (pslot == 0)
387 return_error(e_dictfull);
388 break;
389 }
390 kp += size + 1;
391 } else if (r_has_attr(kp, a_executable)) { /* Deleted entry, save the slot. */
392 if (pslot == 0)
393 pslot = kp;
394 } else /* key not found */
395 break;
396 } else {
397 if (obj_eq(mem, kp, pkey)) {
398 *ppvalue = pdict->values.value.refs + (kp - kbot);
399 return 1;
400 }
401 }
402 }
403 if (d_length(pdict) == d_maxlength(pdict))
404 return_error(e_dictfull);
405 *ppvalue = pdict->values.value.refs +
406 ((pslot != 0 ? pslot : kp) - kbot);
407 return 0;
408 }
409 }
410
411 /*
412 * Look up a (constant) C string in a dictionary.
413 * Return 1 if found, <= 0 if not.
414 */
415 int
dict_find_string(const ref * pdref,const char * kstr,ref ** ppvalue)416 dict_find_string(const ref * pdref, const char *kstr, ref ** ppvalue)
417 {
418 int code;
419 ref kname;
420 if ( pdref != 0 ) {
421 dict *pdict = pdref->value.pdict;
422
423 if ((code = name_ref(dict_mem(pdict),
424 (const byte *)kstr, strlen(kstr), &kname, -1)) < 0)
425 return code;
426 return dict_find(pdref, &kname, ppvalue);
427 }
428 return 0;
429 }
430
431 /*
432 * Enter a key-value pair in a dictionary.
433 * See idict.h for the possible return values.
434 */
435 int
dict_put(ref * pdref,const ref * pkey,const ref * pvalue,dict_stack_t * pds)436 dict_put(ref * pdref /* t_dictionary */ , const ref * pkey, const ref * pvalue,
437 dict_stack_t *pds)
438 {
439 dict *pdict = pdref->value.pdict;
440 gs_ref_memory_t *mem = dict_memory(pdict);
441 gs_memory_t *pmem = dict_mem(pdict);
442 int rcode = 0;
443 int code;
444 ref *pvslot;
445
446 /* Check the value. */
447 store_check_dest(pdref, pvalue);
448 top:if ((code = dict_find(pdref, pkey, &pvslot)) <= 0) { /* not found *//* Check for overflow */
449 ref kname;
450 uint index;
451
452 switch (code) {
453 case 0:
454 break;
455 case e_dictfull:
456 if (!pmem->gs_lib_ctx->dict_auto_expand)
457 return_error(e_dictfull);
458 code = dict_grow(pdref, pds);
459 if (code < 0)
460 return code;
461 goto top; /* keep things simple */
462 default: /* e_typecheck */
463 return code;
464 }
465 index = pvslot - pdict->values.value.refs;
466 /* If the key is a string, convert it to a name. */
467 if (r_has_type(pkey, t_string)) {
468 int code;
469
470 if (!r_has_attr(pkey, a_read))
471 return_error(e_invalidaccess);
472 code = name_from_string(pmem, pkey, &kname);
473 if (code < 0)
474 return code;
475 pkey = &kname;
476 }
477 if (dict_is_packed(pdict)) {
478 ref_packed *kp;
479
480 if (!r_has_type(pkey, t_name) ||
481 name_index(pmem, pkey) > packed_name_max_index
482 ) { /* Change to unpacked representation. */
483 int code = dict_unpack(pdref, pds);
484
485 if (code < 0)
486 return code;
487 goto top;
488 }
489 kp = pdict->keys.value.writable_packed + index;
490 if (ref_must_save_in(mem, &pdict->keys)) { /* See initial comment for why it is safe */
491 /* not to save the change if the keys */
492 /* array itself is new. */
493 ref_do_save_in(mem, &pdict->keys, kp, "dict_put(key)");
494 }
495 *kp = pt_tag(pt_literal_name) + name_index(pmem, pkey);
496 } else {
497 ref *kp = pdict->keys.value.refs + index;
498
499 if_debug2('d', "[d]0x%lx: fill key at 0x%lx\n",
500 (ulong) pdict, (ulong) kp);
501 store_check_dest(pdref, pkey);
502 ref_assign_old_in(mem, &pdict->keys, kp, pkey,
503 "dict_put(key)"); /* set key of pair */
504 }
505 ref_save_in(mem, pdref, &pdict->count, "dict_put(count)");
506 pdict->count.value.intval++;
507 /* If the key is a name, update its 1-element cache. */
508 if (r_has_type(pkey, t_name)) {
509 name *pname = pkey->value.pname;
510
511 if (pname->pvalue == pv_no_defn &&
512 CAN_SET_PVALUE_CACHE(pds, pdref, mem)
513 ) { /* Set the cache. */
514 if_debug0('d', "[d]set cache\n");
515 pname->pvalue = pvslot;
516 } else { /* The cache can't be used. */
517 if_debug0('d', "[d]no cache\n");
518 pname->pvalue = pv_other;
519 }
520 }
521 rcode = 1;
522 }
523 if_debug8('d', "[d]0x%lx: put key 0x%lx 0x%lx\n value at 0x%lx: old 0x%lx 0x%lx, new 0x%lx 0x%lx\n",
524 (ulong) pdref->value.pdict,
525 ((const ulong *)pkey)[0], ((const ulong *)pkey)[1],
526 (ulong) pvslot,
527 ((const ulong *)pvslot)[0], ((const ulong *)pvslot)[1],
528 ((const ulong *)pvalue)[0], ((const ulong *)pvalue)[1]);
529 ref_assign_old_in(mem, &pdref->value.pdict->values, pvslot, pvalue,
530 "dict_put(value)");
531 return rcode;
532 }
533
534 /*
535 * Enter a key-value pair where the key is a (constant) C string.
536 */
537 int
dict_put_string(ref * pdref,const char * kstr,const ref * pvalue,dict_stack_t * pds)538 dict_put_string(ref * pdref, const char *kstr, const ref * pvalue,
539 dict_stack_t *pds)
540 {
541 int code;
542 ref kname;
543 dict *pdict = pdref->value.pdict;
544
545 if ((code = name_ref(dict_mem(pdict),
546 (const byte *)kstr, strlen(kstr), &kname, 0)) < 0)
547 return code;
548 return dict_put(pdref, &kname, pvalue, pds);
549 }
550
551 /* Remove an element from a dictionary. */
552 int
dict_undef(ref * pdref,const ref * pkey,dict_stack_t * pds)553 dict_undef(ref * pdref, const ref * pkey, dict_stack_t *pds)
554 {
555 gs_ref_memory_t *mem;
556 ref *pvslot;
557 dict *pdict;
558 uint index;
559
560 if (dict_find(pdref, pkey, &pvslot) <= 0)
561 return (e_undefined);
562 /* Remove the entry from the dictionary. */
563 pdict = pdref->value.pdict;
564 index = pvslot - pdict->values.value.refs;
565 mem = dict_memory(pdict);
566 if (dict_is_packed(pdict)) {
567 ref_packed *pkp = pdict->keys.value.writable_packed + index;
568
569 if_debug3('d', "[d]0x%lx: removing key at 0%lx: 0x%x\n",
570 (ulong)pdict, (ulong)pkp, (uint)*pkp);
571 /* See the initial comment for why it is safe not to save */
572 /* the change if the keys array itself is new. */
573 if (ref_must_save_in(mem, &pdict->keys))
574 ref_do_save_in(mem, &pdict->keys, pkp, "dict_undef(key)");
575 /*
576 * Accumulating deleted entries slows down lookup.
577 * Detect the easy case where we can use an empty entry
578 * rather than a deleted one, namely, when the next entry
579 * in the probe order is empty.
580 */
581 if (pkp[-1] == packed_key_empty) {
582 /*
583 * In this case we can replace any preceding deleted keys with
584 * empty ones as well.
585 */
586 uint end = nslots(pdict);
587
588 *pkp = packed_key_empty;
589 while (++index < end && *++pkp == packed_key_deleted)
590 *pkp = packed_key_empty;
591 } else
592 *pkp = packed_key_deleted;
593 } else { /* not packed */
594 ref *kp = pdict->keys.value.refs + index;
595
596 if_debug4('d', "[d]0x%lx: removing key at 0%lx: 0x%lx 0x%lx\n",
597 (ulong)pdict, (ulong)kp, ((ulong *)kp)[0], ((ulong *)kp)[1]);
598 make_null_old_in(mem, &pdict->keys, kp, "dict_undef(key)");
599 /*
600 * Accumulating deleted entries slows down lookup.
601 * Detect the easy case where we can use an empty entry
602 * rather than a deleted one, namely, when the next entry
603 * in the probe order is empty.
604 */
605 if (!r_has_type(kp - 1, t_null) || /* full entry */
606 r_has_attr(kp - 1, a_executable) /* deleted or wraparound */
607 )
608 r_set_attrs(kp, a_executable); /* mark as deleted */
609 }
610 ref_save_in(mem, pdref, &pdict->count, "dict_undef(count)");
611 pdict->count.value.intval--;
612 /* If the key is a name, update its 1-element cache. */
613 if (r_has_type(pkey, t_name)) {
614 name *pname = pkey->value.pname;
615
616 if (pv_valid(pname->pvalue)) {
617 #ifdef DEBUG
618 /* Check the the cache is correct. */
619 if (!(pds && dstack_dict_is_permanent(pds, pdref)))
620 lprintf1("dict_undef: cached name value pointer 0x%lx is incorrect!\n",
621 (ulong) pname->pvalue);
622 #endif
623 /* Clear the cache */
624 pname->pvalue = pv_no_defn;
625 }
626 }
627 make_null_old_in(mem, &pdict->values, pvslot, "dict_undef(value)");
628 return 0;
629 }
630
631 /* Return the number of elements in a dictionary. */
632 uint
dict_length(const ref * pdref)633 dict_length(const ref * pdref /* t_dictionary */ )
634 {
635 return d_length(pdref->value.pdict);
636 }
637
638 /* Return the capacity of a dictionary. */
639 uint
dict_maxlength(const ref * pdref)640 dict_maxlength(const ref * pdref /* t_dictionary */ )
641 {
642 return d_maxlength(pdref->value.pdict);
643 }
644
645 /* Return the maximum index of a slot within a dictionary. */
646 uint
dict_max_index(const ref * pdref)647 dict_max_index(const ref * pdref /* t_dictionary */ )
648 {
649 return npairs(pdref->value.pdict) - 1;
650 }
651
652 /*
653 * Copy one dictionary into another.
654 * If COPY_NEW_ONLY is set, only copy entries whose keys
655 * aren't already present in the destination.
656 * If COPY_FOR_RESIZE is set, reset any valid name cache entries to
657 * pv_no_defn before doing the dict_put.
658 */
659 #define COPY_NEW_ONLY 1
660 #define COPY_FOR_RESIZE 2
661 private int
dict_copy_elements(const ref * pdrfrom,ref * pdrto,int options,dict_stack_t * pds)662 dict_copy_elements(const ref * pdrfrom /* t_dictionary */ ,
663 ref * pdrto /* t_dictionary */ , int options,
664 dict_stack_t *pds)
665 {
666 int space = r_space(pdrto);
667 int index;
668 ref elt[2];
669 ref *pvslot;
670 int code;
671
672 if (space != avm_max) {
673 /* Do the store check before starting the copy. */
674 index = dict_first(pdrfrom);
675 while ((index = dict_next(pdrfrom, index, elt)) >= 0)
676 if (!(options & COPY_NEW_ONLY) ||
677 dict_find(pdrto, &elt[0], &pvslot) <= 0
678 ) {
679 store_check_space(space, &elt[0]);
680 store_check_space(space, &elt[1]);
681 }
682 }
683 /* Now copy the contents. */
684 index = dict_first(pdrfrom);
685 while ((index = dict_next(pdrfrom, index, elt)) >= 0) {
686 ref *pvalue = pv_no_defn;
687
688 if ((options & COPY_NEW_ONLY) &&
689 dict_find(pdrto, &elt[0], &pvslot) > 0
690 )
691 continue;
692 if ((options & COPY_FOR_RESIZE) &&
693 r_has_type(&elt[0], t_name) &&
694 (pvalue = elt[0].value.pname->pvalue, pv_valid(pvalue))
695 )
696 elt[0].value.pname->pvalue = pv_no_defn;
697 if ((code = dict_put(pdrto, &elt[0], &elt[1], pds)) < 0) {
698 /*
699 * If COPY_FOR_RESIZE is set, the dict_put isn't supposed to
700 * be able to fail, but we don't want to depend on this.
701 */
702 if (pvalue != pv_no_defn)
703 elt[0].value.pname->pvalue = pvalue;
704 return code;
705 }
706 }
707 return 0;
708 }
709 int
dict_copy_entries(const ref * pdrfrom,ref * pdrto,bool new_only,dict_stack_t * pds)710 dict_copy_entries(const ref *pdrfrom, ref *pdrto, bool new_only,
711 dict_stack_t *pds)
712 {
713 return dict_copy_elements(pdrfrom, pdrto, (new_only ? COPY_NEW_ONLY : 0),
714 pds);
715 }
716
717 /* Resize a dictionary. */
718 int
dict_resize(ref * pdref,uint new_size,dict_stack_t * pds)719 dict_resize(ref * pdref, uint new_size, dict_stack_t *pds)
720 {
721 dict *pdict = pdref->value.pdict;
722 gs_ref_memory_t *mem = dict_memory(pdict);
723 uint new_mask = imemory_new_mask(mem);
724 dict dnew;
725 ref drto;
726 int code;
727
728 if (new_size < d_length(pdict)) {
729 if (!mem->gs_lib_ctx->dict_auto_expand)
730 return_error(e_dictfull);
731 new_size = d_length(pdict);
732 }
733 make_tav(&drto, t_dictionary, r_space(pdref) | a_all | new_mask,
734 pdict, &dnew);
735 dnew.memory = pdict->memory;
736 if ((code = dict_create_contents(new_size, &drto, dict_is_packed(pdict))) < 0)
737 return code;
738 /*
739 * We must suppress the store check, in case we are expanding
740 * systemdict or another global dictionary that is allowed
741 * to reference local objects.
742 */
743 r_set_space(&drto, avm_local);
744 /*
745 * If we are expanding a permanent dictionary, we must make sure that
746 * dict_put doesn't think this is a second definition for any
747 * single-definition names. This in turn requires that
748 * dstack_dict_is_permanent must be true for the second ("to")
749 * argument of dict_copy_elements, which requires temporarily
750 * setting *pdref = drto.
751 */
752 if (CAN_SET_PVALUE_CACHE(pds, pdref, mem)) {
753 ref drfrom;
754
755 drfrom = *pdref;
756 *pdref = drto;
757 dict_copy_elements(&drfrom, pdref, COPY_FOR_RESIZE, pds);
758 *pdref = drfrom;
759 } else {
760 dict_copy_elements(pdref, &drto, 0, pds);
761 }
762 /* Save or free the old dictionary. */
763 if (ref_must_save_in(mem, &pdict->values))
764 ref_do_save_in(mem, pdref, &pdict->values, "dict_resize(values)");
765 else
766 gs_free_ref_array(mem, &pdict->values, "dict_resize(old values)");
767 if (ref_must_save_in(mem, &pdict->keys))
768 ref_do_save_in(mem, pdref, &pdict->keys, "dict_resize(keys)");
769 else
770 gs_free_ref_array(mem, &pdict->keys, "dict_resize(old keys)");
771 ref_assign(&pdict->keys, &dnew.keys);
772 ref_assign(&pdict->values, &dnew.values);
773 ref_save_in(dict_memory(pdict), pdref, &pdict->maxlength,
774 "dict_resize(maxlength)");
775 d_set_maxlength(pdict, new_size);
776 if (pds)
777 dstack_set_top(pds); /* just in case this is the top dict */
778 return 0;
779 }
780
781 /* Grow a dictionary for dict_put. */
782 int
dict_grow(ref * pdref,dict_stack_t * pds)783 dict_grow(ref * pdref, dict_stack_t *pds)
784 {
785 dict *pdict = pdref->value.pdict;
786 /* We might have maxlength < npairs, if */
787 /* dict_round_size increased the size. */
788 ulong new_size = (ulong) d_maxlength(pdict) * 3 / 2 + 2;
789
790 #if arch_sizeof_int < arch_sizeof_long
791 if (new_size > max_uint)
792 new_size = max_uint;
793 #endif
794 if (new_size > npairs(pdict)) {
795 int code = dict_resize(pdref, (uint) new_size, pds);
796
797 if (code >= 0)
798 return code;
799 /* new_size was too big. */
800 if (npairs(pdict) < dict_max_size) {
801 code = dict_resize(pdref, dict_max_size, pds);
802 if (code >= 0)
803 return code;
804 }
805 if (npairs(pdict) == d_maxlength(pdict)) { /* Can't do it. */
806 return code;
807 }
808 /* We can't grow to new_size, but we can grow to npairs. */
809 new_size = npairs(pdict);
810 }
811 /* maxlength < npairs, we can grow in place */
812 ref_save_in(dict_memory(pdict), pdref, &pdict->maxlength,
813 "dict_put(maxlength)");
814 d_set_maxlength(pdict, new_size);
815 return 0;
816 }
817
818 /* Prepare to enumerate a dictionary. */
819 int
dict_first(const ref * pdref)820 dict_first(const ref * pdref)
821 {
822 return (int)nslots(pdref->value.pdict);
823 }
824
825 /* Enumerate the next element of a dictionary. */
826 int
dict_next(const ref * pdref,int index,ref * eltp)827 dict_next(const ref * pdref, int index, ref * eltp /* ref eltp[2] */ )
828 {
829 dict *pdict = pdref->value.pdict;
830 ref *vp = pdict->values.value.refs + index;
831
832 while (vp--, --index >= 0) {
833 array_get(dict_mem(pdict), &pdict->keys, (long)index, eltp);
834 /* Make sure this is a valid entry. */
835 if (r_has_type(eltp, t_name) ||
836 (!dict_is_packed(pdict) && !r_has_type(eltp, t_null))
837 ) {
838 eltp[1] = *vp;
839 if_debug6('d', "[d]0x%lx: index %d: %lx %lx, %lx %lx\n",
840 (ulong) pdict, index,
841 ((ulong *) eltp)[0], ((ulong *) eltp)[1],
842 ((ulong *) vp)[0], ((ulong *) vp)[1]);
843 return index;
844 }
845 }
846 return -1; /* no more elements */
847 }
848
849 /* Return the index of a value within a dictionary. */
850 int
dict_value_index(const ref * pdref,const ref * pvalue)851 dict_value_index(const ref * pdref, const ref * pvalue)
852 {
853 return (int)(pvalue - pdref->value.pdict->values.value.refs - 1);
854 }
855
856 /* Return the entry at a given index within a dictionary. */
857 /* If the index designates an unoccupied entry, return e_undefined. */
858 int
dict_index_entry(const ref * pdref,int index,ref * eltp)859 dict_index_entry(const ref * pdref, int index, ref * eltp /* ref eltp[2] */ )
860 {
861 const dict *pdict = pdref->value.pdict;
862
863 array_get(dict_mem(pdict), &pdict->keys, (long)(index + 1), eltp);
864 if (r_has_type(eltp, t_name) ||
865 (!dict_is_packed(pdict) && !r_has_type(eltp, t_null))
866 ) {
867 eltp[1] = pdict->values.value.refs[index + 1];
868 return 0;
869 }
870 return e_undefined;
871 }
872