| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | /***********************************************************
 | 
					
						
							| 
									
										
										
										
											1995-01-04 19:07:38 +00:00
										 |  |  | Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam, | 
					
						
							|  |  |  | The Netherlands. | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                         All Rights Reserved | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Permission to use, copy, modify, and distribute this software and its  | 
					
						
							|  |  |  | documentation for any purpose and without fee is hereby granted,  | 
					
						
							|  |  |  | provided that the above copyright notice appear in all copies and that | 
					
						
							|  |  |  | both that copyright notice and this permission notice appear in  | 
					
						
							|  |  |  | supporting documentation, and that the names of Stichting Mathematisch | 
					
						
							|  |  |  | Centrum or CWI not be used in advertising or publicity pertaining to | 
					
						
							|  |  |  | distribution of the software without specific, written prior permission. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO | 
					
						
							|  |  |  | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | 
					
						
							|  |  |  | FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE | 
					
						
							|  |  |  | FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 
					
						
							|  |  |  | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 
					
						
							|  |  |  | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | 
					
						
							|  |  |  | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ******************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Mapping object implementation; using a hash table */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-03-29 10:43:31 +00:00
										 |  |  | /* This file should really be called "dictobject.c", since "mapping"
 | 
					
						
							|  |  |  |   is the generic name for objects with an unorderred arbitrary key | 
					
						
							|  |  |  |   set (just like lists are sequences), but since it improves (and was | 
					
						
							|  |  |  |   originally derived from) a file by that name I had to change its | 
					
						
							|  |  |  |   name.  For the user these objects are still called "dictionaries". */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | #include "allobjects.h"
 | 
					
						
							|  |  |  | #include "modsupport.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | Table of primes suitable as keys, in ascending order. | 
					
						
							|  |  |  | The first line are the largest primes less than some powers of two, | 
					
						
							|  |  |  | the second line is the largest prime less than 6000, | 
					
						
							| 
									
										
										
										
											1994-08-30 08:27:36 +00:00
										 |  |  | the third line is a selection from Knuth, Vol. 3, Sec. 6.1, Table 1, | 
					
						
							|  |  |  | and the next three lines were suggested by Steve Kirsch. | 
					
						
							|  |  |  | The final value is a sentinel. | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | */ | 
					
						
							| 
									
										
										
										
											1994-08-30 08:27:36 +00:00
										 |  |  | static long primes[] = { | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	3, 7, 13, 31, 61, 127, 251, 509, 1021, 2017, 4093, | 
					
						
							|  |  |  | 	5987, | 
					
						
							|  |  |  | 	9551, 15683, 19609, 31397, | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 	65521L, 131071L, 262139L, 524287L, 1048573L, 2097143L, | 
					
						
							|  |  |  | 	4194301L, 8388593L, 16777213L, 33554393L, 67108859L, | 
					
						
							|  |  |  | 	134217689L, 268435399L, 536870909L, 1073741789L, | 
					
						
							| 
									
										
										
										
											1994-08-30 08:27:36 +00:00
										 |  |  | 	0 | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Object used as dummy key to fill deleted entries */ | 
					
						
							|  |  |  | static object *dummy; /* Initialized by first call to newmappingobject() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | Invariant for entries: when in use, de_value is not NULL and de_key is | 
					
						
							|  |  |  | not NULL and not dummy; when not in use, de_value is NULL and de_key | 
					
						
							|  |  |  | is either NULL or dummy.  A dummy key value cannot be replaced by | 
					
						
							|  |  |  | NULL, since otherwise other keys may be lost. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | typedef struct { | 
					
						
							|  |  |  | 	long me_hash; | 
					
						
							|  |  |  | 	object *me_key; | 
					
						
							|  |  |  | 	object *me_value; | 
					
						
							|  |  |  | } mappingentry; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | To ensure the lookup algorithm terminates, the table size must be a | 
					
						
							|  |  |  | prime number and there must be at least one NULL key in the table. | 
					
						
							|  |  |  | The value ma_fill is the number of non-NULL keys; ma_used is the number | 
					
						
							|  |  |  | of non-NULL, non-dummy keys. | 
					
						
							|  |  |  | To avoid slowing down lookups on a near-full table, we resize the table | 
					
						
							|  |  |  | when it is more than half filled. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | typedef struct { | 
					
						
							|  |  |  | 	OB_HEAD | 
					
						
							|  |  |  | 	int ma_fill; | 
					
						
							|  |  |  | 	int ma_used; | 
					
						
							|  |  |  | 	int ma_size; | 
					
						
							|  |  |  | 	mappingentry *ma_table; | 
					
						
							|  |  |  | } mappingobject; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | object * | 
					
						
							|  |  |  | newmappingobject() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	register mappingobject *mp; | 
					
						
							|  |  |  | 	if (dummy == NULL) { /* Auto-initialize dummy */ | 
					
						
							|  |  |  | 		dummy = newstringobject("<dummy key>"); | 
					
						
							|  |  |  | 		if (dummy == NULL) | 
					
						
							|  |  |  | 			return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	mp = NEWOBJ(mappingobject, &Mappingtype); | 
					
						
							|  |  |  | 	if (mp == NULL) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 	mp->ma_size = 0; | 
					
						
							|  |  |  | 	mp->ma_table = NULL; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	mp->ma_fill = 0; | 
					
						
							|  |  |  | 	mp->ma_used = 0; | 
					
						
							|  |  |  | 	return (object *)mp; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | The basic lookup function used by all operations. | 
					
						
							|  |  |  | This is essentially Algorithm D from Knuth Vol. 3, Sec. 6.4. | 
					
						
							|  |  |  | Open addressing is preferred over chaining since the link overhead for | 
					
						
							|  |  |  | chaining would be substantial (100% with typical malloc overhead). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | First a 32-bit hash value, 'sum', is computed from the key string. | 
					
						
							|  |  |  | The first character is added an extra time shifted by 8 to avoid hashing | 
					
						
							|  |  |  | single-character keys (often heavily used variables) too close together. | 
					
						
							|  |  |  | All arithmetic on sum should ignore overflow. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The initial probe index is then computed as sum mod the table size. | 
					
						
							|  |  |  | Subsequent probe indices are incr apart (mod table size), where incr | 
					
						
							|  |  |  | is also derived from sum, with the additional requirement that it is | 
					
						
							|  |  |  | relative prime to the table size (i.e., 1 <= incr < size, since the size | 
					
						
							|  |  |  | is a prime number).  My choice for incr is somewhat arbitrary. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | static mappingentry *lookmapping PROTO((mappingobject *, object *, long)); | 
					
						
							|  |  |  | static mappingentry * | 
					
						
							|  |  |  | lookmapping(mp, key, hash) | 
					
						
							|  |  |  | 	register mappingobject *mp; | 
					
						
							|  |  |  | 	object *key; | 
					
						
							|  |  |  | 	long hash; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	register int i, incr; | 
					
						
							|  |  |  | 	register unsigned long sum = (unsigned long) hash; | 
					
						
							|  |  |  | 	register mappingentry *freeslot = NULL; | 
					
						
							| 
									
										
										
										
											1996-07-30 16:45:31 +00:00
										 |  |  | 	register int size = mp->ma_size; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	/* We must come up with (i, incr) such that 0 <= i < ma_size
 | 
					
						
							|  |  |  | 	   and 0 < incr < ma_size and both are a function of hash */ | 
					
						
							| 
									
										
										
										
											1996-07-30 16:45:31 +00:00
										 |  |  | 	i = sum % size; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	do { | 
					
						
							| 
									
										
										
										
											1995-03-09 12:12:50 +00:00
										 |  |  | 		sum = 3*sum + 1; | 
					
						
							| 
									
										
										
										
											1996-07-30 16:45:31 +00:00
										 |  |  | 		incr = sum % size; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	} while (incr == 0); | 
					
						
							|  |  |  | 	for (;;) { | 
					
						
							|  |  |  | 		register mappingentry *ep = &mp->ma_table[i]; | 
					
						
							|  |  |  | 		if (ep->me_key == NULL) { | 
					
						
							|  |  |  | 			if (freeslot != NULL) | 
					
						
							|  |  |  | 				return freeslot; | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 				return ep; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (ep->me_key == dummy) { | 
					
						
							| 
									
										
										
										
											1993-11-10 12:53:24 +00:00
										 |  |  | 			if (freeslot == NULL) | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 				freeslot = ep; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else if (ep->me_hash == hash && | 
					
						
							|  |  |  | 			 cmpobject(ep->me_key, key) == 0) { | 
					
						
							|  |  |  | 			return ep; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											1996-07-30 16:45:31 +00:00
										 |  |  | 		i = (i + incr) % size; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | Internal routine to insert a new item into the table. | 
					
						
							|  |  |  | Used both by the internal resize routine and by the public insert routine. | 
					
						
							|  |  |  | Eats a reference to key and one to value. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | static void insertmapping PROTO((mappingobject *, object *, long, object *)); | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | insertmapping(mp, key, hash, value) | 
					
						
							|  |  |  | 	register mappingobject *mp; | 
					
						
							|  |  |  | 	object *key; | 
					
						
							|  |  |  | 	long hash; | 
					
						
							|  |  |  | 	object *value; | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 	object *old_value; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	register mappingentry *ep; | 
					
						
							|  |  |  | 	ep = lookmapping(mp, key, hash); | 
					
						
							|  |  |  | 	if (ep->me_value != NULL) { | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 		old_value = ep->me_value; | 
					
						
							|  |  |  | 		ep->me_value = value; | 
					
						
							|  |  |  | 		DECREF(old_value); /* which **CAN** re-enter */ | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 		DECREF(key); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		if (ep->me_key == NULL) | 
					
						
							|  |  |  | 			mp->ma_fill++; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			DECREF(ep->me_key); | 
					
						
							|  |  |  | 		ep->me_key = key; | 
					
						
							|  |  |  | 		ep->me_hash = hash; | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 		ep->me_value = value; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 		mp->ma_used++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | Restructure the table by allocating a new table and reinserting all | 
					
						
							|  |  |  | items again.  When entries have been deleted, the new table may | 
					
						
							|  |  |  | actually be smaller than the old one. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | static int mappingresize PROTO((mappingobject *)); | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | mappingresize(mp) | 
					
						
							|  |  |  | 	mappingobject *mp; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	register int oldsize = mp->ma_size; | 
					
						
							|  |  |  | 	register int newsize; | 
					
						
							|  |  |  | 	register mappingentry *oldtable = mp->ma_table; | 
					
						
							|  |  |  | 	register mappingentry *newtable; | 
					
						
							|  |  |  | 	register mappingentry *ep; | 
					
						
							|  |  |  | 	register int i; | 
					
						
							|  |  |  | 	newsize = mp->ma_size; | 
					
						
							|  |  |  | 	for (i = 0; ; i++) { | 
					
						
							| 
									
										
										
										
											1994-08-30 08:27:36 +00:00
										 |  |  | 		if (primes[i] <= 0) { | 
					
						
							|  |  |  | 			/* Ran out of primes */ | 
					
						
							|  |  |  | 			err_nomem(); | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 		if (primes[i] > mp->ma_used*2) { | 
					
						
							|  |  |  | 			newsize = primes[i]; | 
					
						
							| 
									
										
										
										
											1994-08-30 08:27:36 +00:00
										 |  |  | 			if (newsize != primes[i]) { | 
					
						
							|  |  |  | 				/* Integer truncation */ | 
					
						
							|  |  |  | 				err_nomem(); | 
					
						
							|  |  |  | 				return -1; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	newtable = (mappingentry *) calloc(sizeof(mappingentry), newsize); | 
					
						
							|  |  |  | 	if (newtable == NULL) { | 
					
						
							|  |  |  | 		err_nomem(); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	mp->ma_size = newsize; | 
					
						
							|  |  |  | 	mp->ma_table = newtable; | 
					
						
							|  |  |  | 	mp->ma_fill = 0; | 
					
						
							|  |  |  | 	mp->ma_used = 0; | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Make two passes, so we can avoid decrefs
 | 
					
						
							|  |  |  | 	   (and possible side effects) till the table is copied */ | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	for (i = 0, ep = oldtable; i < oldsize; i++, ep++) { | 
					
						
							|  |  |  | 		if (ep->me_value != NULL) | 
					
						
							|  |  |  | 			insertmapping(mp,ep->me_key,ep->me_hash,ep->me_value); | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for (i = 0, ep = oldtable; i < oldsize; i++, ep++) { | 
					
						
							|  |  |  | 		if (ep->me_value == NULL) | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 			XDECREF(ep->me_key); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	XDEL(oldtable); | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | object * | 
					
						
							|  |  |  | mappinglookup(op, key) | 
					
						
							|  |  |  | 	object *op; | 
					
						
							|  |  |  | 	object *key; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	long hash; | 
					
						
							|  |  |  | 	if (!is_mappingobject(op)) { | 
					
						
							|  |  |  | 		err_badcall(); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 	if (((mappingobject *)op)->ma_table == NULL) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											1993-10-22 12:04:32 +00:00
										 |  |  | #ifdef CACHE_HASH
 | 
					
						
							|  |  |  | 	if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1) | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	hash = hashobject(key); | 
					
						
							|  |  |  | 	if (hash == -1) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	return lookmapping((mappingobject *)op, key, hash) -> me_value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | mappinginsert(op, key, value) | 
					
						
							|  |  |  | 	register object *op; | 
					
						
							|  |  |  | 	object *key; | 
					
						
							|  |  |  | 	object *value; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	register mappingobject *mp; | 
					
						
							|  |  |  | 	register long hash; | 
					
						
							|  |  |  | 	if (!is_mappingobject(op)) { | 
					
						
							|  |  |  | 		err_badcall(); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1993-10-22 12:04:32 +00:00
										 |  |  | #ifdef CACHE_HASH
 | 
					
						
							|  |  |  | 	if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1) | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	hash = hashobject(key); | 
					
						
							|  |  |  | 	if (hash == -1) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	mp = (mappingobject *)op; | 
					
						
							|  |  |  | 	/* if fill >= 2/3 size, resize */ | 
					
						
							|  |  |  | 	if (mp->ma_fill*3 >= mp->ma_size*2) { | 
					
						
							|  |  |  | 		if (mappingresize(mp) != 0) { | 
					
						
							|  |  |  | 			if (mp->ma_fill+1 > mp->ma_size) | 
					
						
							|  |  |  | 				return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	INCREF(value); | 
					
						
							|  |  |  | 	INCREF(key); | 
					
						
							|  |  |  | 	insertmapping(mp, key, hash, value); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | mappingremove(op, key) | 
					
						
							|  |  |  | 	object *op; | 
					
						
							|  |  |  | 	object *key; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	register mappingobject *mp; | 
					
						
							|  |  |  | 	register long hash; | 
					
						
							|  |  |  | 	register mappingentry *ep; | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 	object *old_value, *old_key; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	if (!is_mappingobject(op)) { | 
					
						
							|  |  |  | 		err_badcall(); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1993-10-22 12:04:32 +00:00
										 |  |  | #ifdef CACHE_HASH
 | 
					
						
							|  |  |  | 	if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1) | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	hash = hashobject(key); | 
					
						
							|  |  |  | 	if (hash == -1) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	mp = (mappingobject *)op; | 
					
						
							| 
									
										
										
										
											1995-01-02 19:42:39 +00:00
										 |  |  | 	if (((mappingobject *)op)->ma_table == NULL) | 
					
						
							|  |  |  | 		goto empty; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	ep = lookmapping(mp, key, hash); | 
					
						
							|  |  |  | 	if (ep->me_value == NULL) { | 
					
						
							| 
									
										
										
										
											1995-01-02 19:42:39 +00:00
										 |  |  | 	empty: | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 		err_setval(KeyError, key); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 	old_key = ep->me_key; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	INCREF(dummy); | 
					
						
							|  |  |  | 	ep->me_key = dummy; | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 	old_value = ep->me_value; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	ep->me_value = NULL; | 
					
						
							|  |  |  | 	mp->ma_used--; | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 	DECREF(old_value);  | 
					
						
							|  |  |  | 	DECREF(old_key);  | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-05-19 14:50:45 +00:00
										 |  |  | void | 
					
						
							|  |  |  | mappingclear(op) | 
					
						
							|  |  |  | 	object *op; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 	int i, n; | 
					
						
							|  |  |  | 	register mappingentry *table; | 
					
						
							|  |  |  | 	mappingobject *mp; | 
					
						
							| 
									
										
										
										
											1993-05-19 14:50:45 +00:00
										 |  |  | 	if (!is_mappingobject(op)) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	mp = (mappingobject *)op; | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 	table = mp->ma_table; | 
					
						
							|  |  |  | 	if (table == NULL) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	n = mp->ma_size; | 
					
						
							|  |  |  | 	mp->ma_size = mp->ma_used = mp->ma_fill = 0; | 
					
						
							|  |  |  | 	mp->ma_table = NULL; | 
					
						
							|  |  |  | 	for (i = 0; i < n; i++) { | 
					
						
							|  |  |  | 		XDECREF(table[i].me_key); | 
					
						
							|  |  |  | 		XDECREF(table[i].me_value); | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 	DEL(table); | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-05-19 14:50:45 +00:00
										 |  |  | int | 
					
						
							|  |  |  | mappinggetnext(op, ppos, pkey, pvalue) | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	object *op; | 
					
						
							| 
									
										
										
										
											1993-05-19 14:50:45 +00:00
										 |  |  | 	int *ppos; | 
					
						
							|  |  |  | 	object **pkey; | 
					
						
							|  |  |  | 	object **pvalue; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											1993-05-19 14:50:45 +00:00
										 |  |  | 	int i; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	register mappingobject *mp; | 
					
						
							| 
									
										
										
										
											1993-05-19 14:50:45 +00:00
										 |  |  | 	if (!is_dictobject(op)) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	mp = (mappingobject *)op; | 
					
						
							| 
									
										
										
										
											1993-05-19 14:50:45 +00:00
										 |  |  | 	i = *ppos; | 
					
						
							|  |  |  | 	if (i < 0) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	while (i < mp->ma_size && mp->ma_table[i].me_value == NULL) | 
					
						
							|  |  |  | 		i++; | 
					
						
							|  |  |  | 	*ppos = i+1; | 
					
						
							|  |  |  | 	if (i >= mp->ma_size) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	if (pkey) | 
					
						
							|  |  |  | 		*pkey = mp->ma_table[i].me_key; | 
					
						
							|  |  |  | 	if (pvalue) | 
					
						
							|  |  |  | 		*pvalue = mp->ma_table[i].me_value; | 
					
						
							|  |  |  | 	return 1; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Methods */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | mapping_dealloc(mp) | 
					
						
							|  |  |  | 	register mappingobject *mp; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	register int i; | 
					
						
							|  |  |  | 	register mappingentry *ep; | 
					
						
							|  |  |  | 	for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) { | 
					
						
							|  |  |  | 		if (ep->me_key != NULL) | 
					
						
							|  |  |  | 			DECREF(ep->me_key); | 
					
						
							|  |  |  | 		if (ep->me_value != NULL) | 
					
						
							|  |  |  | 			DECREF(ep->me_value); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 	XDEL(mp->ma_table); | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	DEL(mp); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | mapping_print(mp, fp, flags) | 
					
						
							|  |  |  | 	register mappingobject *mp; | 
					
						
							|  |  |  | 	register FILE *fp; | 
					
						
							|  |  |  | 	register int flags; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	register int i; | 
					
						
							|  |  |  | 	register int any; | 
					
						
							|  |  |  | 	register mappingentry *ep; | 
					
						
							|  |  |  | 	fprintf(fp, "{"); | 
					
						
							|  |  |  | 	any = 0; | 
					
						
							|  |  |  | 	for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) { | 
					
						
							|  |  |  | 		if (ep->me_value != NULL) { | 
					
						
							|  |  |  | 			if (any++ > 0) | 
					
						
							|  |  |  | 				fprintf(fp, ", "); | 
					
						
							| 
									
										
										
										
											1993-11-10 09:23:53 +00:00
										 |  |  | 			if (printobject((object *)ep->me_key, fp, 0) != 0) | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 				return -1; | 
					
						
							|  |  |  | 			fprintf(fp, ": "); | 
					
						
							| 
									
										
										
										
											1993-11-10 09:23:53 +00:00
										 |  |  | 			if (printobject(ep->me_value, fp, 0) != 0) | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 				return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	fprintf(fp, "}"); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static object * | 
					
						
							|  |  |  | mapping_repr(mp) | 
					
						
							|  |  |  | 	mappingobject *mp; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	auto object *v; | 
					
						
							|  |  |  | 	object *sepa, *colon; | 
					
						
							|  |  |  | 	register int i; | 
					
						
							|  |  |  | 	register int any; | 
					
						
							|  |  |  | 	register mappingentry *ep; | 
					
						
							|  |  |  | 	v = newstringobject("{"); | 
					
						
							|  |  |  | 	sepa = newstringobject(", "); | 
					
						
							|  |  |  | 	colon = newstringobject(": "); | 
					
						
							|  |  |  | 	any = 0; | 
					
						
							| 
									
										
										
										
											1994-08-30 08:27:36 +00:00
										 |  |  | 	for (i = 0, ep = mp->ma_table; i < mp->ma_size && v; i++, ep++) { | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 		if (ep->me_value != NULL) { | 
					
						
							|  |  |  | 			if (any++) | 
					
						
							|  |  |  | 				joinstring(&v, sepa); | 
					
						
							| 
									
										
										
										
											1994-08-30 08:27:36 +00:00
										 |  |  | 			joinstring_decref(&v, reprobject(ep->me_key)); | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 			joinstring(&v, colon); | 
					
						
							| 
									
										
										
										
											1994-08-30 08:27:36 +00:00
										 |  |  | 			joinstring_decref(&v, reprobject(ep->me_value)); | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1994-08-30 08:27:36 +00:00
										 |  |  | 	joinstring_decref(&v, newstringobject("}")); | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	XDECREF(sepa); | 
					
						
							|  |  |  | 	XDECREF(colon); | 
					
						
							|  |  |  | 	return v; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | mapping_length(mp) | 
					
						
							|  |  |  | 	mappingobject *mp; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return mp->ma_used; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static object * | 
					
						
							|  |  |  | mapping_subscript(mp, key) | 
					
						
							|  |  |  | 	mappingobject *mp; | 
					
						
							|  |  |  | 	register object *key; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	object *v; | 
					
						
							| 
									
										
										
										
											1993-10-22 12:04:32 +00:00
										 |  |  | 	long hash; | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 	if (mp->ma_table == NULL) { | 
					
						
							|  |  |  | 		err_setval(KeyError, key); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1993-10-22 12:04:32 +00:00
										 |  |  | #ifdef CACHE_HASH
 | 
					
						
							|  |  |  | 	if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1) | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	hash = hashobject(key); | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	if (hash == -1) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	v = lookmapping(mp, key, hash) -> me_value; | 
					
						
							|  |  |  | 	if (v == NULL) | 
					
						
							|  |  |  | 		err_setval(KeyError, key); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		INCREF(v); | 
					
						
							|  |  |  | 	return v; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | mapping_ass_sub(mp, v, w) | 
					
						
							|  |  |  | 	mappingobject *mp; | 
					
						
							|  |  |  | 	object *v, *w; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (w == NULL) | 
					
						
							|  |  |  | 		return mappingremove((object *)mp, v); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		return mappinginsert((object *)mp, v, w); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static mapping_methods mapping_as_mapping = { | 
					
						
							| 
									
										
										
										
											1994-08-30 08:27:36 +00:00
										 |  |  | 	(inquiry)mapping_length, /*mp_length*/ | 
					
						
							|  |  |  | 	(binaryfunc)mapping_subscript, /*mp_subscript*/ | 
					
						
							|  |  |  | 	(objobjargproc)mapping_ass_sub, /*mp_ass_subscript*/ | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static object * | 
					
						
							|  |  |  | mapping_keys(mp, args) | 
					
						
							|  |  |  | 	register mappingobject *mp; | 
					
						
							|  |  |  | 	object *args; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	register object *v; | 
					
						
							|  |  |  | 	register int i, j; | 
					
						
							|  |  |  | 	if (!getnoarg(args)) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	v = newlistobject(mp->ma_used); | 
					
						
							|  |  |  | 	if (v == NULL) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	for (i = 0, j = 0; i < mp->ma_size; i++) { | 
					
						
							|  |  |  | 		if (mp->ma_table[i].me_value != NULL) { | 
					
						
							|  |  |  | 			object *key = mp->ma_table[i].me_key; | 
					
						
							|  |  |  | 			INCREF(key); | 
					
						
							|  |  |  | 			setlistitem(v, j, key); | 
					
						
							|  |  |  | 			j++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return v; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-05-19 14:50:45 +00:00
										 |  |  | static object * | 
					
						
							|  |  |  | mapping_values(mp, args) | 
					
						
							|  |  |  | 	register mappingobject *mp; | 
					
						
							|  |  |  | 	object *args; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	register object *v; | 
					
						
							|  |  |  | 	register int i, j; | 
					
						
							|  |  |  | 	if (!getnoarg(args)) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	v = newlistobject(mp->ma_used); | 
					
						
							|  |  |  | 	if (v == NULL) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	for (i = 0, j = 0; i < mp->ma_size; i++) { | 
					
						
							|  |  |  | 		if (mp->ma_table[i].me_value != NULL) { | 
					
						
							|  |  |  | 			object *value = mp->ma_table[i].me_value; | 
					
						
							|  |  |  | 			INCREF(value); | 
					
						
							|  |  |  | 			setlistitem(v, j, value); | 
					
						
							|  |  |  | 			j++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return v; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static object * | 
					
						
							|  |  |  | mapping_items(mp, args) | 
					
						
							|  |  |  | 	register mappingobject *mp; | 
					
						
							|  |  |  | 	object *args; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	register object *v; | 
					
						
							|  |  |  | 	register int i, j; | 
					
						
							|  |  |  | 	if (!getnoarg(args)) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	v = newlistobject(mp->ma_used); | 
					
						
							|  |  |  | 	if (v == NULL) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	for (i = 0, j = 0; i < mp->ma_size; i++) { | 
					
						
							|  |  |  | 		if (mp->ma_table[i].me_value != NULL) { | 
					
						
							|  |  |  | 			object *key = mp->ma_table[i].me_key; | 
					
						
							|  |  |  | 			object *value = mp->ma_table[i].me_value; | 
					
						
							|  |  |  | 			object *item = newtupleobject(2); | 
					
						
							|  |  |  | 			if (item == NULL) { | 
					
						
							|  |  |  | 				DECREF(v); | 
					
						
							|  |  |  | 				return NULL; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			INCREF(key); | 
					
						
							|  |  |  | 			settupleitem(item, 0, key); | 
					
						
							|  |  |  | 			INCREF(value); | 
					
						
							|  |  |  | 			settupleitem(item, 1, value); | 
					
						
							|  |  |  | 			setlistitem(v, j, item); | 
					
						
							|  |  |  | 			j++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return v; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-11-05 10:18:44 +00:00
										 |  |  | int | 
					
						
							|  |  |  | getmappingsize(mp) | 
					
						
							|  |  |  | 	object *mp; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (mp == NULL || !is_mappingobject(mp)) { | 
					
						
							|  |  |  | 		err_badcall(); | 
					
						
							| 
									
										
										
										
											1993-11-23 17:53:17 +00:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											1993-11-05 10:18:44 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return ((mappingobject *)mp)->ma_used; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | object * | 
					
						
							|  |  |  | getmappingkeys(mp) | 
					
						
							|  |  |  | 	object *mp; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (mp == NULL || !is_mappingobject(mp)) { | 
					
						
							|  |  |  | 		err_badcall(); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return mapping_keys((mappingobject *)mp, (object *)NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-05-19 14:50:45 +00:00
										 |  |  | object * | 
					
						
							|  |  |  | getmappingvalues(mp) | 
					
						
							|  |  |  | 	object *mp; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (mp == NULL || !is_mappingobject(mp)) { | 
					
						
							|  |  |  | 		err_badcall(); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return mapping_values((mappingobject *)mp, (object *)NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | object * | 
					
						
							|  |  |  | getmappingitems(mp) | 
					
						
							|  |  |  | 	object *mp; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (mp == NULL || !is_mappingobject(mp)) { | 
					
						
							|  |  |  | 		err_badcall(); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1994-08-30 08:27:36 +00:00
										 |  |  | 	return mapping_items((mappingobject *)mp, (object *)NULL); | 
					
						
							| 
									
										
										
										
											1993-05-19 14:50:45 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | static int | 
					
						
							|  |  |  | mapping_compare(a, b) | 
					
						
							|  |  |  | 	mappingobject *a, *b; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	object *akeys, *bkeys; | 
					
						
							|  |  |  | 	int i, n, res; | 
					
						
							|  |  |  | 	if (a == b) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	if (a->ma_used == 0) { | 
					
						
							|  |  |  | 		if (b->ma_used != 0) | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		if (b->ma_used == 0) | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	akeys = mapping_keys(a, (object *)NULL); | 
					
						
							|  |  |  | 	bkeys = mapping_keys(b, (object *)NULL); | 
					
						
							|  |  |  | 	if (akeys == NULL || bkeys == NULL) { | 
					
						
							|  |  |  | 		/* Oops, out of memory -- what to do? */ | 
					
						
							|  |  |  | 		/* For now, sort on address! */ | 
					
						
							|  |  |  | 		XDECREF(akeys); | 
					
						
							|  |  |  | 		XDECREF(bkeys); | 
					
						
							|  |  |  | 		if (a < b) | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	sortlist(akeys); | 
					
						
							|  |  |  | 	sortlist(bkeys); | 
					
						
							|  |  |  | 	n = a->ma_used < b->ma_used ? a->ma_used : b->ma_used; /* smallest */ | 
					
						
							|  |  |  | 	res = 0; | 
					
						
							|  |  |  | 	for (i = 0; i < n; i++) { | 
					
						
							|  |  |  | 		object *akey, *bkey, *aval, *bval; | 
					
						
							|  |  |  | 		long ahash, bhash; | 
					
						
							|  |  |  | 		akey = getlistitem(akeys, i); | 
					
						
							|  |  |  | 		bkey = getlistitem(bkeys, i); | 
					
						
							|  |  |  | 		res = cmpobject(akey, bkey); | 
					
						
							|  |  |  | 		if (res != 0) | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											1993-10-22 12:04:32 +00:00
										 |  |  | #ifdef CACHE_HASH
 | 
					
						
							|  |  |  | 		if (!is_stringobject(akey) || (ahash = ((stringobject *) akey)->ob_shash) == -1) | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 		ahash = hashobject(akey); | 
					
						
							|  |  |  | 		if (ahash == -1) | 
					
						
							|  |  |  | 			err_clear(); /* Don't want errors here */ | 
					
						
							| 
									
										
										
										
											1993-10-22 12:04:32 +00:00
										 |  |  | #ifdef CACHE_HASH
 | 
					
						
							|  |  |  | 		if (!is_stringobject(bkey) || (bhash = ((stringobject *) bkey)->ob_shash) == -1) | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 		bhash = hashobject(bkey); | 
					
						
							|  |  |  | 		if (bhash == -1) | 
					
						
							|  |  |  | 			err_clear(); /* Don't want errors here */ | 
					
						
							|  |  |  | 		aval = lookmapping(a, akey, ahash) -> me_value; | 
					
						
							|  |  |  | 		bval = lookmapping(b, bkey, bhash) -> me_value; | 
					
						
							|  |  |  | 		res = cmpobject(aval, bval); | 
					
						
							|  |  |  | 		if (res != 0) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (res == 0) { | 
					
						
							|  |  |  | 		if (a->ma_used < b->ma_used) | 
					
						
							|  |  |  | 			res = -1; | 
					
						
							|  |  |  | 		else if (a->ma_used > b->ma_used) | 
					
						
							|  |  |  | 			res = 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	DECREF(akeys); | 
					
						
							|  |  |  | 	DECREF(bkeys); | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static object * | 
					
						
							|  |  |  | mapping_has_key(mp, args) | 
					
						
							|  |  |  | 	register mappingobject *mp; | 
					
						
							|  |  |  | 	object *args; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	object *key; | 
					
						
							|  |  |  | 	long hash; | 
					
						
							|  |  |  | 	register long ok; | 
					
						
							|  |  |  | 	if (!getargs(args, "O", &key)) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											1993-10-22 12:04:32 +00:00
										 |  |  | #ifdef CACHE_HASH
 | 
					
						
							|  |  |  | 	if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1) | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	hash = hashobject(key); | 
					
						
							|  |  |  | 	if (hash == -1) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											1995-01-02 19:07:15 +00:00
										 |  |  | 	ok = mp->ma_size != 0 && lookmapping(mp, key, hash)->me_value != NULL; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	return newintobject(ok); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct methodlist mapp_methods[] = { | 
					
						
							| 
									
										
										
										
											1994-08-30 08:27:36 +00:00
										 |  |  | 	{"has_key",	(method)mapping_has_key}, | 
					
						
							|  |  |  | 	{"items",	(method)mapping_items}, | 
					
						
							|  |  |  | 	{"keys",	(method)mapping_keys}, | 
					
						
							|  |  |  | 	{"values",	(method)mapping_values}, | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	{NULL,		NULL}		/* sentinel */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static object * | 
					
						
							|  |  |  | mapping_getattr(mp, name) | 
					
						
							|  |  |  | 	mappingobject *mp; | 
					
						
							|  |  |  | 	char *name; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return findmethod(mapp_methods, (object *)mp, name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typeobject Mappingtype = { | 
					
						
							|  |  |  | 	OB_HEAD_INIT(&Typetype) | 
					
						
							|  |  |  | 	0, | 
					
						
							| 
									
										
										
										
											1993-03-29 10:43:31 +00:00
										 |  |  | 	"dictionary", | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	sizeof(mappingobject), | 
					
						
							|  |  |  | 	0, | 
					
						
							| 
									
										
										
										
											1994-08-30 08:27:36 +00:00
										 |  |  | 	(destructor)mapping_dealloc, /*tp_dealloc*/ | 
					
						
							|  |  |  | 	(printfunc)mapping_print, /*tp_print*/ | 
					
						
							|  |  |  | 	(getattrfunc)mapping_getattr, /*tp_getattr*/ | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	0,			/*tp_setattr*/ | 
					
						
							| 
									
										
										
										
											1994-08-30 08:27:36 +00:00
										 |  |  | 	(cmpfunc)mapping_compare, /*tp_compare*/ | 
					
						
							|  |  |  | 	(reprfunc)mapping_repr, /*tp_repr*/ | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	0,			/*tp_as_number*/ | 
					
						
							|  |  |  | 	0,			/*tp_as_sequence*/ | 
					
						
							|  |  |  | 	&mapping_as_mapping,	/*tp_as_mapping*/ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* For backward compatibility with old dictionary interface */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static object *last_name_object; | 
					
						
							| 
									
										
										
										
											1995-12-08 01:16:31 +00:00
										 |  |  | static char *last_name_char; /* NULL or == getstringvalue(last_name_object) */ | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | object * | 
					
						
							|  |  |  | getattro(v, name) | 
					
						
							|  |  |  | 	object *v; | 
					
						
							|  |  |  | 	object *name; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (name != last_name_object) { | 
					
						
							|  |  |  | 		XDECREF(last_name_object); | 
					
						
							|  |  |  | 		INCREF(name); | 
					
						
							|  |  |  | 		last_name_object = name; | 
					
						
							|  |  |  | 		last_name_char = getstringvalue(name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return getattr(v, last_name_char); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | setattro(v, name, value) | 
					
						
							|  |  |  | 	object *v; | 
					
						
							|  |  |  | 	object *name; | 
					
						
							|  |  |  | 	object *value; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (name != last_name_object) { | 
					
						
							|  |  |  | 		XDECREF(last_name_object); | 
					
						
							|  |  |  | 		INCREF(name); | 
					
						
							|  |  |  | 		last_name_object = name; | 
					
						
							|  |  |  | 		last_name_char = getstringvalue(name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return setattr(v, last_name_char, value); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | object * | 
					
						
							|  |  |  | dictlookup(v, key) | 
					
						
							|  |  |  | 	object *v; | 
					
						
							|  |  |  | 	char *key; | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											1995-12-08 01:16:31 +00:00
										 |  |  | 	if (key != last_name_char) { | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 		XDECREF(last_name_object); | 
					
						
							|  |  |  | 		last_name_object = newstringobject(key); | 
					
						
							|  |  |  | 		if (last_name_object == NULL) { | 
					
						
							|  |  |  | 			last_name_char = NULL; | 
					
						
							|  |  |  | 			return NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											1995-12-08 01:16:31 +00:00
										 |  |  | 		last_name_char = getstringvalue(last_name_object); | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return mappinglookup(v, last_name_object); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | dictinsert(v, key, item) | 
					
						
							|  |  |  | 	object *v; | 
					
						
							|  |  |  | 	char *key; | 
					
						
							|  |  |  | 	object *item; | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											1995-12-08 01:16:31 +00:00
										 |  |  | 	if (key != last_name_char) { | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 		XDECREF(last_name_object); | 
					
						
							|  |  |  | 		last_name_object = newstringobject(key); | 
					
						
							|  |  |  | 		if (last_name_object == NULL) { | 
					
						
							|  |  |  | 			last_name_char = NULL; | 
					
						
							| 
									
										
										
										
											1993-07-29 08:25:09 +00:00
										 |  |  | 			return -1; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											1995-12-08 01:16:31 +00:00
										 |  |  | 		last_name_char = getstringvalue(last_name_object); | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return mappinginsert(v, last_name_object, item); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | dictremove(v, key) | 
					
						
							|  |  |  | 	object *v; | 
					
						
							|  |  |  | 	char *key; | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											1995-12-08 01:16:31 +00:00
										 |  |  | 	if (key != last_name_char) { | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 		XDECREF(last_name_object); | 
					
						
							|  |  |  | 		last_name_object = newstringobject(key); | 
					
						
							|  |  |  | 		if (last_name_object == NULL) { | 
					
						
							|  |  |  | 			last_name_char = NULL; | 
					
						
							| 
									
										
										
										
											1993-07-29 08:25:09 +00:00
										 |  |  | 			return -1; | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											1995-12-08 01:16:31 +00:00
										 |  |  | 		last_name_char = getstringvalue(last_name_object); | 
					
						
							| 
									
										
										
										
											1993-03-27 18:11:32 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return mappingremove(v, last_name_object); | 
					
						
							|  |  |  | } |