blob: a8b18efb87d542411ddb8454f73eac972cf6e163 [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)
Guido van Rossum7d181591997-01-16 21:06:45 +0000132 mappingobject *mp;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000133 object *key;
134 long hash;
135{
Guido van Rossum7d181591997-01-16 21:06:45 +0000136 /* Optimizations based on observations by Jyrki Alakuijala
137 (paraphrased):
138
139 - This routine is very heavily used, so should be AFAP
140 (As Fast As Possible).
141
142 - Most of the time, the first try is a hit or a definite
143 miss; so postpone the calculation of incr until we know the
144 first try was a miss.
145
146 - Write the loop twice, so we can move the test for
147 freeslot==NULL out of the loop.
148
149 - Write the loop using pointer increments and comparisons
150 rather than using an integer loop index.
151
152 Note that it behooves the compiler to calculate the values
153 of incr*sizeof(*ep) outside the loops and use this in the
154 increment of ep. I've reduced the number of register
155 variables to the two most obvious candidates.
156
157 */
158
159 register mappingentry *ep;
160 mappingentry *end;
161 register object *ekey;
162 mappingentry *freeslot;
163 unsigned long sum;
164 int incr;
165 int size;
166
167 ep = &mp->ma_table[(unsigned long)hash%mp->ma_size];
168 ekey = ep->me_key;
169 if (ekey == NULL)
170 return ep;
171 if (ekey == dummy)
172 freeslot = ep;
173 else if (ep->me_hash == hash && cmpobject(ekey, key) == 0)
174 return ep;
175 else
176 freeslot = NULL;
177
178 size = mp->ma_size;
179 sum = hash;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000180 do {
Guido van Rossum5fe60581995-03-09 12:12:50 +0000181 sum = 3*sum + 1;
Guido van Rossum310968d1996-07-30 16:45:31 +0000182 incr = sum % size;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000183 } while (incr == 0);
Guido van Rossum7d181591997-01-16 21:06:45 +0000184
185 end = mp->ma_table + size;
186
187 if (freeslot == NULL) {
188 for (;;) {
189 ep += incr;
190 if (ep >= end)
191 ep -= size;
192 ekey = ep->me_key;
193 if (ekey == NULL)
194 return ep;
195 if (ekey == dummy) {
196 freeslot = ep;
197 break;
198 }
199 if (ep->me_hash == hash && cmpobject(ekey, key) == 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000200 return ep;
201 }
Guido van Rossum7d181591997-01-16 21:06:45 +0000202 }
203
204 for (;;) {
205 ep += incr;
206 if (ep >= end)
207 ep -= size;
208 ekey = ep->me_key;
209 if (ekey == NULL)
210 return freeslot;
211 if (ekey != dummy &&
212 ep->me_hash == hash && cmpobject(ekey, key) == 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000213 return ep;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000214 }
215}
216
217/*
218Internal routine to insert a new item into the table.
219Used both by the internal resize routine and by the public insert routine.
220Eats a reference to key and one to value.
221*/
222static void insertmapping PROTO((mappingobject *, object *, long, object *));
223static void
224insertmapping(mp, key, hash, value)
225 register mappingobject *mp;
226 object *key;
227 long hash;
228 object *value;
229{
Guido van Rossumd7047b31995-01-02 19:07:15 +0000230 object *old_value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000231 register mappingentry *ep;
232 ep = lookmapping(mp, key, hash);
233 if (ep->me_value != NULL) {
Guido van Rossumd7047b31995-01-02 19:07:15 +0000234 old_value = ep->me_value;
235 ep->me_value = value;
236 DECREF(old_value); /* which **CAN** re-enter */
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000237 DECREF(key);
238 }
239 else {
240 if (ep->me_key == NULL)
241 mp->ma_fill++;
242 else
243 DECREF(ep->me_key);
244 ep->me_key = key;
245 ep->me_hash = hash;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000246 ep->me_value = value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000247 mp->ma_used++;
248 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000249}
250
251/*
252Restructure the table by allocating a new table and reinserting all
253items again. When entries have been deleted, the new table may
254actually be smaller than the old one.
255*/
256static int mappingresize PROTO((mappingobject *));
257static int
258mappingresize(mp)
259 mappingobject *mp;
260{
261 register int oldsize = mp->ma_size;
262 register int newsize;
263 register mappingentry *oldtable = mp->ma_table;
264 register mappingentry *newtable;
265 register mappingentry *ep;
266 register int i;
267 newsize = mp->ma_size;
268 for (i = 0; ; i++) {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000269 if (primes[i] <= 0) {
270 /* Ran out of primes */
271 err_nomem();
272 return -1;
273 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000274 if (primes[i] > mp->ma_used*2) {
275 newsize = primes[i];
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000276 if (newsize != primes[i]) {
277 /* Integer truncation */
278 err_nomem();
279 return -1;
280 }
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000281 break;
282 }
283 }
284 newtable = (mappingentry *) calloc(sizeof(mappingentry), newsize);
285 if (newtable == NULL) {
286 err_nomem();
287 return -1;
288 }
289 mp->ma_size = newsize;
290 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
322 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
323#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000324 hash = hashobject(key);
325 if (hash == -1)
326 return NULL;
327 return lookmapping((mappingobject *)op, key, hash) -> me_value;
328}
329
330int
331mappinginsert(op, key, value)
332 register object *op;
333 object *key;
334 object *value;
335{
336 register mappingobject *mp;
337 register long hash;
338 if (!is_mappingobject(op)) {
339 err_badcall();
340 return -1;
341 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000342#ifdef CACHE_HASH
343 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
344#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000345 hash = hashobject(key);
346 if (hash == -1)
347 return -1;
348 mp = (mappingobject *)op;
349 /* if fill >= 2/3 size, resize */
350 if (mp->ma_fill*3 >= mp->ma_size*2) {
351 if (mappingresize(mp) != 0) {
352 if (mp->ma_fill+1 > mp->ma_size)
353 return -1;
354 }
355 }
356 INCREF(value);
357 INCREF(key);
358 insertmapping(mp, key, hash, value);
359 return 0;
360}
361
362int
363mappingremove(op, key)
364 object *op;
365 object *key;
366{
367 register mappingobject *mp;
368 register long hash;
369 register mappingentry *ep;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000370 object *old_value, *old_key;
371
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000372 if (!is_mappingobject(op)) {
373 err_badcall();
374 return -1;
375 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000376#ifdef CACHE_HASH
377 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
378#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000379 hash = hashobject(key);
380 if (hash == -1)
381 return -1;
382 mp = (mappingobject *)op;
Guido van Rossumefc87131995-01-02 19:42:39 +0000383 if (((mappingobject *)op)->ma_table == NULL)
384 goto empty;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000385 ep = lookmapping(mp, key, hash);
386 if (ep->me_value == NULL) {
Guido van Rossumefc87131995-01-02 19:42:39 +0000387 empty:
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000388 err_setval(KeyError, key);
389 return -1;
390 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000391 old_key = ep->me_key;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000392 INCREF(dummy);
393 ep->me_key = dummy;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000394 old_value = ep->me_value;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000395 ep->me_value = NULL;
396 mp->ma_used--;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000397 DECREF(old_value);
398 DECREF(old_key);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000399 return 0;
400}
401
Guido van Rossum25831651993-05-19 14:50:45 +0000402void
403mappingclear(op)
404 object *op;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000405{
Guido van Rossumd7047b31995-01-02 19:07:15 +0000406 int i, n;
407 register mappingentry *table;
408 mappingobject *mp;
Guido van Rossum25831651993-05-19 14:50:45 +0000409 if (!is_mappingobject(op))
410 return;
411 mp = (mappingobject *)op;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000412 table = mp->ma_table;
413 if (table == NULL)
414 return;
415 n = mp->ma_size;
416 mp->ma_size = mp->ma_used = mp->ma_fill = 0;
417 mp->ma_table = NULL;
418 for (i = 0; i < n; i++) {
419 XDECREF(table[i].me_key);
420 XDECREF(table[i].me_value);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000421 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000422 DEL(table);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000423}
424
Guido van Rossum25831651993-05-19 14:50:45 +0000425int
426mappinggetnext(op, ppos, pkey, pvalue)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000427 object *op;
Guido van Rossum25831651993-05-19 14:50:45 +0000428 int *ppos;
429 object **pkey;
430 object **pvalue;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000431{
Guido van Rossum25831651993-05-19 14:50:45 +0000432 int i;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000433 register mappingobject *mp;
Guido van Rossum25831651993-05-19 14:50:45 +0000434 if (!is_dictobject(op))
435 return 0;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000436 mp = (mappingobject *)op;
Guido van Rossum25831651993-05-19 14:50:45 +0000437 i = *ppos;
438 if (i < 0)
439 return 0;
440 while (i < mp->ma_size && mp->ma_table[i].me_value == NULL)
441 i++;
442 *ppos = i+1;
443 if (i >= mp->ma_size)
444 return 0;
445 if (pkey)
446 *pkey = mp->ma_table[i].me_key;
447 if (pvalue)
448 *pvalue = mp->ma_table[i].me_value;
449 return 1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000450}
451
452/* Methods */
453
454static void
455mapping_dealloc(mp)
456 register mappingobject *mp;
457{
458 register int i;
459 register mappingentry *ep;
460 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
461 if (ep->me_key != NULL)
462 DECREF(ep->me_key);
463 if (ep->me_value != NULL)
464 DECREF(ep->me_value);
465 }
Guido van Rossumd7047b31995-01-02 19:07:15 +0000466 XDEL(mp->ma_table);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000467 DEL(mp);
468}
469
470static int
471mapping_print(mp, fp, flags)
472 register mappingobject *mp;
473 register FILE *fp;
474 register int flags;
475{
476 register int i;
477 register int any;
478 register mappingentry *ep;
479 fprintf(fp, "{");
480 any = 0;
481 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
482 if (ep->me_value != NULL) {
483 if (any++ > 0)
484 fprintf(fp, ", ");
Guido van Rossuma3d78fb1993-11-10 09:23:53 +0000485 if (printobject((object *)ep->me_key, fp, 0) != 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000486 return -1;
487 fprintf(fp, ": ");
Guido van Rossuma3d78fb1993-11-10 09:23:53 +0000488 if (printobject(ep->me_value, fp, 0) != 0)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000489 return -1;
490 }
491 }
492 fprintf(fp, "}");
493 return 0;
494}
495
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000496static object *
497mapping_repr(mp)
498 mappingobject *mp;
499{
500 auto object *v;
501 object *sepa, *colon;
502 register int i;
503 register int any;
504 register mappingentry *ep;
505 v = newstringobject("{");
506 sepa = newstringobject(", ");
507 colon = newstringobject(": ");
508 any = 0;
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000509 for (i = 0, ep = mp->ma_table; i < mp->ma_size && v; i++, ep++) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000510 if (ep->me_value != NULL) {
511 if (any++)
512 joinstring(&v, sepa);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000513 joinstring_decref(&v, reprobject(ep->me_key));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000514 joinstring(&v, colon);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000515 joinstring_decref(&v, reprobject(ep->me_value));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000516 }
517 }
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000518 joinstring_decref(&v, newstringobject("}"));
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000519 XDECREF(sepa);
520 XDECREF(colon);
521 return v;
522}
523
524static int
525mapping_length(mp)
526 mappingobject *mp;
527{
528 return mp->ma_used;
529}
530
531static object *
532mapping_subscript(mp, key)
533 mappingobject *mp;
534 register object *key;
535{
536 object *v;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000537 long hash;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000538 if (mp->ma_table == NULL) {
539 err_setval(KeyError, key);
540 return NULL;
541 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000542#ifdef CACHE_HASH
543 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
544#endif
545 hash = hashobject(key);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000546 if (hash == -1)
547 return NULL;
548 v = lookmapping(mp, key, hash) -> me_value;
549 if (v == NULL)
550 err_setval(KeyError, key);
551 else
552 INCREF(v);
553 return v;
554}
555
556static int
557mapping_ass_sub(mp, v, w)
558 mappingobject *mp;
559 object *v, *w;
560{
561 if (w == NULL)
562 return mappingremove((object *)mp, v);
563 else
564 return mappinginsert((object *)mp, v, w);
565}
566
567static mapping_methods mapping_as_mapping = {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000568 (inquiry)mapping_length, /*mp_length*/
569 (binaryfunc)mapping_subscript, /*mp_subscript*/
570 (objobjargproc)mapping_ass_sub, /*mp_ass_subscript*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000571};
572
573static object *
574mapping_keys(mp, args)
575 register mappingobject *mp;
576 object *args;
577{
578 register object *v;
579 register int i, j;
580 if (!getnoarg(args))
581 return NULL;
582 v = newlistobject(mp->ma_used);
583 if (v == NULL)
584 return NULL;
585 for (i = 0, j = 0; i < mp->ma_size; i++) {
586 if (mp->ma_table[i].me_value != NULL) {
587 object *key = mp->ma_table[i].me_key;
588 INCREF(key);
589 setlistitem(v, j, key);
590 j++;
591 }
592 }
593 return v;
594}
595
Guido van Rossum25831651993-05-19 14:50:45 +0000596static object *
597mapping_values(mp, args)
598 register mappingobject *mp;
599 object *args;
600{
601 register object *v;
602 register int i, j;
603 if (!getnoarg(args))
604 return NULL;
605 v = newlistobject(mp->ma_used);
606 if (v == NULL)
607 return NULL;
608 for (i = 0, j = 0; i < mp->ma_size; i++) {
609 if (mp->ma_table[i].me_value != NULL) {
610 object *value = mp->ma_table[i].me_value;
611 INCREF(value);
612 setlistitem(v, j, value);
613 j++;
614 }
615 }
616 return v;
617}
618
619static object *
620mapping_items(mp, args)
621 register mappingobject *mp;
622 object *args;
623{
624 register object *v;
625 register int i, j;
626 if (!getnoarg(args))
627 return NULL;
628 v = newlistobject(mp->ma_used);
629 if (v == NULL)
630 return NULL;
631 for (i = 0, j = 0; i < mp->ma_size; i++) {
632 if (mp->ma_table[i].me_value != NULL) {
633 object *key = mp->ma_table[i].me_key;
634 object *value = mp->ma_table[i].me_value;
635 object *item = newtupleobject(2);
636 if (item == NULL) {
637 DECREF(v);
638 return NULL;
639 }
640 INCREF(key);
641 settupleitem(item, 0, key);
642 INCREF(value);
643 settupleitem(item, 1, value);
644 setlistitem(v, j, item);
645 j++;
646 }
647 }
648 return v;
649}
650
Guido van Rossum4199fac1993-11-05 10:18:44 +0000651int
652getmappingsize(mp)
653 object *mp;
654{
655 if (mp == NULL || !is_mappingobject(mp)) {
656 err_badcall();
Guido van Rossumb376a4a1993-11-23 17:53:17 +0000657 return 0;
Guido van Rossum4199fac1993-11-05 10:18:44 +0000658 }
659 return ((mappingobject *)mp)->ma_used;
660}
661
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000662object *
663getmappingkeys(mp)
664 object *mp;
665{
666 if (mp == NULL || !is_mappingobject(mp)) {
667 err_badcall();
668 return NULL;
669 }
670 return mapping_keys((mappingobject *)mp, (object *)NULL);
671}
672
Guido van Rossum25831651993-05-19 14:50:45 +0000673object *
674getmappingvalues(mp)
675 object *mp;
676{
677 if (mp == NULL || !is_mappingobject(mp)) {
678 err_badcall();
679 return NULL;
680 }
681 return mapping_values((mappingobject *)mp, (object *)NULL);
682}
683
684object *
685getmappingitems(mp)
686 object *mp;
687{
688 if (mp == NULL || !is_mappingobject(mp)) {
689 err_badcall();
690 return NULL;
691 }
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000692 return mapping_items((mappingobject *)mp, (object *)NULL);
Guido van Rossum25831651993-05-19 14:50:45 +0000693}
694
Guido van Rossuma0a69b81996-12-05 21:55:55 +0000695#define NEWCMP
696
697#ifdef NEWCMP
698
699/* Subroutine which returns the smallest key in a for which b's value
700 is different or absent. The value is returned too, through the
701 pval argument. No reference counts are incremented. */
702
703static object *
704characterize(a, b, pval)
705 mappingobject *a;
706 mappingobject *b;
707 object **pval;
708{
709 object *diff = NULL;
710 int i;
711
712 *pval = NULL;
713 for (i = 0; i < a->ma_size; i++) {
714 if (a->ma_table[i].me_value != NULL) {
715 object *key = a->ma_table[i].me_key;
716 object *aval, *bval;
717 if (diff != NULL && cmpobject(key, diff) > 0)
718 continue;
719 aval = a->ma_table[i].me_value;
720 bval = mappinglookup((object *)b, key);
721 if (bval == NULL || cmpobject(aval, bval) != 0) {
722 diff = key;
723 *pval = aval;
724 }
725 }
726 }
727 return diff;
728}
729
730static int
731mapping_compare(a, b)
732 mappingobject *a, *b;
733{
734 object *adiff, *bdiff, *aval, *bval;
735 int res;
736
737 /* Compare lengths first */
738 if (a->ma_used < b->ma_used)
739 return -1; /* a is shorter */
740 else if (a->ma_used > b->ma_used)
741 return 1; /* b is shorter */
742 /* Same length -- check all keys */
743 adiff = characterize(a, b, &aval);
744 if (adiff == NULL)
745 return 0; /* a is a subset with the same length */
746 bdiff = characterize(b, a, &bval);
747 /* bdiff == NULL would be impossible now */
748 res = cmpobject(adiff, bdiff);
749 if (res == 0)
750 res = cmpobject(aval, bval);
751 return res;
752}
753
754#else /* !NEWCMP */
755
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000756static int
757mapping_compare(a, b)
758 mappingobject *a, *b;
759{
760 object *akeys, *bkeys;
761 int i, n, res;
762 if (a == b)
763 return 0;
764 if (a->ma_used == 0) {
765 if (b->ma_used != 0)
766 return -1;
767 else
768 return 0;
769 }
770 else {
771 if (b->ma_used == 0)
772 return 1;
773 }
774 akeys = mapping_keys(a, (object *)NULL);
775 bkeys = mapping_keys(b, (object *)NULL);
776 if (akeys == NULL || bkeys == NULL) {
777 /* Oops, out of memory -- what to do? */
778 /* For now, sort on address! */
779 XDECREF(akeys);
780 XDECREF(bkeys);
781 if (a < b)
782 return -1;
783 else
784 return 1;
785 }
786 sortlist(akeys);
787 sortlist(bkeys);
788 n = a->ma_used < b->ma_used ? a->ma_used : b->ma_used; /* smallest */
789 res = 0;
790 for (i = 0; i < n; i++) {
791 object *akey, *bkey, *aval, *bval;
792 long ahash, bhash;
793 akey = getlistitem(akeys, i);
794 bkey = getlistitem(bkeys, i);
795 res = cmpobject(akey, bkey);
796 if (res != 0)
797 break;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000798#ifdef CACHE_HASH
799 if (!is_stringobject(akey) || (ahash = ((stringobject *) akey)->ob_shash) == -1)
800#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000801 ahash = hashobject(akey);
802 if (ahash == -1)
803 err_clear(); /* Don't want errors here */
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000804#ifdef CACHE_HASH
805 if (!is_stringobject(bkey) || (bhash = ((stringobject *) bkey)->ob_shash) == -1)
806#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000807 bhash = hashobject(bkey);
808 if (bhash == -1)
809 err_clear(); /* Don't want errors here */
810 aval = lookmapping(a, akey, ahash) -> me_value;
811 bval = lookmapping(b, bkey, bhash) -> me_value;
812 res = cmpobject(aval, bval);
813 if (res != 0)
814 break;
815 }
816 if (res == 0) {
817 if (a->ma_used < b->ma_used)
818 res = -1;
819 else if (a->ma_used > b->ma_used)
820 res = 1;
821 }
822 DECREF(akeys);
823 DECREF(bkeys);
824 return res;
825}
826
Guido van Rossuma0a69b81996-12-05 21:55:55 +0000827#endif /* !NEWCMP */
828
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000829static object *
830mapping_has_key(mp, args)
831 register mappingobject *mp;
832 object *args;
833{
834 object *key;
835 long hash;
836 register long ok;
837 if (!getargs(args, "O", &key))
838 return NULL;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000839#ifdef CACHE_HASH
840 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
841#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000842 hash = hashobject(key);
843 if (hash == -1)
844 return NULL;
Guido van Rossumd7047b31995-01-02 19:07:15 +0000845 ok = mp->ma_size != 0 && lookmapping(mp, key, hash)->me_value != NULL;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000846 return newintobject(ok);
847}
848
849static struct methodlist mapp_methods[] = {
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000850 {"has_key", (method)mapping_has_key},
851 {"items", (method)mapping_items},
852 {"keys", (method)mapping_keys},
853 {"values", (method)mapping_values},
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000854 {NULL, NULL} /* sentinel */
855};
856
857static object *
858mapping_getattr(mp, name)
859 mappingobject *mp;
860 char *name;
861{
862 return findmethod(mapp_methods, (object *)mp, name);
863}
864
865typeobject Mappingtype = {
866 OB_HEAD_INIT(&Typetype)
867 0,
Guido van Rossum9bfef441993-03-29 10:43:31 +0000868 "dictionary",
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000869 sizeof(mappingobject),
870 0,
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000871 (destructor)mapping_dealloc, /*tp_dealloc*/
872 (printfunc)mapping_print, /*tp_print*/
873 (getattrfunc)mapping_getattr, /*tp_getattr*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000874 0, /*tp_setattr*/
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000875 (cmpfunc)mapping_compare, /*tp_compare*/
876 (reprfunc)mapping_repr, /*tp_repr*/
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000877 0, /*tp_as_number*/
878 0, /*tp_as_sequence*/
879 &mapping_as_mapping, /*tp_as_mapping*/
880};
881
882/* For backward compatibility with old dictionary interface */
883
884static object *last_name_object;
Guido van Rossum992ded81995-12-08 01:16:31 +0000885static char *last_name_char; /* NULL or == getstringvalue(last_name_object) */
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000886
887object *
888getattro(v, name)
889 object *v;
890 object *name;
891{
Guido van Rossumd8eb1b31996-08-09 20:52:03 +0000892 if (v->ob_type->tp_getattro != NULL)
893 return (*v->ob_type->tp_getattro)(v, name);
894
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000895 if (name != last_name_object) {
896 XDECREF(last_name_object);
897 INCREF(name);
898 last_name_object = name;
899 last_name_char = getstringvalue(name);
900 }
901 return getattr(v, last_name_char);
902}
903
904int
905setattro(v, name, value)
906 object *v;
907 object *name;
908 object *value;
909{
Guido van Rossumd8eb1b31996-08-09 20:52:03 +0000910 if (v->ob_type->tp_setattro != NULL)
911 return (*v->ob_type->tp_setattro)(v, name, value);
912
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000913 if (name != last_name_object) {
914 XDECREF(last_name_object);
915 INCREF(name);
916 last_name_object = name;
917 last_name_char = getstringvalue(name);
918 }
919 return setattr(v, last_name_char, value);
920}
921
922object *
923dictlookup(v, key)
924 object *v;
925 char *key;
926{
Guido van Rossum992ded81995-12-08 01:16:31 +0000927 if (key != last_name_char) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000928 XDECREF(last_name_object);
929 last_name_object = newstringobject(key);
930 if (last_name_object == NULL) {
931 last_name_char = NULL;
932 return NULL;
933 }
Guido van Rossum992ded81995-12-08 01:16:31 +0000934 last_name_char = getstringvalue(last_name_object);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000935 }
936 return mappinglookup(v, last_name_object);
937}
938
939int
940dictinsert(v, key, item)
941 object *v;
942 char *key;
943 object *item;
944{
Guido van Rossum992ded81995-12-08 01:16:31 +0000945 if (key != last_name_char) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000946 XDECREF(last_name_object);
947 last_name_object = newstringobject(key);
948 if (last_name_object == NULL) {
949 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +0000950 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000951 }
Guido van Rossum992ded81995-12-08 01:16:31 +0000952 last_name_char = getstringvalue(last_name_object);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000953 }
954 return mappinginsert(v, last_name_object, item);
955}
956
957int
958dictremove(v, key)
959 object *v;
960 char *key;
961{
Guido van Rossum992ded81995-12-08 01:16:31 +0000962 if (key != last_name_char) {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000963 XDECREF(last_name_object);
964 last_name_object = newstringobject(key);
965 if (last_name_object == NULL) {
966 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +0000967 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000968 }
Guido van Rossum992ded81995-12-08 01:16:31 +0000969 last_name_char = getstringvalue(last_name_object);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000970 }
971 return mappingremove(v, last_name_object);
972}