blob: e40ac8de39456677f7f318be13ada2506bbe6a79 [file] [log] [blame]
Guido van Rossum4b1302b1993-03-27 18:11:32 +00001/***********************************************************
Guido van Rossum1d5735e1994-08-30 08:27:36 +00002Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
Guido van Rossum4b1302b1993-03-27 18:11:32 +00003Amsterdam, The Netherlands.
4
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
25/* Mapping object implementation; using a hash table */
26
Guido van Rossum9bfef441993-03-29 10:43:31 +000027/* This file should really be called "dictobject.c", since "mapping"
28 is the generic name for objects with an unorderred arbitrary key
29 set (just like lists are sequences), but since it improves (and was
30 originally derived from) a file by that name I had to change its
31 name. For the user these objects are still called "dictionaries". */
32
Guido van Rossum4b1302b1993-03-27 18:11:32 +000033#include "allobjects.h"
Guido van Rossum4b1302b1993-03-27 18:11:32 +000034#include "modsupport.h"
35
36
37/*
38Table of primes suitable as keys, in ascending order.
39The first line are the largest primes less than some powers of two,
40the second line is the largest prime less than 6000,
Guido van Rossum1d5735e1994-08-30 08:27:36 +000041the third line is a selection from Knuth, Vol. 3, Sec. 6.1, Table 1,
42and the next three lines were suggested by Steve Kirsch.
43The final value is a sentinel.
Guido van Rossum4b1302b1993-03-27 18:11:32 +000044*/
Guido van Rossum1d5735e1994-08-30 08:27:36 +000045static long primes[] = {
Guido van Rossum4b1302b1993-03-27 18:11:32 +000046 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2017, 4093,
47 5987,
48 9551, 15683, 19609, 31397,
Guido van Rossum1d5735e1994-08-30 08:27:36 +000049 65521L, 131071L, 262139L, 524287L, 1048573L, 2097143L,
50 4194301L, 8388593L, 16777213L, 33554393L, 67108859L,
51 134217689L, 268435399L, 536870909L, 1073741789L,
52 0
Guido van Rossum4b1302b1993-03-27 18:11:32 +000053};
54
55/* Object used as dummy key to fill deleted entries */
56static object *dummy; /* Initialized by first call to newmappingobject() */
57
58/*
59Invariant for entries: when in use, de_value is not NULL and de_key is
60not NULL and not dummy; when not in use, de_value is NULL and de_key
61is either NULL or dummy. A dummy key value cannot be replaced by
62NULL, since otherwise other keys may be lost.
63*/
64typedef struct {
65 long me_hash;
66 object *me_key;
67 object *me_value;
68} mappingentry;
69
70/*
71To ensure the lookup algorithm terminates, the table size must be a
72prime number and there must be at least one NULL key in the table.
73The value ma_fill is the number of non-NULL keys; ma_used is the number
74of non-NULL, non-dummy keys.
75To avoid slowing down lookups on a near-full table, we resize the table
76when it is more than half filled.
77*/
78typedef struct {
79 OB_HEAD
80 int ma_fill;
81 int ma_used;
82 int ma_size;
83 mappingentry *ma_table;
84} mappingobject;
85
86object *
87newmappingobject()
88{
89 register mappingobject *mp;
90 if (dummy == NULL) { /* Auto-initialize dummy */
91 dummy = newstringobject("<dummy key>");
92 if (dummy == NULL)
93 return NULL;
94 }
95 mp = NEWOBJ(mappingobject, &Mappingtype);
96 if (mp == NULL)
97 return NULL;
98 mp->ma_size = primes[0];
99 mp->ma_table = (mappingentry *) calloc(sizeof(mappingentry), mp->ma_size);
100 if (mp->ma_table == NULL) {
101 DEL(mp);
102 return err_nomem();
103 }
104 mp->ma_fill = 0;
105 mp->ma_used = 0;
106 return (object *)mp;
107}
108
109/*
110The basic lookup function used by all operations.
111This is essentially Algorithm D from Knuth Vol. 3, Sec. 6.4.
112Open addressing is preferred over chaining since the link overhead for
113chaining would be substantial (100% with typical malloc overhead).
114
115First a 32-bit hash value, 'sum', is computed from the key string.
116The first character is added an extra time shifted by 8 to avoid hashing
117single-character keys (often heavily used variables) too close together.
118All arithmetic on sum should ignore overflow.
119
120The initial probe index is then computed as sum mod the table size.
121Subsequent probe indices are incr apart (mod table size), where incr
122is also derived from sum, with the additional requirement that it is
123relative prime to the table size (i.e., 1 <= incr < size, since the size
124is a prime number). My choice for incr is somewhat arbitrary.
125*/
126static mappingentry *lookmapping PROTO((mappingobject *, object *, long));
127static mappingentry *
128lookmapping(mp, key, hash)
129 register mappingobject *mp;
130 object *key;
131 long hash;
132{
133 register int i, incr;
134 register unsigned long sum = (unsigned long) hash;
135 register mappingentry *freeslot = NULL;
136 /* We must come up with (i, incr) such that 0 <= i < ma_size
137 and 0 < incr < ma_size and both are a function of hash */
138 i = sum % mp->ma_size;
139 do {
140 sum = sum + sum + sum + 1;
141 incr = sum % mp->ma_size;
142 } while (incr == 0);
143 for (;;) {
144 register mappingentry *ep = &mp->ma_table[i];
145 if (ep->me_key == NULL) {
146 if (freeslot != NULL)
147 return freeslot;
148 else
149 return ep;
150 }
151 if (ep->me_key == dummy) {
Guido van Rossum52f2c051993-11-10 12:53:24 +0000152 if (freeslot == NULL)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000153 freeslot = ep;
154 }
155 else if (ep->me_hash == hash &&
156 cmpobject(ep->me_key, key) == 0) {
157 return ep;
158 }
159 i = (i + incr) % mp->ma_size;
160 }
161}
162
163/*
164Internal routine to insert a new item into the table.
165Used both by the internal resize routine and by the public insert routine.
166Eats a reference to key and one to value.
167*/
168static void insertmapping PROTO((mappingobject *, object *, long, object *));
169static void
170insertmapping(mp, key, hash, value)
171 register mappingobject *mp;
172 object *key;
173 long hash;
174 object *value;
175{
176 register mappingentry *ep;
177 ep = lookmapping(mp, key, hash);
178 if (ep->me_value != NULL) {
179 DECREF(ep->me_value);
180 DECREF(key);
181 }
182 else {
183 if (ep->me_key == NULL)
184 mp->ma_fill++;
185 else
186 DECREF(ep->me_key);
187 ep->me_key = key;
188 ep->me_hash = hash;
189 mp->ma_used++;
190 }
191 ep->me_value = value;
192}
193
194/*
195Restructure the table by allocating a new table and reinserting all
196items again. When entries have been deleted, the new table may
197actually be smaller than the old one.
198*/
199static int mappingresize PROTO((mappingobject *));
200static int
201mappingresize(mp)
202 mappingobject *mp;
203{
204 register int oldsize = mp->ma_size;
205 register int newsize;
206 register mappingentry *oldtable = mp->ma_table;
207 register mappingentry *newtable;
208 register mappingentry *ep;
209 register int i;
210 newsize = mp->ma_size;
211 for (i = 0; ; i++) {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000212 if (primes[i] <= 0) {
213 /* Ran out of primes */
214 err_nomem();
215 return -1;
216 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000217 if (primes[i] > mp->ma_used*2) {
218 newsize = primes[i];
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000219 if (newsize != primes[i]) {
220 /* Integer truncation */
221 err_nomem();
222 return -1;
223 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000224 break;
225 }
226 }
227 newtable = (mappingentry *) calloc(sizeof(mappingentry), newsize);
228 if (newtable == NULL) {
229 err_nomem();
230 return -1;
231 }
232 mp->ma_size = newsize;
233 mp->ma_table = newtable;
234 mp->ma_fill = 0;
235 mp->ma_used = 0;
236 for (i = 0, ep = oldtable; i < oldsize; i++, ep++) {
237 if (ep->me_value != NULL)
238 insertmapping(mp,ep->me_key,ep->me_hash,ep->me_value);
239 else {
240 XDECREF(ep->me_key);
241 }
242 }
243 DEL(oldtable);
244 return 0;
245}
246
247object *
248mappinglookup(op, key)
249 object *op;
250 object *key;
251{
252 long hash;
253 if (!is_mappingobject(op)) {
254 err_badcall();
255 return NULL;
256 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000257#ifdef CACHE_HASH
258 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
259#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000260 hash = hashobject(key);
261 if (hash == -1)
262 return NULL;
263 return lookmapping((mappingobject *)op, key, hash) -> me_value;
264}
265
266int
267mappinginsert(op, key, value)
268 register object *op;
269 object *key;
270 object *value;
271{
272 register mappingobject *mp;
273 register long hash;
274 if (!is_mappingobject(op)) {
275 err_badcall();
276 return -1;
277 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000278#ifdef CACHE_HASH
279 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
280#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000281 hash = hashobject(key);
282 if (hash == -1)
283 return -1;
284 mp = (mappingobject *)op;
285 /* if fill >= 2/3 size, resize */
286 if (mp->ma_fill*3 >= mp->ma_size*2) {
287 if (mappingresize(mp) != 0) {
288 if (mp->ma_fill+1 > mp->ma_size)
289 return -1;
290 }
291 }
292 INCREF(value);
293 INCREF(key);
294 insertmapping(mp, key, hash, value);
295 return 0;
296}
297
298int
299mappingremove(op, key)
300 object *op;
301 object *key;
302{
303 register mappingobject *mp;
304 register long hash;
305 register mappingentry *ep;
306 if (!is_mappingobject(op)) {
307 err_badcall();
308 return -1;
309 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000310#ifdef CACHE_HASH
311 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
312#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000313 hash = hashobject(key);
314 if (hash == -1)
315 return -1;
316 mp = (mappingobject *)op;
317 ep = lookmapping(mp, key, hash);
318 if (ep->me_value == NULL) {
319 err_setval(KeyError, key);
320 return -1;
321 }
322 DECREF(ep->me_key);
323 INCREF(dummy);
324 ep->me_key = dummy;
325 DECREF(ep->me_value);
326 ep->me_value = NULL;
327 mp->ma_used--;
328 return 0;
329}
330
Guido van Rossum25831651993-05-19 14:50:45 +0000331void
332mappingclear(op)
333 object *op;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000334{
Guido van Rossum25831651993-05-19 14:50:45 +0000335 int i;
336 register mappingobject *mp;
337 if (!is_mappingobject(op))
338 return;
339 mp = (mappingobject *)op;
340 for (i = 0; i < mp->ma_size; i++) {
341 XDECREF(mp->ma_table[i].me_key);
342 XDECREF(mp->ma_table[i].me_value);
343 mp->ma_table[i].me_key = NULL;
344 mp->ma_table[i].me_value = NULL;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000345 }
Guido van Rossum25831651993-05-19 14:50:45 +0000346 mp->ma_used = 0;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000347}
348
Guido van Rossum25831651993-05-19 14:50:45 +0000349int
350mappinggetnext(op, ppos, pkey, pvalue)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000351 object *op;
Guido van Rossum25831651993-05-19 14:50:45 +0000352 int *ppos;
353 object **pkey;
354 object **pvalue;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000355{
Guido van Rossum25831651993-05-19 14:50:45 +0000356 int i;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000357 register mappingobject *mp;
Guido van Rossum25831651993-05-19 14:50:45 +0000358 if (!is_dictobject(op))
359 return 0;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000360 mp = (mappingobject *)op;
Guido van Rossum25831651993-05-19 14:50:45 +0000361 i = *ppos;
362 if (i < 0)
363 return 0;
364 while (i < mp->ma_size && mp->ma_table[i].me_value == NULL)
365 i++;
366 *ppos = i+1;
367 if (i >= mp->ma_size)
368 return 0;
369 if (pkey)
370 *pkey = mp->ma_table[i].me_key;
371 if (pvalue)
372 *pvalue = mp->ma_table[i].me_value;
373 return 1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000374}
375
376/* Methods */
377
378static void
379mapping_dealloc(mp)
380 register mappingobject *mp;
381{
382 register int i;
383 register mappingentry *ep;
384 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
385 if (ep->me_key != NULL)
386 DECREF(ep->me_key);
387 if (ep->me_value != NULL)
388 DECREF(ep->me_value);
389 }
390 if (mp->ma_table != NULL)
391 DEL(mp->ma_table);
392 DEL(mp);
393}
394
395static int
396mapping_print(mp, fp, flags)
397 register mappingobject *mp;
398 register FILE *fp;
399 register int flags;
400{
401 register int i;
402 register int any;
403 register mappingentry *ep;
404 fprintf(fp, "{");
405 any = 0;
406 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
407 if (ep->me_value != NULL) {
408 if (any++ > 0)
409 fprintf(fp, ", ");
Guido van Rossuma3d78fb1993-11-10 09:23:53 +0000410 if (printobject((object *)ep->me_key, fp, 0) != 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000411 return -1;
412 fprintf(fp, ": ");
Guido van Rossuma3d78fb1993-11-10 09:23:53 +0000413 if (printobject(ep->me_value, fp, 0) != 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000414 return -1;
415 }
416 }
417 fprintf(fp, "}");
418 return 0;
419}
420
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000421static object *
422mapping_repr(mp)
423 mappingobject *mp;
424{
425 auto object *v;
426 object *sepa, *colon;
427 register int i;
428 register int any;
429 register mappingentry *ep;
430 v = newstringobject("{");
431 sepa = newstringobject(", ");
432 colon = newstringobject(": ");
433 any = 0;
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000434 for (i = 0, ep = mp->ma_table; i < mp->ma_size && v; i++, ep++) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000435 if (ep->me_value != NULL) {
436 if (any++)
437 joinstring(&v, sepa);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000438 joinstring_decref(&v, reprobject(ep->me_key));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000439 joinstring(&v, colon);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000440 joinstring_decref(&v, reprobject(ep->me_value));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000441 }
442 }
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000443 joinstring_decref(&v, newstringobject("}"));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000444 XDECREF(sepa);
445 XDECREF(colon);
446 return v;
447}
448
449static int
450mapping_length(mp)
451 mappingobject *mp;
452{
453 return mp->ma_used;
454}
455
456static object *
457mapping_subscript(mp, key)
458 mappingobject *mp;
459 register object *key;
460{
461 object *v;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000462 long hash;
463#ifdef CACHE_HASH
464 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
465#endif
466 hash = hashobject(key);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000467 if (hash == -1)
468 return NULL;
469 v = lookmapping(mp, key, hash) -> me_value;
470 if (v == NULL)
471 err_setval(KeyError, key);
472 else
473 INCREF(v);
474 return v;
475}
476
477static int
478mapping_ass_sub(mp, v, w)
479 mappingobject *mp;
480 object *v, *w;
481{
482 if (w == NULL)
483 return mappingremove((object *)mp, v);
484 else
485 return mappinginsert((object *)mp, v, w);
486}
487
488static mapping_methods mapping_as_mapping = {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000489 (inquiry)mapping_length, /*mp_length*/
490 (binaryfunc)mapping_subscript, /*mp_subscript*/
491 (objobjargproc)mapping_ass_sub, /*mp_ass_subscript*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000492};
493
494static object *
495mapping_keys(mp, args)
496 register mappingobject *mp;
497 object *args;
498{
499 register object *v;
500 register int i, j;
501 if (!getnoarg(args))
502 return NULL;
503 v = newlistobject(mp->ma_used);
504 if (v == NULL)
505 return NULL;
506 for (i = 0, j = 0; i < mp->ma_size; i++) {
507 if (mp->ma_table[i].me_value != NULL) {
508 object *key = mp->ma_table[i].me_key;
509 INCREF(key);
510 setlistitem(v, j, key);
511 j++;
512 }
513 }
514 return v;
515}
516
Guido van Rossum25831651993-05-19 14:50:45 +0000517static object *
518mapping_values(mp, args)
519 register mappingobject *mp;
520 object *args;
521{
522 register object *v;
523 register int i, j;
524 if (!getnoarg(args))
525 return NULL;
526 v = newlistobject(mp->ma_used);
527 if (v == NULL)
528 return NULL;
529 for (i = 0, j = 0; i < mp->ma_size; i++) {
530 if (mp->ma_table[i].me_value != NULL) {
531 object *value = mp->ma_table[i].me_value;
532 INCREF(value);
533 setlistitem(v, j, value);
534 j++;
535 }
536 }
537 return v;
538}
539
540static object *
541mapping_items(mp, args)
542 register mappingobject *mp;
543 object *args;
544{
545 register object *v;
546 register int i, j;
547 if (!getnoarg(args))
548 return NULL;
549 v = newlistobject(mp->ma_used);
550 if (v == NULL)
551 return NULL;
552 for (i = 0, j = 0; i < mp->ma_size; i++) {
553 if (mp->ma_table[i].me_value != NULL) {
554 object *key = mp->ma_table[i].me_key;
555 object *value = mp->ma_table[i].me_value;
556 object *item = newtupleobject(2);
557 if (item == NULL) {
558 DECREF(v);
559 return NULL;
560 }
561 INCREF(key);
562 settupleitem(item, 0, key);
563 INCREF(value);
564 settupleitem(item, 1, value);
565 setlistitem(v, j, item);
566 j++;
567 }
568 }
569 return v;
570}
571
Guido van Rossum4199fac1993-11-05 10:18:44 +0000572int
573getmappingsize(mp)
574 object *mp;
575{
576 if (mp == NULL || !is_mappingobject(mp)) {
577 err_badcall();
Guido van Rossumb376a4a1993-11-23 17:53:17 +0000578 return 0;
Guido van Rossum4199fac1993-11-05 10:18:44 +0000579 }
580 return ((mappingobject *)mp)->ma_used;
581}
582
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000583object *
584getmappingkeys(mp)
585 object *mp;
586{
587 if (mp == NULL || !is_mappingobject(mp)) {
588 err_badcall();
589 return NULL;
590 }
591 return mapping_keys((mappingobject *)mp, (object *)NULL);
592}
593
Guido van Rossum25831651993-05-19 14:50:45 +0000594object *
595getmappingvalues(mp)
596 object *mp;
597{
598 if (mp == NULL || !is_mappingobject(mp)) {
599 err_badcall();
600 return NULL;
601 }
602 return mapping_values((mappingobject *)mp, (object *)NULL);
603}
604
605object *
606getmappingitems(mp)
607 object *mp;
608{
609 if (mp == NULL || !is_mappingobject(mp)) {
610 err_badcall();
611 return NULL;
612 }
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000613 return mapping_items((mappingobject *)mp, (object *)NULL);
Guido van Rossum25831651993-05-19 14:50:45 +0000614}
615
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000616static int
617mapping_compare(a, b)
618 mappingobject *a, *b;
619{
620 object *akeys, *bkeys;
621 int i, n, res;
622 if (a == b)
623 return 0;
624 if (a->ma_used == 0) {
625 if (b->ma_used != 0)
626 return -1;
627 else
628 return 0;
629 }
630 else {
631 if (b->ma_used == 0)
632 return 1;
633 }
634 akeys = mapping_keys(a, (object *)NULL);
635 bkeys = mapping_keys(b, (object *)NULL);
636 if (akeys == NULL || bkeys == NULL) {
637 /* Oops, out of memory -- what to do? */
638 /* For now, sort on address! */
639 XDECREF(akeys);
640 XDECREF(bkeys);
641 if (a < b)
642 return -1;
643 else
644 return 1;
645 }
646 sortlist(akeys);
647 sortlist(bkeys);
648 n = a->ma_used < b->ma_used ? a->ma_used : b->ma_used; /* smallest */
649 res = 0;
650 for (i = 0; i < n; i++) {
651 object *akey, *bkey, *aval, *bval;
652 long ahash, bhash;
653 akey = getlistitem(akeys, i);
654 bkey = getlistitem(bkeys, i);
655 res = cmpobject(akey, bkey);
656 if (res != 0)
657 break;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000658#ifdef CACHE_HASH
659 if (!is_stringobject(akey) || (ahash = ((stringobject *) akey)->ob_shash) == -1)
660#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000661 ahash = hashobject(akey);
662 if (ahash == -1)
663 err_clear(); /* Don't want errors here */
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000664#ifdef CACHE_HASH
665 if (!is_stringobject(bkey) || (bhash = ((stringobject *) bkey)->ob_shash) == -1)
666#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000667 bhash = hashobject(bkey);
668 if (bhash == -1)
669 err_clear(); /* Don't want errors here */
670 aval = lookmapping(a, akey, ahash) -> me_value;
671 bval = lookmapping(b, bkey, bhash) -> me_value;
672 res = cmpobject(aval, bval);
673 if (res != 0)
674 break;
675 }
676 if (res == 0) {
677 if (a->ma_used < b->ma_used)
678 res = -1;
679 else if (a->ma_used > b->ma_used)
680 res = 1;
681 }
682 DECREF(akeys);
683 DECREF(bkeys);
684 return res;
685}
686
687static object *
688mapping_has_key(mp, args)
689 register mappingobject *mp;
690 object *args;
691{
692 object *key;
693 long hash;
694 register long ok;
695 if (!getargs(args, "O", &key))
696 return NULL;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000697#ifdef CACHE_HASH
698 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
699#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000700 hash = hashobject(key);
701 if (hash == -1)
702 return NULL;
703 ok = lookmapping(mp, key, hash)->me_value != NULL;
704 return newintobject(ok);
705}
706
707static struct methodlist mapp_methods[] = {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000708 {"has_key", (method)mapping_has_key},
709 {"items", (method)mapping_items},
710 {"keys", (method)mapping_keys},
711 {"values", (method)mapping_values},
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000712 {NULL, NULL} /* sentinel */
713};
714
715static object *
716mapping_getattr(mp, name)
717 mappingobject *mp;
718 char *name;
719{
720 return findmethod(mapp_methods, (object *)mp, name);
721}
722
723typeobject Mappingtype = {
724 OB_HEAD_INIT(&Typetype)
725 0,
Guido van Rossum9bfef441993-03-29 10:43:31 +0000726 "dictionary",
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000727 sizeof(mappingobject),
728 0,
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000729 (destructor)mapping_dealloc, /*tp_dealloc*/
730 (printfunc)mapping_print, /*tp_print*/
731 (getattrfunc)mapping_getattr, /*tp_getattr*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000732 0, /*tp_setattr*/
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000733 (cmpfunc)mapping_compare, /*tp_compare*/
734 (reprfunc)mapping_repr, /*tp_repr*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000735 0, /*tp_as_number*/
736 0, /*tp_as_sequence*/
737 &mapping_as_mapping, /*tp_as_mapping*/
738};
739
740/* For backward compatibility with old dictionary interface */
741
742static object *last_name_object;
743static char *last_name_char;
744
745object *
746getattro(v, name)
747 object *v;
748 object *name;
749{
750 if (name != last_name_object) {
751 XDECREF(last_name_object);
752 INCREF(name);
753 last_name_object = name;
754 last_name_char = getstringvalue(name);
755 }
756 return getattr(v, last_name_char);
757}
758
759int
760setattro(v, name, value)
761 object *v;
762 object *name;
763 object *value;
764{
765 if (name != last_name_object) {
766 XDECREF(last_name_object);
767 INCREF(name);
768 last_name_object = name;
769 last_name_char = getstringvalue(name);
770 }
771 return setattr(v, last_name_char, value);
772}
773
774object *
775dictlookup(v, key)
776 object *v;
777 char *key;
778{
Guido van Rossum8732d6a1993-11-23 17:54:03 +0000779 if (key != last_name_char ||
780 strcmp(key, getstringvalue(last_name_object)) != 0) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000781 XDECREF(last_name_object);
782 last_name_object = newstringobject(key);
783 if (last_name_object == NULL) {
784 last_name_char = NULL;
785 return NULL;
786 }
787 last_name_char = key;
788 }
789 return mappinglookup(v, last_name_object);
790}
791
792int
793dictinsert(v, key, item)
794 object *v;
795 char *key;
796 object *item;
797{
Guido van Rossum8732d6a1993-11-23 17:54:03 +0000798 if (key != last_name_char ||
799 strcmp(key, getstringvalue(last_name_object)) != 0) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000800 XDECREF(last_name_object);
801 last_name_object = newstringobject(key);
802 if (last_name_object == NULL) {
803 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +0000804 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000805 }
806 last_name_char = key;
807 }
808 return mappinginsert(v, last_name_object, item);
809}
810
811int
812dictremove(v, key)
813 object *v;
814 char *key;
815{
Guido van Rossumb376a4a1993-11-23 17:53:17 +0000816 if (key != last_name_char ||
817 strcmp(key, getstringvalue(last_name_object)) != 0) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000818 XDECREF(last_name_object);
819 last_name_object = newstringobject(key);
820 if (last_name_object == NULL) {
821 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +0000822 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000823 }
824 last_name_char = key;
825 }
826 return mappingremove(v, last_name_object);
827}