/*					*/
/*					*/
/*	Canonicalized String Conser	*/
/*					*/
/*					*/

#include "pclu_err.h"
#include "pclu_sys.h"

/* TABLE_SIZE should be  a power of 2: cf hashing */
#define TABLE_SIZE 128
typedef struct entry{
	struct entry*link;
	CLU_string data;
	} entry;
typedef struct entry *entryp;

static entryp clustr_table[TABLE_SIZE];
errcode stringOPcons(cstr, start, len, ans)
char *cstr;
CLUREF start, len, *ans;
{
static bool init = false;
int index;
entryp buck, new_entry;
bool found;
int i;
errcode err;

	if (!init) {
		}
	/* Hash on cstr */
	if (len.num > 1) {
	        index = cstr[0];
        	index = index + (((int)cstr[1]) << 8);
	        index = index + (((int)cstr[len.num - 1]) << 16);
	        index = index + (((int)cstr[len.num - 2]) << 24);
	        index = index & (TABLE_SIZE - 1);
		}
	else {
		if (len.num == 1) {
		        index = cstr[0];
		        index = index & (TABLE_SIZE - 1);
			}
		else index = 0;
		}

	/* Use index to select bucket */
	buck = clustr_table[index];

	/* Check entries in bucket */
	for (;; buck = buck->link) {
		if (buck == (entryp)NULL) break;
		if (len.num != buck->data.size) continue;
		found = true;
		for (i = 0; i < len.num ; i++) {
			if (buck->data.data[i] != cstr[start.num + i - 1]) {
				found = false;
				break;
				}
			}
		/* Found: return addr of clustr */
		if (found) {
			ans->str = &buck->data;
			signal(ERR_ok);
			}
		}
	/* Not found: cons entry & return addr of clustr */
	clu_alloc(sizeof(struct entry) - 1
				+ ((len.num+1+3)/4)*4, &new_entry);
	new_entry->link = clustr_table[index];
	clustr_table[index] = new_entry;
	new_entry->data.size = len.num;
	new_entry->data.typ.val = CT_STRING;
	new_entry->data.typ.mark = 0;
	new_entry->data.typ.refp = 0;
	for (i = 0; i < len.num ; i++) {
		new_entry->data.data[i] = cstr[start.num + i - 1];
		}
	new_entry->data.data[i] = '\000';
	ans->str = &new_entry->data;
	signal(ERR_ok);
	}
