blob: 023de8f2c95bb322a15129363367dfc8265c12ec [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
Guido van Rossumd266eb41996-10-25 14:44:06 +00007Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
Guido van Rossum4b1302b1993-03-27 18:11:32 +00009provided that the above copyright notice appear in all copies and that
Guido van Rossumd266eb41996-10-25 14:44:06 +000010both that copyright notice and this permission notice appear in
Guido van Rossum4b1302b1993-03-27 18:11:32 +000011supporting documentation, and that the names of Stichting Mathematisch
Guido van Rossumd266eb41996-10-25 14:44:06 +000012Centrum or CWI or Corporation for National Research Initiatives or
13CNRI not be used in advertising or publicity pertaining to
14distribution of the software without specific, written prior
15permission.
Guido van Rossum4b1302b1993-03-27 18:11:32 +000016
Guido van Rossumd266eb41996-10-25 14:44:06 +000017While CWI is the initial source for this software, a modified version
18is made available by the Corporation for National Research Initiatives
19(CNRI) at the Internet address ftp://ftp.python.org.
20
21STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28PERFORMANCE OF THIS SOFTWARE.
Guido van Rossum4b1302b1993-03-27 18:11:32 +000029
30******************************************************************/
31
32/* Mapping object implementation; using a hash table */
33
Guido van Rossum9bfef441993-03-29 10:43:31 +000034/* This file should really be called "dictobject.c", since "mapping"
35 is the generic name for objects with an unorderred arbitrary key
36 set (just like lists are sequences), but since it improves (and was
37 originally derived from) a file by that name I had to change its
38 name. For the user these objects are still called "dictionaries". */
39
Guido van Rossum4b1302b1993-03-27 18:11:32 +000040#include "allobjects.h"
Guido van Rossum4b1302b1993-03-27 18:11:32 +000041#include "modsupport.h"
42
43
44/*
45Table of primes suitable as keys, in ascending order.
46The first line are the largest primes less than some powers of two,
47the second line is the largest prime less than 6000,
Guido van Rossum1d5735e1994-08-30 08:27:36 +000048the third line is a selection from Knuth, Vol. 3, Sec. 6.1, Table 1,
49and the next three lines were suggested by Steve Kirsch.
50The final value is a sentinel.
Guido van Rossum4b1302b1993-03-27 18:11:32 +000051*/
Guido van Rossum1d5735e1994-08-30 08:27:36 +000052static long primes[] = {
Guido van Rossum4b1302b1993-03-27 18:11:32 +000053 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2017, 4093,
54 5987,
55 9551, 15683, 19609, 31397,
Guido van Rossumd7047b31995-01-02 19:07:15 +000056 65521L, 131071L, 262139L, 524287L, 1048573L, 2097143L,
57 4194301L, 8388593L, 16777213L, 33554393L, 67108859L,
58 134217689L, 268435399L, 536870909L, 1073741789L,
Guido van Rossum1d5735e1994-08-30 08:27:36 +000059 0
Guido van Rossum4b1302b1993-03-27 18:11:32 +000060};
61
62/* Object used as dummy key to fill deleted entries */
63static object *dummy; /* Initialized by first call to newmappingobject() */
64
65/*
66Invariant for entries: when in use, de_value is not NULL and de_key is
67not NULL and not dummy; when not in use, de_value is NULL and de_key
68is either NULL or dummy. A dummy key value cannot be replaced by
69NULL, since otherwise other keys may be lost.
70*/
71typedef struct {
72 long me_hash;
73 object *me_key;
74 object *me_value;
75} mappingentry;
76
77/*
78To ensure the lookup algorithm terminates, the table size must be a
79prime number and there must be at least one NULL key in the table.
80The value ma_fill is the number of non-NULL keys; ma_used is the number
81of non-NULL, non-dummy keys.
82To avoid slowing down lookups on a near-full table, we resize the table
83when it is more than half filled.
84*/
85typedef struct {
86 OB_HEAD
87 int ma_fill;
88 int ma_used;
89 int ma_size;
90 mappingentry *ma_table;
91} mappingobject;
92
93object *
94newmappingobject()
95{
96 register mappingobject *mp;
97 if (dummy == NULL) { /* Auto-initialize dummy */
98 dummy = newstringobject("<dummy key>");
99 if (dummy == NULL)
100 return NULL;
101 }
102 mp = NEWOBJ(mappingobject, &Mappingtype);
103 if (mp == NULL)
104 return NULL;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000105 mp->ma_size = 0;
106 mp->ma_table = NULL;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000107 mp->ma_fill = 0;
108 mp->ma_used = 0;
109 return (object *)mp;
110}
111
112/*
113The basic lookup function used by all operations.
114This is essentially Algorithm D from Knuth Vol. 3, Sec. 6.4.
115Open addressing is preferred over chaining since the link overhead for
116chaining would be substantial (100% with typical malloc overhead).
117
118First a 32-bit hash value, 'sum', is computed from the key string.
119The first character is added an extra time shifted by 8 to avoid hashing
120single-character keys (often heavily used variables) too close together.
121All arithmetic on sum should ignore overflow.
122
123The initial probe index is then computed as sum mod the table size.
124Subsequent probe indices are incr apart (mod table size), where incr
125is also derived from sum, with the additional requirement that it is
126relative prime to the table size (i.e., 1 <= incr < size, since the size
127is a prime number). My choice for incr is somewhat arbitrary.
128*/
129static mappingentry *lookmapping PROTO((mappingobject *, object *, long));
130static mappingentry *
131lookmapping(mp, key, hash)
132 register mappingobject *mp;
133 object *key;
134 long hash;
135{
136 register int i, incr;
137 register unsigned long sum = (unsigned long) hash;
138 register mappingentry *freeslot = NULL;
Guido van Rossum310968d1996-07-30 16:45:31 +0000139 register int size = mp->ma_size;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000140 /* We must come up with (i, incr) such that 0 <= i < ma_size
141 and 0 < incr < ma_size and both are a function of hash */
Guido van Rossum310968d1996-07-30 16:45:31 +0000142 i = sum % size;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000143 do {
Guido van Rossum5fe60581995-03-09 12:12:50 +0000144 sum = 3*sum + 1;
Guido van Rossum310968d1996-07-30 16:45:31 +0000145 incr = sum % size;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000146 } while (incr == 0);
147 for (;;) {
148 register mappingentry *ep = &mp->ma_table[i];
149 if (ep->me_key == NULL) {
150 if (freeslot != NULL)
151 return freeslot;
152 else
153 return ep;
154 }
155 if (ep->me_key == dummy) {
Guido van Rossum52f2c051993-11-10 12:53:24 +0000156 if (freeslot == NULL)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000157 freeslot = ep;
158 }
159 else if (ep->me_hash == hash &&
160 cmpobject(ep->me_key, key) == 0) {
161 return ep;
162 }
Guido van Rossum310968d1996-07-30 16:45:31 +0000163 i = (i + incr) % size;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000164 }
165}
166
167/*
168Internal routine to insert a new item into the table.
169Used both by the internal resize routine and by the public insert routine.
170Eats a reference to key and one to value.
171*/
172static void insertmapping PROTO((mappingobject *, object *, long, object *));
173static void
174insertmapping(mp, key, hash, value)
175 register mappingobject *mp;
176 object *key;
177 long hash;
178 object *value;
179{
Guido van Rossumd7047b31995-01-02 19:07:15 +0000180 object *old_value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000181 register mappingentry *ep;
182 ep = lookmapping(mp, key, hash);
183 if (ep->me_value != NULL) {
Guido van Rossumd7047b31995-01-02 19:07:15 +0000184 old_value = ep->me_value;
185 ep->me_value = value;
186 DECREF(old_value); /* which **CAN** re-enter */
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000187 DECREF(key);
188 }
189 else {
190 if (ep->me_key == NULL)
191 mp->ma_fill++;
192 else
193 DECREF(ep->me_key);
194 ep->me_key = key;
195 ep->me_hash = hash;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000196 ep->me_value = value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000197 mp->ma_used++;
198 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000199}
200
201/*
202Restructure the table by allocating a new table and reinserting all
203items again. When entries have been deleted, the new table may
204actually be smaller than the old one.
205*/
206static int mappingresize PROTO((mappingobject *));
207static int
208mappingresize(mp)
209 mappingobject *mp;
210{
211 register int oldsize = mp->ma_size;
212 register int newsize;
213 register mappingentry *oldtable = mp->ma_table;
214 register mappingentry *newtable;
215 register mappingentry *ep;
216 register int i;
217 newsize = mp->ma_size;
218 for (i = 0; ; i++) {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000219 if (primes[i] <= 0) {
220 /* Ran out of primes */
221 err_nomem();
222 return -1;
223 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000224 if (primes[i] > mp->ma_used*2) {
225 newsize = primes[i];
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000226 if (newsize != primes[i]) {
227 /* Integer truncation */
228 err_nomem();
229 return -1;
230 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000231 break;
232 }
233 }
234 newtable = (mappingentry *) calloc(sizeof(mappingentry), newsize);
235 if (newtable == NULL) {
236 err_nomem();
237 return -1;
238 }
239 mp->ma_size = newsize;
240 mp->ma_table = newtable;
241 mp->ma_fill = 0;
242 mp->ma_used = 0;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000243
244 /* Make two passes, so we can avoid decrefs
245 (and possible side effects) till the table is copied */
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000246 for (i = 0, ep = oldtable; i < oldsize; i++, ep++) {
247 if (ep->me_value != NULL)
248 insertmapping(mp,ep->me_key,ep->me_hash,ep->me_value);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000249 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000250 for (i = 0, ep = oldtable; i < oldsize; i++, ep++) {
251 if (ep->me_value == NULL)
252 XDECREF(ep->me_key);
253 }
254
255 XDEL(oldtable);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000256 return 0;
257}
258
259object *
260mappinglookup(op, key)
261 object *op;
262 object *key;
263{
264 long hash;
265 if (!is_mappingobject(op)) {
266 err_badcall();
267 return NULL;
268 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000269 if (((mappingobject *)op)->ma_table == NULL)
270 return NULL;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000271#ifdef CACHE_HASH
272 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
273#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000274 hash = hashobject(key);
275 if (hash == -1)
276 return NULL;
277 return lookmapping((mappingobject *)op, key, hash) -> me_value;
278}
279
280int
281mappinginsert(op, key, value)
282 register object *op;
283 object *key;
284 object *value;
285{
286 register mappingobject *mp;
287 register long hash;
288 if (!is_mappingobject(op)) {
289 err_badcall();
290 return -1;
291 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000292#ifdef CACHE_HASH
293 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
294#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000295 hash = hashobject(key);
296 if (hash == -1)
297 return -1;
298 mp = (mappingobject *)op;
299 /* if fill >= 2/3 size, resize */
300 if (mp->ma_fill*3 >= mp->ma_size*2) {
301 if (mappingresize(mp) != 0) {
302 if (mp->ma_fill+1 > mp->ma_size)
303 return -1;
304 }
305 }
306 INCREF(value);
307 INCREF(key);
308 insertmapping(mp, key, hash, value);
309 return 0;
310}
311
312int
313mappingremove(op, key)
314 object *op;
315 object *key;
316{
317 register mappingobject *mp;
318 register long hash;
319 register mappingentry *ep;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000320 object *old_value, *old_key;
321
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000322 if (!is_mappingobject(op)) {
323 err_badcall();
324 return -1;
325 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000326#ifdef CACHE_HASH
327 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
328#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000329 hash = hashobject(key);
330 if (hash == -1)
331 return -1;
332 mp = (mappingobject *)op;
Guido van Rossumefc87131995-01-02 19:42:39 +0000333 if (((mappingobject *)op)->ma_table == NULL)
334 goto empty;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000335 ep = lookmapping(mp, key, hash);
336 if (ep->me_value == NULL) {
Guido van Rossumefc87131995-01-02 19:42:39 +0000337 empty:
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000338 err_setval(KeyError, key);
339 return -1;
340 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000341 old_key = ep->me_key;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000342 INCREF(dummy);
343 ep->me_key = dummy;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000344 old_value = ep->me_value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000345 ep->me_value = NULL;
346 mp->ma_used--;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000347 DECREF(old_value);
348 DECREF(old_key);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000349 return 0;
350}
351
Guido van Rossum25831651993-05-19 14:50:45 +0000352void
353mappingclear(op)
354 object *op;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000355{
Guido van Rossumd7047b31995-01-02 19:07:15 +0000356 int i, n;
357 register mappingentry *table;
358 mappingobject *mp;
Guido van Rossum25831651993-05-19 14:50:45 +0000359 if (!is_mappingobject(op))
360 return;
361 mp = (mappingobject *)op;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000362 table = mp->ma_table;
363 if (table == NULL)
364 return;
365 n = mp->ma_size;
366 mp->ma_size = mp->ma_used = mp->ma_fill = 0;
367 mp->ma_table = NULL;
368 for (i = 0; i < n; i++) {
369 XDECREF(table[i].me_key);
370 XDECREF(table[i].me_value);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000371 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000372 DEL(table);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000373}
374
Guido van Rossum25831651993-05-19 14:50:45 +0000375int
376mappinggetnext(op, ppos, pkey, pvalue)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000377 object *op;
Guido van Rossum25831651993-05-19 14:50:45 +0000378 int *ppos;
379 object **pkey;
380 object **pvalue;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000381{
Guido van Rossum25831651993-05-19 14:50:45 +0000382 int i;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000383 register mappingobject *mp;
Guido van Rossum25831651993-05-19 14:50:45 +0000384 if (!is_dictobject(op))
385 return 0;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000386 mp = (mappingobject *)op;
Guido van Rossum25831651993-05-19 14:50:45 +0000387 i = *ppos;
388 if (i < 0)
389 return 0;
390 while (i < mp->ma_size && mp->ma_table[i].me_value == NULL)
391 i++;
392 *ppos = i+1;
393 if (i >= mp->ma_size)
394 return 0;
395 if (pkey)
396 *pkey = mp->ma_table[i].me_key;
397 if (pvalue)
398 *pvalue = mp->ma_table[i].me_value;
399 return 1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000400}
401
402/* Methods */
403
404static void
405mapping_dealloc(mp)
406 register mappingobject *mp;
407{
408 register int i;
409 register mappingentry *ep;
410 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
411 if (ep->me_key != NULL)
412 DECREF(ep->me_key);
413 if (ep->me_value != NULL)
414 DECREF(ep->me_value);
415 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000416 XDEL(mp->ma_table);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000417 DEL(mp);
418}
419
420static int
421mapping_print(mp, fp, flags)
422 register mappingobject *mp;
423 register FILE *fp;
424 register int flags;
425{
426 register int i;
427 register int any;
428 register mappingentry *ep;
429 fprintf(fp, "{");
430 any = 0;
431 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
432 if (ep->me_value != NULL) {
433 if (any++ > 0)
434 fprintf(fp, ", ");
Guido van Rossuma3d78fb1993-11-10 09:23:53 +0000435 if (printobject((object *)ep->me_key, fp, 0) != 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000436 return -1;
437 fprintf(fp, ": ");
Guido van Rossuma3d78fb1993-11-10 09:23:53 +0000438 if (printobject(ep->me_value, fp, 0) != 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000439 return -1;
440 }
441 }
442 fprintf(fp, "}");
443 return 0;
444}
445
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000446static object *
447mapping_repr(mp)
448 mappingobject *mp;
449{
450 auto object *v;
451 object *sepa, *colon;
452 register int i;
453 register int any;
454 register mappingentry *ep;
455 v = newstringobject("{");
456 sepa = newstringobject(", ");
457 colon = newstringobject(": ");
458 any = 0;
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000459 for (i = 0, ep = mp->ma_table; i < mp->ma_size && v; i++, ep++) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000460 if (ep->me_value != NULL) {
461 if (any++)
462 joinstring(&v, sepa);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000463 joinstring_decref(&v, reprobject(ep->me_key));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000464 joinstring(&v, colon);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000465 joinstring_decref(&v, reprobject(ep->me_value));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000466 }
467 }
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000468 joinstring_decref(&v, newstringobject("}"));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000469 XDECREF(sepa);
470 XDECREF(colon);
471 return v;
472}
473
474static int
475mapping_length(mp)
476 mappingobject *mp;
477{
478 return mp->ma_used;
479}
480
481static object *
482mapping_subscript(mp, key)
483 mappingobject *mp;
484 register object *key;
485{
486 object *v;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000487 long hash;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000488 if (mp->ma_table == NULL) {
489 err_setval(KeyError, key);
490 return NULL;
491 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000492#ifdef CACHE_HASH
493 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
494#endif
495 hash = hashobject(key);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000496 if (hash == -1)
497 return NULL;
498 v = lookmapping(mp, key, hash) -> me_value;
499 if (v == NULL)
500 err_setval(KeyError, key);
501 else
502 INCREF(v);
503 return v;
504}
505
506static int
507mapping_ass_sub(mp, v, w)
508 mappingobject *mp;
509 object *v, *w;
510{
511 if (w == NULL)
512 return mappingremove((object *)mp, v);
513 else
514 return mappinginsert((object *)mp, v, w);
515}
516
517static mapping_methods mapping_as_mapping = {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000518 (inquiry)mapping_length, /*mp_length*/
519 (binaryfunc)mapping_subscript, /*mp_subscript*/
520 (objobjargproc)mapping_ass_sub, /*mp_ass_subscript*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000521};
522
523static object *
524mapping_keys(mp, args)
525 register mappingobject *mp;
526 object *args;
527{
528 register object *v;
529 register int i, j;
530 if (!getnoarg(args))
531 return NULL;
532 v = newlistobject(mp->ma_used);
533 if (v == NULL)
534 return NULL;
535 for (i = 0, j = 0; i < mp->ma_size; i++) {
536 if (mp->ma_table[i].me_value != NULL) {
537 object *key = mp->ma_table[i].me_key;
538 INCREF(key);
539 setlistitem(v, j, key);
540 j++;
541 }
542 }
543 return v;
544}
545
Guido van Rossum25831651993-05-19 14:50:45 +0000546static object *
547mapping_values(mp, args)
548 register mappingobject *mp;
549 object *args;
550{
551 register object *v;
552 register int i, j;
553 if (!getnoarg(args))
554 return NULL;
555 v = newlistobject(mp->ma_used);
556 if (v == NULL)
557 return NULL;
558 for (i = 0, j = 0; i < mp->ma_size; i++) {
559 if (mp->ma_table[i].me_value != NULL) {
560 object *value = mp->ma_table[i].me_value;
561 INCREF(value);
562 setlistitem(v, j, value);
563 j++;
564 }
565 }
566 return v;
567}
568
569static object *
570mapping_items(mp, args)
571 register mappingobject *mp;
572 object *args;
573{
574 register object *v;
575 register int i, j;
576 if (!getnoarg(args))
577 return NULL;
578 v = newlistobject(mp->ma_used);
579 if (v == NULL)
580 return NULL;
581 for (i = 0, j = 0; i < mp->ma_size; i++) {
582 if (mp->ma_table[i].me_value != NULL) {
583 object *key = mp->ma_table[i].me_key;
584 object *value = mp->ma_table[i].me_value;
585 object *item = newtupleobject(2);
586 if (item == NULL) {
587 DECREF(v);
588 return NULL;
589 }
590 INCREF(key);
591 settupleitem(item, 0, key);
592 INCREF(value);
593 settupleitem(item, 1, value);
594 setlistitem(v, j, item);
595 j++;
596 }
597 }
598 return v;
599}
600
Guido van Rossum4199fac1993-11-05 10:18:44 +0000601int
602getmappingsize(mp)
603 object *mp;
604{
605 if (mp == NULL || !is_mappingobject(mp)) {
606 err_badcall();
Guido van Rossumb376a4a1993-11-23 17:53:17 +0000607 return 0;
Guido van Rossum4199fac1993-11-05 10:18:44 +0000608 }
609 return ((mappingobject *)mp)->ma_used;
610}
611
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000612object *
613getmappingkeys(mp)
614 object *mp;
615{
616 if (mp == NULL || !is_mappingobject(mp)) {
617 err_badcall();
618 return NULL;
619 }
620 return mapping_keys((mappingobject *)mp, (object *)NULL);
621}
622
Guido van Rossum25831651993-05-19 14:50:45 +0000623object *
624getmappingvalues(mp)
625 object *mp;
626{
627 if (mp == NULL || !is_mappingobject(mp)) {
628 err_badcall();
629 return NULL;
630 }
631 return mapping_values((mappingobject *)mp, (object *)NULL);
632}
633
634object *
635getmappingitems(mp)
636 object *mp;
637{
638 if (mp == NULL || !is_mappingobject(mp)) {
639 err_badcall();
640 return NULL;
641 }
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000642 return mapping_items((mappingobject *)mp, (object *)NULL);
Guido van Rossum25831651993-05-19 14:50:45 +0000643}
644
Guido van Rossuma0a69b81996-12-05 21:55:55 +0000645#define NEWCMP
646
647#ifdef NEWCMP
648
649/* Subroutine which returns the smallest key in a for which b's value
650 is different or absent. The value is returned too, through the
651 pval argument. No reference counts are incremented. */
652
653static object *
654characterize(a, b, pval)
655 mappingobject *a;
656 mappingobject *b;
657 object **pval;
658{
659 object *diff = NULL;
660 int i;
661
662 *pval = NULL;
663 for (i = 0; i < a->ma_size; i++) {
664 if (a->ma_table[i].me_value != NULL) {
665 object *key = a->ma_table[i].me_key;
666 object *aval, *bval;
667 if (diff != NULL && cmpobject(key, diff) > 0)
668 continue;
669 aval = a->ma_table[i].me_value;
670 bval = mappinglookup((object *)b, key);
671 if (bval == NULL || cmpobject(aval, bval) != 0) {
672 diff = key;
673 *pval = aval;
674 }
675 }
676 }
677 return diff;
678}
679
680static int
681mapping_compare(a, b)
682 mappingobject *a, *b;
683{
684 object *adiff, *bdiff, *aval, *bval;
685 int res;
686
687 /* Compare lengths first */
688 if (a->ma_used < b->ma_used)
689 return -1; /* a is shorter */
690 else if (a->ma_used > b->ma_used)
691 return 1; /* b is shorter */
692 /* Same length -- check all keys */
693 adiff = characterize(a, b, &aval);
694 if (adiff == NULL)
695 return 0; /* a is a subset with the same length */
696 bdiff = characterize(b, a, &bval);
697 /* bdiff == NULL would be impossible now */
698 res = cmpobject(adiff, bdiff);
699 if (res == 0)
700 res = cmpobject(aval, bval);
701 return res;
702}
703
704#else /* !NEWCMP */
705
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000706static int
707mapping_compare(a, b)
708 mappingobject *a, *b;
709{
710 object *akeys, *bkeys;
711 int i, n, res;
712 if (a == b)
713 return 0;
714 if (a->ma_used == 0) {
715 if (b->ma_used != 0)
716 return -1;
717 else
718 return 0;
719 }
720 else {
721 if (b->ma_used == 0)
722 return 1;
723 }
724 akeys = mapping_keys(a, (object *)NULL);
725 bkeys = mapping_keys(b, (object *)NULL);
726 if (akeys == NULL || bkeys == NULL) {
727 /* Oops, out of memory -- what to do? */
728 /* For now, sort on address! */
729 XDECREF(akeys);
730 XDECREF(bkeys);
731 if (a < b)
732 return -1;
733 else
734 return 1;
735 }
736 sortlist(akeys);
737 sortlist(bkeys);
738 n = a->ma_used < b->ma_used ? a->ma_used : b->ma_used; /* smallest */
739 res = 0;
740 for (i = 0; i < n; i++) {
741 object *akey, *bkey, *aval, *bval;
742 long ahash, bhash;
743 akey = getlistitem(akeys, i);
744 bkey = getlistitem(bkeys, i);
745 res = cmpobject(akey, bkey);
746 if (res != 0)
747 break;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000748#ifdef CACHE_HASH
749 if (!is_stringobject(akey) || (ahash = ((stringobject *) akey)->ob_shash) == -1)
750#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000751 ahash = hashobject(akey);
752 if (ahash == -1)
753 err_clear(); /* Don't want errors here */
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000754#ifdef CACHE_HASH
755 if (!is_stringobject(bkey) || (bhash = ((stringobject *) bkey)->ob_shash) == -1)
756#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000757 bhash = hashobject(bkey);
758 if (bhash == -1)
759 err_clear(); /* Don't want errors here */
760 aval = lookmapping(a, akey, ahash) -> me_value;
761 bval = lookmapping(b, bkey, bhash) -> me_value;
762 res = cmpobject(aval, bval);
763 if (res != 0)
764 break;
765 }
766 if (res == 0) {
767 if (a->ma_used < b->ma_used)
768 res = -1;
769 else if (a->ma_used > b->ma_used)
770 res = 1;
771 }
772 DECREF(akeys);
773 DECREF(bkeys);
774 return res;
775}
776
Guido van Rossuma0a69b81996-12-05 21:55:55 +0000777#endif /* !NEWCMP */
778
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000779static object *
780mapping_has_key(mp, args)
781 register mappingobject *mp;
782 object *args;
783{
784 object *key;
785 long hash;
786 register long ok;
787 if (!getargs(args, "O", &key))
788 return NULL;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000789#ifdef CACHE_HASH
790 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
791#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000792 hash = hashobject(key);
793 if (hash == -1)
794 return NULL;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000795 ok = mp->ma_size != 0 && lookmapping(mp, key, hash)->me_value != NULL;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000796 return newintobject(ok);
797}
798
799static struct methodlist mapp_methods[] = {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000800 {"has_key", (method)mapping_has_key},
801 {"items", (method)mapping_items},
802 {"keys", (method)mapping_keys},
803 {"values", (method)mapping_values},
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000804 {NULL, NULL} /* sentinel */
805};
806
807static object *
808mapping_getattr(mp, name)
809 mappingobject *mp;
810 char *name;
811{
812 return findmethod(mapp_methods, (object *)mp, name);
813}
814
815typeobject Mappingtype = {
816 OB_HEAD_INIT(&Typetype)
817 0,
Guido van Rossum9bfef441993-03-29 10:43:31 +0000818 "dictionary",
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000819 sizeof(mappingobject),
820 0,
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000821 (destructor)mapping_dealloc, /*tp_dealloc*/
822 (printfunc)mapping_print, /*tp_print*/
823 (getattrfunc)mapping_getattr, /*tp_getattr*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000824 0, /*tp_setattr*/
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000825 (cmpfunc)mapping_compare, /*tp_compare*/
826 (reprfunc)mapping_repr, /*tp_repr*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000827 0, /*tp_as_number*/
828 0, /*tp_as_sequence*/
829 &mapping_as_mapping, /*tp_as_mapping*/
830};
831
832/* For backward compatibility with old dictionary interface */
833
834static object *last_name_object;
Guido van Rossum992ded81995-12-08 01:16:31 +0000835static char *last_name_char; /* NULL or == getstringvalue(last_name_object) */
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000836
837object *
838getattro(v, name)
839 object *v;
840 object *name;
841{
Guido van Rossumd8eb1b31996-08-09 20:52:03 +0000842 if (v->ob_type->tp_getattro != NULL)
843 return (*v->ob_type->tp_getattro)(v, name);
844
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000845 if (name != last_name_object) {
846 XDECREF(last_name_object);
847 INCREF(name);
848 last_name_object = name;
849 last_name_char = getstringvalue(name);
850 }
851 return getattr(v, last_name_char);
852}
853
854int
855setattro(v, name, value)
856 object *v;
857 object *name;
858 object *value;
859{
Guido van Rossumd8eb1b31996-08-09 20:52:03 +0000860 if (v->ob_type->tp_setattro != NULL)
861 return (*v->ob_type->tp_setattro)(v, name, value);
862
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000863 if (name != last_name_object) {
864 XDECREF(last_name_object);
865 INCREF(name);
866 last_name_object = name;
867 last_name_char = getstringvalue(name);
868 }
869 return setattr(v, last_name_char, value);
870}
871
872object *
873dictlookup(v, key)
874 object *v;
875 char *key;
876{
Guido van Rossum992ded81995-12-08 01:16:31 +0000877 if (key != last_name_char) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000878 XDECREF(last_name_object);
879 last_name_object = newstringobject(key);
880 if (last_name_object == NULL) {
881 last_name_char = NULL;
882 return NULL;
883 }
Guido van Rossum992ded81995-12-08 01:16:31 +0000884 last_name_char = getstringvalue(last_name_object);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000885 }
886 return mappinglookup(v, last_name_object);
887}
888
889int
890dictinsert(v, key, item)
891 object *v;
892 char *key;
893 object *item;
894{
Guido van Rossum992ded81995-12-08 01:16:31 +0000895 if (key != last_name_char) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000896 XDECREF(last_name_object);
897 last_name_object = newstringobject(key);
898 if (last_name_object == NULL) {
899 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +0000900 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000901 }
Guido van Rossum992ded81995-12-08 01:16:31 +0000902 last_name_char = getstringvalue(last_name_object);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000903 }
904 return mappinginsert(v, last_name_object, item);
905}
906
907int
908dictremove(v, key)
909 object *v;
910 char *key;
911{
Guido van Rossum992ded81995-12-08 01:16:31 +0000912 if (key != last_name_char) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000913 XDECREF(last_name_object);
914 last_name_object = newstringobject(key);
915 if (last_name_object == NULL) {
916 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +0000917 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000918 }
Guido van Rossum992ded81995-12-08 01:16:31 +0000919 last_name_char = getstringvalue(last_name_object);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000920 }
921 return mappingremove(v, last_name_object);
922}