blob: 39c2fc90928a9b07a82a1233bfcf81f7b16a5b13 [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/*
Guido van Rossum16e93a81997-01-28 00:00:11 +000045 * MINSIZE is the minimum size of a mapping.
46 */
47
48#define MINSIZE 4
49
50/*
51Table of irreducible polynomials to efficiently cycle through
52GF(2^n)-{0}, 2<=n<=30.
Guido van Rossum4b1302b1993-03-27 18:11:32 +000053*/
Guido van Rossum16e93a81997-01-28 00:00:11 +000054static long polys[] = {
Guido van Rossum9e5656c1997-01-29 04:45:16 +000055 4 + 3,
56 8 + 3,
57 16 + 3,
58 32 + 5,
59 64 + 3,
60 128 + 3,
61 256 + 29,
62 512 + 17,
63 1024 + 9,
64 2048 + 5,
65 4096 + 83,
66 8192 + 27,
67 16384 + 43,
68 32768 + 3,
69 65536 + 45,
70 131072 + 9,
71 262144 + 39,
72 524288 + 39,
73 1048576 + 9,
74 2097152 + 5,
75 4194304 + 3,
76 8388608 + 33,
77 16777216 + 27,
78 33554432 + 9,
79 67108864 + 71,
80 134217728 + 39,
81 268435456 + 9,
82 536870912 + 5,
83 1073741824 + 83,
84 0
Guido van Rossum4b1302b1993-03-27 18:11:32 +000085};
86
87/* Object used as dummy key to fill deleted entries */
88static object *dummy; /* Initialized by first call to newmappingobject() */
89
90/*
91Invariant for entries: when in use, de_value is not NULL and de_key is
92not NULL and not dummy; when not in use, de_value is NULL and de_key
93is either NULL or dummy. A dummy key value cannot be replaced by
94NULL, since otherwise other keys may be lost.
95*/
96typedef struct {
97 long me_hash;
98 object *me_key;
99 object *me_value;
Guido van Rossum36488841997-04-11 19:14:07 +0000100#ifdef USE_CACHE_ALIGNED
101 long aligner;
102#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000103} mappingentry;
104
105/*
106To ensure the lookup algorithm terminates, the table size must be a
107prime number and there must be at least one NULL key in the table.
108The value ma_fill is the number of non-NULL keys; ma_used is the number
109of non-NULL, non-dummy keys.
110To avoid slowing down lookups on a near-full table, we resize the table
111when it is more than half filled.
112*/
113typedef struct {
114 OB_HEAD
115 int ma_fill;
116 int ma_used;
117 int ma_size;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000118 int ma_poly;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000119 mappingentry *ma_table;
120} mappingobject;
121
122object *
123newmappingobject()
124{
125 register mappingobject *mp;
126 if (dummy == NULL) { /* Auto-initialize dummy */
127 dummy = newstringobject("<dummy key>");
128 if (dummy == NULL)
129 return NULL;
130 }
131 mp = NEWOBJ(mappingobject, &Mappingtype);
132 if (mp == NULL)
133 return NULL;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000134 mp->ma_size = 0;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000135 mp->ma_poly = 0;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000136 mp->ma_table = NULL;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000137 mp->ma_fill = 0;
138 mp->ma_used = 0;
139 return (object *)mp;
140}
141
142/*
143The basic lookup function used by all operations.
Guido van Rossum16e93a81997-01-28 00:00:11 +0000144This is based on Algorithm D from Knuth Vol. 3, Sec. 6.4.
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000145Open addressing is preferred over chaining since the link overhead for
146chaining would be substantial (100% with typical malloc overhead).
Guido van Rossum16e93a81997-01-28 00:00:11 +0000147However, instead of going through the table at constant steps, we cycle
148through the values of GF(2^n)-{0}. This avoids modulo computations, being
149much cheaper on RISC machines, without leading to clustering.
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000150
151First a 32-bit hash value, 'sum', is computed from the key string.
152The first character is added an extra time shifted by 8 to avoid hashing
153single-character keys (often heavily used variables) too close together.
154All arithmetic on sum should ignore overflow.
155
156The initial probe index is then computed as sum mod the table size.
Guido van Rossum16e93a81997-01-28 00:00:11 +0000157Subsequent probe indices use the values of x^i in GF(2^n) as an offset,
158where x is a root. The initial value is derived from sum, too.
159
160(This version is due to Reimer Behrends, some ideas are also due to
161Jyrki Alakuijala.)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000162*/
163static mappingentry *lookmapping PROTO((mappingobject *, object *, long));
164static mappingentry *
165lookmapping(mp, key, hash)
Guido van Rossum7d181591997-01-16 21:06:45 +0000166 mappingobject *mp;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000167 object *key;
168 long hash;
169{
Guido van Rossum16e93a81997-01-28 00:00:11 +0000170 register int i;
171 register unsigned incr;
172 register unsigned long sum = (unsigned long) hash;
173 register mappingentry *freeslot = NULL;
Guido van Rossum2095d241997-04-09 19:41:24 +0000174 register unsigned int mask = mp->ma_size-1;
Guido van Rossumefb46091997-01-29 15:53:56 +0000175 mappingentry *ep0 = mp->ma_table;
176 register mappingentry *ep;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000177 /* We must come up with (i, incr) such that 0 <= i < ma_size
178 and 0 < incr < ma_size and both are a function of hash */
179 i = (~sum) & mask;
180 /* We use ~sum instead if sum, as degenerate hash functions, such
181 as for ints <sigh>, can have lots of leading zeros. It's not
182 really a performance risk, but better safe than sorry. */
Guido van Rossumefb46091997-01-29 15:53:56 +0000183 ep = &ep0[i];
Guido van Rossum16e93a81997-01-28 00:00:11 +0000184 if (ep->me_key == NULL)
Guido van Rossum7d181591997-01-16 21:06:45 +0000185 return ep;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000186 if (ep->me_key == dummy)
Guido van Rossum7d181591997-01-16 21:06:45 +0000187 freeslot = ep;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000188 else if (ep->me_key == key ||
189 (ep->me_hash == hash && cmpobject(ep->me_key, key) == 0)) {
190 return ep;
Guido van Rossum2a61e741997-01-18 07:55:05 +0000191 }
Guido van Rossumefb46091997-01-29 15:53:56 +0000192 /* Derive incr from sum, just to make it more arbitrary. Note that
Guido van Rossum16e93a81997-01-28 00:00:11 +0000193 incr must not be 0, or we will get into an infinite loop.*/
Guido van Rossumefb46091997-01-29 15:53:56 +0000194 incr = (sum ^ (sum >> 3)) & mask;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000195 if (!incr)
196 incr = mask;
197 if (incr > mask) /* Cycle through GF(2^n)-{0} */
198 incr ^= mp->ma_poly; /* This will implicitly clear the
199 highest bit */
200 for (;;) {
Guido van Rossumefb46091997-01-29 15:53:56 +0000201 ep = &ep0[(i+incr)&mask];
Guido van Rossum16e93a81997-01-28 00:00:11 +0000202 if (ep->me_key == NULL) {
203 if (freeslot != NULL)
204 return freeslot;
205 else
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000206 return ep;
207 }
Guido van Rossum16e93a81997-01-28 00:00:11 +0000208 if (ep->me_key == dummy) {
209 if (freeslot == NULL)
210 freeslot = ep;
211 }
212 else if (ep->me_key == key ||
213 (ep->me_hash == hash &&
214 cmpobject(ep->me_key, key) == 0)) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000215 return ep;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000216 }
217 /* Cycle through GF(2^n)-{0} */
218 incr = incr << 1;
219 if (incr > mask)
220 incr ^= mp->ma_poly;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000221 }
222}
223
224/*
225Internal routine to insert a new item into the table.
226Used both by the internal resize routine and by the public insert routine.
227Eats a reference to key and one to value.
228*/
229static void insertmapping PROTO((mappingobject *, object *, long, object *));
230static void
231insertmapping(mp, key, hash, value)
232 register mappingobject *mp;
233 object *key;
234 long hash;
235 object *value;
236{
Guido van Rossumd7047b31995-01-02 19:07:15 +0000237 object *old_value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000238 register mappingentry *ep;
239 ep = lookmapping(mp, key, hash);
240 if (ep->me_value != NULL) {
Guido van Rossumd7047b31995-01-02 19:07:15 +0000241 old_value = ep->me_value;
242 ep->me_value = value;
243 DECREF(old_value); /* which **CAN** re-enter */
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000244 DECREF(key);
245 }
246 else {
247 if (ep->me_key == NULL)
248 mp->ma_fill++;
249 else
250 DECREF(ep->me_key);
251 ep->me_key = key;
252 ep->me_hash = hash;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000253 ep->me_value = value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000254 mp->ma_used++;
255 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000256}
257
258/*
259Restructure the table by allocating a new table and reinserting all
260items again. When entries have been deleted, the new table may
261actually be smaller than the old one.
262*/
263static int mappingresize PROTO((mappingobject *));
264static int
265mappingresize(mp)
266 mappingobject *mp;
267{
268 register int oldsize = mp->ma_size;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000269 register int newsize, newpoly;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000270 register mappingentry *oldtable = mp->ma_table;
271 register mappingentry *newtable;
272 register mappingentry *ep;
273 register int i;
274 newsize = mp->ma_size;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000275 for (i = 0, newsize = MINSIZE; ; i++, newsize <<= 1) {
276 if (i > sizeof(polys)/sizeof(polys[0])) {
277 /* Ran out of polynomials */
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000278 err_nomem();
279 return -1;
280 }
Guido van Rossum16e93a81997-01-28 00:00:11 +0000281 if (newsize > mp->ma_used*2) {
282 newpoly = polys[i];
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000283 break;
284 }
285 }
286 newtable = (mappingentry *) calloc(sizeof(mappingentry), newsize);
287 if (newtable == NULL) {
288 err_nomem();
289 return -1;
290 }
291 mp->ma_size = newsize;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000292 mp->ma_poly = newpoly;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000293 mp->ma_table = newtable;
294 mp->ma_fill = 0;
295 mp->ma_used = 0;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000296
297 /* Make two passes, so we can avoid decrefs
298 (and possible side effects) till the table is copied */
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000299 for (i = 0, ep = oldtable; i < oldsize; i++, ep++) {
300 if (ep->me_value != NULL)
301 insertmapping(mp,ep->me_key,ep->me_hash,ep->me_value);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000302 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000303 for (i = 0, ep = oldtable; i < oldsize; i++, ep++) {
304 if (ep->me_value == NULL)
305 XDECREF(ep->me_key);
306 }
307
308 XDEL(oldtable);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000309 return 0;
310}
311
312object *
313mappinglookup(op, key)
314 object *op;
315 object *key;
316{
317 long hash;
318 if (!is_mappingobject(op)) {
319 err_badcall();
320 return NULL;
321 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000322 if (((mappingobject *)op)->ma_table == NULL)
323 return NULL;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000324#ifdef CACHE_HASH
Guido van Rossumca756f21997-01-23 19:39:29 +0000325 if (!is_stringobject(key) ||
326 (hash = ((stringobject *) key)->ob_shash) == -1)
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000327#endif
Guido van Rossumca756f21997-01-23 19:39:29 +0000328 {
329 hash = hashobject(key);
330 if (hash == -1)
331 return NULL;
332 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000333 return lookmapping((mappingobject *)op, key, hash) -> me_value;
334}
335
336int
337mappinginsert(op, key, value)
338 register object *op;
339 object *key;
340 object *value;
341{
342 register mappingobject *mp;
343 register long hash;
344 if (!is_mappingobject(op)) {
345 err_badcall();
346 return -1;
347 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000348 mp = (mappingobject *)op;
Guido van Rossum2a61e741997-01-18 07:55:05 +0000349#ifdef CACHE_HASH
350 if (is_stringobject(key)) {
351#ifdef INTERN_STRINGS
352 if (((stringobject *)key)->ob_sinterned != NULL) {
353 key = ((stringobject *)key)->ob_sinterned;
354 hash = ((stringobject *)key)->ob_shash;
355 }
356 else
357#endif
358 {
359 hash = ((stringobject *)key)->ob_shash;
360 if (hash == -1)
361 hash = hashobject(key);
Guido van Rossum2a61e741997-01-18 07:55:05 +0000362 }
363 }
364 else
365#endif
366 {
367 hash = hashobject(key);
368 if (hash == -1)
369 return -1;
Guido van Rossum2a61e741997-01-18 07:55:05 +0000370 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000371 /* if fill >= 2/3 size, resize */
372 if (mp->ma_fill*3 >= mp->ma_size*2) {
373 if (mappingresize(mp) != 0) {
374 if (mp->ma_fill+1 > mp->ma_size)
375 return -1;
376 }
377 }
378 INCREF(value);
379 INCREF(key);
380 insertmapping(mp, key, hash, value);
381 return 0;
382}
383
384int
385mappingremove(op, key)
386 object *op;
387 object *key;
388{
389 register mappingobject *mp;
390 register long hash;
391 register mappingentry *ep;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000392 object *old_value, *old_key;
393
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000394 if (!is_mappingobject(op)) {
395 err_badcall();
396 return -1;
397 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000398#ifdef CACHE_HASH
Guido van Rossumca756f21997-01-23 19:39:29 +0000399 if (!is_stringobject(key) ||
400 (hash = ((stringobject *) key)->ob_shash) == -1)
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000401#endif
Guido van Rossumca756f21997-01-23 19:39:29 +0000402 {
403 hash = hashobject(key);
404 if (hash == -1)
405 return -1;
406 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000407 mp = (mappingobject *)op;
Guido van Rossumefc87131995-01-02 19:42:39 +0000408 if (((mappingobject *)op)->ma_table == NULL)
409 goto empty;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000410 ep = lookmapping(mp, key, hash);
411 if (ep->me_value == NULL) {
Guido van Rossumefc87131995-01-02 19:42:39 +0000412 empty:
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000413 err_setval(KeyError, key);
414 return -1;
415 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000416 old_key = ep->me_key;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000417 INCREF(dummy);
418 ep->me_key = dummy;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000419 old_value = ep->me_value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000420 ep->me_value = NULL;
421 mp->ma_used--;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000422 DECREF(old_value);
423 DECREF(old_key);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000424 return 0;
425}
426
Guido van Rossum25831651993-05-19 14:50:45 +0000427void
428mappingclear(op)
429 object *op;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000430{
Guido van Rossumd7047b31995-01-02 19:07:15 +0000431 int i, n;
432 register mappingentry *table;
433 mappingobject *mp;
Guido van Rossum25831651993-05-19 14:50:45 +0000434 if (!is_mappingobject(op))
435 return;
436 mp = (mappingobject *)op;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000437 table = mp->ma_table;
438 if (table == NULL)
439 return;
440 n = mp->ma_size;
441 mp->ma_size = mp->ma_used = mp->ma_fill = 0;
442 mp->ma_table = NULL;
443 for (i = 0; i < n; i++) {
444 XDECREF(table[i].me_key);
445 XDECREF(table[i].me_value);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000446 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000447 DEL(table);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000448}
449
Guido van Rossum25831651993-05-19 14:50:45 +0000450int
451mappinggetnext(op, ppos, pkey, pvalue)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000452 object *op;
Guido van Rossum25831651993-05-19 14:50:45 +0000453 int *ppos;
454 object **pkey;
455 object **pvalue;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000456{
Guido van Rossum25831651993-05-19 14:50:45 +0000457 int i;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000458 register mappingobject *mp;
Guido van Rossum25831651993-05-19 14:50:45 +0000459 if (!is_dictobject(op))
460 return 0;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000461 mp = (mappingobject *)op;
Guido van Rossum25831651993-05-19 14:50:45 +0000462 i = *ppos;
463 if (i < 0)
464 return 0;
465 while (i < mp->ma_size && mp->ma_table[i].me_value == NULL)
466 i++;
467 *ppos = i+1;
468 if (i >= mp->ma_size)
469 return 0;
470 if (pkey)
471 *pkey = mp->ma_table[i].me_key;
472 if (pvalue)
473 *pvalue = mp->ma_table[i].me_value;
474 return 1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000475}
476
477/* Methods */
478
479static void
480mapping_dealloc(mp)
481 register mappingobject *mp;
482{
483 register int i;
484 register mappingentry *ep;
485 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
486 if (ep->me_key != NULL)
487 DECREF(ep->me_key);
488 if (ep->me_value != NULL)
489 DECREF(ep->me_value);
490 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000491 XDEL(mp->ma_table);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000492 DEL(mp);
493}
494
495static int
496mapping_print(mp, fp, flags)
497 register mappingobject *mp;
498 register FILE *fp;
499 register int flags;
500{
501 register int i;
502 register int any;
503 register mappingentry *ep;
504 fprintf(fp, "{");
505 any = 0;
506 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
507 if (ep->me_value != NULL) {
508 if (any++ > 0)
509 fprintf(fp, ", ");
Guido van Rossuma3d78fb1993-11-10 09:23:53 +0000510 if (printobject((object *)ep->me_key, fp, 0) != 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000511 return -1;
512 fprintf(fp, ": ");
Guido van Rossuma3d78fb1993-11-10 09:23:53 +0000513 if (printobject(ep->me_value, fp, 0) != 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000514 return -1;
515 }
516 }
517 fprintf(fp, "}");
518 return 0;
519}
520
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000521static object *
522mapping_repr(mp)
523 mappingobject *mp;
524{
525 auto object *v;
526 object *sepa, *colon;
527 register int i;
528 register int any;
529 register mappingentry *ep;
530 v = newstringobject("{");
531 sepa = newstringobject(", ");
532 colon = newstringobject(": ");
533 any = 0;
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000534 for (i = 0, ep = mp->ma_table; i < mp->ma_size && v; i++, ep++) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000535 if (ep->me_value != NULL) {
536 if (any++)
537 joinstring(&v, sepa);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000538 joinstring_decref(&v, reprobject(ep->me_key));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000539 joinstring(&v, colon);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000540 joinstring_decref(&v, reprobject(ep->me_value));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000541 }
542 }
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000543 joinstring_decref(&v, newstringobject("}"));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000544 XDECREF(sepa);
545 XDECREF(colon);
546 return v;
547}
548
549static int
550mapping_length(mp)
551 mappingobject *mp;
552{
553 return mp->ma_used;
554}
555
556static object *
557mapping_subscript(mp, key)
558 mappingobject *mp;
559 register object *key;
560{
561 object *v;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000562 long hash;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000563 if (mp->ma_table == NULL) {
564 err_setval(KeyError, key);
565 return NULL;
566 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000567#ifdef CACHE_HASH
Guido van Rossumca756f21997-01-23 19:39:29 +0000568 if (!is_stringobject(key) ||
569 (hash = ((stringobject *) key)->ob_shash) == -1)
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000570#endif
Guido van Rossumca756f21997-01-23 19:39:29 +0000571 {
572 hash = hashobject(key);
573 if (hash == -1)
574 return NULL;
575 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000576 v = lookmapping(mp, key, hash) -> me_value;
577 if (v == NULL)
578 err_setval(KeyError, key);
579 else
580 INCREF(v);
581 return v;
582}
583
584static int
585mapping_ass_sub(mp, v, w)
586 mappingobject *mp;
587 object *v, *w;
588{
589 if (w == NULL)
590 return mappingremove((object *)mp, v);
591 else
592 return mappinginsert((object *)mp, v, w);
593}
594
595static mapping_methods mapping_as_mapping = {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000596 (inquiry)mapping_length, /*mp_length*/
597 (binaryfunc)mapping_subscript, /*mp_subscript*/
598 (objobjargproc)mapping_ass_sub, /*mp_ass_subscript*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000599};
600
601static object *
602mapping_keys(mp, args)
603 register mappingobject *mp;
604 object *args;
605{
606 register object *v;
607 register int i, j;
608 if (!getnoarg(args))
609 return NULL;
610 v = newlistobject(mp->ma_used);
611 if (v == NULL)
612 return NULL;
613 for (i = 0, j = 0; i < mp->ma_size; i++) {
614 if (mp->ma_table[i].me_value != NULL) {
615 object *key = mp->ma_table[i].me_key;
616 INCREF(key);
617 setlistitem(v, j, key);
618 j++;
619 }
620 }
621 return v;
622}
623
Guido van Rossum25831651993-05-19 14:50:45 +0000624static object *
625mapping_values(mp, args)
626 register mappingobject *mp;
627 object *args;
628{
629 register object *v;
630 register int i, j;
631 if (!getnoarg(args))
632 return NULL;
633 v = newlistobject(mp->ma_used);
634 if (v == NULL)
635 return NULL;
636 for (i = 0, j = 0; i < mp->ma_size; i++) {
637 if (mp->ma_table[i].me_value != NULL) {
638 object *value = mp->ma_table[i].me_value;
639 INCREF(value);
640 setlistitem(v, j, value);
641 j++;
642 }
643 }
644 return v;
645}
646
647static object *
648mapping_items(mp, args)
649 register mappingobject *mp;
650 object *args;
651{
652 register object *v;
653 register int i, j;
654 if (!getnoarg(args))
655 return NULL;
656 v = newlistobject(mp->ma_used);
657 if (v == NULL)
658 return NULL;
659 for (i = 0, j = 0; i < mp->ma_size; i++) {
660 if (mp->ma_table[i].me_value != NULL) {
661 object *key = mp->ma_table[i].me_key;
662 object *value = mp->ma_table[i].me_value;
663 object *item = newtupleobject(2);
664 if (item == NULL) {
665 DECREF(v);
666 return NULL;
667 }
668 INCREF(key);
669 settupleitem(item, 0, key);
670 INCREF(value);
671 settupleitem(item, 1, value);
672 setlistitem(v, j, item);
673 j++;
674 }
675 }
676 return v;
677}
678
Guido van Rossum4199fac1993-11-05 10:18:44 +0000679int
680getmappingsize(mp)
681 object *mp;
682{
683 if (mp == NULL || !is_mappingobject(mp)) {
684 err_badcall();
Guido van Rossumb376a4a1993-11-23 17:53:17 +0000685 return 0;
Guido van Rossum4199fac1993-11-05 10:18:44 +0000686 }
687 return ((mappingobject *)mp)->ma_used;
688}
689
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000690object *
691getmappingkeys(mp)
692 object *mp;
693{
694 if (mp == NULL || !is_mappingobject(mp)) {
695 err_badcall();
696 return NULL;
697 }
698 return mapping_keys((mappingobject *)mp, (object *)NULL);
699}
700
Guido van Rossum25831651993-05-19 14:50:45 +0000701object *
702getmappingvalues(mp)
703 object *mp;
704{
705 if (mp == NULL || !is_mappingobject(mp)) {
706 err_badcall();
707 return NULL;
708 }
709 return mapping_values((mappingobject *)mp, (object *)NULL);
710}
711
712object *
713getmappingitems(mp)
714 object *mp;
715{
716 if (mp == NULL || !is_mappingobject(mp)) {
717 err_badcall();
718 return NULL;
719 }
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000720 return mapping_items((mappingobject *)mp, (object *)NULL);
Guido van Rossum25831651993-05-19 14:50:45 +0000721}
722
Guido van Rossuma0a69b81996-12-05 21:55:55 +0000723#define NEWCMP
724
725#ifdef NEWCMP
726
727/* Subroutine which returns the smallest key in a for which b's value
728 is different or absent. The value is returned too, through the
729 pval argument. No reference counts are incremented. */
730
731static object *
732characterize(a, b, pval)
733 mappingobject *a;
734 mappingobject *b;
735 object **pval;
736{
737 object *diff = NULL;
738 int i;
739
740 *pval = NULL;
741 for (i = 0; i < a->ma_size; i++) {
742 if (a->ma_table[i].me_value != NULL) {
743 object *key = a->ma_table[i].me_key;
744 object *aval, *bval;
745 if (diff != NULL && cmpobject(key, diff) > 0)
746 continue;
747 aval = a->ma_table[i].me_value;
748 bval = mappinglookup((object *)b, key);
749 if (bval == NULL || cmpobject(aval, bval) != 0) {
750 diff = key;
751 *pval = aval;
752 }
753 }
754 }
755 return diff;
756}
757
758static int
759mapping_compare(a, b)
760 mappingobject *a, *b;
761{
762 object *adiff, *bdiff, *aval, *bval;
763 int res;
764
765 /* Compare lengths first */
766 if (a->ma_used < b->ma_used)
767 return -1; /* a is shorter */
768 else if (a->ma_used > b->ma_used)
769 return 1; /* b is shorter */
770 /* Same length -- check all keys */
771 adiff = characterize(a, b, &aval);
772 if (adiff == NULL)
773 return 0; /* a is a subset with the same length */
774 bdiff = characterize(b, a, &bval);
775 /* bdiff == NULL would be impossible now */
776 res = cmpobject(adiff, bdiff);
777 if (res == 0)
778 res = cmpobject(aval, bval);
779 return res;
780}
781
782#else /* !NEWCMP */
783
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000784static int
785mapping_compare(a, b)
786 mappingobject *a, *b;
787{
788 object *akeys, *bkeys;
789 int i, n, res;
790 if (a == b)
791 return 0;
792 if (a->ma_used == 0) {
793 if (b->ma_used != 0)
794 return -1;
795 else
796 return 0;
797 }
798 else {
799 if (b->ma_used == 0)
800 return 1;
801 }
802 akeys = mapping_keys(a, (object *)NULL);
803 bkeys = mapping_keys(b, (object *)NULL);
804 if (akeys == NULL || bkeys == NULL) {
805 /* Oops, out of memory -- what to do? */
806 /* For now, sort on address! */
807 XDECREF(akeys);
808 XDECREF(bkeys);
809 if (a < b)
810 return -1;
811 else
812 return 1;
813 }
814 sortlist(akeys);
815 sortlist(bkeys);
816 n = a->ma_used < b->ma_used ? a->ma_used : b->ma_used; /* smallest */
817 res = 0;
818 for (i = 0; i < n; i++) {
819 object *akey, *bkey, *aval, *bval;
820 long ahash, bhash;
821 akey = getlistitem(akeys, i);
822 bkey = getlistitem(bkeys, i);
823 res = cmpobject(akey, bkey);
824 if (res != 0)
825 break;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000826#ifdef CACHE_HASH
Guido van Rossumca756f21997-01-23 19:39:29 +0000827 if (!is_stringobject(akey) ||
828 (ahash = ((stringobject *) akey)->ob_shash) == -1)
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000829#endif
Guido van Rossumca756f21997-01-23 19:39:29 +0000830 {
831 ahash = hashobject(akey);
832 if (ahash == -1)
833 err_clear(); /* Don't want errors here */
834 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000835#ifdef CACHE_HASH
Guido van Rossumca756f21997-01-23 19:39:29 +0000836 if (!is_stringobject(bkey) ||
837 (bhash = ((stringobject *) bkey)->ob_shash) == -1)
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000838#endif
Guido van Rossumca756f21997-01-23 19:39:29 +0000839 {
840 bhash = hashobject(bkey);
841 if (bhash == -1)
842 err_clear(); /* Don't want errors here */
843 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000844 aval = lookmapping(a, akey, ahash) -> me_value;
845 bval = lookmapping(b, bkey, bhash) -> me_value;
846 res = cmpobject(aval, bval);
847 if (res != 0)
848 break;
849 }
850 if (res == 0) {
851 if (a->ma_used < b->ma_used)
852 res = -1;
853 else if (a->ma_used > b->ma_used)
854 res = 1;
855 }
856 DECREF(akeys);
857 DECREF(bkeys);
858 return res;
859}
860
Guido van Rossuma0a69b81996-12-05 21:55:55 +0000861#endif /* !NEWCMP */
862
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000863static object *
864mapping_has_key(mp, args)
865 register mappingobject *mp;
866 object *args;
867{
868 object *key;
869 long hash;
870 register long ok;
871 if (!getargs(args, "O", &key))
872 return NULL;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000873#ifdef CACHE_HASH
Guido van Rossumca756f21997-01-23 19:39:29 +0000874 if (!is_stringobject(key) ||
875 (hash = ((stringobject *) key)->ob_shash) == -1)
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000876#endif
Guido van Rossumca756f21997-01-23 19:39:29 +0000877 {
878 hash = hashobject(key);
879 if (hash == -1)
880 return NULL;
881 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000882 ok = mp->ma_size != 0 && lookmapping(mp, key, hash)->me_value != NULL;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000883 return newintobject(ok);
884}
885
Guido van Rossumfb8f1ca1997-03-21 21:55:12 +0000886static object *
887mapping_clear(mp, args)
888 register mappingobject *mp;
889 object *args;
890{
891 if (!getnoarg(args))
892 return NULL;
893 mappingclear((object *)mp);
894 INCREF(None);
895 return None;
896}
897
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000898static struct methodlist mapp_methods[] = {
Guido van Rossumfb8f1ca1997-03-21 21:55:12 +0000899 {"clear", (method)mapping_clear},
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000900 {"has_key", (method)mapping_has_key},
901 {"items", (method)mapping_items},
902 {"keys", (method)mapping_keys},
903 {"values", (method)mapping_values},
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000904 {NULL, NULL} /* sentinel */
905};
906
907static object *
908mapping_getattr(mp, name)
909 mappingobject *mp;
910 char *name;
911{
912 return findmethod(mapp_methods, (object *)mp, name);
913}
914
915typeobject Mappingtype = {
916 OB_HEAD_INIT(&Typetype)
917 0,
Guido van Rossum9bfef441993-03-29 10:43:31 +0000918 "dictionary",
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000919 sizeof(mappingobject),
920 0,
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000921 (destructor)mapping_dealloc, /*tp_dealloc*/
922 (printfunc)mapping_print, /*tp_print*/
923 (getattrfunc)mapping_getattr, /*tp_getattr*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000924 0, /*tp_setattr*/
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000925 (cmpfunc)mapping_compare, /*tp_compare*/
926 (reprfunc)mapping_repr, /*tp_repr*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000927 0, /*tp_as_number*/
928 0, /*tp_as_sequence*/
929 &mapping_as_mapping, /*tp_as_mapping*/
930};
931
932/* For backward compatibility with old dictionary interface */
933
934static object *last_name_object;
Guido van Rossum992ded81995-12-08 01:16:31 +0000935static char *last_name_char; /* NULL or == getstringvalue(last_name_object) */
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000936
937object *
938getattro(v, name)
939 object *v;
940 object *name;
941{
Guido van Rossumd8eb1b31996-08-09 20:52:03 +0000942 if (v->ob_type->tp_getattro != NULL)
943 return (*v->ob_type->tp_getattro)(v, name);
944
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000945 if (name != last_name_object) {
946 XDECREF(last_name_object);
947 INCREF(name);
948 last_name_object = name;
949 last_name_char = getstringvalue(name);
950 }
951 return getattr(v, last_name_char);
952}
953
954int
955setattro(v, name, value)
956 object *v;
957 object *name;
958 object *value;
959{
Guido van Rossum2a61e741997-01-18 07:55:05 +0000960 int err;
961 INCREF(name);
962 PyString_InternInPlace(&name);
Guido van Rossumd8eb1b31996-08-09 20:52:03 +0000963 if (v->ob_type->tp_setattro != NULL)
Guido van Rossum2a61e741997-01-18 07:55:05 +0000964 err = (*v->ob_type->tp_setattro)(v, name, value);
965 else {
966 if (name != last_name_object) {
967 XDECREF(last_name_object);
968 INCREF(name);
969 last_name_object = name;
970 last_name_char = getstringvalue(name);
971 }
972 err = setattr(v, last_name_char, value);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000973 }
Guido van Rossum2a61e741997-01-18 07:55:05 +0000974 DECREF(name);
975 return err;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000976}
977
978object *
979dictlookup(v, key)
980 object *v;
981 char *key;
982{
Guido van Rossum992ded81995-12-08 01:16:31 +0000983 if (key != last_name_char) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000984 XDECREF(last_name_object);
985 last_name_object = newstringobject(key);
986 if (last_name_object == NULL) {
987 last_name_char = NULL;
988 return NULL;
989 }
Guido van Rossum2a61e741997-01-18 07:55:05 +0000990 PyString_InternInPlace(&last_name_object);
Guido van Rossum992ded81995-12-08 01:16:31 +0000991 last_name_char = getstringvalue(last_name_object);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000992 }
993 return mappinglookup(v, last_name_object);
994}
995
996int
997dictinsert(v, key, item)
998 object *v;
999 char *key;
1000 object *item;
1001{
Guido van Rossum992ded81995-12-08 01:16:31 +00001002 if (key != last_name_char) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +00001003 XDECREF(last_name_object);
1004 last_name_object = newstringobject(key);
1005 if (last_name_object == NULL) {
1006 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +00001007 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +00001008 }
Guido van Rossum2a61e741997-01-18 07:55:05 +00001009 PyString_InternInPlace(&last_name_object);
Guido van Rossum992ded81995-12-08 01:16:31 +00001010 last_name_char = getstringvalue(last_name_object);
Guido van Rossum4b1302b1993-03-27 18:11:32 +00001011 }
1012 return mappinginsert(v, last_name_object, item);
1013}
1014
1015int
1016dictremove(v, key)
1017 object *v;
1018 char *key;
1019{
Guido van Rossum992ded81995-12-08 01:16:31 +00001020 if (key != last_name_char) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +00001021 XDECREF(last_name_object);
1022 last_name_object = newstringobject(key);
1023 if (last_name_object == NULL) {
1024 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +00001025 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +00001026 }
Guido van Rossum992ded81995-12-08 01:16:31 +00001027 last_name_char = getstringvalue(last_name_object);
Guido van Rossum4b1302b1993-03-27 18:11:32 +00001028 }
1029 return mappingremove(v, last_name_object);
1030}