blob: f6558283eddfc46fea0765b01cbe881bb8df6fa9 [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;
Guido van Rossum310968d1996-07-30 16:45:31 +0000132 register int size = mp->ma_size;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000133 /* We must come up with (i, incr) such that 0 <= i < ma_size
134 and 0 < incr < ma_size and both are a function of hash */
Guido van Rossum310968d1996-07-30 16:45:31 +0000135 i = sum % size;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000136 do {
Guido van Rossum5fe60581995-03-09 12:12:50 +0000137 sum = 3*sum + 1;
Guido van Rossum310968d1996-07-30 16:45:31 +0000138 incr = sum % size;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000139 } while (incr == 0);
140 for (;;) {
141 register mappingentry *ep = &mp->ma_table[i];
142 if (ep->me_key == NULL) {
143 if (freeslot != NULL)
144 return freeslot;
145 else
146 return ep;
147 }
148 if (ep->me_key == dummy) {
Guido van Rossum52f2c051993-11-10 12:53:24 +0000149 if (freeslot == NULL)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000150 freeslot = ep;
151 }
152 else if (ep->me_hash == hash &&
153 cmpobject(ep->me_key, key) == 0) {
154 return ep;
155 }
Guido van Rossum310968d1996-07-30 16:45:31 +0000156 i = (i + incr) % size;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000157 }
158}
159
160/*
161Internal routine to insert a new item into the table.
162Used both by the internal resize routine and by the public insert routine.
163Eats a reference to key and one to value.
164*/
165static void insertmapping PROTO((mappingobject *, object *, long, object *));
166static void
167insertmapping(mp, key, hash, value)
168 register mappingobject *mp;
169 object *key;
170 long hash;
171 object *value;
172{
Guido van Rossumd7047b31995-01-02 19:07:15 +0000173 object *old_value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000174 register mappingentry *ep;
175 ep = lookmapping(mp, key, hash);
176 if (ep->me_value != NULL) {
Guido van Rossumd7047b31995-01-02 19:07:15 +0000177 old_value = ep->me_value;
178 ep->me_value = value;
179 DECREF(old_value); /* which **CAN** re-enter */
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000180 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;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000189 ep->me_value = value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000190 mp->ma_used++;
191 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000192}
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;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000236
237 /* Make two passes, so we can avoid decrefs
238 (and possible side effects) till the table is copied */
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000239 for (i = 0, ep = oldtable; i < oldsize; i++, ep++) {
240 if (ep->me_value != NULL)
241 insertmapping(mp,ep->me_key,ep->me_hash,ep->me_value);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000242 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000243 for (i = 0, ep = oldtable; i < oldsize; i++, ep++) {
244 if (ep->me_value == NULL)
245 XDECREF(ep->me_key);
246 }
247
248 XDEL(oldtable);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000249 return 0;
250}
251
252object *
253mappinglookup(op, key)
254 object *op;
255 object *key;
256{
257 long hash;
258 if (!is_mappingobject(op)) {
259 err_badcall();
260 return NULL;
261 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000262 if (((mappingobject *)op)->ma_table == NULL)
263 return NULL;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000264#ifdef CACHE_HASH
265 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
266#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000267 hash = hashobject(key);
268 if (hash == -1)
269 return NULL;
270 return lookmapping((mappingobject *)op, key, hash) -> me_value;
271}
272
273int
274mappinginsert(op, key, value)
275 register object *op;
276 object *key;
277 object *value;
278{
279 register mappingobject *mp;
280 register long hash;
281 if (!is_mappingobject(op)) {
282 err_badcall();
283 return -1;
284 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000285#ifdef CACHE_HASH
286 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
287#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000288 hash = hashobject(key);
289 if (hash == -1)
290 return -1;
291 mp = (mappingobject *)op;
292 /* if fill >= 2/3 size, resize */
293 if (mp->ma_fill*3 >= mp->ma_size*2) {
294 if (mappingresize(mp) != 0) {
295 if (mp->ma_fill+1 > mp->ma_size)
296 return -1;
297 }
298 }
299 INCREF(value);
300 INCREF(key);
301 insertmapping(mp, key, hash, value);
302 return 0;
303}
304
305int
306mappingremove(op, key)
307 object *op;
308 object *key;
309{
310 register mappingobject *mp;
311 register long hash;
312 register mappingentry *ep;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000313 object *old_value, *old_key;
314
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000315 if (!is_mappingobject(op)) {
316 err_badcall();
317 return -1;
318 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000319#ifdef CACHE_HASH
320 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
321#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000322 hash = hashobject(key);
323 if (hash == -1)
324 return -1;
325 mp = (mappingobject *)op;
Guido van Rossumefc87131995-01-02 19:42:39 +0000326 if (((mappingobject *)op)->ma_table == NULL)
327 goto empty;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000328 ep = lookmapping(mp, key, hash);
329 if (ep->me_value == NULL) {
Guido van Rossumefc87131995-01-02 19:42:39 +0000330 empty:
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000331 err_setval(KeyError, key);
332 return -1;
333 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000334 old_key = ep->me_key;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000335 INCREF(dummy);
336 ep->me_key = dummy;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000337 old_value = ep->me_value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000338 ep->me_value = NULL;
339 mp->ma_used--;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000340 DECREF(old_value);
341 DECREF(old_key);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000342 return 0;
343}
344
Guido van Rossum25831651993-05-19 14:50:45 +0000345void
346mappingclear(op)
347 object *op;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000348{
Guido van Rossumd7047b31995-01-02 19:07:15 +0000349 int i, n;
350 register mappingentry *table;
351 mappingobject *mp;
Guido van Rossum25831651993-05-19 14:50:45 +0000352 if (!is_mappingobject(op))
353 return;
354 mp = (mappingobject *)op;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000355 table = mp->ma_table;
356 if (table == NULL)
357 return;
358 n = mp->ma_size;
359 mp->ma_size = mp->ma_used = mp->ma_fill = 0;
360 mp->ma_table = NULL;
361 for (i = 0; i < n; i++) {
362 XDECREF(table[i].me_key);
363 XDECREF(table[i].me_value);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000364 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000365 DEL(table);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000366}
367
Guido van Rossum25831651993-05-19 14:50:45 +0000368int
369mappinggetnext(op, ppos, pkey, pvalue)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000370 object *op;
Guido van Rossum25831651993-05-19 14:50:45 +0000371 int *ppos;
372 object **pkey;
373 object **pvalue;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000374{
Guido van Rossum25831651993-05-19 14:50:45 +0000375 int i;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000376 register mappingobject *mp;
Guido van Rossum25831651993-05-19 14:50:45 +0000377 if (!is_dictobject(op))
378 return 0;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000379 mp = (mappingobject *)op;
Guido van Rossum25831651993-05-19 14:50:45 +0000380 i = *ppos;
381 if (i < 0)
382 return 0;
383 while (i < mp->ma_size && mp->ma_table[i].me_value == NULL)
384 i++;
385 *ppos = i+1;
386 if (i >= mp->ma_size)
387 return 0;
388 if (pkey)
389 *pkey = mp->ma_table[i].me_key;
390 if (pvalue)
391 *pvalue = mp->ma_table[i].me_value;
392 return 1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000393}
394
395/* Methods */
396
397static void
398mapping_dealloc(mp)
399 register mappingobject *mp;
400{
401 register int i;
402 register mappingentry *ep;
403 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
404 if (ep->me_key != NULL)
405 DECREF(ep->me_key);
406 if (ep->me_value != NULL)
407 DECREF(ep->me_value);
408 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000409 XDEL(mp->ma_table);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000410 DEL(mp);
411}
412
413static int
414mapping_print(mp, fp, flags)
415 register mappingobject *mp;
416 register FILE *fp;
417 register int flags;
418{
419 register int i;
420 register int any;
421 register mappingentry *ep;
422 fprintf(fp, "{");
423 any = 0;
424 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
425 if (ep->me_value != NULL) {
426 if (any++ > 0)
427 fprintf(fp, ", ");
Guido van Rossuma3d78fb1993-11-10 09:23:53 +0000428 if (printobject((object *)ep->me_key, fp, 0) != 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000429 return -1;
430 fprintf(fp, ": ");
Guido van Rossuma3d78fb1993-11-10 09:23:53 +0000431 if (printobject(ep->me_value, fp, 0) != 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000432 return -1;
433 }
434 }
435 fprintf(fp, "}");
436 return 0;
437}
438
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000439static object *
440mapping_repr(mp)
441 mappingobject *mp;
442{
443 auto object *v;
444 object *sepa, *colon;
445 register int i;
446 register int any;
447 register mappingentry *ep;
448 v = newstringobject("{");
449 sepa = newstringobject(", ");
450 colon = newstringobject(": ");
451 any = 0;
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000452 for (i = 0, ep = mp->ma_table; i < mp->ma_size && v; i++, ep++) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000453 if (ep->me_value != NULL) {
454 if (any++)
455 joinstring(&v, sepa);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000456 joinstring_decref(&v, reprobject(ep->me_key));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000457 joinstring(&v, colon);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000458 joinstring_decref(&v, reprobject(ep->me_value));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000459 }
460 }
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000461 joinstring_decref(&v, newstringobject("}"));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000462 XDECREF(sepa);
463 XDECREF(colon);
464 return v;
465}
466
467static int
468mapping_length(mp)
469 mappingobject *mp;
470{
471 return mp->ma_used;
472}
473
474static object *
475mapping_subscript(mp, key)
476 mappingobject *mp;
477 register object *key;
478{
479 object *v;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000480 long hash;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000481 if (mp->ma_table == NULL) {
482 err_setval(KeyError, key);
483 return NULL;
484 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000485#ifdef CACHE_HASH
486 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
487#endif
488 hash = hashobject(key);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000489 if (hash == -1)
490 return NULL;
491 v = lookmapping(mp, key, hash) -> me_value;
492 if (v == NULL)
493 err_setval(KeyError, key);
494 else
495 INCREF(v);
496 return v;
497}
498
499static int
500mapping_ass_sub(mp, v, w)
501 mappingobject *mp;
502 object *v, *w;
503{
504 if (w == NULL)
505 return mappingremove((object *)mp, v);
506 else
507 return mappinginsert((object *)mp, v, w);
508}
509
510static mapping_methods mapping_as_mapping = {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000511 (inquiry)mapping_length, /*mp_length*/
512 (binaryfunc)mapping_subscript, /*mp_subscript*/
513 (objobjargproc)mapping_ass_sub, /*mp_ass_subscript*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000514};
515
516static object *
517mapping_keys(mp, args)
518 register mappingobject *mp;
519 object *args;
520{
521 register object *v;
522 register int i, j;
523 if (!getnoarg(args))
524 return NULL;
525 v = newlistobject(mp->ma_used);
526 if (v == NULL)
527 return NULL;
528 for (i = 0, j = 0; i < mp->ma_size; i++) {
529 if (mp->ma_table[i].me_value != NULL) {
530 object *key = mp->ma_table[i].me_key;
531 INCREF(key);
532 setlistitem(v, j, key);
533 j++;
534 }
535 }
536 return v;
537}
538
Guido van Rossum25831651993-05-19 14:50:45 +0000539static object *
540mapping_values(mp, args)
541 register mappingobject *mp;
542 object *args;
543{
544 register object *v;
545 register int i, j;
546 if (!getnoarg(args))
547 return NULL;
548 v = newlistobject(mp->ma_used);
549 if (v == NULL)
550 return NULL;
551 for (i = 0, j = 0; i < mp->ma_size; i++) {
552 if (mp->ma_table[i].me_value != NULL) {
553 object *value = mp->ma_table[i].me_value;
554 INCREF(value);
555 setlistitem(v, j, value);
556 j++;
557 }
558 }
559 return v;
560}
561
562static object *
563mapping_items(mp, args)
564 register mappingobject *mp;
565 object *args;
566{
567 register object *v;
568 register int i, j;
569 if (!getnoarg(args))
570 return NULL;
571 v = newlistobject(mp->ma_used);
572 if (v == NULL)
573 return NULL;
574 for (i = 0, j = 0; i < mp->ma_size; i++) {
575 if (mp->ma_table[i].me_value != NULL) {
576 object *key = mp->ma_table[i].me_key;
577 object *value = mp->ma_table[i].me_value;
578 object *item = newtupleobject(2);
579 if (item == NULL) {
580 DECREF(v);
581 return NULL;
582 }
583 INCREF(key);
584 settupleitem(item, 0, key);
585 INCREF(value);
586 settupleitem(item, 1, value);
587 setlistitem(v, j, item);
588 j++;
589 }
590 }
591 return v;
592}
593
Guido van Rossum4199fac1993-11-05 10:18:44 +0000594int
595getmappingsize(mp)
596 object *mp;
597{
598 if (mp == NULL || !is_mappingobject(mp)) {
599 err_badcall();
Guido van Rossumb376a4a1993-11-23 17:53:17 +0000600 return 0;
Guido van Rossum4199fac1993-11-05 10:18:44 +0000601 }
602 return ((mappingobject *)mp)->ma_used;
603}
604
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000605object *
606getmappingkeys(mp)
607 object *mp;
608{
609 if (mp == NULL || !is_mappingobject(mp)) {
610 err_badcall();
611 return NULL;
612 }
613 return mapping_keys((mappingobject *)mp, (object *)NULL);
614}
615
Guido van Rossum25831651993-05-19 14:50:45 +0000616object *
617getmappingvalues(mp)
618 object *mp;
619{
620 if (mp == NULL || !is_mappingobject(mp)) {
621 err_badcall();
622 return NULL;
623 }
624 return mapping_values((mappingobject *)mp, (object *)NULL);
625}
626
627object *
628getmappingitems(mp)
629 object *mp;
630{
631 if (mp == NULL || !is_mappingobject(mp)) {
632 err_badcall();
633 return NULL;
634 }
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000635 return mapping_items((mappingobject *)mp, (object *)NULL);
Guido van Rossum25831651993-05-19 14:50:45 +0000636}
637
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000638static int
639mapping_compare(a, b)
640 mappingobject *a, *b;
641{
642 object *akeys, *bkeys;
643 int i, n, res;
644 if (a == b)
645 return 0;
646 if (a->ma_used == 0) {
647 if (b->ma_used != 0)
648 return -1;
649 else
650 return 0;
651 }
652 else {
653 if (b->ma_used == 0)
654 return 1;
655 }
656 akeys = mapping_keys(a, (object *)NULL);
657 bkeys = mapping_keys(b, (object *)NULL);
658 if (akeys == NULL || bkeys == NULL) {
659 /* Oops, out of memory -- what to do? */
660 /* For now, sort on address! */
661 XDECREF(akeys);
662 XDECREF(bkeys);
663 if (a < b)
664 return -1;
665 else
666 return 1;
667 }
668 sortlist(akeys);
669 sortlist(bkeys);
670 n = a->ma_used < b->ma_used ? a->ma_used : b->ma_used; /* smallest */
671 res = 0;
672 for (i = 0; i < n; i++) {
673 object *akey, *bkey, *aval, *bval;
674 long ahash, bhash;
675 akey = getlistitem(akeys, i);
676 bkey = getlistitem(bkeys, i);
677 res = cmpobject(akey, bkey);
678 if (res != 0)
679 break;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000680#ifdef CACHE_HASH
681 if (!is_stringobject(akey) || (ahash = ((stringobject *) akey)->ob_shash) == -1)
682#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000683 ahash = hashobject(akey);
684 if (ahash == -1)
685 err_clear(); /* Don't want errors here */
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000686#ifdef CACHE_HASH
687 if (!is_stringobject(bkey) || (bhash = ((stringobject *) bkey)->ob_shash) == -1)
688#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000689 bhash = hashobject(bkey);
690 if (bhash == -1)
691 err_clear(); /* Don't want errors here */
692 aval = lookmapping(a, akey, ahash) -> me_value;
693 bval = lookmapping(b, bkey, bhash) -> me_value;
694 res = cmpobject(aval, bval);
695 if (res != 0)
696 break;
697 }
698 if (res == 0) {
699 if (a->ma_used < b->ma_used)
700 res = -1;
701 else if (a->ma_used > b->ma_used)
702 res = 1;
703 }
704 DECREF(akeys);
705 DECREF(bkeys);
706 return res;
707}
708
709static object *
710mapping_has_key(mp, args)
711 register mappingobject *mp;
712 object *args;
713{
714 object *key;
715 long hash;
716 register long ok;
717 if (!getargs(args, "O", &key))
718 return NULL;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000719#ifdef CACHE_HASH
720 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
721#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000722 hash = hashobject(key);
723 if (hash == -1)
724 return NULL;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000725 ok = mp->ma_size != 0 && lookmapping(mp, key, hash)->me_value != NULL;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000726 return newintobject(ok);
727}
728
729static struct methodlist mapp_methods[] = {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000730 {"has_key", (method)mapping_has_key},
731 {"items", (method)mapping_items},
732 {"keys", (method)mapping_keys},
733 {"values", (method)mapping_values},
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000734 {NULL, NULL} /* sentinel */
735};
736
737static object *
738mapping_getattr(mp, name)
739 mappingobject *mp;
740 char *name;
741{
742 return findmethod(mapp_methods, (object *)mp, name);
743}
744
745typeobject Mappingtype = {
746 OB_HEAD_INIT(&Typetype)
747 0,
Guido van Rossum9bfef441993-03-29 10:43:31 +0000748 "dictionary",
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000749 sizeof(mappingobject),
750 0,
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000751 (destructor)mapping_dealloc, /*tp_dealloc*/
752 (printfunc)mapping_print, /*tp_print*/
753 (getattrfunc)mapping_getattr, /*tp_getattr*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000754 0, /*tp_setattr*/
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000755 (cmpfunc)mapping_compare, /*tp_compare*/
756 (reprfunc)mapping_repr, /*tp_repr*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000757 0, /*tp_as_number*/
758 0, /*tp_as_sequence*/
759 &mapping_as_mapping, /*tp_as_mapping*/
760};
761
762/* For backward compatibility with old dictionary interface */
763
764static object *last_name_object;
Guido van Rossum992ded81995-12-08 01:16:31 +0000765static char *last_name_char; /* NULL or == getstringvalue(last_name_object) */
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000766
767object *
768getattro(v, name)
769 object *v;
770 object *name;
771{
772 if (name != last_name_object) {
773 XDECREF(last_name_object);
774 INCREF(name);
775 last_name_object = name;
776 last_name_char = getstringvalue(name);
777 }
778 return getattr(v, last_name_char);
779}
780
781int
782setattro(v, name, value)
783 object *v;
784 object *name;
785 object *value;
786{
787 if (name != last_name_object) {
788 XDECREF(last_name_object);
789 INCREF(name);
790 last_name_object = name;
791 last_name_char = getstringvalue(name);
792 }
793 return setattr(v, last_name_char, value);
794}
795
796object *
797dictlookup(v, key)
798 object *v;
799 char *key;
800{
Guido van Rossum992ded81995-12-08 01:16:31 +0000801 if (key != last_name_char) {
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 }
Guido van Rossum992ded81995-12-08 01:16:31 +0000808 last_name_char = getstringvalue(last_name_object);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000809 }
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 Rossum992ded81995-12-08 01:16:31 +0000819 if (key != last_name_char) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000820 XDECREF(last_name_object);
821 last_name_object = newstringobject(key);
822 if (last_name_object == NULL) {
823 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +0000824 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000825 }
Guido van Rossum992ded81995-12-08 01:16:31 +0000826 last_name_char = getstringvalue(last_name_object);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000827 }
828 return mappinginsert(v, last_name_object, item);
829}
830
831int
832dictremove(v, key)
833 object *v;
834 char *key;
835{
Guido van Rossum992ded81995-12-08 01:16:31 +0000836 if (key != last_name_char) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000837 XDECREF(last_name_object);
838 last_name_object = newstringobject(key);
839 if (last_name_object == NULL) {
840 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +0000841 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000842 }
Guido van Rossum992ded81995-12-08 01:16:31 +0000843 last_name_char = getstringvalue(last_name_object);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000844 }
845 return mappingremove(v, last_name_object);
846}