qse/ase/stx/dict.c

191 lines
5.3 KiB
C
Raw Normal View History

2005-07-18 11:53:01 +00:00
/*
2007-03-22 11:19:28 +00:00
* $Id: dict.c,v 1.11 2007-03-22 11:19:28 bacon Exp $
2005-07-18 11:53:01 +00:00
*/
2007-03-22 11:19:28 +00:00
#include <ase/stx/dict.h>
#include <ase/stx/object.h>
#include <ase/stx/misc.h>
2005-07-18 11:53:01 +00:00
2005-08-11 10:18:35 +00:00
/* NOTE:
* The code here implements SystemDictionary whose key is always a symbol.
* Dictionary, on the contrary, can accept any object as a key.
*/
2007-03-22 11:19:28 +00:00
ase_word_t __new_association (
ase_stx_t* stx, ase_word_t key, ase_word_t value)
2005-07-18 11:53:01 +00:00
{
2007-03-22 11:19:28 +00:00
ase_word_t x;
2005-07-19 15:00:09 +00:00
#ifdef __GNUC__
2007-03-22 11:19:28 +00:00
ase_word_t data[2] = { key, value };
2005-07-19 15:00:09 +00:00
#else
2007-03-22 11:19:28 +00:00
ase_word_t data[2];
2005-07-19 15:00:09 +00:00
data[0] = key;
data[1] = value;
#endif
2007-03-22 11:19:28 +00:00
x = ase_stx_alloc_word_object (
stx, data, ASE_STX_ASSOCIATION_SIZE, ASE_NULL, 0);
ASE_STX_CLASS(stx,x) = stx->class_association;
2005-07-18 11:53:01 +00:00
return x;
}
2007-03-22 11:19:28 +00:00
static ase_word_t __dict_find_slot (
ase_stx_t* stx, ase_word_t dict, ase_word_t key)
2005-07-18 11:53:01 +00:00
{
2007-03-22 11:19:28 +00:00
ase_word_t size, hash, index, assoc, symbol;
ase_stx_word_object_t* dict_obj;
2005-07-18 11:53:01 +00:00
2007-03-22 11:19:28 +00:00
ase_assert (!ASE_STX_IS_SMALLINT(dict) &&
ASE_STX_IS_WORD_OBJECT(stx, dict));
ase_assert (dict == stx->smalltalk ||
ase_stx_classof(stx,dict) == stx->class_system_dictionary);
ase_assert (ase_stx_classof(stx,key) == stx->class_symbol);
2005-07-18 11:53:01 +00:00
2007-03-22 11:19:28 +00:00
size = ASE_STX_SIZE(stx,dict);
hash = ase_stx_hash_object(stx, key);
2005-07-18 11:53:01 +00:00
2005-07-19 12:08:04 +00:00
/* consider tally, the only instance variable of a system dictionary */
index = hash % (size - 1) + 1;
2005-07-18 11:53:01 +00:00
2007-03-22 11:19:28 +00:00
dict_obj = ASE_STX_WORD_OBJECT(stx,dict);
2005-07-19 12:08:04 +00:00
while (1) {
assoc = dict_obj->data[index];
if (assoc == stx->nil) break;
2007-03-22 11:19:28 +00:00
symbol = ASE_STX_WORD_AT(stx,assoc,ASE_STX_ASSOCIATION_KEY);
ase_assert (ase_stx_classof(stx,symbol) == stx->class_symbol);
2005-07-19 12:08:04 +00:00
2005-08-11 10:11:26 +00:00
/* NOTE:
2005-07-19 12:08:04 +00:00
* shallow comparison is enough for identity check
2005-08-11 10:18:35 +00:00
* because a symbol can just be a key of a system dictionary
2005-07-19 12:08:04 +00:00
*/
2007-03-22 11:19:28 +00:00
if (ase_strxncmp(
ASE_STX_DATA(stx,key), ASE_STX_SIZE(stx,key),
ASE_STX_DATA(stx,symbol), ASE_STX_SIZE(stx,symbol)) == 0) break;
2005-07-19 12:08:04 +00:00
/* consider tally here too */
index = index % (size - 1) + 1;
2005-07-18 11:53:01 +00:00
}
2005-07-19 12:08:04 +00:00
return index;
2005-07-18 11:53:01 +00:00
}
2007-03-22 11:19:28 +00:00
static void __grow_dict (ase_stx_t* stx, ase_word_t dict)
2005-07-18 11:53:01 +00:00
{
2007-03-22 11:19:28 +00:00
ase_word_t new, size, index, assoc;
2005-07-19 12:08:04 +00:00
2005-08-11 10:11:26 +00:00
/* WARNING:
2005-07-19 12:08:04 +00:00
* if this assertion fails, adjust the initial size of the
* system dictionary. i don't want this function to be called
* during the bootstrapping.
*/
2007-03-22 11:19:28 +00:00
ase_assert (stx->class_system_dictionary != stx->nil);
ase_assert (ase_stx_classof(stx,dict) == stx->class_system_dictionary);
2005-07-19 12:08:04 +00:00
2007-03-22 11:19:28 +00:00
size = ASE_STX_SIZE(stx,dict);
new = ase_stx_instantiate (stx,
ASE_STX_CLASS(stx,dict), ASE_NULL, ASE_NULL, (size - 1) * 2);
ASE_STX_WORD_AT(stx,new,0) = ASE_STX_TO_SMALLINT(0);
2005-07-19 12:08:04 +00:00
for (index = 1; index < size; index++) {
2007-03-22 11:19:28 +00:00
assoc = ASE_STX_WORD_AT(stx,dict,index);
2005-07-19 12:08:04 +00:00
if (assoc == stx->nil) continue;
2007-03-22 11:19:28 +00:00
ase_stx_dict_put (stx, new,
ASE_STX_WORD_AT(stx,assoc,ASE_STX_ASSOCIATION_KEY),
ASE_STX_WORD_AT(stx,assoc,ASE_STX_ASSOCIATION_VALUE));
2005-07-19 12:08:04 +00:00
}
2005-08-11 10:11:26 +00:00
/* TODO: explore if dict can be immediately destroyed. */
2007-03-22 11:19:28 +00:00
ase_assert (ase_sizeof(ase_stx_object_t*) == ase_sizeof(ase_uint_t));
ASE_SWAP (ASE_STX_OBJECT(stx,dict),
ASE_STX_OBJECT(stx,new),
ase_stx_object_t*, ase_uint_t);
2005-07-19 12:08:04 +00:00
}
2005-07-18 11:53:01 +00:00
2007-03-22 11:19:28 +00:00
ase_word_t ase_stx_dict_lookup (
ase_stx_t* stx, ase_word_t dict, const ase_char_t* key)
2005-07-19 12:08:04 +00:00
{
2007-03-22 11:19:28 +00:00
ase_word_t size, hash, index, assoc, symbol;
ase_stx_word_object_t* dict_obj;
2005-07-19 12:08:04 +00:00
2007-03-22 11:19:28 +00:00
ase_assert (!ASE_STX_IS_SMALLINT(dict) &&
ASE_STX_IS_WORD_OBJECT(stx, dict));
ase_assert (dict == stx->smalltalk ||
ase_stx_classof(stx,dict) == stx->class_system_dictionary);
2005-07-19 12:08:04 +00:00
2007-03-22 11:19:28 +00:00
size = ASE_STX_SIZE(stx,dict);
hash = ase_stx_hash(key, ase_strlen(key) * ase_sizeof(ase_char_t));
2005-07-19 12:08:04 +00:00
/* consider tally, the only instance variable of a system dictionary */
index = hash % (size - 1) + 1;
2007-03-22 11:19:28 +00:00
dict_obj = ASE_STX_WORD_OBJECT(stx,dict);
2005-07-19 12:08:04 +00:00
while (1) {
assoc = dict_obj->data[index];
if (assoc == stx->nil) break;
2007-03-22 11:19:28 +00:00
symbol = ASE_STX_WORD_AT(stx,assoc,ASE_STX_ASSOCIATION_KEY);
ase_assert (ase_stx_classof(stx,symbol) == stx->class_symbol);
2005-07-19 15:52:19 +00:00
2007-03-22 11:19:28 +00:00
if (ase_strxcmp (ASE_STX_DATA(stx,symbol),
ASE_STX_SIZE(stx,symbol), key) == 0) break;
2005-07-19 12:08:04 +00:00
/* consider tally here too */
index = index % (size - 1) + 1;
2005-07-18 11:53:01 +00:00
}
2007-03-22 11:19:28 +00:00
return ASE_STX_WORD_AT(stx,dict,index);
2005-07-18 11:53:01 +00:00
}
2007-03-22 11:19:28 +00:00
ase_word_t ase_stx_dict_get (ase_stx_t* stx, ase_word_t dict, ase_word_t key)
2005-07-18 11:53:01 +00:00
{
2007-03-22 11:19:28 +00:00
return ASE_STX_WORD_AT(stx,dict,__dict_find_slot(stx, dict, key));
2005-07-19 12:08:04 +00:00
}
2005-07-18 11:53:01 +00:00
2007-03-22 11:19:28 +00:00
ase_word_t ase_stx_dict_put (
ase_stx_t* stx, ase_word_t dict, ase_word_t key, ase_word_t value)
2005-07-19 12:08:04 +00:00
{
2007-03-22 11:19:28 +00:00
ase_word_t slot, capa, tally, assoc;
2005-07-18 11:53:01 +00:00
2005-07-19 12:08:04 +00:00
/* the dictionary must have at least one slot excluding tally */
2007-03-22 11:19:28 +00:00
ase_assert (ASE_STX_SIZE(stx,dict) > 1);
2005-07-18 11:53:01 +00:00
2007-03-22 11:19:28 +00:00
capa = ASE_STX_SIZE(stx,dict) - 1;
tally = ASE_STX_FROM_SMALLINT(ASE_STX_WORD_AT(stx,dict,0));
2005-07-19 12:08:04 +00:00
if (capa <= tally + 1) {
2005-08-11 09:57:54 +00:00
__grow_dict (stx, dict);
2005-07-19 12:08:04 +00:00
/* refresh tally */
2007-03-22 11:19:28 +00:00
tally = ASE_STX_FROM_SMALLINT(ASE_STX_WORD_AT(stx,dict,0));
2005-07-18 11:53:01 +00:00
}
2005-07-19 12:08:04 +00:00
slot = __dict_find_slot (stx, dict, key);
2007-03-22 11:19:28 +00:00
assoc = ASE_STX_WORD_AT(stx,dict,slot);
2005-07-19 12:08:04 +00:00
if (assoc == stx->nil) {
2007-03-22 11:19:28 +00:00
ASE_STX_WORD_AT(stx,dict,slot) =
2005-07-19 12:08:04 +00:00
__new_association (stx, key, value);
2007-03-22 11:19:28 +00:00
ASE_STX_WORD_AT(stx,dict,0) = ASE_STX_TO_SMALLINT(tally + 1);
2005-07-18 11:53:01 +00:00
}
2007-03-22 11:19:28 +00:00
else ASE_STX_WORD_AT(stx,assoc,ASE_STX_ASSOCIATION_VALUE) = value;
2005-07-19 12:08:04 +00:00
2007-03-22 11:19:28 +00:00
return ASE_STX_WORD_AT(stx,dict,slot);
2005-07-18 11:53:01 +00:00
}
2007-03-22 11:19:28 +00:00
void ase_stx_dict_traverse (
ase_stx_t* stx, ase_word_t dict,
void (*func) (ase_stx_t*,ase_word_t,void*), void* data)
2005-07-18 11:53:01 +00:00
{
2007-03-22 11:19:28 +00:00
ase_word_t index, assoc;
ase_word_t size = ASE_STX_SIZE(stx,dict);
2005-07-18 11:53:01 +00:00
2005-07-19 12:08:04 +00:00
for (index = 1; index < size; index++) {
2007-03-22 11:19:28 +00:00
assoc = ASE_STX_WORD_AT(stx,dict,index);
2005-07-19 12:08:04 +00:00
if (assoc == stx->nil) continue;
func (stx, assoc, data);
2005-07-18 11:53:01 +00:00
}
}