/* A collecting of various string hashing functions. */

int hash_string(text, len)
     char* text;
     int len;
{
    return StrHash((unsigned char*)text, len);
}

/* By Per Bothner. originally written for assembler. */

StrHash(s, n) unsigned char *s; int n;
{
    register unsigned short caseHash;	/* hash, including case */
    register unsigned short foldHash;	/* hash, ignoring case */
    unsigned char c0; register unsigned short c2;
    if (n <= 0) return 0;
    caseHash = 0; foldHash = 0;
    for (n -= 1; n > 0; n -= 2)
      {
	c0 = *s++; c2 = (c0 << 8) | *s++;
	caseHash ^= c2;
	c2 &= 0xDFDF;
	foldHash ^= c2;
	foldHash = (foldHash << 3) | (foldHash >> (16-3)); /* rotate left 3 */
      }
    if (n >= 0) {
	c2 = (*s++ << 8);
	caseHash ^= c2;
	c2 &= 0xDFDF;
	foldHash ^= c2;
	foldHash = (foldHash << 3) | (foldHash >> (16-3)); /* rotate left 3 */
      }
    foldHash ^= (foldHash << (16-7))| (foldHash >> 7); /* rotate right 7 */
    caseHash &= 0x2020;
    foldHash ^= (caseHash >>= 5) & 0xFF;
    foldHash ^= (caseHash >>= 7);
    return foldHash;
}

#if 0
/* Produce a 16-bit hash of the string s, of length n
 * s must be zero-terminated (if n is odd).
 */
#ifdef MC68000
asm("	.text");
asm("	.globl wHash");
asm("wHash:");
/* Input:
 *	arg1:	Pointer to word-aligned string
 *	arg2:	Length in words of arg1
 * Result: (d0)	A 16-bit hash value, where only the low-order 2bits are
 *	influenced by case, assuming arg1 is an Ascii string.
 * Registers used (d2 and d3 are restored):
 *	d1	count of remaining words
 *	d3	current pair of characters
 *	d2	hash, including case
 *	d0	hash, ignoring case
 */
asm("	moveq	#0,d0");	/* Clear hash */
asm("	movl	sp@(4),a0");	/* Get arg1 in a0 */
asm("	movl	sp@(8),d1");	/* Get arg2 (count) in d1 */
asm("	beq	ret");		/* Return if count=0 */
asm("	subqw	#1,d1");	/* Pre-decrement count, so dbf works */
asm("	movw	d2,sp@-");	/* Save d2 */
asm("	movw	d3,sp@-");	/* - and d3 on stack */
asm("	clrw	d2");		/* Clear d2 */
asm("loop:");			/* Do: */
asm("	movw	a0@+,d3");	/*  - Get next word */
asm("	eorw	d3,d2");	/*  - d2 becomes xor of all the words */
asm("	andw	#0xDFDF,d3");	/*  - Mask out lower-case-bit */
asm("	eorw	d3,d0");	/*  - Xor */
asm("	rolw	#3,d0");	/*  - rotate; d0 becomes hash of masked words */
asm("	dbf	d1,loop");	/* repeat until count exhausted */
asm("	movw	d0,d1");	/* Mix the bits around a bit in d0 */
asm("	rorw	#7,d1");
asm("	eorw	d1,d0");
asm("	andw	#0x2020,d2");	/* Only want case-bit */
asm("	lsrw	#5,d2");	/* Get case bit of right charcter */
asm("	eorb	d2,d0");	/* - and xor it to rightmost bit of result */
asm("	lsrw	#7,d2");	/* Get case bit of left character */
asm("	eorb	d2,d0");	/* - and xor it to next-to-rightmost bit */
asm("	movw	sp@+,d3");	/* Restore d3 */
asm("	movw	sp@+,d2");	/* - and d2 from stack */
asm("ret:");
asm("	rts");			/* Return with result in d0 */

asm("	.globl	NullFunc"); /* should be gotten rid of */
asm("NullFunc:");
asm("	rts");
asm("	.data");
#else
wHash(str, len)
    register unsigned short *str;
    register int len; /* in shorts */
{   register hash = 0;
    register unsigned short tmp, all_xor = 0;
    if (len <= 0) return;
    do {
	all_xor ^= tmp = *str++;
	hash = (hash << 3) ^ (tmp & 0xDFDF);
    } while (--len > 0);
    all_xor >>= 5;
    all_xor &= 0x0101;
    all_xor |= all_xor >> 8;
    return hash ^ (all_xor & 0x3);
}
#endif MC68000
#endif

