blob: 8f3d3a6476d425122fd24ac047985a638ee55094 [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;
100} mappingentry;
101
102/*
103To ensure the lookup algorithm terminates, the table size must be a
104prime number and there must be at least one NULL key in the table.
105The value ma_fill is the number of non-NULL keys; ma_used is the number
106of non-NULL, non-dummy keys.
107To avoid slowing down lookups on a near-full table, we resize the table
108when it is more than half filled.
109*/
110typedef struct {
111 OB_HEAD
112 int ma_fill;
113 int ma_used;
114 int ma_size;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000115 int ma_poly;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000116 mappingentry *ma_table;
117} mappingobject;
118
119object *
120newmappingobject()
121{
122 register mappingobject *mp;
123 if (dummy == NULL) { /* Auto-initialize dummy */
124 dummy = newstringobject("<dummy key>");
125 if (dummy == NULL)
126 return NULL;
127 }
128 mp = NEWOBJ(mappingobject, &Mappingtype);
129 if (mp == NULL)
130 return NULL;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000131 mp->ma_size = 0;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000132 mp->ma_poly = 0;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000133 mp->ma_table = NULL;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000134 mp->ma_fill = 0;
135 mp->ma_used = 0;
136 return (object *)mp;
137}
138
139/*
140The basic lookup function used by all operations.
Guido van Rossum16e93a81997-01-28 00:00:11 +0000141This is based on Algorithm D from Knuth Vol. 3, Sec. 6.4.
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000142Open addressing is preferred over chaining since the link overhead for
143chaining would be substantial (100% with typical malloc overhead).
Guido van Rossum16e93a81997-01-28 00:00:11 +0000144However, instead of going through the table at constant steps, we cycle
145through the values of GF(2^n)-{0}. This avoids modulo computations, being
146much cheaper on RISC machines, without leading to clustering.
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000147
148First a 32-bit hash value, 'sum', is computed from the key string.
149The first character is added an extra time shifted by 8 to avoid hashing
150single-character keys (often heavily used variables) too close together.
151All arithmetic on sum should ignore overflow.
152
153The initial probe index is then computed as sum mod the table size.
Guido van Rossum16e93a81997-01-28 00:00:11 +0000154Subsequent probe indices use the values of x^i in GF(2^n) as an offset,
155where x is a root. The initial value is derived from sum, too.
156
157(This version is due to Reimer Behrends, some ideas are also due to
158Jyrki Alakuijala.)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000159*/
160static mappingentry *lookmapping PROTO((mappingobject *, object *, long));
161static mappingentry *
162lookmapping(mp, key, hash)
Guido van Rossum7d181591997-01-16 21:06:45 +0000163 mappingobject *mp;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000164 object *key;
165 long hash;
166{
Guido van Rossum16e93a81997-01-28 00:00:11 +0000167 register int i;
168 register unsigned incr;
169 register unsigned long sum = (unsigned long) hash;
170 register mappingentry *freeslot = NULL;
171 register int mask = mp->ma_size-1;
Guido van Rossumefb46091997-01-29 15:53:56 +0000172 mappingentry *ep0 = mp->ma_table;
173 register mappingentry *ep;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000174 /* We must come up with (i, incr) such that 0 <= i < ma_size
175 and 0 < incr < ma_size and both are a function of hash */
176 i = (~sum) & mask;
177 /* We use ~sum instead if sum, as degenerate hash functions, such
178 as for ints <sigh>, can have lots of leading zeros. It's not
179 really a performance risk, but better safe than sorry. */
Guido van Rossumefb46091997-01-29 15:53:56 +0000180 ep = &ep0[i];
Guido van Rossum16e93a81997-01-28 00:00:11 +0000181 if (ep->me_key == NULL)
Guido van Rossum7d181591997-01-16 21:06:45 +0000182 return ep;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000183 if (ep->me_key == dummy)
Guido van Rossum7d181591997-01-16 21:06:45 +0000184 freeslot = ep;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000185 else if (ep->me_key == key ||
186 (ep->me_hash == hash && cmpobject(ep->me_key, key) == 0)) {
187 return ep;
Guido van Rossum2a61e741997-01-18 07:55:05 +0000188 }
Guido van Rossumefb46091997-01-29 15:53:56 +0000189 /* Derive incr from sum, just to make it more arbitrary. Note that
Guido van Rossum16e93a81997-01-28 00:00:11 +0000190 incr must not be 0, or we will get into an infinite loop.*/
Guido van Rossumefb46091997-01-29 15:53:56 +0000191 incr = (sum ^ (sum >> 3)) & mask;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000192 if (!incr)
193 incr = mask;
194 if (incr > mask) /* Cycle through GF(2^n)-{0} */
195 incr ^= mp->ma_poly; /* This will implicitly clear the
196 highest bit */
197 for (;;) {
Guido van Rossumefb46091997-01-29 15:53:56 +0000198 ep = &ep0[(i+incr)&mask];
Guido van Rossum16e93a81997-01-28 00:00:11 +0000199 if (ep->me_key == NULL) {
200 if (freeslot != NULL)
201 return freeslot;
202 else
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000203 return ep;
204 }
Guido van Rossum16e93a81997-01-28 00:00:11 +0000205 if (ep->me_key == dummy) {
206 if (freeslot == NULL)
207 freeslot = ep;
208 }
209 else if (ep->me_key == key ||
210 (ep->me_hash == hash &&
211 cmpobject(ep->me_key, key) == 0)) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000212 return ep;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000213 }
214 /* Cycle through GF(2^n)-{0} */
215 incr = incr << 1;
216 if (incr > mask)
217 incr ^= mp->ma_poly;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000218 }
219}
220
221/*
222Internal routine to insert a new item into the table.
223Used both by the internal resize routine and by the public insert routine.
224Eats a reference to key and one to value.
225*/
226static void insertmapping PROTO((mappingobject *, object *, long, object *));
227static void
228insertmapping(mp, key, hash, value)
229 register mappingobject *mp;
230 object *key;
231 long hash;
232 object *value;
233{
Guido van Rossumd7047b31995-01-02 19:07:15 +0000234 object *old_value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000235 register mappingentry *ep;
236 ep = lookmapping(mp, key, hash);
237 if (ep->me_value != NULL) {
Guido van Rossumd7047b31995-01-02 19:07:15 +0000238 old_value = ep->me_value;
239 ep->me_value = value;
240 DECREF(old_value); /* which **CAN** re-enter */
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000241 DECREF(key);
242 }
243 else {
244 if (ep->me_key == NULL)
245 mp->ma_fill++;
246 else
247 DECREF(ep->me_key);
248 ep->me_key = key;
249 ep->me_hash = hash;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000250 ep->me_value = value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000251 mp->ma_used++;
252 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000253}
254
255/*
256Restructure the table by allocating a new table and reinserting all
257items again. When entries have been deleted, the new table may
258actually be smaller than the old one.
259*/
260static int mappingresize PROTO((mappingobject *));
261static int
262mappingresize(mp)
263 mappingobject *mp;
264{
265 register int oldsize = mp->ma_size;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000266 register int newsize, newpoly;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000267 register mappingentry *oldtable = mp->ma_table;
268 register mappingentry *newtable;
269 register mappingentry *ep;
270 register int i;
271 newsize = mp->ma_size;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000272 for (i = 0, newsize = MINSIZE; ; i++, newsize <<= 1) {
273 if (i > sizeof(polys)/sizeof(polys[0])) {
274 /* Ran out of polynomials */
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000275 err_nomem();
276 return -1;
277 }
Guido van Rossum16e93a81997-01-28 00:00:11 +0000278 if (newsize > mp->ma_used*2) {
279 newpoly = polys[i];
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000280 break;
281 }
282 }
283 newtable = (mappingentry *) calloc(sizeof(mappingentry), newsize);
284 if (newtable == NULL) {
285 err_nomem();
286 return -1;
287 }
288 mp->ma_size = newsize;
Guido van Rossum16e93a81997-01-28 00:00:11 +0000289 mp->ma_poly = newpoly;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000290 mp->ma_table = newtable;
291 mp->ma_fill = 0;
292 mp->ma_used = 0;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000293
294 /* Make two passes, so we can avoid decrefs
295 (and possible side effects) till the table is copied */
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000296 for (i = 0, ep = oldtable; i < oldsize; i++, ep++) {
297 if (ep->me_value != NULL)
298 insertmapping(mp,ep->me_key,ep->me_hash,ep->me_value);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000299 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000300 for (i = 0, ep = oldtable; i < oldsize; i++, ep++) {
301 if (ep->me_value == NULL)
302 XDECREF(ep->me_key);
303 }
304
305 XDEL(oldtable);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000306 return 0;
307}
308
309object *
310mappinglookup(op, key)
311 object *op;
312 object *key;
313{
314 long hash;
315 if (!is_mappingobject(op)) {
316 err_badcall();
317 return NULL;
318 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000319 if (((mappingobject *)op)->ma_table == NULL)
320 return NULL;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000321#ifdef CACHE_HASH
Guido van Rossumca756f21997-01-23 19:39:29 +0000322 if (!is_stringobject(key) ||
323 (hash = ((stringobject *) key)->ob_shash) == -1)
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000324#endif
Guido van Rossumca756f21997-01-23 19:39:29 +0000325 {
326 hash = hashobject(key);
327 if (hash == -1)
328 return NULL;
329 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000330 return lookmapping((mappingobject *)op, key, hash) -> me_value;
331}
332
333int
334mappinginsert(op, key, value)
335 register object *op;
336 object *key;
337 object *value;
338{
339 register mappingobject *mp;
340 register long hash;
341 if (!is_mappingobject(op)) {
342 err_badcall();
343 return -1;
344 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000345 mp = (mappingobject *)op;
Guido van Rossum2a61e741997-01-18 07:55:05 +0000346#ifdef CACHE_HASH
347 if (is_stringobject(key)) {
348#ifdef INTERN_STRINGS
349 if (((stringobject *)key)->ob_sinterned != NULL) {
350 key = ((stringobject *)key)->ob_sinterned;
351 hash = ((stringobject *)key)->ob_shash;
352 }
353 else
354#endif
355 {
356 hash = ((stringobject *)key)->ob_shash;
357 if (hash == -1)
358 hash = hashobject(key);
Guido van Rossum2a61e741997-01-18 07:55:05 +0000359 }
360 }
361 else
362#endif
363 {
364 hash = hashobject(key);
365 if (hash == -1)
366 return -1;
Guido van Rossum2a61e741997-01-18 07:55:05 +0000367 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000368 /* if fill >= 2/3 size, resize */
369 if (mp->ma_fill*3 >= mp->ma_size*2) {
370 if (mappingresize(mp) != 0) {
371 if (mp->ma_fill+1 > mp->ma_size)
372 return -1;
373 }
374 }
375 INCREF(value);
376 INCREF(key);
377 insertmapping(mp, key, hash, value);
378 return 0;
379}
380
381int
382mappingremove(op, key)
383 object *op;
384 object *key;
385{
386 register mappingobject *mp;
387 register long hash;
388 register mappingentry *ep;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000389 object *old_value, *old_key;
390
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000391 if (!is_mappingobject(op)) {
392 err_badcall();
393 return -1;
394 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000395#ifdef CACHE_HASH
Guido van Rossumca756f21997-01-23 19:39:29 +0000396 if (!is_stringobject(key) ||
397 (hash = ((stringobject *) key)->ob_shash) == -1)
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000398#endif
Guido van Rossumca756f21997-01-23 19:39:29 +0000399 {
400 hash = hashobject(key);
401 if (hash == -1)
402 return -1;
403 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000404 mp = (mappingobject *)op;
Guido van Rossumefc87131995-01-02 19:42:39 +0000405 if (((mappingobject *)op)->ma_table == NULL)
406 goto empty;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000407 ep = lookmapping(mp, key, hash);
408 if (ep->me_value == NULL) {
Guido van Rossumefc87131995-01-02 19:42:39 +0000409 empty:
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000410 err_setval(KeyError, key);
411 return -1;
412 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000413 old_key = ep->me_key;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000414 INCREF(dummy);
415 ep->me_key = dummy;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000416 old_value = ep->me_value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000417 ep->me_value = NULL;
418 mp->ma_used--;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000419 DECREF(old_value);
420 DECREF(old_key);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000421 return 0;
422}
423
Guido van Rossum25831651993-05-19 14:50:45 +0000424void
425mappingclear(op)
426 object *op;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000427{
Guido van Rossumd7047b31995-01-02 19:07:15 +0000428 int i, n;
429 register mappingentry *table;
430 mappingobject *mp;
Guido van Rossum25831651993-05-19 14:50:45 +0000431 if (!is_mappingobject(op))
432 return;
433 mp = (mappingobject *)op;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000434 table = mp->ma_table;
435 if (table == NULL)
436 return;
437 n = mp->ma_size;
438 mp->ma_size = mp->ma_used = mp->ma_fill = 0;
439 mp->ma_table = NULL;
440 for (i = 0; i < n; i++) {
441 XDECREF(table[i].me_key);
442 XDECREF(table[i].me_value);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000443 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000444 DEL(table);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000445}
446
Guido van Rossum25831651993-05-19 14:50:45 +0000447int
448mappinggetnext(op, ppos, pkey, pvalue)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000449 object *op;
Guido van Rossum25831651993-05-19 14:50:45 +0000450 int *ppos;
451 object **pkey;
452 object **pvalue;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000453{
Guido van Rossum25831651993-05-19 14:50:45 +0000454 int i;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000455 register mappingobject *mp;
Guido van Rossum25831651993-05-19 14:50:45 +0000456 if (!is_dictobject(op))
457 return 0;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000458 mp = (mappingobject *)op;
Guido van Rossum25831651993-05-19 14:50:45 +0000459 i = *ppos;
460 if (i < 0)
461 return 0;
462 while (i < mp->ma_size && mp->ma_table[i].me_value == NULL)
463 i++;
464 *ppos = i+1;
465 if (i >= mp->ma_size)
466 return 0;
467 if (pkey)
468 *pkey = mp->ma_table[i].me_key;
469 if (pvalue)
470 *pvalue = mp->ma_table[i].me_value;
471 return 1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000472}
473
474/* Methods */
475
476static void
477mapping_dealloc(mp)
478 register mappingobject *mp;
479{
480 register int i;
481 register mappingentry *ep;
482 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
483 if (ep->me_key != NULL)
484 DECREF(ep->me_key);
485 if (ep->me_value != NULL)
486 DECREF(ep->me_value);
487 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000488 XDEL(mp->ma_table);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000489 DEL(mp);
490}
491
492static int
493mapping_print(mp, fp, flags)
494 register mappingobject *mp;
495 register FILE *fp;
496 register int flags;
497{
498 register int i;
499 register int any;
500 register mappingentry *ep;
501 fprintf(fp, "{");
502 any = 0;
503 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
504 if (ep->me_value != NULL) {
505 if (any++ > 0)
506 fprintf(fp, ", ");
Guido van Rossuma3d78fb1993-11-10 09:23:53 +0000507 if (printobject((object *)ep->me_key, fp, 0) != 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000508 return -1;
509 fprintf(fp, ": ");
Guido van Rossuma3d78fb1993-11-10 09:23:53 +0000510 if (printobject(ep->me_value, fp, 0) != 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000511 return -1;
512 }
513 }
514 fprintf(fp, "}");
515 return 0;
516}
517
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000518static object *
519mapping_repr(mp)
520 mappingobject *mp;
521{
522 auto object *v;
523 object *sepa, *colon;
524 register int i;
525 register int any;
526 register mappingentry *ep;
527 v = newstringobject("{");
528 sepa = newstringobject(", ");
529 colon = newstringobject(": ");
530 any = 0;
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000531 for (i = 0, ep = mp->ma_table; i < mp->ma_size && v; i++, ep++) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000532 if (ep->me_value != NULL) {
533 if (any++)
534 joinstring(&v, sepa);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000535 joinstring_decref(&v, reprobject(ep->me_key));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000536 joinstring(&v, colon);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000537 joinstring_decref(&v, reprobject(ep->me_value));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000538 }
539 }
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000540 joinstring_decref(&v, newstringobject("}"));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000541 XDECREF(sepa);
542 XDECREF(colon);
543 return v;
544}
545
546static int
547mapping_length(mp)
548 mappingobject *mp;
549{
550 return mp->ma_used;
551}
552
553static object *
554mapping_subscript(mp, key)
555 mappingobject *mp;
556 register object *key;
557{
558 object *v;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000559 long hash;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000560 if (mp->ma_table == NULL) {
561 err_setval(KeyError, key);
562 return NULL;
563 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000564#ifdef CACHE_HASH
Guido van Rossumca756f21997-01-23 19:39:29 +0000565 if (!is_stringobject(key) ||
566 (hash = ((stringobject *) key)->ob_shash) == -1)
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000567#endif
Guido van Rossumca756f21997-01-23 19:39:29 +0000568 {
569 hash = hashobject(key);
570 if (hash == -1)
571 return NULL;
572 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000573 v = lookmapping(mp, key, hash) -> me_value;
574 if (v == NULL)
575 err_setval(KeyError, key);
576 else
577 INCREF(v);
578 return v;
579}
580
581static int
582mapping_ass_sub(mp, v, w)
583 mappingobject *mp;
584 object *v, *w;
585{
586 if (w == NULL)
587 return mappingremove((object *)mp, v);
588 else
589 return mappinginsert((object *)mp, v, w);
590}
591
592static mapping_methods mapping_as_mapping = {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000593 (inquiry)mapping_length, /*mp_length*/
594 (binaryfunc)mapping_subscript, /*mp_subscript*/
595 (objobjargproc)mapping_ass_sub, /*mp_ass_subscript*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000596};
597
598static object *
599mapping_keys(mp, args)
600 register mappingobject *mp;
601 object *args;
602{
603 register object *v;
604 register int i, j;
605 if (!getnoarg(args))
606 return NULL;
607 v = newlistobject(mp->ma_used);
608 if (v == NULL)
609 return NULL;
610 for (i = 0, j = 0; i < mp->ma_size; i++) {
611 if (mp->ma_table[i].me_value != NULL) {
612 object *key = mp->ma_table[i].me_key;
613 INCREF(key);
614 setlistitem(v, j, key);
615 j++;
616 }
617 }
618 return v;
619}
620
Guido van Rossum25831651993-05-19 14:50:45 +0000621static object *
622mapping_values(mp, args)
623 register mappingobject *mp;
624 object *args;
625{
626 register object *v;
627 register int i, j;
628 if (!getnoarg(args))
629 return NULL;
630 v = newlistobject(mp->ma_used);
631 if (v == NULL)
632 return NULL;
633 for (i = 0, j = 0; i < mp->ma_size; i++) {
634 if (mp->ma_table[i].me_value != NULL) {
635 object *value = mp->ma_table[i].me_value;
636 INCREF(value);
637 setlistitem(v, j, value);
638 j++;
639 }
640 }
641 return v;
642}
643
644static object *
645mapping_items(mp, args)
646 register mappingobject *mp;
647 object *args;
648{
649 register object *v;
650 register int i, j;
651 if (!getnoarg(args))
652 return NULL;
653 v = newlistobject(mp->ma_used);
654 if (v == NULL)
655 return NULL;
656 for (i = 0, j = 0; i < mp->ma_size; i++) {
657 if (mp->ma_table[i].me_value != NULL) {
658 object *key = mp->ma_table[i].me_key;
659 object *value = mp->ma_table[i].me_value;
660 object *item = newtupleobject(2);
661 if (item == NULL) {
662 DECREF(v);
663 return NULL;
664 }
665 INCREF(key);
666 settupleitem(item, 0, key);
667 INCREF(value);
668 settupleitem(item, 1, value);
669 setlistitem(v, j, item);
670 j++;
671 }
672 }
673 return v;
674}
675
Guido van Rossum4199fac1993-11-05 10:18:44 +0000676int
677getmappingsize(mp)
678 object *mp;
679{
680 if (mp == NULL || !is_mappingobject(mp)) {
681 err_badcall();
Guido van Rossumb376a4a1993-11-23 17:53:17 +0000682 return 0;
Guido van Rossum4199fac1993-11-05 10:18:44 +0000683 }
684 return ((mappingobject *)mp)->ma_used;
685}
686
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000687object *
688getmappingkeys(mp)
689 object *mp;
690{
691 if (mp == NULL || !is_mappingobject(mp)) {
692 err_badcall();
693 return NULL;
694 }
695 return mapping_keys((mappingobject *)mp, (object *)NULL);
696}
697
Guido van Rossum25831651993-05-19 14:50:45 +0000698object *
699getmappingvalues(mp)
700 object *mp;
701{
702 if (mp == NULL || !is_mappingobject(mp)) {
703 err_badcall();
704 return NULL;
705 }
706 return mapping_values((mappingobject *)mp, (object *)NULL);
707}
708
709object *
710getmappingitems(mp)
711 object *mp;
712{
713 if (mp == NULL || !is_mappingobject(mp)) {
714 err_badcall();
715 return NULL;
716 }
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000717 return mapping_items((mappingobject *)mp, (object *)NULL);
Guido van Rossum25831651993-05-19 14:50:45 +0000718}
719
Guido van Rossuma0a69b81996-12-05 21:55:55 +0000720#define NEWCMP
721
722#ifdef NEWCMP
723
724/* Subroutine which returns the smallest key in a for which b's value
725 is different or absent. The value is returned too, through the
726 pval argument. No reference counts are incremented. */
727
728static object *
729characterize(a, b, pval)
730 mappingobject *a;
731 mappingobject *b;
732 object **pval;
733{
734 object *diff = NULL;
735 int i;
736
737 *pval = NULL;
738 for (i = 0; i < a->ma_size; i++) {
739 if (a->ma_table[i].me_value != NULL) {
740 object *key = a->ma_table[i].me_key;
741 object *aval, *bval;
742 if (diff != NULL && cmpobject(key, diff) > 0)
743 continue;
744 aval = a->ma_table[i].me_value;
745 bval = mappinglookup((object *)b, key);
746 if (bval == NULL || cmpobject(aval, bval) != 0) {
747 diff = key;
748 *pval = aval;
749 }
750 }
751 }
752 return diff;
753}
754
755static int
756mapping_compare(a, b)
757 mappingobject *a, *b;
758{
759 object *adiff, *bdiff, *aval, *bval;
760 int res;
761
762 /* Compare lengths first */
763 if (a->ma_used < b->ma_used)
764 return -1; /* a is shorter */
765 else if (a->ma_used > b->ma_used)
766 return 1; /* b is shorter */
767 /* Same length -- check all keys */
768 adiff = characterize(a, b, &aval);
769 if (adiff == NULL)
770 return 0; /* a is a subset with the same length */
771 bdiff = characterize(b, a, &bval);
772 /* bdiff == NULL would be impossible now */
773 res = cmpobject(adiff, bdiff);
774 if (res == 0)
775 res = cmpobject(aval, bval);
776 return res;
777}
778
779#else /* !NEWCMP */
780
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000781static int
782mapping_compare(a, b)
783 mappingobject *a, *b;
784{
785 object *akeys, *bkeys;
786 int i, n, res;
787 if (a == b)
788 return 0;
789 if (a->ma_used == 0) {
790 if (b->ma_used != 0)
791 return -1;
792 else
793 return 0;
794 }
795 else {
796 if (b->ma_used == 0)
797 return 1;
798 }
799 akeys = mapping_keys(a, (object *)NULL);
800 bkeys = mapping_keys(b, (object *)NULL);
801 if (akeys == NULL || bkeys == NULL) {
802 /* Oops, out of memory -- what to do? */
803 /* For now, sort on address! */
804 XDECREF(akeys);
805 XDECREF(bkeys);
806 if (a < b)
807 return -1;
808 else
809 return 1;
810 }
811 sortlist(akeys);
812 sortlist(bkeys);
813 n = a->ma_used < b->ma_used ? a->ma_used : b->ma_used; /* smallest */
814 res = 0;
815 for (i = 0; i < n; i++) {
816 object *akey, *bkey, *aval, *bval;
817 long ahash, bhash;
818 akey = getlistitem(akeys, i);
819 bkey = getlistitem(bkeys, i);
820 res = cmpobject(akey, bkey);
821 if (res != 0)
822 break;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000823#ifdef CACHE_HASH
Guido van Rossumca756f21997-01-23 19:39:29 +0000824 if (!is_stringobject(akey) ||
825 (ahash = ((stringobject *) akey)->ob_shash) == -1)
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000826#endif
Guido van Rossumca756f21997-01-23 19:39:29 +0000827 {
828 ahash = hashobject(akey);
829 if (ahash == -1)
830 err_clear(); /* Don't want errors here */
831 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000832#ifdef CACHE_HASH
Guido van Rossumca756f21997-01-23 19:39:29 +0000833 if (!is_stringobject(bkey) ||
834 (bhash = ((stringobject *) bkey)->ob_shash) == -1)
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000835#endif
Guido van Rossumca756f21997-01-23 19:39:29 +0000836 {
837 bhash = hashobject(bkey);
838 if (bhash == -1)
839 err_clear(); /* Don't want errors here */
840 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000841 aval = lookmapping(a, akey, ahash) -> me_value;
842 bval = lookmapping(b, bkey, bhash) -> me_value;
843 res = cmpobject(aval, bval);
844 if (res != 0)
845 break;
846 }
847 if (res == 0) {
848 if (a->ma_used < b->ma_used)
849 res = -1;
850 else if (a->ma_used > b->ma_used)
851 res = 1;
852 }
853 DECREF(akeys);
854 DECREF(bkeys);
855 return res;
856}
857
Guido van Rossuma0a69b81996-12-05 21:55:55 +0000858#endif /* !NEWCMP */
859
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000860static object *
861mapping_has_key(mp, args)
862 register mappingobject *mp;
863 object *args;
864{
865 object *key;
866 long hash;
867 register long ok;
868 if (!getargs(args, "O", &key))
869 return NULL;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000870#ifdef CACHE_HASH
Guido van Rossumca756f21997-01-23 19:39:29 +0000871 if (!is_stringobject(key) ||
872 (hash = ((stringobject *) key)->ob_shash) == -1)
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000873#endif
Guido van Rossumca756f21997-01-23 19:39:29 +0000874 {
875 hash = hashobject(key);
876 if (hash == -1)
877 return NULL;
878 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000879 ok = mp->ma_size != 0 && lookmapping(mp, key, hash)->me_value != NULL;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000880 return newintobject(ok);
881}
882
883static struct methodlist mapp_methods[] = {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000884 {"has_key", (method)mapping_has_key},
885 {"items", (method)mapping_items},
886 {"keys", (method)mapping_keys},
887 {"values", (method)mapping_values},
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000888 {NULL, NULL} /* sentinel */
889};
890
891static object *
892mapping_getattr(mp, name)
893 mappingobject *mp;
894 char *name;
895{
896 return findmethod(mapp_methods, (object *)mp, name);
897}
898
899typeobject Mappingtype = {
900 OB_HEAD_INIT(&Typetype)
901 0,
Guido van Rossum9bfef441993-03-29 10:43:31 +0000902 "dictionary",
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000903 sizeof(mappingobject),
904 0,
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000905 (destructor)mapping_dealloc, /*tp_dealloc*/
906 (printfunc)mapping_print, /*tp_print*/
907 (getattrfunc)mapping_getattr, /*tp_getattr*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000908 0, /*tp_setattr*/
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000909 (cmpfunc)mapping_compare, /*tp_compare*/
910 (reprfunc)mapping_repr, /*tp_repr*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000911 0, /*tp_as_number*/
912 0, /*tp_as_sequence*/
913 &mapping_as_mapping, /*tp_as_mapping*/
914};
915
916/* For backward compatibility with old dictionary interface */
917
918static object *last_name_object;
Guido van Rossum992ded81995-12-08 01:16:31 +0000919static char *last_name_char; /* NULL or == getstringvalue(last_name_object) */
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000920
921object *
922getattro(v, name)
923 object *v;
924 object *name;
925{
Guido van Rossumd8eb1b31996-08-09 20:52:03 +0000926 if (v->ob_type->tp_getattro != NULL)
927 return (*v->ob_type->tp_getattro)(v, name);
928
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000929 if (name != last_name_object) {
930 XDECREF(last_name_object);
931 INCREF(name);
932 last_name_object = name;
933 last_name_char = getstringvalue(name);
934 }
935 return getattr(v, last_name_char);
936}
937
938int
939setattro(v, name, value)
940 object *v;
941 object *name;
942 object *value;
943{
Guido van Rossum2a61e741997-01-18 07:55:05 +0000944 int err;
945 INCREF(name);
946 PyString_InternInPlace(&name);
Guido van Rossumd8eb1b31996-08-09 20:52:03 +0000947 if (v->ob_type->tp_setattro != NULL)
Guido van Rossum2a61e741997-01-18 07:55:05 +0000948 err = (*v->ob_type->tp_setattro)(v, name, value);
949 else {
950 if (name != last_name_object) {
951 XDECREF(last_name_object);
952 INCREF(name);
953 last_name_object = name;
954 last_name_char = getstringvalue(name);
955 }
956 err = setattr(v, last_name_char, value);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000957 }
Guido van Rossum2a61e741997-01-18 07:55:05 +0000958 DECREF(name);
959 return err;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000960}
961
962object *
963dictlookup(v, key)
964 object *v;
965 char *key;
966{
Guido van Rossum992ded81995-12-08 01:16:31 +0000967 if (key != last_name_char) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000968 XDECREF(last_name_object);
969 last_name_object = newstringobject(key);
970 if (last_name_object == NULL) {
971 last_name_char = NULL;
972 return NULL;
973 }
Guido van Rossum2a61e741997-01-18 07:55:05 +0000974 PyString_InternInPlace(&last_name_object);
Guido van Rossum992ded81995-12-08 01:16:31 +0000975 last_name_char = getstringvalue(last_name_object);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000976 }
977 return mappinglookup(v, last_name_object);
978}
979
980int
981dictinsert(v, key, item)
982 object *v;
983 char *key;
984 object *item;
985{
Guido van Rossum992ded81995-12-08 01:16:31 +0000986 if (key != last_name_char) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000987 XDECREF(last_name_object);
988 last_name_object = newstringobject(key);
989 if (last_name_object == NULL) {
990 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +0000991 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000992 }
Guido van Rossum2a61e741997-01-18 07:55:05 +0000993 PyString_InternInPlace(&last_name_object);
Guido van Rossum992ded81995-12-08 01:16:31 +0000994 last_name_char = getstringvalue(last_name_object);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000995 }
996 return mappinginsert(v, last_name_object, item);
997}
998
999int
1000dictremove(v, key)
1001 object *v;
1002 char *key;
1003{
Guido van Rossum992ded81995-12-08 01:16:31 +00001004 if (key != last_name_char) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +00001005 XDECREF(last_name_object);
1006 last_name_object = newstringobject(key);
1007 if (last_name_object == NULL) {
1008 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +00001009 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +00001010 }
Guido van Rossum992ded81995-12-08 01:16:31 +00001011 last_name_char = getstringvalue(last_name_object);
Guido van Rossum4b1302b1993-03-27 18:11:32 +00001012 }
1013 return mappingremove(v, last_name_object);
1014}