asm {
//************************************
SYS_HASH_STR::
// IN:	RSI=Addr of string
// OUT:	RAX
	XOR	RAX,RAX
	TEST	RSI,RSI
	JZ	@@15

	PUSH	RSI
	PUSH	RBX
	XOR	RBX,RBX
	JMP	@@10

@@05:	SHL1	RBX
	ADC	RBX,RAX
@@10:	LODSB
	TEST	AL,AL
	JNZ	@@05

	MOV	RAX,RBX
	SHR	RBX,16
	ADC	RAX,RBX
	POP	RBX
	POP	RSI

@@15:	RET
//************************************
SYS_HASH_SINGLE_TABLE_FIND1::
// IN:	RAX=HASHED STRING VAL
//	RSI=STR
//	RBX=TYPE MASK
//	RDI=TABLE
//	RCX=INSTANCE, NOT ZERO
// OUT: RAX=ENTRY OR ZERO NOT FOUND
//	RDX=POINTER TO POINTER TO ENTRY
//	RCX IF NOT FOUND ENOUGH, DECREMENTED BY NUM MATCHES
//	ZERO FLAG SET NOT FOUND
	MOV	RCX,1
SYS_HASH_SINGLE_TABLE_FIND::
	TEST	RCX,RCX
	JNZ	@@05
	XOR	RAX,RAX
	RET
@@05:	AND	RAX,U64 CHashTable.mask[RDI]
	MOV	RDX,U64 CHashTable.body[RDI]
	LEA	RDX,U64 [RDX+RAX*8]
@@10:	MOV	RAX,U64 [RDX]
	TEST	RAX,RAX
	JNZ	@@15
	RET

@@15:	TEST	U32 CHash.type[RAX],EBX
	JZ	@@30
	PUSH	RAX
	PUSH	RDI
	PUSH	RSI
	MOV	RDI,U64 CHash.str[RAX]
@@20:	LODSB
	CMP	U8 [RDI],AL
	JNE	@@25
	INC	RDI
	TEST	AL,AL
	JNZ	@@20
	POP	RSI
	POP	RDI
	POP	RAX
	LOOP	@@30
	INC	U32 CHash.use_count[RAX]
	TEST	RAX,RAX
	RET

@@25:	POP	RSI
	POP	RDI
	POP	RAX

@@30:	LEA	RDX,U64 CHash.next[RAX]
	JMP	@@10
//************************************
SYS_HASH_FIND1::
// IN:	RSI=STR
//	RBX=TYPE MASK
//	RDI=TABLE
//	RCX=INSTANCE NUM
// OUT: RAX=ENTRY OR ZERO NOT FOUND
//	ZERO FLAG SET NOT FOUND
	MOV	RCX,1
SYS_HASH_FIND::
	PUSH	RDI
	CALL	SYS_HASH_STR
	
@@05:	PUSH	RAX
	CALL	SYS_HASH_SINGLE_TABLE_FIND
	JNZ	@@15
	POP	RAX
@@10:	MOV	RDI,U64 CHashTable.next[RDI]
	TEST	RDI,RDI
	JNZ	@@05
	POP	RDI
	XOR	RAX,RAX
	RET

@@15:	ADD	RSP,8
	POP	RDI
	TEST	RAX,RAX
	RET
//************************************
SYS_HASH_BUCKET_FIND::
// IN:	RSI=STR
//	RDI=TABLE
// OUT: RAX=BUCKET
	PUSH	RDX
	CALL	SYS_HASH_STR
	AND	RAX,U64 CHashTable.mask[RDI]
	MOV	RDX,U64 CHashTable.body[RDI]
	LEA	RAX,U64 [RDX+RAX*8]
	POP	RDX
	RET
_HASH_STR::
	PUSH	RBP
	MOV	RBP,RSP
	PUSH	RSI
	MOV	RSI,U64 SF_ARG1[RBP]
	CALL	SYS_HASH_STR
	POP	RSI
	POP	RBP
	RET1	8
_HASH_FIND::
	PUSH	RBP
	MOV	RBP,RSP
	PUSH	RSI
	PUSH	RDI
	MOV	RSI,U64 SF_ARG1[RBP]
	MOV	RDI,U64 SF_ARG2[RBP]
	MOV	RBX,U64 SF_ARG3[RBP]
	MOV	RCX,U64 SF_ARG4[RBP]
	CALL	SYS_HASH_FIND
	POP	RDI
	POP	RSI
	POP	RBP
	RET1	32
_HASH_SINGLE_TABLE_FIND::
	PUSH	RBP
	MOV	RBP,RSP
	PUSH	RSI
	PUSH	RDI
	MOV	RSI,U64 SF_ARG1[RBP]
	MOV	RDI,U64 SF_ARG2[RBP]
	MOV	RBX,U64 SF_ARG3[RBP]
	MOV	RCX,U64 SF_ARG4[RBP]
	CALL	SYS_HASH_STR
	CALL	SYS_HASH_SINGLE_TABLE_FIND
	POP	RDI
	POP	RSI
	POP	RBP
	RET1	32
_HASH_BUCKET_FIND::
	PUSH	RBP
	MOV	RBP,RSP
	PUSH	RSI
	PUSH	RDI
	MOV	RSI,U64 SF_ARG1[RBP]
	MOV	RDI,U64 SF_ARG2[RBP]
	CALL	SYS_HASH_BUCKET_FIND
	POP	RDI
	POP	RSI
	POP	RBP
	RET1	16
_HASH_ADD::
	PUSH	RBP
	MOV	RBP,RSP
	PUSH	RSI
	PUSH	RDI
	MOV	RCX,U64 SF_ARG1[RBP]
	MOV	RSI,U64 CHash.str[RCX]
	MOV	RDI,U64 SF_ARG2[RBP]
	CALL	SYS_HASH_BUCKET_FIND
	MOV	RCX,U64 SF_ARG1[RBP]
	PUSHFD
	CLI
	MOV	RBX,U64 [RAX]
	MOV	U64 CHash.next[RCX],RBX
	MOV	U64 [RAX],RCX

	POPFD
	POP	RDI
	POP	RSI
	POP	RBP
	RET1	16
_HASH_ADD_AFTER::
	PUSH	RBP
	MOV	RBP,RSP
	PUSH	RDI
	MOV	RCX,U64 SF_ARG1[RBP]
	MOV	RDI,U64 SF_ARG3[RBP]
	PUSHFD
	CLI
	MOV	RAX,SF_ARG2[RBP]
	MOV	RBX,U64 [RAX]
	MOV	U64 CHash.next[RCX],RBX
	MOV	U64 [RAX],RCX

	POPFD
	POP	RDI
	POP	RBP
	RET1	24
_HASH_REM_DEL::
	PUSH	RBP
	MOV	RBP,RSP
	PUSH	RSI
	PUSH	RDI
	MOV	RCX,U64 SF_ARG1[RBP]
	TEST	RCX,RCX
	JZ	@@10
	MOV	RSI,U64 CHash.str[RCX]
	XOR	RBX,RBX
	MOV	EBX,U32 CHash.type[RCX]
	AND	EBX,~HTG_FLAGS_MASK&0xFFFFFFFF
	MOV	RDI,U64 SF_ARG2[RBP]
	MOV	RCX,U64 SF_ARG3[RBP]
	CALL	SYS_HASH_STR

	PUSHFD
	CLI
	CALL	SYS_HASH_SINGLE_TABLE_FIND
	JZ	@@05
	CMP	RAX,U64 SF_ARG1[RBP]
	JNE	@@05

	MOV	RBX,U64 CHash.next[RAX]
	MOV	U64 [RDX],RBX

	POPFD

	PUSH_C_REGS
	PUSH	RAX
	CALL	&HashDel
	POP_C_REGS

	POP	RDI
	POP	RSI
	MOV	RAX,1
	POP	RBP
	RET1	24

@@05:	POPFD
@@10:	POP	RDI
	POP	RSI
	XOR	RAX,RAX
	POP	RBP
	RET1	24
}

_extern _HASH_STR I64 HashStr(U8 *st); //Hash a string.
_extern _HASH_FIND CHash *HashFind(U8 *needle_str,CHashTable *haystack_table,
	I64 mask,I64 instance=1);//Find string in hash table.
_extern _HASH_SINGLE_TABLE_FIND CHash *HashSingleTableFind(U8 *needle_str,
	CHashTable *haystack_table,
	I64 mask,I64 instance=1);//Find string in single hash table.
_extern _HASH_BUCKET_FIND CHash **HashBucketFind(U8 *needle_str,
	CHashTable *haystack_table); //Find hash bucket.
_extern _HASH_ADD U0 HashAdd(CHash *tmph,
	CHashTable *table); //Add entry to hash table.
_extern _HASH_REM_DEL Bool HashRemDel(CHash *tmph,CHashTable *table,
	I64 instance=1);//Remove hash entry and del. Instance must match.