#if 0
/* From libg++/src/hash.cc */
unsigned int hashpjw(const char* x) /* From Dragon book, p436 */
{
  unsigned int h = 0;
  unsigned int g;

  while (*x != 0)
  {
    h = (h << 4) + *x++;
    if ((g = h & 0xf0000000) != 0)
      h = (h ^ (g >> 24)) ^ g;
  }
  return h;
}

/* From GNU ld */
/* Compute the hash code for symbol name KEY.  */

int
hash_string (key)
     char *key;
{
  register char *cp;
  register int k;

  cp = key;
  k = 0;
  while (*cp)
    k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;

  return k;
}

/* From gcc: get_identifier() in tree.c */
#define HASHBITS 30
hash_string(text, len)
     char*text;
     int len;
{
  /* Compute hash code */
  int hi = hash_len;
  for (i = 0; i < hash_len; i++)
    hi = ((hi * 613) + (unsigned)(text[i]));

  hi &= (1 << HASHBITS) - 1;
  return hi;
}

/* From akcl c/hash.d */
	case t_string:
		for (i = x->st.st_fillp, s = x->st.st_self;  i > 0;  --i, s++)
			h += (*s & 0377)*12345 + 1;
		return(h);
	case t_symbol:
		/* case t_string could share this code--wfs */
		{int len=x->st.st_fillp;
		 s=x->st.st_self;
		 switch(len) {
		 case 0: break;
		 default:
		 case 4: h+= s[--len] << 24;
		 case 3: h+= s[--len]<< 16;
		 case 2: h+= s[1] << 8;
		 case 1: h+= s[0] ;
		   
		   
		 }
		 return(h);
	       }

/* From akcl c/package.d */
/*
	Pack_hash(st) hashes string st
	and returns the index for a hash table of a package.
*/

int
pack_hash(x)
object x;
{unsigned int h=0;
 {int len=x->st.st_fillp;
  char *s;
#define HADD(i,j,k,l) (h+=s[i],h+=s[j]<<8,h+=s[k]<<13,h+=s[l]<<23)
#define HADD2(i,j) (h+=s[i]<<5,h+=s[j]<<15)
  s=x->st.st_self;
  switch(len) {
  case 0: break;
  case 10: 
  case 9: HADD(1,4,6,8); HADD2(5,7); goto END;
  case 8: HADD(1,3,5,7); HADD2(2,4); goto END;
  case 7: HADD(1,3,4,5); HADD2(6,2); goto END;
  case 6: HADD(1,3,4,5); HADD2(0,2); goto END;
  case 5: h+= s[4] << 13;
  case 4: h+= s[3] << 24;
  case 3: h+= s[2]<< 16;
  case 2: h+= s[1] << 8;
  case 1: h+= s[0] ;
    break;
  default:
    HADD(3,6,len-2,len-4); HADD2(1,len-1);
    if (len > 15) {HADD2(7,10);		   
		 }
  }
 END:
  h &= 0x7fffffff; 
  return(h);
}}

/* From kcl c/package.d */
#define	HASHCOEF	12345		/*  hashing coefficient  */
int
pack_hash(st)
object st;
{
	int h, i;

	for (h = 0, i = 0;  i < st->st.st_fillp;  i++)
		h += (st->st.st_self[i] & 0377) * HASHCOEF + 1;
	h &= 0x7fffffff;
	return(h %= PHTABSIZE);
}

/* From Scheme->C src/symbol.c */
/* Only looks at first 5 chars, + length */

Hash (str, len) char *str; {
    register h;
    register char *p, *ep;

    h = 5 * len;
    if (len > 5)
	len = 5;
    for (p = str, ep = p+len; p < ep; ++p)
	h = (h << 2) ^ *p;
    return h & 017777777777;
}


/* Peter Pearson, CACM 33(16)p.677- June 1990 */
unsigned char Hash0 (unsigned char *str, int len, unsigned char extra)
{
    static unsigned char[256] = { some permutation of 0..255 };
    int i;
    int h = T[str[0] + extra];
    for (i = 1; i < len; i++)
	h = T[h ^ str[i]];
    return h;    
}

/* 1-byte hash code */
unsigned char Hash1 (unsigned char *str, int len)
{
    return Hash0(str, len, 0);
}

/* 2-byte hash code */
unsigned short Hash2 (unsigned char *str, int len)
{
    union {
	unsigned char c[2];
	unsigned short s;
    } u;
    u.c[0] = Hash0(str, len, 0);
    u.c[1] = Hash0(str, len, 1);
    return u.s;
}
#endif
