| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * $Id$ | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-02-07 14:13:13 +00:00
										 |  |  |     Copyright (c) 2016-2018 Chung, Hyung-Hwan. All rights reserved. | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |     modification, are permitted provided that the following conditions | 
					
						
							|  |  |  |     are met: | 
					
						
							|  |  |  |     1. Redistributions of source code must retain the above copyright | 
					
						
							|  |  |  |        notice, this list of conditions and the following disclaimer. | 
					
						
							|  |  |  |     2. Redistributions in binary form must reproduce the above copyright | 
					
						
							|  |  |  |        notice, this list of conditions and the following disclaimer in the | 
					
						
							|  |  |  |        documentation and/or other materials provided with the distribution. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR | 
					
						
							|  |  |  |     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 
					
						
							|  |  |  |     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 
					
						
							|  |  |  |     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 
					
						
							|  |  |  |     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 
					
						
							|  |  |  |     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
					
						
							|  |  |  |     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
					
						
							|  |  |  |     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
					
						
							|  |  |  |     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 
					
						
							|  |  |  |     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "hcl-prv.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-08 03:41:17 +00:00
										 |  |  | /* The dictionary functions in this file are used for storing
 | 
					
						
							|  |  |  |  * a dictionary object enclosed in {}. So putting a non-symbol | 
					
						
							|  |  |  |  * key is allowed like { 1 2 3 4 } where 1 and 3 are keys. | 
					
						
							|  |  |  |  * so SYMBOL_ONLY_KEY must not be defined */ | 
					
						
							|  |  |  | /*#define SYMBOL_ONLY_KEY*/ | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | static hcl_oop_oop_t expand_bucket (hcl_t* hcl, hcl_oop_oop_t oldbuc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	hcl_oop_oop_t newbuc; | 
					
						
							|  |  |  | 	hcl_oow_t oldsz, newsz, index; | 
					
						
							|  |  |  | 	hcl_oop_cons_t ass; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	oldsz = HCL_OBJ_GET_SIZE(oldbuc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* TODO: better growth policy? */ | 
					
						
							|  |  |  | 	if (oldsz < 5000) newsz = oldsz + oldsz; | 
					
						
							|  |  |  | 	else if (oldsz < 50000) newsz = oldsz + (oldsz / 2); | 
					
						
							|  |  |  | 	else if (oldsz < 100000) newsz = oldsz + (oldsz / 4); | 
					
						
							|  |  |  | 	else if (oldsz < 200000) newsz = oldsz + (oldsz / 8); | 
					
						
							|  |  |  | 	else if (oldsz < 400000) newsz = oldsz + (oldsz / 16); | 
					
						
							|  |  |  | 	else if (oldsz < 800000) newsz = oldsz + (oldsz / 32); | 
					
						
							|  |  |  | 	else if (oldsz < 1600000) newsz = oldsz + (oldsz / 64); | 
					
						
							|  |  |  | 	else  | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		hcl_oow_t inc, inc_max; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		inc = oldsz / 128; | 
					
						
							|  |  |  | 		inc_max = HCL_OBJ_SIZE_MAX - oldsz; | 
					
						
							|  |  |  | 		if (inc > inc_max)  | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			if (inc_max > 0) inc = inc_max; | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-02-05 10:43:25 +00:00
										 |  |  | 				hcl_seterrnum (hcl, HCL_EOOMEM); | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 				return HCL_NULL; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		newsz = oldsz + inc; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-31 17:48:47 +00:00
										 |  |  | 	hcl_pushvolat (hcl, (hcl_oop_t*)&oldbuc); | 
					
						
							| 
									
										
										
										
											2018-02-22 07:41:03 +00:00
										 |  |  | 	newbuc = (hcl_oop_oop_t)hcl_makearray (hcl, newsz, 0);  | 
					
						
							| 
									
										
										
										
											2020-12-31 17:48:47 +00:00
										 |  |  | 	hcl_popvolat (hcl); | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 	if (!newbuc) return HCL_NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (oldsz > 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		ass = (hcl_oop_cons_t)oldbuc->slot[--oldsz]; | 
					
						
							|  |  |  | 		if ((hcl_oop_t)ass != hcl->_nil) | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | 		#if defined(SYMBOL_ONLY_KEY)
 | 
					
						
							| 
									
										
										
										
											2018-08-02 17:09:32 +00:00
										 |  |  | 			hcl_oop_char_t key; | 
					
						
							| 
									
										
										
										
											2018-02-07 07:35:30 +00:00
										 |  |  | 			HCL_ASSERT (hcl, HCL_IS_CONS(hcl,ass)); | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 			key = (hcl_oop_char_t)ass->car; | 
					
						
							| 
									
										
										
										
											2018-02-07 07:35:30 +00:00
										 |  |  | 			HCL_ASSERT (hcl, HCL_IS_SYMBOL(hcl,key)); | 
					
						
							| 
									
										
										
										
											2019-03-06 01:50:46 +00:00
										 |  |  | 			index = hcl_hash_oochars(key->slot, HCL_OBJ_GET_SIZE(key)) % newsz; | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | 		#else
 | 
					
						
							|  |  |  | 			int n; | 
					
						
							|  |  |  | 			HCL_ASSERT (hcl, HCL_IS_CONS(hcl,ass)); | 
					
						
							|  |  |  | 			n = hcl_hashobj(hcl, ass->car, &index); | 
					
						
							| 
									
										
										
										
											2018-08-02 17:09:32 +00:00
										 |  |  | 			HCL_ASSERT (hcl, n == 0); /* since it's expanding, the existing one in the bucket should always be hashable */ | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | 			index %= newsz; | 
					
						
							|  |  |  | 		#endif
 | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 			while (newbuc->slot[index] != hcl->_nil) index = (index + 1) % newsz; | 
					
						
							|  |  |  | 			newbuc->slot[index] = (hcl_oop_t)ass; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return newbuc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-08 14:18:30 +00:00
										 |  |  | static hcl_oop_cons_t find_or_upsert (hcl_t* hcl, hcl_oop_dic_t dic, hcl_oop_t key, hcl_oop_t value) | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	hcl_ooi_t tally; | 
					
						
							|  |  |  | 	hcl_oow_t index; | 
					
						
							|  |  |  | 	hcl_oop_cons_t ass; | 
					
						
							|  |  |  | 	hcl_oow_t tmp_count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* the system dictionary is not a generic dictionary.
 | 
					
						
							|  |  |  | 	 * it accepts only a symbol as a key. */ | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | #if defined(SYMBOL_ONLY_KEY)
 | 
					
						
							| 
									
										
										
										
											2018-02-05 10:43:25 +00:00
										 |  |  | 	HCL_ASSERT (hcl, HCL_IS_SYMBOL(hcl,key)); | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-02-05 10:43:25 +00:00
										 |  |  | 	HCL_ASSERT (hcl, HCL_OOP_IS_SMOOI(dic->tally)); | 
					
						
							|  |  |  | 	HCL_ASSERT (hcl, HCL_IS_ARRAY(hcl,dic->bucket)); | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | #if defined(SYMBOL_ONLY_KEY)
 | 
					
						
							| 
									
										
										
										
											2019-03-06 01:50:46 +00:00
										 |  |  | 	index = hcl_hash_oochars(HCL_OBJ_GET_CHAR_SLOT(key), HCL_OBJ_GET_SIZE(key)) % HCL_OBJ_GET_SIZE(dic->bucket); | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2018-03-08 14:18:30 +00:00
										 |  |  | 	if (hcl_hashobj(hcl, key, &index) <= -1) return HCL_NULL; | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | 	index %= HCL_OBJ_GET_SIZE(dic->bucket); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* find */ | 
					
						
							|  |  |  | 	while (dic->bucket->slot[index] != hcl->_nil)  | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | 	#if defined(SYMBOL_ONLY_KEY)
 | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 		ass = (hcl_oop_cons_t)dic->bucket->slot[index]; | 
					
						
							| 
									
										
										
										
											2018-02-07 07:35:30 +00:00
										 |  |  | 		HCL_ASSERT (hcl, HCL_IS_CONS(hcl,ass)); | 
					
						
							|  |  |  | 		HCL_ASSERT (hcl, HCL_IS_SYMBOL(hcl,ass->car)); | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (HCL_OBJ_GET_SIZE(key) == HCL_OBJ_GET_SIZE(ass->car) && | 
					
						
							| 
									
										
										
										
											2021-01-22 14:43:47 +00:00
										 |  |  | 		    hcl_equal_oochars(HCL_OBJ_GET_CHAR_SLOT(key), HCL_OBJ_GET_CHAR_SLOT(ass->car), HCL_OBJ_GET_SIZE(key)))  | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			/* the value of HCL_NULL indicates no insertion or update. */ | 
					
						
							|  |  |  | 			if (value) ass->cdr = value; /* update */ | 
					
						
							|  |  |  | 			return ass; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | 	#else
 | 
					
						
							|  |  |  | 		int n; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ass = (hcl_oop_cons_t)dic->bucket->slot[index]; | 
					
						
							|  |  |  | 		HCL_ASSERT (hcl, HCL_IS_CONS(hcl,ass)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-08 14:18:30 +00:00
										 |  |  | 		n = hcl_equalobjs(hcl, key, ass->car); | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | 		if (n <= -1) return HCL_NULL; | 
					
						
							|  |  |  | 		if (n >= 1) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			/* the value of HCL_NULL indicates no insertion or update. */ | 
					
						
							|  |  |  | 			if (value) ass->cdr = value; /* update */ | 
					
						
							|  |  |  | 			return ass; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	#endif
 | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		index = (index + 1) % HCL_OBJ_GET_SIZE(dic->bucket); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!value) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		/* when value is HCL_NULL, perform no insertion.
 | 
					
						
							|  |  |  | 		 * the value of HCL_NULL indicates no insertion or update. */ | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | 		hcl_seterrbfmt (hcl, HCL_ENOENT, "key not found - %O", key); | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 		return HCL_NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* the key is not found. insert it. */ | 
					
						
							| 
									
										
										
										
											2018-02-05 10:43:25 +00:00
										 |  |  | 	HCL_ASSERT (hcl, HCL_OOP_IS_SMOOI(dic->tally)); | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 	tally = HCL_OOP_TO_SMOOI(dic->tally); | 
					
						
							|  |  |  | 	if (tally >= HCL_SMOOI_MAX) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		/* this built-in dictionary is not allowed to hold more than 
 | 
					
						
							|  |  |  | 		 * HCL_SMOOI_MAX items for efficiency sake */ | 
					
						
							| 
									
										
										
										
											2018-02-05 10:43:25 +00:00
										 |  |  | 		hcl_seterrnum (hcl, HCL_EDFULL); | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 		return HCL_NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-31 17:48:47 +00:00
										 |  |  | 	hcl_pushvolat (hcl, (hcl_oop_t*)&dic); tmp_count++; | 
					
						
							|  |  |  | 	hcl_pushvolat (hcl, (hcl_oop_t*)&key); tmp_count++; | 
					
						
							|  |  |  | 	hcl_pushvolat (hcl, &value); tmp_count++; | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* no conversion to hcl_oow_t is necessary for tally + 1.
 | 
					
						
							|  |  |  | 	 * the maximum value of tally is checked to be HCL_SMOOI_MAX - 1. | 
					
						
							|  |  |  | 	 * tally + 1 can produce at most HCL_SMOOI_MAX. above all,  | 
					
						
							|  |  |  | 	 * HCL_SMOOI_MAX is way smaller than HCL_TYPE_MAX(hcl_ooi_t). */ | 
					
						
							|  |  |  | 	if (tally + 1 >= HCL_OBJ_GET_SIZE(dic->bucket)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		hcl_oop_oop_t bucket; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* TODO: make the growth policy configurable instead of growing
 | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | 		         it just before it gets full. The polcy can be grow it | 
					
						
							|  |  |  | 		         if it's 70% full */ | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* enlarge the bucket before it gets full to
 | 
					
						
							|  |  |  | 		 * make sure that it has at least one free slot left | 
					
						
							|  |  |  | 		 * after having added a new symbol. this is to help | 
					
						
							|  |  |  | 		 * traversal end at a _nil slot if no entry is found. */ | 
					
						
							|  |  |  | 		bucket = expand_bucket (hcl, dic->bucket); | 
					
						
							|  |  |  | 		if (!bucket) goto oops; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dic->bucket = bucket; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | 	#if defined(SYMBOL_ONLY_KEY)
 | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 		/* recalculate the index for the expanded bucket */ | 
					
						
							| 
									
										
										
										
											2019-03-06 01:50:46 +00:00
										 |  |  | 		index = hcl_hash_oochars(HCL_OBJ_GET_CHAR_SLOT(key), HCL_OBJ_GET_SIZE(key)) % HCL_OBJ_GET_SIZE(dic->bucket); | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | 	#else
 | 
					
						
							| 
									
										
										
										
											2018-03-08 14:18:30 +00:00
										 |  |  | 		hcl_hashobj(hcl, key, &index); /* this must succeed as i know 'key' is hashable */ | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | 		index %= HCL_OBJ_GET_SIZE(dic->bucket); | 
					
						
							|  |  |  | 	#endif
 | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		while (dic->bucket->slot[index] != hcl->_nil)  | 
					
						
							|  |  |  | 			index = (index + 1) % HCL_OBJ_GET_SIZE(dic->bucket); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* create a new assocation of a key and a value since 
 | 
					
						
							|  |  |  | 	 * the key isn't found in the root dictionary */ | 
					
						
							| 
									
										
										
										
											2018-03-08 14:18:30 +00:00
										 |  |  | 	ass = (hcl_oop_cons_t)hcl_makecons (hcl, (hcl_oop_t)key, value); | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 	if (!ass) goto oops; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* the current tally must be less than the maximum value. otherwise,
 | 
					
						
							|  |  |  | 	 * it overflows after increment below */ | 
					
						
							| 
									
										
										
										
											2018-02-05 10:43:25 +00:00
										 |  |  | 	HCL_ASSERT (hcl, tally < HCL_SMOOI_MAX); | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 	dic->tally = HCL_SMOOI_TO_OOP(tally + 1); | 
					
						
							|  |  |  | 	dic->bucket->slot[index] = (hcl_oop_t)ass; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-31 17:48:47 +00:00
										 |  |  | 	hcl_popvolats (hcl, tmp_count); | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 	return ass; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | oops: | 
					
						
							| 
									
										
										
										
											2020-12-31 17:48:47 +00:00
										 |  |  | 	hcl_popvolats (hcl, tmp_count); | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 	return HCL_NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-22 14:43:47 +00:00
										 |  |  | static hcl_oop_cons_t lookupdic_noseterr (hcl_t* hcl, hcl_oop_dic_t dic, const hcl_oocs_t* name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* this is special version of hcl_getatsysdic() that performs
 | 
					
						
							|  |  |  | 	 * lookup using a plain symbol specified */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hcl_oow_t index; | 
					
						
							|  |  |  | 	hcl_oop_cons_t ass; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HCL_ASSERT (hcl, HCL_OOP_IS_SMOOI(dic->tally)); | 
					
						
							|  |  |  | 	HCL_ASSERT (hcl, HCL_IS_ARRAY(hcl,dic->bucket)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	index = hcl_hash_oochars(name->ptr, name->len) % HCL_OBJ_GET_SIZE(dic->bucket); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while ((hcl_oop_t)(ass = (hcl_oop_cons_t)HCL_OBJ_GET_OOP_VAL(dic->bucket, index)) != hcl->_nil)  | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		HCL_ASSERT (hcl, HCL_IS_CONS(hcl,ass)); | 
					
						
							|  |  |  | 		if (HCL_IS_SYMBOL(hcl, ass->car)) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			if (name->len == HCL_OBJ_GET_SIZE(ass->car) && | 
					
						
							|  |  |  | 			    hcl_equal_oochars(name->ptr, HCL_OBJ_GET_CHAR_SLOT(ass->car), name->len))  | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				return ass; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		index = (index + 1) % HCL_OBJ_GET_SIZE(dic->bucket); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* when value is HCL_NULL, perform no insertion */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* hcl_seterrXXX() is not called here. the dictionary lookup is very frequent 
 | 
					
						
							|  |  |  | 	 * and so is lookup failure. for instance, hcl_findmethod() calls this over  | 
					
						
							|  |  |  | 	 * a class chain. there might be a failure at each class level. it's waste to | 
					
						
							|  |  |  | 	 * set the error information whenever the failure occurs. | 
					
						
							|  |  |  | 	 * the caller of this function must set the error information upon failure */ | 
					
						
							|  |  |  | 	return HCL_NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static HCL_INLINE hcl_oop_cons_t lookupdic (hcl_t* hcl, hcl_oop_dic_t dic, const hcl_oocs_t* name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	hcl_oop_cons_t ass = lookupdic_noseterr(hcl, dic, name); | 
					
						
							|  |  |  | 	if (!ass) hcl_seterrbfmt(hcl, HCL_ENOENT, "unable to find %.*js in a dictionary", name->len, name->ptr); | 
					
						
							|  |  |  | 	return ass; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | hcl_oop_cons_t hcl_putatsysdic (hcl_t* hcl, hcl_oop_t key, hcl_oop_t value) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | #if defined(SYMBOL_ONLY_KEY)
 | 
					
						
							| 
									
										
										
										
											2018-02-05 10:43:25 +00:00
										 |  |  | 	HCL_ASSERT (hcl, HCL_IS_SYMBOL(hcl,key)); | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-03-08 14:18:30 +00:00
										 |  |  | 	return find_or_upsert(hcl, hcl->sysdic, key, value); | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | hcl_oop_cons_t hcl_getatsysdic (hcl_t* hcl, hcl_oop_t key) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | #if defined(SYMBOL_ONLY_KEY)
 | 
					
						
							| 
									
										
										
										
											2018-02-05 10:43:25 +00:00
										 |  |  | 	HCL_ASSERT (hcl, HCL_IS_SYMBOL(hcl,key)); | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-03-08 14:18:30 +00:00
										 |  |  | 	return find_or_upsert(hcl, hcl->sysdic, key, HCL_NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-22 14:43:47 +00:00
										 |  |  | hcl_oop_cons_t hcl_lookupsysdicforsymbol_noseterr (hcl_t* hcl, const hcl_oocs_t* name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return lookupdic_noseterr(hcl, hcl->sysdic, name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | hcl_oop_cons_t hcl_lookupsysdicforsymbol (hcl_t* hcl, const hcl_oocs_t* name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return lookupdic(hcl, hcl->sysdic, name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-08 14:18:30 +00:00
										 |  |  | int hcl_zapatsysdic (hcl_t* hcl, hcl_oop_t key) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #if defined(SYMBOL_ONLY_KEY)
 | 
					
						
							|  |  |  | 	HCL_ASSERT (hcl, HCL_IS_SYMBOL(hcl,key)); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	return hcl_zapatdic(hcl, hcl->sysdic, key); | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | hcl_oop_cons_t hcl_putatdic (hcl_t* hcl, hcl_oop_dic_t dic, hcl_oop_t key, hcl_oop_t value) | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | #if defined(SYMBOL_ONLY_KEY)
 | 
					
						
							| 
									
										
										
										
											2018-02-07 07:35:30 +00:00
										 |  |  | 	HCL_ASSERT (hcl, HCL_IS_SYMBOL(hcl,key)); | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-03-08 14:18:30 +00:00
										 |  |  | 	return find_or_upsert(hcl, dic, key, value); | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | hcl_oop_cons_t hcl_getatdic (hcl_t* hcl, hcl_oop_dic_t dic, hcl_oop_t key) | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | #if defined(SYMBOL_ONLY_KEY)
 | 
					
						
							| 
									
										
										
										
											2018-02-07 07:35:30 +00:00
										 |  |  | 	HCL_ASSERT (hcl, HCL_IS_SYMBOL(hcl,key)); | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-03-08 14:18:30 +00:00
										 |  |  | 	return find_or_upsert(hcl, dic, key, HCL_NULL); | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-08 14:18:30 +00:00
										 |  |  | int hcl_zapatdic (hcl_t* hcl, hcl_oop_dic_t dic, hcl_oop_t key) | 
					
						
							| 
									
										
										
										
											2018-03-08 10:00:57 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	hcl_ooi_t tally; | 
					
						
							| 
									
										
										
										
											2018-03-08 14:18:30 +00:00
										 |  |  | 	hcl_oow_t index, bs, i, x, y, z; | 
					
						
							| 
									
										
										
										
											2018-03-08 10:00:57 +00:00
										 |  |  | 	hcl_oop_cons_t ass; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tally = HCL_OOP_TO_SMOOI(dic->tally); | 
					
						
							|  |  |  | 	bs = HCL_OBJ_GET_SIZE(dic->bucket); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* the system dictionary is not a generic dictionary.
 | 
					
						
							|  |  |  | 	 * it accepts only a symbol as a key. */ | 
					
						
							|  |  |  | #if defined(SYMBOL_ONLY_KEY)
 | 
					
						
							|  |  |  | 	HCL_ASSERT (hcl, HCL_IS_SYMBOL(hcl,key)); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	HCL_ASSERT (hcl, HCL_OOP_IS_SMOOI(dic->tally)); | 
					
						
							|  |  |  | 	HCL_ASSERT (hcl, HCL_IS_ARRAY(hcl,dic->bucket)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined(SYMBOL_ONLY_KEY)
 | 
					
						
							| 
									
										
										
										
											2019-03-06 01:50:46 +00:00
										 |  |  | 	index = hcl_hash_oochars(HCL_OBJ_GET_CHAR_SLOT(key), HCL_OBJ_GET_SIZE(key)) % bs; | 
					
						
							| 
									
										
										
										
											2018-03-08 10:00:57 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2018-03-08 14:18:30 +00:00
										 |  |  | 	if (hcl_hashobj(hcl, key, &index) <= -1) return -1; | 
					
						
							| 
									
										
										
										
											2018-03-08 10:00:57 +00:00
										 |  |  | 	index %= bs; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* find */ | 
					
						
							|  |  |  | 	while (dic->bucket->slot[index] != hcl->_nil)  | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	#if defined(SYMBOL_ONLY_KEY)
 | 
					
						
							|  |  |  | 		ass = (hcl_oop_cons_t)dic->bucket->slot[index]; | 
					
						
							|  |  |  | 		HCL_ASSERT (hcl, HCL_IS_CONS(hcl,ass)); | 
					
						
							|  |  |  | 		HCL_ASSERT (hcl, HCL_IS_SYMBOL(hcl,ass->car)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (HCL_OBJ_GET_SIZE(key) == HCL_OBJ_GET_SIZE(ass->car) && | 
					
						
							| 
									
										
										
										
											2018-04-07 15:54:16 +00:00
										 |  |  | 		    hcl_equal_oochars(HCL_OBJ_GET_CHAR_SLOT(key), HCL_OBJ_GET_CHAR_SLOT(ass->car), HCL_OBJ_GET_SIZE(key)))  | 
					
						
							| 
									
										
										
										
											2018-03-08 10:00:57 +00:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			/* the value of HCL_NULL indicates no insertion or update. */ | 
					
						
							|  |  |  | 			goto found; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	#else
 | 
					
						
							|  |  |  | 		int n; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ass = (hcl_oop_cons_t)dic->bucket->slot[index]; | 
					
						
							|  |  |  | 		HCL_ASSERT (hcl, HCL_IS_CONS(hcl,ass)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		n = hcl_equalobjs(hcl, (hcl_oop_t)key, ass->car); | 
					
						
							|  |  |  | 		if (n <= -1) return -1; | 
					
						
							|  |  |  | 		if (n >= 1) goto found; | 
					
						
							|  |  |  | 	#endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-08 14:18:30 +00:00
										 |  |  | 		index = (index + 1) % bs; | 
					
						
							| 
									
										
										
										
											2018-03-08 10:00:57 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hcl_seterrnum (hcl, HCL_ENOENT); | 
					
						
							|  |  |  | 	return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | found: | 
					
						
							|  |  |  | 	/* compact the cluster */ | 
					
						
							|  |  |  | 	for (i = 0, x = index, y = index; i < tally; i++) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		y = (y + 1) % bs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* done if the slot at the current index is empty */ | 
					
						
							|  |  |  | 		if (dic->bucket->slot[y] == hcl->_nil) break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ass = (hcl_oop_cons_t)dic->bucket->slot[y]; | 
					
						
							|  |  |  | 	#if defined(SYMBOL_ONLY_KEY)
 | 
					
						
							|  |  |  | 		/* get the natural hash index for the data in the slot at
 | 
					
						
							|  |  |  | 		 * the current hash index */ | 
					
						
							| 
									
										
										
										
											2019-03-06 01:50:46 +00:00
										 |  |  | 		z = hcl_hash_oochars(HCL_OBJ_GET_CHAR_SLOT(ass->car), HCL_OBJ_GET_SIZE(ass->car)) % bs; | 
					
						
							| 
									
										
										
										
											2018-03-08 10:00:57 +00:00
										 |  |  | 	#else
 | 
					
						
							|  |  |  | 		if (hcl_hashobj(hcl, ass->car, &z) <= -1) return -1; | 
					
						
							| 
									
										
										
										
											2018-03-08 14:18:30 +00:00
										 |  |  | 		z %= bs; | 
					
						
							| 
									
										
										
										
											2018-03-08 10:00:57 +00:00
										 |  |  | 	#endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* move an element if necesary */ | 
					
						
							|  |  |  | 		if ((y > x && (z <= x || z > y)) || | 
					
						
							|  |  |  | 		    (y < x && (z <= x && z > y))) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			dic->bucket->slot[x] = dic->bucket->slot[y]; | 
					
						
							|  |  |  | 			x = y; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dic->bucket->slot[x] = hcl->_nil; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tally--; | 
					
						
							|  |  |  | 	dic->tally = HCL_SMOOI_TO_OOP(tally); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | hcl_oop_t hcl_makedic (hcl_t* hcl, hcl_oow_t inisize) | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | 	hcl_oop_dic_t obj; | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-04 18:21:05 +00:00
										 |  |  | 	obj = (hcl_oop_dic_t)hcl_allocoopobj(hcl, HCL_BRAND_DIC, 2); | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | 	if (obj) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		hcl_oop_oop_t bucket; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		obj->tally = HCL_SMOOI_TO_OOP(0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-31 17:48:47 +00:00
										 |  |  | 		hcl_pushvolat (hcl, (hcl_oop_t*)&obj); | 
					
						
							| 
									
										
										
										
											2018-02-22 07:41:03 +00:00
										 |  |  | 		bucket = (hcl_oop_oop_t)hcl_makearray(hcl, inisize, 0); | 
					
						
							| 
									
										
										
										
											2020-12-31 17:48:47 +00:00
										 |  |  | 		hcl_popvolat (hcl); | 
					
						
							| 
									
										
										
										
											2018-02-07 10:55:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (!bucket) obj = HCL_NULL; | 
					
						
							|  |  |  | 		else obj->bucket = bucket; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return (hcl_oop_t)obj; | 
					
						
							| 
									
										
										
										
											2016-09-28 14:40:37 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-02-12 16:51:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | int hcl_walkdic (hcl_t* hcl, hcl_oop_dic_t dic, hcl_dic_walker_t walker, void* ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	hcl_oow_t i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-31 17:48:47 +00:00
										 |  |  | 	hcl_pushvolat (hcl, (hcl_oop_t*)&dic); | 
					
						
							| 
									
										
										
										
											2018-02-12 16:51:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < HCL_OBJ_GET_SIZE(dic->bucket); i++) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		hcl_oop_t tmp = dic->bucket->slot[i]; | 
					
						
							|  |  |  | 		if (HCL_IS_CONS(hcl, tmp) && walker(hcl, dic, (hcl_oop_cons_t)tmp, ctx) <= -1) return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-31 17:48:47 +00:00
										 |  |  | 	hcl_popvolat (hcl); | 
					
						
							| 
									
										
										
										
											2018-02-12 16:51:38 +00:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |