/*					*/
/*					*/
/*	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;
	CLUREF 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;
CLUREF new_string;
errcode err;

	if (!init) {
		}
	/* Hash on cstr */
	if (len.num > 1) {
	        index = cstr[0];
        	index = index + cstr[1] << 8;
	        index = index + cstr[len.num - 1] << 16;
	        index = index + 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.str->size) continue;
		found = true;
		for (i = 0; i < len.num ; i++) {
			if (buck->data.str->data[i] != cstr[start.num + i - 1]) {
				found = false;
				break;
				}
			}
		/* Found: return addr of clustr */
		if (found) {
			ans->str = buck->data.str;
			signal(ERR_ok);
			}
		}
	/* Not found: cons entry & return addr of clustr */
	clu_alloc(sizeof(struct entry), &new_entry);
	clu_alloc_atomic(sizeof(CLU_string) - 1
				+ ((len.num+1+3)/4)*4, &new_string);
	new_entry->link = buck;
	clustr_table[index] = new_entry;
	new_entry->data.str = new_string.str;
	new_string.str->size = len.num;
	new_string.str->typ.val = CT_STRING;
	new_string.str->typ.mark = 0;
	new_string.str->typ.refp = 0;
	for (i = 0; i < len.num ; i++) {
		new_string.str->data[i] = cstr[start.num + i - 1];
		}
	new_string.str->data[i] = '\000';
	ans->str = new_entry->data.str;
	signal(ERR_ok);
	}
