blob: 2a51d51dae2677ba70871c855678f1346a24ddd5 [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 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000245#ifdef CACHE_HASH
246 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
247#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000248 hash = hashobject(key);
249 if (hash == -1)
250 return NULL;
251 return lookmapping((mappingobject *)op, key, hash) -> me_value;
252}
253
254int
255mappinginsert(op, key, value)
256 register object *op;
257 object *key;
258 object *value;
259{
260 register mappingobject *mp;
261 register long hash;
262 if (!is_mappingobject(op)) {
263 err_badcall();
264 return -1;
265 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000266#ifdef CACHE_HASH
267 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
268#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000269 hash = hashobject(key);
270 if (hash == -1)
271 return -1;
272 mp = (mappingobject *)op;
273 /* if fill >= 2/3 size, resize */
274 if (mp->ma_fill*3 >= mp->ma_size*2) {
275 if (mappingresize(mp) != 0) {
276 if (mp->ma_fill+1 > mp->ma_size)
277 return -1;
278 }
279 }
280 INCREF(value);
281 INCREF(key);
282 insertmapping(mp, key, hash, value);
283 return 0;
284}
285
286int
287mappingremove(op, key)
288 object *op;
289 object *key;
290{
291 register mappingobject *mp;
292 register long hash;
293 register mappingentry *ep;
294 if (!is_mappingobject(op)) {
295 err_badcall();
296 return -1;
297 }
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000298#ifdef CACHE_HASH
299 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
300#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000301 hash = hashobject(key);
302 if (hash == -1)
303 return -1;
304 mp = (mappingobject *)op;
305 ep = lookmapping(mp, key, hash);
306 if (ep->me_value == NULL) {
307 err_setval(KeyError, key);
308 return -1;
309 }
310 DECREF(ep->me_key);
311 INCREF(dummy);
312 ep->me_key = dummy;
313 DECREF(ep->me_value);
314 ep->me_value = NULL;
315 mp->ma_used--;
316 return 0;
317}
318
Guido van Rossum25831651993-05-19 14:50:45 +0000319void
320mappingclear(op)
321 object *op;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000322{
Guido van Rossum25831651993-05-19 14:50:45 +0000323 int i;
324 register mappingobject *mp;
325 if (!is_mappingobject(op))
326 return;
327 mp = (mappingobject *)op;
328 for (i = 0; i < mp->ma_size; i++) {
329 XDECREF(mp->ma_table[i].me_key);
330 XDECREF(mp->ma_table[i].me_value);
331 mp->ma_table[i].me_key = NULL;
332 mp->ma_table[i].me_value = NULL;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000333 }
Guido van Rossum25831651993-05-19 14:50:45 +0000334 mp->ma_used = 0;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000335}
336
Guido van Rossum25831651993-05-19 14:50:45 +0000337int
338mappinggetnext(op, ppos, pkey, pvalue)
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000339 object *op;
Guido van Rossum25831651993-05-19 14:50:45 +0000340 int *ppos;
341 object **pkey;
342 object **pvalue;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000343{
Guido van Rossum25831651993-05-19 14:50:45 +0000344 int i;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000345 register mappingobject *mp;
Guido van Rossum25831651993-05-19 14:50:45 +0000346 if (!is_dictobject(op))
347 return 0;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000348 mp = (mappingobject *)op;
Guido van Rossum25831651993-05-19 14:50:45 +0000349 i = *ppos;
350 if (i < 0)
351 return 0;
352 while (i < mp->ma_size && mp->ma_table[i].me_value == NULL)
353 i++;
354 *ppos = i+1;
355 if (i >= mp->ma_size)
356 return 0;
357 if (pkey)
358 *pkey = mp->ma_table[i].me_key;
359 if (pvalue)
360 *pvalue = mp->ma_table[i].me_value;
361 return 1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000362}
363
364/* Methods */
365
366static void
367mapping_dealloc(mp)
368 register mappingobject *mp;
369{
370 register int i;
371 register mappingentry *ep;
372 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
373 if (ep->me_key != NULL)
374 DECREF(ep->me_key);
375 if (ep->me_value != NULL)
376 DECREF(ep->me_value);
377 }
378 if (mp->ma_table != NULL)
379 DEL(mp->ma_table);
380 DEL(mp);
381}
382
383static int
384mapping_print(mp, fp, flags)
385 register mappingobject *mp;
386 register FILE *fp;
387 register int flags;
388{
389 register int i;
390 register int any;
391 register mappingentry *ep;
392 fprintf(fp, "{");
393 any = 0;
394 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
395 if (ep->me_value != NULL) {
396 if (any++ > 0)
397 fprintf(fp, ", ");
398 if (printobject((object *)ep->me_key, fp, flags) != 0)
399 return -1;
400 fprintf(fp, ": ");
401 if (printobject(ep->me_value, fp, flags) != 0)
402 return -1;
403 }
404 }
405 fprintf(fp, "}");
406 return 0;
407}
408
409static void
410js(pv, w)
411 object **pv;
412 object *w;
413{
414 joinstring(pv, w);
415 XDECREF(w);
416}
417
418static object *
419mapping_repr(mp)
420 mappingobject *mp;
421{
422 auto object *v;
423 object *sepa, *colon;
424 register int i;
425 register int any;
426 register mappingentry *ep;
427 v = newstringobject("{");
428 sepa = newstringobject(", ");
429 colon = newstringobject(": ");
430 any = 0;
431 for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
432 if (ep->me_value != NULL) {
433 if (any++)
434 joinstring(&v, sepa);
435 js(&v, reprobject(ep->me_key));
436 joinstring(&v, colon);
437 js(&v, reprobject(ep->me_value));
438 }
439 }
440 js(&v, newstringobject("}"));
441 XDECREF(sepa);
442 XDECREF(colon);
443 return v;
444}
445
446static int
447mapping_length(mp)
448 mappingobject *mp;
449{
450 return mp->ma_used;
451}
452
453static object *
454mapping_subscript(mp, key)
455 mappingobject *mp;
456 register object *key;
457{
458 object *v;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000459 long hash;
460#ifdef CACHE_HASH
461 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
462#endif
463 hash = hashobject(key);
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000464 if (hash == -1)
465 return NULL;
466 v = lookmapping(mp, key, hash) -> me_value;
467 if (v == NULL)
468 err_setval(KeyError, key);
469 else
470 INCREF(v);
471 return v;
472}
473
474static int
475mapping_ass_sub(mp, v, w)
476 mappingobject *mp;
477 object *v, *w;
478{
479 if (w == NULL)
480 return mappingremove((object *)mp, v);
481 else
482 return mappinginsert((object *)mp, v, w);
483}
484
485static mapping_methods mapping_as_mapping = {
486 mapping_length, /*mp_length*/
487 mapping_subscript, /*mp_subscript*/
488 mapping_ass_sub, /*mp_ass_subscript*/
489};
490
491static object *
492mapping_keys(mp, args)
493 register mappingobject *mp;
494 object *args;
495{
496 register object *v;
497 register int i, j;
498 if (!getnoarg(args))
499 return NULL;
500 v = newlistobject(mp->ma_used);
501 if (v == NULL)
502 return NULL;
503 for (i = 0, j = 0; i < mp->ma_size; i++) {
504 if (mp->ma_table[i].me_value != NULL) {
505 object *key = mp->ma_table[i].me_key;
506 INCREF(key);
507 setlistitem(v, j, key);
508 j++;
509 }
510 }
511 return v;
512}
513
Guido van Rossum25831651993-05-19 14:50:45 +0000514static object *
515mapping_values(mp, args)
516 register mappingobject *mp;
517 object *args;
518{
519 register object *v;
520 register int i, j;
521 if (!getnoarg(args))
522 return NULL;
523 v = newlistobject(mp->ma_used);
524 if (v == NULL)
525 return NULL;
526 for (i = 0, j = 0; i < mp->ma_size; i++) {
527 if (mp->ma_table[i].me_value != NULL) {
528 object *value = mp->ma_table[i].me_value;
529 INCREF(value);
530 setlistitem(v, j, value);
531 j++;
532 }
533 }
534 return v;
535}
536
537static object *
538mapping_items(mp, args)
539 register mappingobject *mp;
540 object *args;
541{
542 register object *v;
543 register int i, j;
544 if (!getnoarg(args))
545 return NULL;
546 v = newlistobject(mp->ma_used);
547 if (v == NULL)
548 return NULL;
549 for (i = 0, j = 0; i < mp->ma_size; i++) {
550 if (mp->ma_table[i].me_value != NULL) {
551 object *key = mp->ma_table[i].me_key;
552 object *value = mp->ma_table[i].me_value;
553 object *item = newtupleobject(2);
554 if (item == NULL) {
555 DECREF(v);
556 return NULL;
557 }
558 INCREF(key);
559 settupleitem(item, 0, key);
560 INCREF(value);
561 settupleitem(item, 1, value);
562 setlistitem(v, j, item);
563 j++;
564 }
565 }
566 return v;
567}
568
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000569object *
570getmappingkeys(mp)
571 object *mp;
572{
573 if (mp == NULL || !is_mappingobject(mp)) {
574 err_badcall();
575 return NULL;
576 }
577 return mapping_keys((mappingobject *)mp, (object *)NULL);
578}
579
Guido van Rossum25831651993-05-19 14:50:45 +0000580object *
581getmappingvalues(mp)
582 object *mp;
583{
584 if (mp == NULL || !is_mappingobject(mp)) {
585 err_badcall();
586 return NULL;
587 }
588 return mapping_values((mappingobject *)mp, (object *)NULL);
589}
590
591object *
592getmappingitems(mp)
593 object *mp;
594{
595 if (mp == NULL || !is_mappingobject(mp)) {
596 err_badcall();
597 return NULL;
598 }
599 return mapping_values((mappingobject *)mp, (object *)NULL);
600}
601
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000602static int
603mapping_compare(a, b)
604 mappingobject *a, *b;
605{
606 object *akeys, *bkeys;
607 int i, n, res;
608 if (a == b)
609 return 0;
610 if (a->ma_used == 0) {
611 if (b->ma_used != 0)
612 return -1;
613 else
614 return 0;
615 }
616 else {
617 if (b->ma_used == 0)
618 return 1;
619 }
620 akeys = mapping_keys(a, (object *)NULL);
621 bkeys = mapping_keys(b, (object *)NULL);
622 if (akeys == NULL || bkeys == NULL) {
623 /* Oops, out of memory -- what to do? */
624 /* For now, sort on address! */
625 XDECREF(akeys);
626 XDECREF(bkeys);
627 if (a < b)
628 return -1;
629 else
630 return 1;
631 }
632 sortlist(akeys);
633 sortlist(bkeys);
634 n = a->ma_used < b->ma_used ? a->ma_used : b->ma_used; /* smallest */
635 res = 0;
636 for (i = 0; i < n; i++) {
637 object *akey, *bkey, *aval, *bval;
638 long ahash, bhash;
639 akey = getlistitem(akeys, i);
640 bkey = getlistitem(bkeys, i);
641 res = cmpobject(akey, bkey);
642 if (res != 0)
643 break;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000644#ifdef CACHE_HASH
645 if (!is_stringobject(akey) || (ahash = ((stringobject *) akey)->ob_shash) == -1)
646#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000647 ahash = hashobject(akey);
648 if (ahash == -1)
649 err_clear(); /* Don't want errors here */
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000650#ifdef CACHE_HASH
651 if (!is_stringobject(bkey) || (bhash = ((stringobject *) bkey)->ob_shash) == -1)
652#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000653 bhash = hashobject(bkey);
654 if (bhash == -1)
655 err_clear(); /* Don't want errors here */
656 aval = lookmapping(a, akey, ahash) -> me_value;
657 bval = lookmapping(b, bkey, bhash) -> me_value;
658 res = cmpobject(aval, bval);
659 if (res != 0)
660 break;
661 }
662 if (res == 0) {
663 if (a->ma_used < b->ma_used)
664 res = -1;
665 else if (a->ma_used > b->ma_used)
666 res = 1;
667 }
668 DECREF(akeys);
669 DECREF(bkeys);
670 return res;
671}
672
673static object *
674mapping_has_key(mp, args)
675 register mappingobject *mp;
676 object *args;
677{
678 object *key;
679 long hash;
680 register long ok;
681 if (!getargs(args, "O", &key))
682 return NULL;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000683#ifdef CACHE_HASH
684 if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1)
685#endif
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000686 hash = hashobject(key);
687 if (hash == -1)
688 return NULL;
689 ok = lookmapping(mp, key, hash)->me_value != NULL;
690 return newintobject(ok);
691}
692
693static struct methodlist mapp_methods[] = {
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000694 {"has_key", mapping_has_key},
Guido van Rossum25831651993-05-19 14:50:45 +0000695 {"items", mapping_items},
696 {"keys", mapping_keys},
697 {"values", mapping_values},
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000698 {NULL, NULL} /* sentinel */
699};
700
701static object *
702mapping_getattr(mp, name)
703 mappingobject *mp;
704 char *name;
705{
706 return findmethod(mapp_methods, (object *)mp, name);
707}
708
709typeobject Mappingtype = {
710 OB_HEAD_INIT(&Typetype)
711 0,
Guido van Rossum9bfef441993-03-29 10:43:31 +0000712 "dictionary",
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000713 sizeof(mappingobject),
714 0,
715 mapping_dealloc, /*tp_dealloc*/
716 mapping_print, /*tp_print*/
717 mapping_getattr, /*tp_getattr*/
718 0, /*tp_setattr*/
719 mapping_compare, /*tp_compare*/
720 mapping_repr, /*tp_repr*/
721 0, /*tp_as_number*/
722 0, /*tp_as_sequence*/
723 &mapping_as_mapping, /*tp_as_mapping*/
724};
725
726/* For backward compatibility with old dictionary interface */
727
728static object *last_name_object;
729static char *last_name_char;
730
731object *
732getattro(v, name)
733 object *v;
734 object *name;
735{
736 if (name != last_name_object) {
737 XDECREF(last_name_object);
738 INCREF(name);
739 last_name_object = name;
740 last_name_char = getstringvalue(name);
741 }
742 return getattr(v, last_name_char);
743}
744
745int
746setattro(v, name, value)
747 object *v;
748 object *name;
749 object *value;
750{
751 if (name != last_name_object) {
752 XDECREF(last_name_object);
753 INCREF(name);
754 last_name_object = name;
755 last_name_char = getstringvalue(name);
756 }
757 return setattr(v, last_name_char, value);
758}
759
760object *
761dictlookup(v, key)
762 object *v;
763 char *key;
764{
765 if (key != last_name_char) {
766 XDECREF(last_name_object);
767 last_name_object = newstringobject(key);
768 if (last_name_object == NULL) {
769 last_name_char = NULL;
770 return NULL;
771 }
772 last_name_char = key;
773 }
774 return mappinglookup(v, last_name_object);
775}
776
777int
778dictinsert(v, key, item)
779 object *v;
780 char *key;
781 object *item;
782{
783 if (key != last_name_char) {
784 XDECREF(last_name_object);
785 last_name_object = newstringobject(key);
786 if (last_name_object == NULL) {
787 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +0000788 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000789 }
790 last_name_char = key;
791 }
792 return mappinginsert(v, last_name_object, item);
793}
794
795int
796dictremove(v, key)
797 object *v;
798 char *key;
799{
800 if (key != last_name_char) {
801 XDECREF(last_name_object);
802 last_name_object = newstringobject(key);
803 if (last_name_object == NULL) {
804 last_name_char = NULL;
Guido van Rossum1fc238a1993-07-29 08:25:09 +0000805 return -1;
Guido van Rossum4b1302b1993-03-27 18:11:32 +0000806 }
807 last_name_char = key;
808 }
809 return mappingremove(v, last_name_object);
810}