blob: 11d344a9742ed99933f3d5d31cafebfcdf2cbfc0 [file] [log] [blame]
Guido van Rossum4b1302b1993-03-27 18:11:32 +00001/***********************************************************
Guido van Rossum6610ad91995-01-04 19:07:38 +00002Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
Guido van Rossum4b1302b1993-03-27 18:11:32 +00004
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 Rossumd7047b31995-01-02 19:07:15 +000049 65521L, 131071L, 262139L, 524287L, 1048573L, 2097143L,
50 4194301L, 8388593L, 16777213L, 33554393L, 67108859L,
51 134217689L, 268435399L, 536870909L, 1073741789L,
Guido van Rossum1d5735e1994-08-30 08:27:36 +000052 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;
Guido van Rossumd7047b31995-01-02 19:07:15 +000098 mp->ma_size = 0;
99 mp->ma_table = NULL;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000100 mp->ma_fill = 0;
101 mp->ma_used = 0;
102 return (object *)mp;
103}
104
105/*
106The basic lookup function used by all operations.
107This is essentially Algorithm D from Knuth Vol. 3, Sec. 6.4.
108Open addressing is preferred over chaining since the link overhead for
109chaining would be substantial (100% with typical malloc overhead).
110
111First a 32-bit hash value, 'sum', is computed from the key string.
112The first character is added an extra time shifted by 8 to avoid hashing
113single-character keys (often heavily used variables) too close together.
114All arithmetic on sum should ignore overflow.
115
116The initial probe index is then computed as sum mod the table size.
117Subsequent probe indices are incr apart (mod table size), where incr
118is also derived from sum, with the additional requirement that it is
119relative prime to the table size (i.e., 1 <= incr < size, since the size
120is a prime number). My choice for incr is somewhat arbitrary.
121*/
122static mappingentry *lookmapping PROTO((mappingobject *, object *, long));
123static mappingentry *
124lookmapping(mp, key, hash)
125 register mappingobject *mp;
126 object *key;
127 long hash;
128{
129 register int i, incr;
130 register unsigned long sum = (unsigned long) hash;
131 register mappingentry *freeslot = NULL;
132 /* We must come up with (i, incr) such that 0 <= i < ma_size
133 and 0 < incr < ma_size and both are a function of hash */
134 i = sum % mp->ma_size;
135 do {
Guido van Rossum5fe60581995-03-09 12:12:50 +0000136 sum = 3*sum + 1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000137 incr = sum % mp->ma_size;
138 } while (incr == 0);
139 for (;;) {
140 register mappingentry *ep = &mp->ma_table[i];
141 if (ep->me_key == NULL) {
142 if (freeslot != NULL)
143 return freeslot;
144 else
145 return ep;
146 }
147 if (ep->me_key == dummy) {
Guido van Rossum52f2c051993-11-10 12:53:24 +0000148 if (freeslot == NULL)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000149 freeslot = ep;
150 }
151 else if (ep->me_hash == hash &&
152 cmpobject(ep->me_key, key) == 0) {
153 return ep;
154 }
155 i = (i + incr) % mp->ma_size;
156 }
157}
158
159/*
160Internal routine to insert a new item into the table.
161Used both by the internal resize routine and by the public insert routine.
162Eats a reference to key and one to value.
163*/
164static void insertmapping PROTO((mappingobject *, object *, long, object *));
165static void
166insertmapping(mp, key, hash, value)
167 register mappingobject *mp;
168 object *key;
169 long hash;
170 object *value;
171{
Guido van Rossumd7047b31995-01-02 19:07:15 +0000172 object *old_value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000173 register mappingentry *ep;
174 ep = lookmapping(mp, key, hash);
175 if (ep->me_value != NULL) {
Guido van Rossumd7047b31995-01-02 19:07:15 +0000176 old_value = ep->me_value;
177 ep->me_value = value;
178 DECREF(old_value); /* which **CAN** re-enter */
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000179 DECREF(key);
180 }
181 else {
182 if (ep->me_key == NULL)
183 mp->ma_fill++;
184 else
185 DECREF(ep->me_key);
186 ep->me_key = key;
187 ep->me_hash = hash;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000188 ep->me_value = value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000189 mp->ma_used++;
190 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000191}
192
193/*
194Restructure the table by allocating a new table and reinserting all
195items again. When entries have been deleted, the new table may
196actually be smaller than the old one.
197*/
198static int mappingresize PROTO((mappingobject *));
199static int
200mappingresize(mp)
201 mappingobject *mp;
202{
203 register int oldsize = mp->ma_size;
204 register int newsize;
205 register mappingentry *oldtable = mp->ma_table;
206 register mappingentry *newtable;
207 register mappingentry *ep;
208 register int i;
209 newsize = mp->ma_size;
210 for (i = 0; ; i++) {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000211 if (primes[i] <= 0) {
212 /* Ran out of primes */
213 err_nomem();
214 return -1;
215 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000216 if (primes[i] > mp->ma_used*2) {
217 newsize = primes[i];
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000218 if (newsize != primes[i]) {
219 /* Integer truncation */
220 err_nomem();
221 return -1;
222 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000223 break;
224 }
225 }
226 newtable = (mappingentry *) calloc(sizeof(mappingentry), newsize);
227 if (newtable == NULL) {
228 err_nomem();
229 return -1;
230 }
231 mp->ma_size = newsize;
232 mp->ma_table = newtable;
233 mp->ma_fill = 0;
234 mp->ma_used = 0;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000235
236 /* Make two passes, so we can avoid decrefs
237 (and possible side effects) till the table is copied */
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000238 for (i = 0, ep = oldtable; i < oldsize; i++, ep++) {
239 if (ep->me_value != NULL)
240 insertmapping(mp,ep->me_key,ep->me_hash,ep->me_value);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000241 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000242 for (i = 0, ep = oldtable; i < oldsize; i++, ep++) {
243 if (ep->me_value == NULL)
244 XDECREF(ep->me_key);
245 }
246
247 XDEL(oldtable);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000248 return 0;
249}
250
251object *
252mappinglookup(op, key)
253 object *op;
254 object *key;
255{
256 long hash;
257 if (!is_mappingobject(op)) {
258 err_badcall();
259 return NULL;
260 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000261 if (((mappingobject *)op)->ma_table == NULL)
262 return NULL;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000263#ifdef CACHE_HASH
264 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
265#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000266 hash = hashobject(key);
267 if (hash == -1)
268 return NULL;
269 return lookmapping((mappingobject *)op, key, hash) -> me_value;
270}
271
272int
273mappinginsert(op, key, value)
274 register object *op;
275 object *key;
276 object *value;
277{
278 register mappingobject *mp;
279 register long hash;
280 if (!is_mappingobject(op)) {
281 err_badcall();
282 return -1;
283 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000284#ifdef CACHE_HASH
285 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
286#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000287 hash = hashobject(key);
288 if (hash == -1)
289 return -1;
290 mp = (mappingobject *)op;
291 /* if fill >= 2/3 size, resize */
292 if (mp->ma_fill*3 >= mp->ma_size*2) {
293 if (mappingresize(mp) != 0) {
294 if (mp->ma_fill+1 > mp->ma_size)
295 return -1;
296 }
297 }
298 INCREF(value);
299 INCREF(key);
300 insertmapping(mp, key, hash, value);
301 return 0;
302}
303
304int
305mappingremove(op, key)
306 object *op;
307 object *key;
308{
309 register mappingobject *mp;
310 register long hash;
311 register mappingentry *ep;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000312 object *old_value, *old_key;
313
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000314 if (!is_mappingobject(op)) {
315 err_badcall();
316 return -1;
317 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000318#ifdef CACHE_HASH
319 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
320#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000321 hash = hashobject(key);
322 if (hash == -1)
323 return -1;
324 mp = (mappingobject *)op;
Guido van Rossumefc87131995-01-02 19:42:39 +0000325 if (((mappingobject *)op)->ma_table == NULL)
326 goto empty;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000327 ep = lookmapping(mp, key, hash);
328 if (ep->me_value == NULL) {
Guido van Rossumefc87131995-01-02 19:42:39 +0000329 empty:
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000330 err_setval(KeyError, key);
331 return -1;
332 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000333 old_key = ep->me_key;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000334 INCREF(dummy);
335 ep->me_key = dummy;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000336 old_value = ep->me_value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000337 ep->me_value = NULL;
338 mp->ma_used--;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000339 DECREF(old_value);
340 DECREF(old_key);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000341 return 0;
342}
343
Guido van Rossum25831651993-05-19 14:50:45 +0000344void
345mappingclear(op)
346 object *op;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000347{
Guido van Rossumd7047b31995-01-02 19:07:15 +0000348 int i, n;
349 register mappingentry *table;
350 mappingobject *mp;
Guido van Rossum25831651993-05-19 14:50:45 +0000351 if (!is_mappingobject(op))
352 return;
353 mp = (mappingobject *)op;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000354 table = mp->ma_table;
355 if (table == NULL)
356 return;
357 n = mp->ma_size;
358 mp->ma_size = mp->ma_used = mp->ma_fill = 0;
359 mp->ma_table = NULL;
360 for (i = 0; i < n; i++) {
361 XDECREF(table[i].me_key);
362 XDECREF(table[i].me_value);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000363 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000364 DEL(table);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000365}
366
Guido van Rossum25831651993-05-19 14:50:45 +0000367int
368mappinggetnext(op, ppos, pkey, pvalue)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000369 object *op;
Guido van Rossum25831651993-05-19 14:50:45 +0000370 int *ppos;
371 object **pkey;
372 object **pvalue;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000373{
Guido van Rossum25831651993-05-19 14:50:45 +0000374 int i;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000375 register mappingobject *mp;
Guido van Rossum25831651993-05-19 14:50:45 +0000376 if (!is_dictobject(op))
377 return 0;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000378 mp = (mappingobject *)op;
Guido van Rossum25831651993-05-19 14:50:45 +0000379 i = *ppos;
380 if (i < 0)
381 return 0;
382 while (i < mp->ma_size && mp->ma_table[i].me_value == NULL)
383 i++;
384 *ppos = i+1;
385 if (i >= mp->ma_size)
386 return 0;
387 if (pkey)
388 *pkey = mp->ma_table[i].me_key;
389 if (pvalue)
390 *pvalue = mp->ma_table[i].me_value;
391 return 1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000392}
393
394/* Methods */
395
396static void
397mapping_dealloc(mp)
398 register mappingobject *mp;
399{
400 register int i;
401 register mappingentry *ep;
402 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
403 if (ep->me_key != NULL)
404 DECREF(ep->me_key);
405 if (ep->me_value != NULL)
406 DECREF(ep->me_value);
407 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000408 XDEL(mp->ma_table);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000409 DEL(mp);
410}
411
412static int
413mapping_print(mp, fp, flags)
414 register mappingobject *mp;
415 register FILE *fp;
416 register int flags;
417{
418 register int i;
419 register int any;
420 register mappingentry *ep;
421 fprintf(fp, "{");
422 any = 0;
423 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
424 if (ep->me_value != NULL) {
425 if (any++ > 0)
426 fprintf(fp, ", ");
Guido van Rossuma3d78fb1993-11-10 09:23:53 +0000427 if (printobject((object *)ep->me_key, fp, 0) != 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000428 return -1;
429 fprintf(fp, ": ");
Guido van Rossuma3d78fb1993-11-10 09:23:53 +0000430 if (printobject(ep->me_value, fp, 0) != 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000431 return -1;
432 }
433 }
434 fprintf(fp, "}");
435 return 0;
436}
437
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000438static object *
439mapping_repr(mp)
440 mappingobject *mp;
441{
442 auto object *v;
443 object *sepa, *colon;
444 register int i;
445 register int any;
446 register mappingentry *ep;
447 v = newstringobject("{");
448 sepa = newstringobject(", ");
449 colon = newstringobject(": ");
450 any = 0;
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000451 for (i = 0, ep = mp->ma_table; i < mp->ma_size && v; i++, ep++) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000452 if (ep->me_value != NULL) {
453 if (any++)
454 joinstring(&v, sepa);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000455 joinstring_decref(&v, reprobject(ep->me_key));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000456 joinstring(&v, colon);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000457 joinstring_decref(&v, reprobject(ep->me_value));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000458 }
459 }
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000460 joinstring_decref(&v, newstringobject("}"));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000461 XDECREF(sepa);
462 XDECREF(colon);
463 return v;
464}
465
466static int
467mapping_length(mp)
468 mappingobject *mp;
469{
470 return mp->ma_used;
471}
472
473static object *
474mapping_subscript(mp, key)
475 mappingobject *mp;
476 register object *key;
477{
478 object *v;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000479 long hash;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000480 if (mp->ma_table == NULL) {
481 err_setval(KeyError, key);
482 return NULL;
483 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000484#ifdef CACHE_HASH
485 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
486#endif
487 hash = hashobject(key);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000488 if (hash == -1)
489 return NULL;
490 v = lookmapping(mp, key, hash) -> me_value;
491 if (v == NULL)
492 err_setval(KeyError, key);
493 else
494 INCREF(v);
495 return v;
496}
497
498static int
499mapping_ass_sub(mp, v, w)
500 mappingobject *mp;
501 object *v, *w;
502{
503 if (w == NULL)
504 return mappingremove((object *)mp, v);
505 else
506 return mappinginsert((object *)mp, v, w);
507}
508
509static mapping_methods mapping_as_mapping = {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000510 (inquiry)mapping_length, /*mp_length*/
511 (binaryfunc)mapping_subscript, /*mp_subscript*/
512 (objobjargproc)mapping_ass_sub, /*mp_ass_subscript*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000513};
514
515static object *
516mapping_keys(mp, args)
517 register mappingobject *mp;
518 object *args;
519{
520 register object *v;
521 register int i, j;
522 if (!getnoarg(args))
523 return NULL;
524 v = newlistobject(mp->ma_used);
525 if (v == NULL)
526 return NULL;
527 for (i = 0, j = 0; i < mp->ma_size; i++) {
528 if (mp->ma_table[i].me_value != NULL) {
529 object *key = mp->ma_table[i].me_key;
530 INCREF(key);
531 setlistitem(v, j, key);
532 j++;
533 }
534 }
535 return v;
536}
537
Guido van Rossum25831651993-05-19 14:50:45 +0000538static object *
539mapping_values(mp, args)
540 register mappingobject *mp;
541 object *args;
542{
543 register object *v;
544 register int i, j;
545 if (!getnoarg(args))
546 return NULL;
547 v = newlistobject(mp->ma_used);
548 if (v == NULL)
549 return NULL;
550 for (i = 0, j = 0; i < mp->ma_size; i++) {
551 if (mp->ma_table[i].me_value != NULL) {
552 object *value = mp->ma_table[i].me_value;
553 INCREF(value);
554 setlistitem(v, j, value);
555 j++;
556 }
557 }
558 return v;
559}
560
561static object *
562mapping_items(mp, args)
563 register mappingobject *mp;
564 object *args;
565{
566 register object *v;
567 register int i, j;
568 if (!getnoarg(args))
569 return NULL;
570 v = newlistobject(mp->ma_used);
571 if (v == NULL)
572 return NULL;
573 for (i = 0, j = 0; i < mp->ma_size; i++) {
574 if (mp->ma_table[i].me_value != NULL) {
575 object *key = mp->ma_table[i].me_key;
576 object *value = mp->ma_table[i].me_value;
577 object *item = newtupleobject(2);
578 if (item == NULL) {
579 DECREF(v);
580 return NULL;
581 }
582 INCREF(key);
583 settupleitem(item, 0, key);
584 INCREF(value);
585 settupleitem(item, 1, value);
586 setlistitem(v, j, item);
587 j++;
588 }
589 }
590 return v;
591}
592
Guido van Rossum4199fac1993-11-05 10:18:44 +0000593int
594getmappingsize(mp)
595 object *mp;
596{
597 if (mp == NULL || !is_mappingobject(mp)) {
598 err_badcall();
Guido van Rossumb376a4a1993-11-23 17:53:17 +0000599 return 0;
Guido van Rossum4199fac1993-11-05 10:18:44 +0000600 }
601 return ((mappingobject *)mp)->ma_used;
602}
603
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000604object *
605getmappingkeys(mp)
606 object *mp;
607{
608 if (mp == NULL || !is_mappingobject(mp)) {
609 err_badcall();
610 return NULL;
611 }
612 return mapping_keys((mappingobject *)mp, (object *)NULL);
613}
614
Guido van Rossum25831651993-05-19 14:50:45 +0000615object *
616getmappingvalues(mp)
617 object *mp;
618{
619 if (mp == NULL || !is_mappingobject(mp)) {
620 err_badcall();
621 return NULL;
622 }
623 return mapping_values((mappingobject *)mp, (object *)NULL);
624}
625
626object *
627getmappingitems(mp)
628 object *mp;
629{
630 if (mp == NULL || !is_mappingobject(mp)) {
631 err_badcall();
632 return NULL;
633 }
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000634 return mapping_items((mappingobject *)mp, (object *)NULL);
Guido van Rossum25831651993-05-19 14:50:45 +0000635}
636
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000637static int
638mapping_compare(a, b)
639 mappingobject *a, *b;
640{
641 object *akeys, *bkeys;
642 int i, n, res;
643 if (a == b)
644 return 0;
645 if (a->ma_used == 0) {
646 if (b->ma_used != 0)
647 return -1;
648 else
649 return 0;
650 }
651 else {
652 if (b->ma_used == 0)
653 return 1;
654 }
655 akeys = mapping_keys(a, (object *)NULL);
656 bkeys = mapping_keys(b, (object *)NULL);
657 if (akeys == NULL || bkeys == NULL) {
658 /* Oops, out of memory -- what to do? */
659 /* For now, sort on address! */
660 XDECREF(akeys);
661 XDECREF(bkeys);
662 if (a < b)
663 return -1;
664 else
665 return 1;
666 }
667 sortlist(akeys);
668 sortlist(bkeys);
669 n = a->ma_used < b->ma_used ? a->ma_used : b->ma_used; /* smallest */
670 res = 0;
671 for (i = 0; i < n; i++) {
672 object *akey, *bkey, *aval, *bval;
673 long ahash, bhash;
674 akey = getlistitem(akeys, i);
675 bkey = getlistitem(bkeys, i);
676 res = cmpobject(akey, bkey);
677 if (res != 0)
678 break;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000679#ifdef CACHE_HASH
680 if (!is_stringobject(akey) || (ahash = ((stringobject *) akey)->ob_shash) == -1)
681#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000682 ahash = hashobject(akey);
683 if (ahash == -1)
684 err_clear(); /* Don't want errors here */
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000685#ifdef CACHE_HASH
686 if (!is_stringobject(bkey) || (bhash = ((stringobject *) bkey)->ob_shash) == -1)
687#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000688 bhash = hashobject(bkey);
689 if (bhash == -1)
690 err_clear(); /* Don't want errors here */
691 aval = lookmapping(a, akey, ahash) -> me_value;
692 bval = lookmapping(b, bkey, bhash) -> me_value;
693 res = cmpobject(aval, bval);
694 if (res != 0)
695 break;
696 }
697 if (res == 0) {
698 if (a->ma_used < b->ma_used)
699 res = -1;
700 else if (a->ma_used > b->ma_used)
701 res = 1;
702 }
703 DECREF(akeys);
704 DECREF(bkeys);
705 return res;
706}
707
708static object *
709mapping_has_key(mp, args)
710 register mappingobject *mp;
711 object *args;
712{
713 object *key;
714 long hash;
715 register long ok;
716 if (!getargs(args, "O", &key))
717 return NULL;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000718#ifdef CACHE_HASH
719 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
720#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000721 hash = hashobject(key);
722 if (hash == -1)
723 return NULL;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000724 ok = mp->ma_size != 0 && lookmapping(mp, key, hash)->me_value != NULL;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000725 return newintobject(ok);
726}
727
728static struct methodlist mapp_methods[] = {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000729 {"has_key", (method)mapping_has_key},
730 {"items", (method)mapping_items},
731 {"keys", (method)mapping_keys},
732 {"values", (method)mapping_values},
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000733 {NULL, NULL} /* sentinel */
734};
735
736static object *
737mapping_getattr(mp, name)
738 mappingobject *mp;
739 char *name;
740{
741 return findmethod(mapp_methods, (object *)mp, name);
742}
743
744typeobject Mappingtype = {
745 OB_HEAD_INIT(&Typetype)
746 0,
Guido van Rossum9bfef441993-03-29 10:43:31 +0000747 "dictionary",
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000748 sizeof(mappingobject),
749 0,
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000750 (destructor)mapping_dealloc, /*tp_dealloc*/
751 (printfunc)mapping_print, /*tp_print*/
752 (getattrfunc)mapping_getattr, /*tp_getattr*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000753 0, /*tp_setattr*/
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000754 (cmpfunc)mapping_compare, /*tp_compare*/
755 (reprfunc)mapping_repr, /*tp_repr*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000756 0, /*tp_as_number*/
757 0, /*tp_as_sequence*/
758 &mapping_as_mapping, /*tp_as_mapping*/
759};
760
761/* For backward compatibility with old dictionary interface */
762
763static object *last_name_object;
764static char *last_name_char;
765
766object *
767getattro(v, name)
768 object *v;
769 object *name;
770{
771 if (name != last_name_object) {
772 XDECREF(last_name_object);
773 INCREF(name);
774 last_name_object = name;
775 last_name_char = getstringvalue(name);
776 }
777 return getattr(v, last_name_char);
778}
779
780int
781setattro(v, name, value)
782 object *v;
783 object *name;
784 object *value;
785{
786 if (name != last_name_object) {
787 XDECREF(last_name_object);
788 INCREF(name);
789 last_name_object = name;
790 last_name_char = getstringvalue(name);
791 }
792 return setattr(v, last_name_char, value);
793}
794
795object *
796dictlookup(v, key)
797 object *v;
798 char *key;
799{
Guido van Rossum8732d6a1993-11-23 17:54:03 +0000800 if (key != last_name_char ||
801 strcmp(key, getstringvalue(last_name_object)) != 0) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000802 XDECREF(last_name_object);
803 last_name_object = newstringobject(key);
804 if (last_name_object == NULL) {
805 last_name_char = NULL;
806 return NULL;
807 }
808 last_name_char = key;
809 }
810 return mappinglookup(v, last_name_object);
811}
812
813int
814dictinsert(v, key, item)
815 object *v;
816 char *key;
817 object *item;
818{
Guido van Rossum8732d6a1993-11-23 17:54:03 +0000819 if (key != last_name_char ||
820 strcmp(key, getstringvalue(last_name_object)) != 0) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000821 XDECREF(last_name_object);
822 last_name_object = newstringobject(key);
823 if (last_name_object == NULL) {
824 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +0000825 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000826 }
827 last_name_char = key;
828 }
829 return mappinginsert(v, last_name_object, item);
830}
831
832int
833dictremove(v, key)
834 object *v;
835 char *key;
836{
Guido van Rossumb376a4a1993-11-23 17:53:17 +0000837 if (key != last_name_char ||
838 strcmp(key, getstringvalue(last_name_object)) != 0) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000839 XDECREF(last_name_object);
840 last_name_object = newstringobject(key);
841 if (last_name_object == NULL) {
842 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +0000843 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000844 }
845 last_name_char = key;
846 }
847 return mappingremove(v, last_name_object);
848}