blob: fa66a9d73fc63e011d8dc7def7be9d48cfcc805e [file] [log] [blame]
Guido van Rossum4b1302b1993-03-27 18:11:32 +00001/***********************************************************
2Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum,
3Amsterdam, The Netherlands.
4
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
25/* Mapping object implementation; using a hash table */
26
Guido van Rossum9bfef441993-03-29 10:43:31 +000027/* This file should really be called "dictobject.c", since "mapping"
28 is the generic name for objects with an unorderred arbitrary key
29 set (just like lists are sequences), but since it improves (and was
30 originally derived from) a file by that name I had to change its
31 name. For the user these objects are still called "dictionaries". */
32
Guido van Rossum4b1302b1993-03-27 18:11:32 +000033#include "allobjects.h"
Guido van Rossum4b1302b1993-03-27 18:11:32 +000034#include "modsupport.h"
35
36
37/*
38Table of primes suitable as keys, in ascending order.
39The first line are the largest primes less than some powers of two,
40the second line is the largest prime less than 6000,
41and the third line is a selection from Knuth, Vol. 3, Sec. 6.1, Table 1.
42The final value is a sentinel and should cause the memory allocation
43of that many entries to fail (if none of the earlier values cause such
44failure already).
45*/
46static unsigned int primes[] = {
47 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2017, 4093,
48 5987,
49 9551, 15683, 19609, 31397,
50 0xffffffff /* All bits set -- truncation OK */
51};
52
53/* Object used as dummy key to fill deleted entries */
54static object *dummy; /* Initialized by first call to newmappingobject() */
55
56/*
57Invariant for entries: when in use, de_value is not NULL and de_key is
58not NULL and not dummy; when not in use, de_value is NULL and de_key
59is either NULL or dummy. A dummy key value cannot be replaced by
60NULL, since otherwise other keys may be lost.
61*/
62typedef struct {
63 long me_hash;
64 object *me_key;
65 object *me_value;
66} mappingentry;
67
68/*
69To ensure the lookup algorithm terminates, the table size must be a
70prime number and there must be at least one NULL key in the table.
71The value ma_fill is the number of non-NULL keys; ma_used is the number
72of non-NULL, non-dummy keys.
73To avoid slowing down lookups on a near-full table, we resize the table
74when it is more than half filled.
75*/
76typedef struct {
77 OB_HEAD
78 int ma_fill;
79 int ma_used;
80 int ma_size;
81 mappingentry *ma_table;
82} mappingobject;
83
84object *
85newmappingobject()
86{
87 register mappingobject *mp;
88 if (dummy == NULL) { /* Auto-initialize dummy */
89 dummy = newstringobject("<dummy key>");
90 if (dummy == NULL)
91 return NULL;
92 }
93 mp = NEWOBJ(mappingobject, &Mappingtype);
94 if (mp == NULL)
95 return NULL;
96 mp->ma_size = primes[0];
97 mp->ma_table = (mappingentry *) calloc(sizeof(mappingentry), mp->ma_size);
98 if (mp->ma_table == NULL) {
99 DEL(mp);
100 return err_nomem();
101 }
102 mp->ma_fill = 0;
103 mp->ma_used = 0;
104 return (object *)mp;
105}
106
107/*
108The basic lookup function used by all operations.
109This is essentially Algorithm D from Knuth Vol. 3, Sec. 6.4.
110Open addressing is preferred over chaining since the link overhead for
111chaining would be substantial (100% with typical malloc overhead).
112
113First a 32-bit hash value, 'sum', is computed from the key string.
114The first character is added an extra time shifted by 8 to avoid hashing
115single-character keys (often heavily used variables) too close together.
116All arithmetic on sum should ignore overflow.
117
118The initial probe index is then computed as sum mod the table size.
119Subsequent probe indices are incr apart (mod table size), where incr
120is also derived from sum, with the additional requirement that it is
121relative prime to the table size (i.e., 1 <= incr < size, since the size
122is a prime number). My choice for incr is somewhat arbitrary.
123*/
124static mappingentry *lookmapping PROTO((mappingobject *, object *, long));
125static mappingentry *
126lookmapping(mp, key, hash)
127 register mappingobject *mp;
128 object *key;
129 long hash;
130{
131 register int i, incr;
132 register unsigned long sum = (unsigned long) hash;
133 register mappingentry *freeslot = NULL;
134 /* We must come up with (i, incr) such that 0 <= i < ma_size
135 and 0 < incr < ma_size and both are a function of hash */
136 i = sum % mp->ma_size;
137 do {
138 sum = sum + sum + sum + 1;
139 incr = sum % mp->ma_size;
140 } while (incr == 0);
141 for (;;) {
142 register mappingentry *ep = &mp->ma_table[i];
143 if (ep->me_key == NULL) {
144 if (freeslot != NULL)
145 return freeslot;
146 else
147 return ep;
148 }
149 if (ep->me_key == dummy) {
150 if (freeslot != NULL)
151 freeslot = ep;
152 }
153 else if (ep->me_hash == hash &&
154 cmpobject(ep->me_key, key) == 0) {
155 return ep;
156 }
157 i = (i + incr) % mp->ma_size;
158 }
159}
160
161/*
162Internal routine to insert a new item into the table.
163Used both by the internal resize routine and by the public insert routine.
164Eats a reference to key and one to value.
165*/
166static void insertmapping PROTO((mappingobject *, object *, long, object *));
167static void
168insertmapping(mp, key, hash, value)
169 register mappingobject *mp;
170 object *key;
171 long hash;
172 object *value;
173{
174 register mappingentry *ep;
175 ep = lookmapping(mp, key, hash);
176 if (ep->me_value != NULL) {
177 DECREF(ep->me_value);
178 DECREF(key);
179 }
180 else {
181 if (ep->me_key == NULL)
182 mp->ma_fill++;
183 else
184 DECREF(ep->me_key);
185 ep->me_key = key;
186 ep->me_hash = hash;
187 mp->ma_used++;
188 }
189 ep->me_value = value;
190}
191
192/*
193Restructure the table by allocating a new table and reinserting all
194items again. When entries have been deleted, the new table may
195actually be smaller than the old one.
196*/
197static int mappingresize PROTO((mappingobject *));
198static int
199mappingresize(mp)
200 mappingobject *mp;
201{
202 register int oldsize = mp->ma_size;
203 register int newsize;
204 register mappingentry *oldtable = mp->ma_table;
205 register mappingentry *newtable;
206 register mappingentry *ep;
207 register int i;
208 newsize = mp->ma_size;
209 for (i = 0; ; i++) {
210 if (primes[i] > mp->ma_used*2) {
211 newsize = primes[i];
212 break;
213 }
214 }
215 newtable = (mappingentry *) calloc(sizeof(mappingentry), newsize);
216 if (newtable == NULL) {
217 err_nomem();
218 return -1;
219 }
220 mp->ma_size = newsize;
221 mp->ma_table = newtable;
222 mp->ma_fill = 0;
223 mp->ma_used = 0;
224 for (i = 0, ep = oldtable; i < oldsize; i++, ep++) {
225 if (ep->me_value != NULL)
226 insertmapping(mp,ep->me_key,ep->me_hash,ep->me_value);
227 else {
228 XDECREF(ep->me_key);
229 }
230 }
231 DEL(oldtable);
232 return 0;
233}
234
235object *
236mappinglookup(op, key)
237 object *op;
238 object *key;
239{
240 long hash;
241 if (!is_mappingobject(op)) {
242 err_badcall();
243 return NULL;
244 }
245 hash = hashobject(key);
246 if (hash == -1)
247 return NULL;
248 return lookmapping((mappingobject *)op, key, hash) -> me_value;
249}
250
251int
252mappinginsert(op, key, value)
253 register object *op;
254 object *key;
255 object *value;
256{
257 register mappingobject *mp;
258 register long hash;
259 if (!is_mappingobject(op)) {
260 err_badcall();
261 return -1;
262 }
263 hash = hashobject(key);
264 if (hash == -1)
265 return -1;
266 mp = (mappingobject *)op;
267 /* if fill >= 2/3 size, resize */
268 if (mp->ma_fill*3 >= mp->ma_size*2) {
269 if (mappingresize(mp) != 0) {
270 if (mp->ma_fill+1 > mp->ma_size)
271 return -1;
272 }
273 }
274 INCREF(value);
275 INCREF(key);
276 insertmapping(mp, key, hash, value);
277 return 0;
278}
279
280int
281mappingremove(op, key)
282 object *op;
283 object *key;
284{
285 register mappingobject *mp;
286 register long hash;
287 register mappingentry *ep;
288 if (!is_mappingobject(op)) {
289 err_badcall();
290 return -1;
291 }
292 hash = hashobject(key);
293 if (hash == -1)
294 return -1;
295 mp = (mappingobject *)op;
296 ep = lookmapping(mp, key, hash);
297 if (ep->me_value == NULL) {
298 err_setval(KeyError, key);
299 return -1;
300 }
301 DECREF(ep->me_key);
302 INCREF(dummy);
303 ep->me_key = dummy;
304 DECREF(ep->me_value);
305 ep->me_value = NULL;
306 mp->ma_used--;
307 return 0;
308}
309
310int
311getmappingsize(op)
312 register object *op;
313{
314 if (!is_mappingobject(op)) {
315 err_badcall();
316 return -1;
317 }
318 return ((mappingobject *)op) -> ma_size;
319}
320
321object *
322getmappingkey(op, i)
323 object *op;
324 register int i;
325{
326 /* XXX This can't return errors since its callers assume
327 that NULL means there was no key at that point */
328 register mappingobject *mp;
329 if (!is_mappingobject(op)) {
330 /* err_badcall(); */
331 return NULL;
332 }
333 mp = (mappingobject *)op;
334 if (i < 0 || i >= mp->ma_size) {
335 /* err_badarg(); */
336 return NULL;
337 }
338 if (mp->ma_table[i].me_value == NULL) {
339 /* Not an error! */
340 return NULL;
341 }
342 return (object *) mp->ma_table[i].me_key;
343}
344
345/* Methods */
346
347static void
348mapping_dealloc(mp)
349 register mappingobject *mp;
350{
351 register int i;
352 register mappingentry *ep;
353 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
354 if (ep->me_key != NULL)
355 DECREF(ep->me_key);
356 if (ep->me_value != NULL)
357 DECREF(ep->me_value);
358 }
359 if (mp->ma_table != NULL)
360 DEL(mp->ma_table);
361 DEL(mp);
362}
363
364static int
365mapping_print(mp, fp, flags)
366 register mappingobject *mp;
367 register FILE *fp;
368 register int flags;
369{
370 register int i;
371 register int any;
372 register mappingentry *ep;
373 fprintf(fp, "{");
374 any = 0;
375 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
376 if (ep->me_value != NULL) {
377 if (any++ > 0)
378 fprintf(fp, ", ");
379 if (printobject((object *)ep->me_key, fp, flags) != 0)
380 return -1;
381 fprintf(fp, ": ");
382 if (printobject(ep->me_value, fp, flags) != 0)
383 return -1;
384 }
385 }
386 fprintf(fp, "}");
387 return 0;
388}
389
390static void
391js(pv, w)
392 object **pv;
393 object *w;
394{
395 joinstring(pv, w);
396 XDECREF(w);
397}
398
399static object *
400mapping_repr(mp)
401 mappingobject *mp;
402{
403 auto object *v;
404 object *sepa, *colon;
405 register int i;
406 register int any;
407 register mappingentry *ep;
408 v = newstringobject("{");
409 sepa = newstringobject(", ");
410 colon = newstringobject(": ");
411 any = 0;
412 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
413 if (ep->me_value != NULL) {
414 if (any++)
415 joinstring(&v, sepa);
416 js(&v, reprobject(ep->me_key));
417 joinstring(&v, colon);
418 js(&v, reprobject(ep->me_value));
419 }
420 }
421 js(&v, newstringobject("}"));
422 XDECREF(sepa);
423 XDECREF(colon);
424 return v;
425}
426
427static int
428mapping_length(mp)
429 mappingobject *mp;
430{
431 return mp->ma_used;
432}
433
434static object *
435mapping_subscript(mp, key)
436 mappingobject *mp;
437 register object *key;
438{
439 object *v;
440 long hash = hashobject(key);
441 if (hash == -1)
442 return NULL;
443 v = lookmapping(mp, key, hash) -> me_value;
444 if (v == NULL)
445 err_setval(KeyError, key);
446 else
447 INCREF(v);
448 return v;
449}
450
451static int
452mapping_ass_sub(mp, v, w)
453 mappingobject *mp;
454 object *v, *w;
455{
456 if (w == NULL)
457 return mappingremove((object *)mp, v);
458 else
459 return mappinginsert((object *)mp, v, w);
460}
461
462static mapping_methods mapping_as_mapping = {
463 mapping_length, /*mp_length*/
464 mapping_subscript, /*mp_subscript*/
465 mapping_ass_sub, /*mp_ass_subscript*/
466};
467
468static object *
469mapping_keys(mp, args)
470 register mappingobject *mp;
471 object *args;
472{
473 register object *v;
474 register int i, j;
475 if (!getnoarg(args))
476 return NULL;
477 v = newlistobject(mp->ma_used);
478 if (v == NULL)
479 return NULL;
480 for (i = 0, j = 0; i < mp->ma_size; i++) {
481 if (mp->ma_table[i].me_value != NULL) {
482 object *key = mp->ma_table[i].me_key;
483 INCREF(key);
484 setlistitem(v, j, key);
485 j++;
486 }
487 }
488 return v;
489}
490
491object *
492getmappingkeys(mp)
493 object *mp;
494{
495 if (mp == NULL || !is_mappingobject(mp)) {
496 err_badcall();
497 return NULL;
498 }
499 return mapping_keys((mappingobject *)mp, (object *)NULL);
500}
501
502static int
503mapping_compare(a, b)
504 mappingobject *a, *b;
505{
506 object *akeys, *bkeys;
507 int i, n, res;
508 if (a == b)
509 return 0;
510 if (a->ma_used == 0) {
511 if (b->ma_used != 0)
512 return -1;
513 else
514 return 0;
515 }
516 else {
517 if (b->ma_used == 0)
518 return 1;
519 }
520 akeys = mapping_keys(a, (object *)NULL);
521 bkeys = mapping_keys(b, (object *)NULL);
522 if (akeys == NULL || bkeys == NULL) {
523 /* Oops, out of memory -- what to do? */
524 /* For now, sort on address! */
525 XDECREF(akeys);
526 XDECREF(bkeys);
527 if (a < b)
528 return -1;
529 else
530 return 1;
531 }
532 sortlist(akeys);
533 sortlist(bkeys);
534 n = a->ma_used < b->ma_used ? a->ma_used : b->ma_used; /* smallest */
535 res = 0;
536 for (i = 0; i < n; i++) {
537 object *akey, *bkey, *aval, *bval;
538 long ahash, bhash;
539 akey = getlistitem(akeys, i);
540 bkey = getlistitem(bkeys, i);
541 res = cmpobject(akey, bkey);
542 if (res != 0)
543 break;
544 ahash = hashobject(akey);
545 if (ahash == -1)
546 err_clear(); /* Don't want errors here */
547 bhash = hashobject(bkey);
548 if (bhash == -1)
549 err_clear(); /* Don't want errors here */
550 aval = lookmapping(a, akey, ahash) -> me_value;
551 bval = lookmapping(b, bkey, bhash) -> me_value;
552 res = cmpobject(aval, bval);
553 if (res != 0)
554 break;
555 }
556 if (res == 0) {
557 if (a->ma_used < b->ma_used)
558 res = -1;
559 else if (a->ma_used > b->ma_used)
560 res = 1;
561 }
562 DECREF(akeys);
563 DECREF(bkeys);
564 return res;
565}
566
567static object *
568mapping_has_key(mp, args)
569 register mappingobject *mp;
570 object *args;
571{
572 object *key;
573 long hash;
574 register long ok;
575 if (!getargs(args, "O", &key))
576 return NULL;
577 hash = hashobject(key);
578 if (hash == -1)
579 return NULL;
580 ok = lookmapping(mp, key, hash)->me_value != NULL;
581 return newintobject(ok);
582}
583
584static struct methodlist mapp_methods[] = {
585 {"keys", mapping_keys},
586 {"has_key", mapping_has_key},
587 {NULL, NULL} /* sentinel */
588};
589
590static object *
591mapping_getattr(mp, name)
592 mappingobject *mp;
593 char *name;
594{
595 return findmethod(mapp_methods, (object *)mp, name);
596}
597
598typeobject Mappingtype = {
599 OB_HEAD_INIT(&Typetype)
600 0,
Guido van Rossum9bfef441993-03-29 10:43:31 +0000601 "dictionary",
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000602 sizeof(mappingobject),
603 0,
604 mapping_dealloc, /*tp_dealloc*/
605 mapping_print, /*tp_print*/
606 mapping_getattr, /*tp_getattr*/
607 0, /*tp_setattr*/
608 mapping_compare, /*tp_compare*/
609 mapping_repr, /*tp_repr*/
610 0, /*tp_as_number*/
611 0, /*tp_as_sequence*/
612 &mapping_as_mapping, /*tp_as_mapping*/
613};
614
615/* For backward compatibility with old dictionary interface */
616
617static object *last_name_object;
618static char *last_name_char;
619
620object *
621getattro(v, name)
622 object *v;
623 object *name;
624{
625 if (name != last_name_object) {
626 XDECREF(last_name_object);
627 INCREF(name);
628 last_name_object = name;
629 last_name_char = getstringvalue(name);
630 }
631 return getattr(v, last_name_char);
632}
633
634int
635setattro(v, name, value)
636 object *v;
637 object *name;
638 object *value;
639{
640 if (name != last_name_object) {
641 XDECREF(last_name_object);
642 INCREF(name);
643 last_name_object = name;
644 last_name_char = getstringvalue(name);
645 }
646 return setattr(v, last_name_char, value);
647}
648
649object *
650dictlookup(v, key)
651 object *v;
652 char *key;
653{
654 if (key != last_name_char) {
655 XDECREF(last_name_object);
656 last_name_object = newstringobject(key);
657 if (last_name_object == NULL) {
658 last_name_char = NULL;
659 return NULL;
660 }
661 last_name_char = key;
662 }
663 return mappinglookup(v, last_name_object);
664}
665
666int
667dictinsert(v, key, item)
668 object *v;
669 char *key;
670 object *item;
671{
672 if (key != last_name_char) {
673 XDECREF(last_name_object);
674 last_name_object = newstringobject(key);
675 if (last_name_object == NULL) {
676 last_name_char = NULL;
677 return NULL;
678 }
679 last_name_char = key;
680 }
681 return mappinginsert(v, last_name_object, item);
682}
683
684int
685dictremove(v, key)
686 object *v;
687 char *key;
688{
689 if (key != last_name_char) {
690 XDECREF(last_name_object);
691 last_name_object = newstringobject(key);
692 if (last_name_object == NULL) {
693 last_name_char = NULL;
694 return NULL;
695 }
696 last_name_char = key;
697 }
698 return mappingremove(v, last_name_object);
699}
700
701char *
702getdictkey(v, i)
703 object *v;
704 int i;
705{
706 object *key = getmappingkey(v, i);
707 if (key == NULL)
708 return NULL;
709 return getstringvalue(key);
710}