blob: 89fd314ef4b52ceb856f78c3b1fc83b91e3bf9e2 [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 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 {
136 sum = sum + sum + sum + 1;
137 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;
325 ep = lookmapping(mp, key, hash);
326 if (ep->me_value == NULL) {
327 err_setval(KeyError, key);
328 return -1;
329 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000330 old_key = ep->me_key;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000331 INCREF(dummy);
332 ep->me_key = dummy;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000333 old_value = ep->me_value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000334 ep->me_value = NULL;
335 mp->ma_used--;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000336 DECREF(old_value);
337 DECREF(old_key);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000338 return 0;
339}
340
Guido van Rossum25831651993-05-19 14:50:45 +0000341void
342mappingclear(op)
343 object *op;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000344{
Guido van Rossumd7047b31995-01-02 19:07:15 +0000345 int i, n;
346 register mappingentry *table;
347 mappingobject *mp;
Guido van Rossum25831651993-05-19 14:50:45 +0000348 if (!is_mappingobject(op))
349 return;
350 mp = (mappingobject *)op;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000351 table = mp->ma_table;
352 if (table == NULL)
353 return;
354 n = mp->ma_size;
355 mp->ma_size = mp->ma_used = mp->ma_fill = 0;
356 mp->ma_table = NULL;
357 for (i = 0; i < n; i++) {
358 XDECREF(table[i].me_key);
359 XDECREF(table[i].me_value);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000360 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000361 DEL(table);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000362}
363
Guido van Rossum25831651993-05-19 14:50:45 +0000364int
365mappinggetnext(op, ppos, pkey, pvalue)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000366 object *op;
Guido van Rossum25831651993-05-19 14:50:45 +0000367 int *ppos;
368 object **pkey;
369 object **pvalue;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000370{
Guido van Rossum25831651993-05-19 14:50:45 +0000371 int i;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000372 register mappingobject *mp;
Guido van Rossum25831651993-05-19 14:50:45 +0000373 if (!is_dictobject(op))
374 return 0;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000375 mp = (mappingobject *)op;
Guido van Rossum25831651993-05-19 14:50:45 +0000376 i = *ppos;
377 if (i < 0)
378 return 0;
379 while (i < mp->ma_size && mp->ma_table[i].me_value == NULL)
380 i++;
381 *ppos = i+1;
382 if (i >= mp->ma_size)
383 return 0;
384 if (pkey)
385 *pkey = mp->ma_table[i].me_key;
386 if (pvalue)
387 *pvalue = mp->ma_table[i].me_value;
388 return 1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000389}
390
391/* Methods */
392
393static void
394mapping_dealloc(mp)
395 register mappingobject *mp;
396{
397 register int i;
398 register mappingentry *ep;
399 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
400 if (ep->me_key != NULL)
401 DECREF(ep->me_key);
402 if (ep->me_value != NULL)
403 DECREF(ep->me_value);
404 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000405 XDEL(mp->ma_table);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000406 DEL(mp);
407}
408
409static int
410mapping_print(mp, fp, flags)
411 register mappingobject *mp;
412 register FILE *fp;
413 register int flags;
414{
415 register int i;
416 register int any;
417 register mappingentry *ep;
418 fprintf(fp, "{");
419 any = 0;
420 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
421 if (ep->me_value != NULL) {
422 if (any++ > 0)
423 fprintf(fp, ", ");
Guido van Rossuma3d78fb1993-11-10 09:23:53 +0000424 if (printobject((object *)ep->me_key, fp, 0) != 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000425 return -1;
426 fprintf(fp, ": ");
Guido van Rossuma3d78fb1993-11-10 09:23:53 +0000427 if (printobject(ep->me_value, fp, 0) != 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000428 return -1;
429 }
430 }
431 fprintf(fp, "}");
432 return 0;
433}
434
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000435static object *
436mapping_repr(mp)
437 mappingobject *mp;
438{
439 auto object *v;
440 object *sepa, *colon;
441 register int i;
442 register int any;
443 register mappingentry *ep;
444 v = newstringobject("{");
445 sepa = newstringobject(", ");
446 colon = newstringobject(": ");
447 any = 0;
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000448 for (i = 0, ep = mp->ma_table; i < mp->ma_size && v; i++, ep++) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000449 if (ep->me_value != NULL) {
450 if (any++)
451 joinstring(&v, sepa);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000452 joinstring_decref(&v, reprobject(ep->me_key));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000453 joinstring(&v, colon);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000454 joinstring_decref(&v, reprobject(ep->me_value));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000455 }
456 }
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000457 joinstring_decref(&v, newstringobject("}"));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000458 XDECREF(sepa);
459 XDECREF(colon);
460 return v;
461}
462
463static int
464mapping_length(mp)
465 mappingobject *mp;
466{
467 return mp->ma_used;
468}
469
470static object *
471mapping_subscript(mp, key)
472 mappingobject *mp;
473 register object *key;
474{
475 object *v;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000476 long hash;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000477 if (mp->ma_table == NULL) {
478 err_setval(KeyError, key);
479 return NULL;
480 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000481#ifdef CACHE_HASH
482 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
483#endif
484 hash = hashobject(key);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000485 if (hash == -1)
486 return NULL;
487 v = lookmapping(mp, key, hash) -> me_value;
488 if (v == NULL)
489 err_setval(KeyError, key);
490 else
491 INCREF(v);
492 return v;
493}
494
495static int
496mapping_ass_sub(mp, v, w)
497 mappingobject *mp;
498 object *v, *w;
499{
500 if (w == NULL)
501 return mappingremove((object *)mp, v);
502 else
503 return mappinginsert((object *)mp, v, w);
504}
505
506static mapping_methods mapping_as_mapping = {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000507 (inquiry)mapping_length, /*mp_length*/
508 (binaryfunc)mapping_subscript, /*mp_subscript*/
509 (objobjargproc)mapping_ass_sub, /*mp_ass_subscript*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000510};
511
512static object *
513mapping_keys(mp, args)
514 register mappingobject *mp;
515 object *args;
516{
517 register object *v;
518 register int i, j;
519 if (!getnoarg(args))
520 return NULL;
521 v = newlistobject(mp->ma_used);
522 if (v == NULL)
523 return NULL;
524 for (i = 0, j = 0; i < mp->ma_size; i++) {
525 if (mp->ma_table[i].me_value != NULL) {
526 object *key = mp->ma_table[i].me_key;
527 INCREF(key);
528 setlistitem(v, j, key);
529 j++;
530 }
531 }
532 return v;
533}
534
Guido van Rossum25831651993-05-19 14:50:45 +0000535static object *
536mapping_values(mp, args)
537 register mappingobject *mp;
538 object *args;
539{
540 register object *v;
541 register int i, j;
542 if (!getnoarg(args))
543 return NULL;
544 v = newlistobject(mp->ma_used);
545 if (v == NULL)
546 return NULL;
547 for (i = 0, j = 0; i < mp->ma_size; i++) {
548 if (mp->ma_table[i].me_value != NULL) {
549 object *value = mp->ma_table[i].me_value;
550 INCREF(value);
551 setlistitem(v, j, value);
552 j++;
553 }
554 }
555 return v;
556}
557
558static object *
559mapping_items(mp, args)
560 register mappingobject *mp;
561 object *args;
562{
563 register object *v;
564 register int i, j;
565 if (!getnoarg(args))
566 return NULL;
567 v = newlistobject(mp->ma_used);
568 if (v == NULL)
569 return NULL;
570 for (i = 0, j = 0; i < mp->ma_size; i++) {
571 if (mp->ma_table[i].me_value != NULL) {
572 object *key = mp->ma_table[i].me_key;
573 object *value = mp->ma_table[i].me_value;
574 object *item = newtupleobject(2);
575 if (item == NULL) {
576 DECREF(v);
577 return NULL;
578 }
579 INCREF(key);
580 settupleitem(item, 0, key);
581 INCREF(value);
582 settupleitem(item, 1, value);
583 setlistitem(v, j, item);
584 j++;
585 }
586 }
587 return v;
588}
589
Guido van Rossum4199fac1993-11-05 10:18:44 +0000590int
591getmappingsize(mp)
592 object *mp;
593{
594 if (mp == NULL || !is_mappingobject(mp)) {
595 err_badcall();
Guido van Rossumb376a4a1993-11-23 17:53:17 +0000596 return 0;
Guido van Rossum4199fac1993-11-05 10:18:44 +0000597 }
598 return ((mappingobject *)mp)->ma_used;
599}
600
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000601object *
602getmappingkeys(mp)
603 object *mp;
604{
605 if (mp == NULL || !is_mappingobject(mp)) {
606 err_badcall();
607 return NULL;
608 }
609 return mapping_keys((mappingobject *)mp, (object *)NULL);
610}
611
Guido van Rossum25831651993-05-19 14:50:45 +0000612object *
613getmappingvalues(mp)
614 object *mp;
615{
616 if (mp == NULL || !is_mappingobject(mp)) {
617 err_badcall();
618 return NULL;
619 }
620 return mapping_values((mappingobject *)mp, (object *)NULL);
621}
622
623object *
624getmappingitems(mp)
625 object *mp;
626{
627 if (mp == NULL || !is_mappingobject(mp)) {
628 err_badcall();
629 return NULL;
630 }
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000631 return mapping_items((mappingobject *)mp, (object *)NULL);
Guido van Rossum25831651993-05-19 14:50:45 +0000632}
633
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000634static int
635mapping_compare(a, b)
636 mappingobject *a, *b;
637{
638 object *akeys, *bkeys;
639 int i, n, res;
640 if (a == b)
641 return 0;
642 if (a->ma_used == 0) {
643 if (b->ma_used != 0)
644 return -1;
645 else
646 return 0;
647 }
648 else {
649 if (b->ma_used == 0)
650 return 1;
651 }
652 akeys = mapping_keys(a, (object *)NULL);
653 bkeys = mapping_keys(b, (object *)NULL);
654 if (akeys == NULL || bkeys == NULL) {
655 /* Oops, out of memory -- what to do? */
656 /* For now, sort on address! */
657 XDECREF(akeys);
658 XDECREF(bkeys);
659 if (a < b)
660 return -1;
661 else
662 return 1;
663 }
664 sortlist(akeys);
665 sortlist(bkeys);
666 n = a->ma_used < b->ma_used ? a->ma_used : b->ma_used; /* smallest */
667 res = 0;
668 for (i = 0; i < n; i++) {
669 object *akey, *bkey, *aval, *bval;
670 long ahash, bhash;
671 akey = getlistitem(akeys, i);
672 bkey = getlistitem(bkeys, i);
673 res = cmpobject(akey, bkey);
674 if (res != 0)
675 break;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000676#ifdef CACHE_HASH
677 if (!is_stringobject(akey) || (ahash = ((stringobject *) akey)->ob_shash) == -1)
678#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000679 ahash = hashobject(akey);
680 if (ahash == -1)
681 err_clear(); /* Don't want errors here */
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000682#ifdef CACHE_HASH
683 if (!is_stringobject(bkey) || (bhash = ((stringobject *) bkey)->ob_shash) == -1)
684#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000685 bhash = hashobject(bkey);
686 if (bhash == -1)
687 err_clear(); /* Don't want errors here */
688 aval = lookmapping(a, akey, ahash) -> me_value;
689 bval = lookmapping(b, bkey, bhash) -> me_value;
690 res = cmpobject(aval, bval);
691 if (res != 0)
692 break;
693 }
694 if (res == 0) {
695 if (a->ma_used < b->ma_used)
696 res = -1;
697 else if (a->ma_used > b->ma_used)
698 res = 1;
699 }
700 DECREF(akeys);
701 DECREF(bkeys);
702 return res;
703}
704
705static object *
706mapping_has_key(mp, args)
707 register mappingobject *mp;
708 object *args;
709{
710 object *key;
711 long hash;
712 register long ok;
713 if (!getargs(args, "O", &key))
714 return NULL;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000715#ifdef CACHE_HASH
716 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
717#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000718 hash = hashobject(key);
719 if (hash == -1)
720 return NULL;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000721 ok = mp->ma_size != 0 && lookmapping(mp, key, hash)->me_value != NULL;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000722 return newintobject(ok);
723}
724
725static struct methodlist mapp_methods[] = {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000726 {"has_key", (method)mapping_has_key},
727 {"items", (method)mapping_items},
728 {"keys", (method)mapping_keys},
729 {"values", (method)mapping_values},
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000730 {NULL, NULL} /* sentinel */
731};
732
733static object *
734mapping_getattr(mp, name)
735 mappingobject *mp;
736 char *name;
737{
738 return findmethod(mapp_methods, (object *)mp, name);
739}
740
741typeobject Mappingtype = {
742 OB_HEAD_INIT(&Typetype)
743 0,
Guido van Rossum9bfef441993-03-29 10:43:31 +0000744 "dictionary",
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000745 sizeof(mappingobject),
746 0,
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000747 (destructor)mapping_dealloc, /*tp_dealloc*/
748 (printfunc)mapping_print, /*tp_print*/
749 (getattrfunc)mapping_getattr, /*tp_getattr*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000750 0, /*tp_setattr*/
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000751 (cmpfunc)mapping_compare, /*tp_compare*/
752 (reprfunc)mapping_repr, /*tp_repr*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000753 0, /*tp_as_number*/
754 0, /*tp_as_sequence*/
755 &mapping_as_mapping, /*tp_as_mapping*/
756};
757
758/* For backward compatibility with old dictionary interface */
759
760static object *last_name_object;
761static char *last_name_char;
762
763object *
764getattro(v, name)
765 object *v;
766 object *name;
767{
768 if (name != last_name_object) {
769 XDECREF(last_name_object);
770 INCREF(name);
771 last_name_object = name;
772 last_name_char = getstringvalue(name);
773 }
774 return getattr(v, last_name_char);
775}
776
777int
778setattro(v, name, value)
779 object *v;
780 object *name;
781 object *value;
782{
783 if (name != last_name_object) {
784 XDECREF(last_name_object);
785 INCREF(name);
786 last_name_object = name;
787 last_name_char = getstringvalue(name);
788 }
789 return setattr(v, last_name_char, value);
790}
791
792object *
793dictlookup(v, key)
794 object *v;
795 char *key;
796{
Guido van Rossum8732d6a1993-11-23 17:54:03 +0000797 if (key != last_name_char ||
798 strcmp(key, getstringvalue(last_name_object)) != 0) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000799 XDECREF(last_name_object);
800 last_name_object = newstringobject(key);
801 if (last_name_object == NULL) {
802 last_name_char = NULL;
803 return NULL;
804 }
805 last_name_char = key;
806 }
807 return mappinglookup(v, last_name_object);
808}
809
810int
811dictinsert(v, key, item)
812 object *v;
813 char *key;
814 object *item;
815{
Guido van Rossum8732d6a1993-11-23 17:54:03 +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 mappinginsert(v, last_name_object, item);
827}
828
829int
830dictremove(v, key)
831 object *v;
832 char *key;
833{
Guido van Rossumb376a4a1993-11-23 17:53:17 +0000834 if (key != last_name_char ||
835 strcmp(key, getstringvalue(last_name_object)) != 0) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000836 XDECREF(last_name_object);
837 last_name_object = newstringobject(key);
838 if (last_name_object == NULL) {
839 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +0000840 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000841 }
842 last_name_char = key;
843 }
844 return mappingremove(v, last_name_object);
845}