313 lines (275 with data), 6.4 kB
/*
* Parsing bag object.
*
* A bag is a 1 to many mapping of key to data.
*
* setup(string savefile,int primesize, int start_new)
* add(key, data) -
* query(key) -
* remove(key) -
*
* save_me () - usually called by save server
* show_stats () - returns the hash array (Just stat the object)
* dump_hash () - returns a pointer to the hash array,NOT a copy!
*
* 20000507 Dredd Modified /RO/lib/dictionary
*/
inherit "RO/Servers";
inherit "RO/parse/parse_types";
import "RO/lib/dict_class" chash;
/* Key hash table vars */
class chash hash_table[0];
int hash_size;
static string save_file = 0;
/* Some accounting vars */
int no_items;
int no_neg_query;
int no_pos_query;
/*
* Function : setup_hash (string file, int size, int start_new)
*
* Must be called first when you wish to use this object
* file: file name of where the data is to be stored.
* If you arnt going to save your data, file = 0
* size: needs to be used only once, when the hash table is set up.
* should dynamically resize on day. (not supported initially)
* start_new: if you are going to set up a new hash data store.
*
* Returns 1 for success
*
*/
int setup((string|int) file, int size, int start_new)
{
save_file = file;
if (start_new)
{
if (file && (file_size (file + ".o") >= 0
|| file_size (file + ".o.bak") >= 0 ))
{
throw("For safeties sake I dont want to overwrite the " +
"old data file. Please make sure there is not a file named " +
file + ".\n");
return 0;
}
// already initialised.
if (hash_size != 0) return 0;
hash_size = size;
hash_table = allocate(size);
no_items = 0;
return 1;
}
else if (!restore_object(file,this_object()))
{
throw("Could not restore from save file.\n");
return 0;
}
if (size && size != hash_size)
{
/* Opps, dont match. add code for dynamic resizeing here! */
throw("We dont currently support dynamic hash resizeing in the hash obj.\n");
return 0;
}
return 1;
}
/*
* Name: add(key, data)
* Returns:
*/
int add(key, data)
{
array tmp;
class chash incoming = create chash;
class chash node;
int hashpos;
int x, dataoff;
if (!hash_size)
{
throw("The bag has not been initialised yet.\n");
return 0;
}
incoming.key = key;
incoming.data = [ data ];
hashpos = hash_value(key) % hash_size;
tmp = hash_table[hashpos];
if (!tmp || sizeof(tmp) == 0)
{
hash_table[hashpos] = [ incoming ];
}
else
{
/* check through existing nodes */
for (x = 0; x < sizeof(tmp); x++)
{
node = tmp[x];
if (node.key == key)
{
node.data = node.data + [ data ];
dataoff = 1;
break;
}
}
/* doesn't exist so we add another */
if (!dataoff)
{
hash_table[hashpos] = tmp + [ incoming ];
}
}
if (save_file) AUTOSAVE_SERV->set_auto_save(this_object());
return 1;
}
/*
* Name: query(key)
*
* Returns whatever was in the hash table, or 0 if nothing was there.
* last is a pointer to whatever data you searched for at hash_postition
* before and it returned another bit of data. This is a result
* of using a hash table and linked lists.
*
*/
query(key)
{
int pos, found = 0;
int x;
array nodel;
class chash node;
if (!hash_size)
{
throw("The bag has not been initialised yet.\n");
return 0;
}
pos = hash_value(key) % hash_size;
nodel = hash_table[pos];
if (nodel)
{
for (x = 0; x < sizeof(nodel); x++)
{
node = nodel[x];
if (node.key == key) return node.data;
}
}
return 0;
}
/*
* Function : remove_hash(key, data)
* Removes the data at the key position
*
*/
remove(key, data)
{
int pos, found = 0;
int x, i;
array nodel, bag;
class chash node;
pos = hash_value(key) % hash_size;
nodel = hash_table[pos];
if (nodel)
{
for (x = 0; x < sizeof(nodel); x++)
{
node = nodel[x];
if (node.key == key)
{
bag = node.data;
for (i = 0; i < sizeof(bag); i++)
{
if (bag[i] == data)
{
node.data = bag[..i-1] + bag[i+1..];
break;
}
}
AUTOSAVE_SERV->set_auto_save(this_object());
return 1;
}
}
}
return 0;
}
erase(key)
{
int pos, found = 0;
int x, i;
array nodel, bag;
class chash node;
pos = hash_value(key) % hash_size;
nodel = hash_table[pos];
if (nodel)
{
for (x = 0; x < sizeof(nodel); x++)
{
node = nodel[x];
if (node.key == key)
{
hash_table[pos] = hash_table[pos][..x-1] + hash_table[pos][x+1..];
AUTOSAVE_SERV->set_auto_save(this_object());
return 1;
}
}
}
return 0;
}
/*
* Print out the data in some readable form
*/
out_data(x)
{
int k;
string od = "";
if (arrayp(x))
{
od = od + "[";
for (k = 0; k < sizeof(x); k++)
{
od = od + " " + out_data(x[k]);
}
od = od + "]";
return od;
}
else if (objectp(x))
{
return file_name(x);
}
else
{
return x;
}
}
/*
* Standard "show_stats" function
*/
show_stats()
{
int i, j, k;
array nodel;
class chash node;
for (i=0; i<hash_size; i++)
{
nodel = hash_table[i];
if (nodel) for (j = 0; j < sizeof(nodel); j++)
{
node = nodel[j];
if (stringp(node.key))
{
write("num("+i+","+j+"): "+(node.key)+ " = ");
write(out_data(node.data) + "\n");
}
}
}
write("Save file is : " + save_file + ".\n");
write("No items in table : "+ no_items +"\n");
write("+ve queries / Total : "+ no_pos_query + "/" + (no_pos_query+
no_neg_query) + "\n");
}
query_no_items() { return no_items; }
save_me ()
{
save_object(save_file,this_object());
return 1;
}
dump_hash()
{
return hash_table;
}
reset()
{
}