Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_tlsv12/sys/src/cmd/gs/src/idict.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
114
dict_round_size_small(uint rsize)
115
{
116
    return (rsize > dict_max_size ? 0 : rsize);
117
}
118
uint
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
}