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_cnt[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.