Yes the linker spat out some symbols not found but I was using it via exporting an interface only which gets around the issue of options in functions. the lib works with c backend but not asm, it's compiled with thread safe 
 Code: Select all
; Macro Comments() 
;   ; SQUINT 3, Sparse Quad Union Indexed Nibble Trie
;   ; Copyright Andrew Ferguson aka Idle (c) 2020 - 2024 
;   ; Version 3.2.2 b2
;   ; PB 5.72-6.02b 32bit/64bit asm and c backends for Windows,Mac OSX,Linux,PI,M1
;   ; Thanks Wilbert for the high low insight and utf8 conversion help.
;   ; Squint is a lock free concurrent compact prefix Trie indexed by nibbles into a sparse array with performance metrics close to a map
;   ; It provides O(K) performance with a memory size ~32 times smaller than a 256 node trie
;   ; Squint is at worst 2 times slower than a Map for set operations, look ups are closer to 1:1 or faster   
;   ; as squint can bail out as soon as a char of a key isn't found unlike a map that has to evaluate the whole key. 
;   ; Squint is lexographicaly sorted so sorting is magnitudes faster than what you could achieve with a map list or unsorted array 
;   ; Squint also supports collections or subtries, which facilitates tasks like in memory DB's  
;   ; The Numeric mode of squint behaves like a map and is closer to 1:1 perfromace with a sized map 
;   ; 
;   ; see https://en.wikipedia.org/wiki/Trie 
;   ;     https://en.wikipedia.org/wiki/Ctrie
;   ;     https://dotat.at/prog/qp/blog-2015-10-04.html
;   ;     https://cr.yp.to/critbit.html 
;   ;
;   ; Squint supports Set, Get, Enum, EnumNode , Walk, WalkNode, Merge, Delete and Prune with a flag in Delete
;   ; String keys can be Unicode, Ascii or UTF8 the type must be specified 
;   ; all string keys get mapped to UTF8 
;   ;
;   ; SquintNumeric supports, SetNumeric GetNumeric DeleteNumeric and WalkNumeric
;   ; it's provided as a direct subtitute for a map, keys can be any size upto #SQUINT_MAX_KEY =1024
;   ; keys are returned as pointers in walk     
;   ; keys can be anything that's serial and optionaly you can hash longer keys which will be sizeof integer 
;   ;
;   ; Note while you can mix string and numeric keys in the same trie it's not recomended unless you only require set and get 
;   ;  
;   ; Eclipse Public License - v 2.0
;   ;
;   ; mzHash64 https://github.com/matteo65/mzHash64 
;   
; EndMacro 
  
  #SQUINT_MAX_KEY = 1024
  
  Structure squint_node Align #PB_Structure_AlignC
    *vertex.edge
    StructureUnion
      squint.q
      value.i 
    EndStructureUnion 
  EndStructure   
  
  Structure edge   Align #PB_Structure_AlignC
    e.squint_node[0]
  EndStructure 
  
  Structure squint Align #PB_Structure_AlignC
    *vt
    size.i
    count.i
    mwrite.i
    menum.i
    *cursor.squint 
    *merge.squint
    *root.squint_node
    sb.a[#SQUINT_MAX_KEY]
  EndStructure
  
  CompilerIf #PB_Compiler_32Bit 
    #Squint_Pmask = $fffffffe
    #Squint_Integer = 4 
  CompilerElse
    #Squint_Pmask = $fffffffffffe
    #Squint_Integer = 8 
  CompilerEndIf
  
  ;External Squint Callback prototype 
  Prototype Squint_CB(*key,*value=0,*userdata=0)
  ;External 
  Prototype Squint_CBFree(*mem) 
  
  DeclareDLL SquintNew()
  Declare SquintFree(*this.Squint,*pfn.Squint_CBFree=0)
  Declare SquintMerge(*this.squint,*target.squint,freesource=0,numeric=0) 
  
  Declare SquintSetNode(*this.squint,*subtrie,*key,value.i,mode=#PB_Unicode)
  Declare SquintGetNode(*this.squint,*subtrie,*key,mode=#PB_Unicode,bval=1)
  Declare SquintDeleteNode(*this.squint,*subtrie,*key,prune=0,mode=#PB_Unicode)
  Declare SquintWalkNode(*this.squint,*subtrie,*pfn.squint_CB,*userdata=0) 
  Declare SquintEnum(*this.squint,*key,*pfn.squint_CB,*userdata=0,mode=#PB_Unicode)
  Declare SquintEnumNode(*this.squint,*subtrie,*key,*pfn.squint_CB,*userdata=0,mode=#PB_Unicode)
  
  Declare SquintSetNumeric(*this.squint,*key,value.i,size=#Squint_Integer,bhash=0)
  Declare SquintGetNumeric(*this.squint,*key,size = #Squint_Integer,bhash=0)
  Declare SquintDeleteNumeric(*this.squint,*key,size = #Squint_Integer,bhash=0)
  Declare SquintWalkNumeric(*this.squint,*pfn.squint_CB,size=#Squint_Integer,*userdata=0)  
  
  Declare SquintSetBinary(*this.squint,*subtrie,*key,value.i,size)
  Declare SquintGetBinary(*this.squint,*subtrie,*key,size)
  Declare SquintDeleteBinary(*this.squint,*subtrie,*key,size,prune=0)
  Declare SquintEnumBinary(*this.squint,*subtrie,*key,size,*pfn.squint_CB,*userdata=0)
  Declare SquintWalkBinary(*this.squint,*subtrie,*pfn.squint_CB,size,*userdata=0) 
  
  Declare SquintSize(*this.squint)
  Declare SquintNumKeys(*this.squint)
    
  
  ;Residents 
  Interface iSquint
    Free(*pfn)
    Merge(*target,freesource=0,numeric=0)  
    Delete(*subtrie,*key,prune=0,mode=#PB_Unicode)
    Set(*subtrie,*key,value.i,mode=#PB_Unicode)
    Get(*subtrie,*key,mode=#PB_Unicode,bval=1)
    Enum(*key,*pfn,*userdata=0,mode=#PB_Unicode)
    EnumNode(*subtrie,*key,*pfn,*userdata=0,mode=#PB_Unicode)
    Walk(*subtrie,*pfn,*userdata=0)
    SetNumeric(*key,value.i,size=#PB_Integer,bhash=0) 
    GetNumeric(*key,size= #PB_Integer,bhash=0) 
    DeleteNumeric(*key,size=#PB_Integer,bhash=0)
    WalkNumeric(*pfn,size=#PB_Integer,*userdata=0)
    SetBinary(*subtrie,*key,value.i,size) 
    GetBinary(*subtrie,*key,size) 
    DeleteBinary(*subtrie,*key,size,prune=0) 
    EnumBinary(*subtrie,*key,size,*pfn,*userdata=0)
    WalkBinary(*subtrie,*pfn,size,*userdata=0) 
    Size()
    NumKeys()
  EndInterface
  ;EndResidents  
  
   
   DataSection: vtSquint:
    Data.i @SquintFree()
    Data.i @SquintMerge() 
    Data.i @SquintDeleteNode() 
    Data.i @SquintSetNode()
    Data.i @SquintGetNode()
    Data.i @SquintEnum()
    Data.i @SquintEnumNode() 
    Data.i @SquintWalkNode()
    Data.i @SquintSetNumeric()
    Data.i @SquintGetNumeric()
    Data.i @SquintDeleteNumeric()
    Data.i @SquintWalkNumeric() 
    Data.i @SquintSetBinary() 
    Data.i @SquintGetBinary() 
    Data.i @SquintDeleteBinary() 
    Data.i @SquintEnumBinary()
    Data.i @SquintWalkBinary()
    Data.i @SquintSize() 
    Data.i @SquintNumKeys()
  EndDataSection   
  
  
  EnableExplicit
  
  ;-macros 
  Macro _SETINDEX(in,index,number)
    in = in & ~(15 << (index << 2)) | (number << (index << 2))
  EndMacro
  
  Macro _GETNODECOUNT()
    CompilerIf #PB_Compiler_32Bit 
      nodecount = MemorySize(*node\vertex) / SizeOf(squint_node)
    CompilerElse
      nodecount = (*node\vertex >> 48)
    CompilerEndIf
  EndMacro
  
  Macro _POKENHL(in,Index,Number)
    *Mem.Ascii = in
    *Mem + Index >> 1
    If Index & 1
      *Mem\a = (*Mem\a & $f0) | (Number & $f)
    Else
      *Mem\a = (*Mem\a & $0f) | (Number << 4)
    EndIf
  EndMacro
  
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86 
    Macro rax : eax : EndMacro 
  CompilerEndIf   
  
  CompilerIf #PB_Compiler_Thread 
    Macro _LockMutex(mut) 
      LockMutex(mut) 
    EndMacro 
    Macro _UnlockMutex(mut)
      UnlockMutex(mut)
    EndMacro   
  CompilerElse 
    Macro _Lockmutex(mut) 
    EndMacro 
    Macro _UnlockMutex(mut)
    EndMacro   
  CompilerEndIf   
  
  Macro _gLockXCHG(var,var1) 
    CompilerIf #PB_Compiler_Backend = #PB_Backend_C 
      !__atomic_exchange_n(&p_node->f_vertex,p_new,__ATOMIC_SEQ_CST) ; 
    CompilerElse 
      CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
        !mov eax , [p.p_#var1]
        !mov edx , [p.p_#var]
        !xchg dword [edx] , eax
      CompilerElse 
        !mov rax , [p.p_#var1]
        !mov rdx , [p.p_#var] 
        !lock xchg qword [rdx] , rax
      CompilerEndIf 
    CompilerEndIf 
  EndMacro
  ;External  
  Macro _sfence
    CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm  
      !sfence 
    CompilerElse 
      CompilerIf #PB_Compiler_Processor = #PB_Processor_Arm32 Or #PB_Compiler_Processor = #PB_Processor_Arm64
        !__sync_synchronize();
      CompilerElse   
        !__asm__("sfence" ::: "memory");   
      CompilerEndIf   
    CompilerEndIf   
  EndMacro 
  ;External
  Macro _lfence 
    CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm   
       !lfence
    CompilerElse
      CompilerIf #PB_Compiler_Processor = #PB_Processor_Arm32 Or #PB_Compiler_Processor = #PB_Processor_Arm64 
        !__sync_synchronize();
      CompilerElse  
        !__asm__("lfence" ::: "memory"); 
      CompilerEndIf   
    CompilerEndIf    
  EndMacro 
  
  Macro _CONVERTUTF8() 
    
    vchar = PeekU(*key)
    
    If mode = #PB_Unicode  
      CompilerIf #PB_Compiler_Backend = #PB_Backend_C  
        If vchar > $7f
          If vchar > $7ff
            vchar = $8080E0 | (vchar >> 12) | ((vchar << 2) & $3F00) | ((vchar << 16) & $3F0000)
          Else
            vchar = $80C0 | (vchar >> 6) | ((vchar << 8) & $3F00)
          EndIf
        EndIf   
      CompilerElse  
        
        !mov	eax, [p.v_vchar] 
        !cmp eax, 0x80 
        !jb .l2 
        !cmp	eax, 0x0800
        !jae .l1
        !mov edx, eax 
        !sal	edx, 8
        !and	edx, 0x3f00 
        !sar	eax, 6
        !or	edx, eax
        !or  edx, 0x80C0 
        !mov eax,edx
        !jmp	.l2
        !.l1:
        !mov edx, eax 
        !sal	edx, 16
        !and	edx, 0x3f0000
        !mov ecx, eax 
        !sal ecx, 2 
        !and ecx, 0x3f00
        !or  edx,ecx 
        !sar eax, 12 
        !or  edx, eax 
        !or  edx, 0x8080e0 
        !mov eax,edx 
        !.l2:
        !mov	[p.v_vchar], eax  
        
      CompilerEndIf    
      
    EndIf  
    
  EndMacro 
  
  Macro _MODECHECK()
    _CONVERTUTF8()
    If mode <> #PB_Unicode
      If (vchar >> ((count&1)<<4) & $ff = 0)
        Break
      EndIf 
    EndIf
  EndMacro 
  
  Macro _SETNODE()
    
    If *node\vertex
       
      _GETNODECOUNT()
      If (offset <> 15 Or nodecount = 16)
         XCHG_(@*node,(*node\Vertex\e[offset] & #Squint_Pmask))  
      Else  
        
        *node\Vertex = bts(*node\Vertex)
               
        offset = nodecount
        nodecount+1 
        
        *new = AllocateMemory((nodecount)*SizeOf(squint_node)) 
        *old = *node\vertex & #Squint_Pmask
        CopyMemory(*old,*new,(offset)*SizeOf(squint_node)) 
                
        CompilerIf #PB_Compiler_64Bit; 
          *new | ((nodecount) << 48)
        CompilerEndIf  
               
        XCHG_(@*node\vertex,*new) 
        
        _SETINDEX(*node\squint,idx,offset)
                        
        XCHG_(@*node,(*node\Vertex\e[offset] & #Squint_Pmask))
               
        FreeMemory(*old) 
        
        If *this\merge  
          *this\merge\size + SizeOf(squint_node) 
        Else   
          *this\size  +SizeOf(squint_node) 
        EndIf 
                
      EndIf 
      
    Else
            
      *node\vertex = AllocateMemory(SizeOf(squint_Node))
      
      *node\Vertex = bts(*node\Vertex)
      
      CompilerIf #PB_Compiler_64Bit; 
        *node\vertex | (1 << 48)
      CompilerEndIf
      *node\squint = -1
      _SETINDEX(*node\squint,idx,0)
      
      *node\Vertex = BTC(*node\Vertex)
      
      XCHG_(@*node,(*node\Vertex\e[0] & #Squint_Pmask))
      
      If *this\merge  
       *this\merge\size +SizeOf(squint_node) 
      Else   
        *this\size+SizeOf(squint_node) 
      EndIf 
           
    EndIf 
    
  EndMacro
     
  Procedure XCHG_(*ptr.Integer,v1) 
    
    CompilerIf #PB_Compiler_Backend = #PB_Backend_C 
      !__atomic_exchange_n(&p_ptr->f_i,v_v1,__ATOMIC_SEQ_CST); 
    CompilerElse 
      CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
        !mov ecx,[p.p_ptr]
        !mov eax,[p.v_v1]
        !xchg dword [ecx],eax
      CompilerElse 
        !mov rcx, [p.p_ptr]
        !mov rax, [p.v_v1 ] 
        !xchg qword [rcx],rax
      CompilerEndIf
    CompilerEndIf 
    
  EndProcedure 
  
  Procedure CMPXCHG_(*ptr.Integer,eq,chg) 
    
    CompilerIf #PB_Compiler_Backend = #PB_Backend_C 
      !__atomic_compare_exchange_n(&p_ptr->f_i,&v_eq,v_chg,0,__ATOMIC_SEQ_CST,__ATOMIC_RELAXED); 
    CompilerElse 
      
      CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
        !mov eax, dword [p.v_eq]
        !mov ecx, dword [p.v_chg]
        !mov edx, dword [p.p_ptr] 
        !lock cmpxchg dword [edx],ecx 
      CompilerElse 
        !mov rax, qword [p.v_eq]
        !mov rcx, qword [p.v_chg]
        !mov rdx, qword [p.p_ptr] 
        !lock cmpxchg qword [rdx],rcx 
      CompilerEndIf  
      
    CompilerEndIf 
  EndProcedure
  
  Procedure BTS(*node) 
    CompilerIf #PB_Compiler_Backend = #PB_Backend_C 
      !asm("lock bts %1, %0" : "+m" (p_node) : "r" (0)); 
    CompilerElseIf #PB_Compiler_Processor = #PB_Processor_x86
      !lock BTS dword [p.p_node],0 
    CompilerElse
      !lock BTS qword [p.p_node],0 
    CompilerEndIf  
         
    ProcedureReturn *node  
  EndProcedure 
 Procedure BTC(*node) 
   CompilerIf #PB_Compiler_Backend = #PB_Backend_C 
      !asm("lock btc %1, %0" : "+m" (p_node) : "r" (0)); 
    CompilerElseIf #PB_Compiler_Processor = #PB_Processor_x86
      !lock BTC dword [p.p_node],0 
    CompilerElse
      !lock BTC qword [p.p_node],0 
    CompilerEndIf  
    ProcedureReturn *node
 EndProcedure   
  
  ;-General functions 
  
  ;##################################################################################
  ;# Create a new Squint Trie 
  ;#  
  ;# example    
  ;#   global sq.iSquint = SquintNew() use via an interface with isquint           
  ;#   or 
  ;#   global sq = SquintNew() or normal use      
  ;################################################################################## 
  
  ProcedureDLL SquintNew()
    
    Protected *this.squint,a
    *this = AllocateMemory(SizeOf(squint))
    If *this
      *this\vt = ?vtSquint
      *this\root = AllocateMemory(SizeOf(squint_node)*16)
      *this\mwrite = CreateMutex() 
      *this\menum = CreateMutex()
      
      ProcedureReturn *this
    EndIf
  EndProcedure
  
  Procedure ISquintFree(*this.squint,*node.squint_node=0,*pfn.Squint_CBFree=0)
    Protected a,offset,nodecount
    If Not *node
      ProcedureReturn 0
    EndIf
    For a=0 To 15
      offset = (*node\squint >> (a<<2)) & $f
      If *node\vertex
        _GETNODECOUNT()
        If (offset <> 15 Or nodecount = 16)
          *this\size - SizeOf(squint_node)
          ISquintFree(*this,*node\Vertex\e[offset] & #Squint_Pmask)
        EndIf
      EndIf
    Next
    _LockMutex(*this\mwrite)
    If *node\vertex
      _GETNODECOUNT()
      If *pfn 
        If *node <> *this\root 
          *pfn(*node\value)
        EndIf   
      EndIf 
      FreeMemory(*node\Vertex & #Squint_Pmask) 
      *node\vertex=0
    EndIf
    _UnlockMutex(*this\mwrite) 
    ProcedureReturn *node
  EndProcedure
  
  ;##################################################################################
  ;# Free Squint Trie 
  ;# If you need to free your own pointers, Walk the trie 1st to free them  
  ;# then call sq\free() or SquintFree(sq)   
  ;################################################################################## 
  
  Procedure SquintFree(*this.squint,*pfn.Squint_CBFree=0)  
    
    Protected a,offset,*node.squint_node,nodecount
    
    *node = *this\root
    For a=0 To 15
      offset = (*node\squint >> (a<<2)) & $f
      If *node\vertex
        _GETNODECOUNT()
        If (offset <> 15 Or nodecount = 16)
          ISquintFree(*this,*node,*pfn)
        EndIf
      EndIf
    Next
    FreeMutex(*this\mwrite)
    FreeMutex(*this\menum) 
    FreeMemory(*this\root)
    nodecount = *this\size 
    FreeMemory(*this) 
    
    ProcedureReturn  nodecount  
  EndProcedure
  
  Procedure ISquintMerge(*this.squint,*node.squint_Node,*target.squint,depth,*outkey,numeric)
    Protected a.i,offset,nodecount,*mem.Ascii,key.s,*tnode 
    
    If Not *node
      ProcedureReturn 0
    EndIf
    
    For a =0 To 15
      
      offset = (*node\squint >> (a<<2)) & $f
      If (*node\vertex And *node\squint)
        _GETNODECOUNT()
        If (offset <> 15 Or nodecount = 16)
          _POKENHL(*outkey,depth,a)
          XCHG_(@*tnode,(*node\Vertex\e[offset] & #Squint_Pmask))
          If ISquintMerge(*this,*tnode,*target,depth+1,*outkey,numeric) = 0 
            Break 
          EndIf  
        EndIf
        
      EndIf
    Next
    
    If *node\vertex=0
      
      PokeA(*outkey+((depth>>1)),0)
      If numeric = 0 
        If *node\value
          SquintSetNode(*target,0,*outkey,*node\value,#PB_UTF8)
        EndIf  
      Else 
        If *node\value
          SquintSetNumeric(*target,*outkey,*node\value)
        EndIf   
      EndIf 
    EndIf
    ProcedureReturn *node
    
  EndProcedure
  
  ;#################################################################################
  ;#    merge tries    
  ;#    *this.squint instance from SquintNew() 
  ;#    *target squint to merge into  
  ;#    freesource frees the souce 
  ;##################################################################################
  
  Procedure SquintMerge(*this.squint,*target.squint,freesource=0,numeric=0)   
    
    Protected outkey.s{#SQUINT_MAX_KEY} 
    
    *target\merge=0 
    
    ISquintMerge(*this,*this\root,*target,0,@outkey,numeric)
    
    If freesource
      
      SquintFree(*this) 
      
    EndIf   
    
  EndProcedure   
  
  ;-string functions 
  
  ;#################################################################################
  ;#    Set a node from the root or from a previously set node   
  ;#    *this.squint instance from SquintNew() 
  ;#    *subtrie 0 Or the addess of a previously stored node retuned from this function 
  ;#   
  ;#    *key   address of a null terminated string can be unicode ascii or UTF8
  ;#    value.i  non zero value or address of something  
  ;#    mode.i  Desired key format #PB_Uniocde, #PB_Ascii, #PB_UTF8  
  ;#    returns *subtrie the node       
  ;# example     
  ;#    *cars = SquintSetNode(sq,0,@"cars:",100)          the key = "cars:"        
  ;#     *toyota = squintSetNode(sq,*cars,@"Toyota:",200) the key = "cars:toyota" 
  ;#     squintSetNode(sq,*toyota,@"Corolla",201)         the key = "cars:toyota:corolla" 
  ;#     squintSetNode(sq,*toyota,@"Cameray",202)         the key = "cars:toyota:Cameray"
  ;# via interface  
  ;#     sq\set(*toyota,@"Cameray",202)                   the key = "cars:toyota:Cameray"   
  ;################################################################################## 
  
  Procedure SquintSetNode(*this.squint,*subtrie,*key,value.i,mode=#PB_Unicode)
    
    Protected *node.squint_node,idx,offset,nodecount,vchar.l,vret.l,count,*out
    Protected *new.squint_node,*old.squint_node,*adr 
    Protected bmerge      
      
    
    _LockMutex(*this\mwrite)
    
    XCHG_(@bmerge,*this\merge) 
    If bmerge 
      XCHG_(@*node,(*this\merge\root & #Squint_Pmask))
    Else 
      If *subtrie = 0
        XCHG_(@*node,(*this\root & #Squint_Pmask))
      Else 
        *node = *subtrie & #Squint_Pmask
      EndIf
    EndIf 
      
    _CONVERTUTF8()
    
    While vchar
      
      idx = (vchar >> 4) & $f
      offset = (*node\squint >> (idx<<2)) & $f
      _SETNODE()     
      
      idx = vchar & $0f
      offset = (*node\squint >> (idx<<2)) & $f
      _SETNODE()    
      
      vchar >> 8
      count+1
      If vchar = 0
        *key+2
        _MODECHECK()
      EndIf
      Delay(0)
    Wend
    
    
    idx=0
    *out = *node 
    offset = *node\squint & $f
    
    _SETNODE()
   
    If bmerge 
      *this\merge\count+1 
    Else 
      *this\count +1
    EndIf 
    
    If value 
      *node\value = value
    EndIf 
    
    _UnlockMutex(*this\mwrite)
    
    ProcedureReturn *out
    
  EndProcedure
    
  
  ;##################################################################################
  ;#    Get a node from the root or from a previously stored node aka subtrie    
  ;#    *this.squint instance from SquintNew() 
  ;#    *subtrie 0 Or the addess of a previously stored node retuned from this function 
  ;#   *key   address of a null terminated string can be unicode ascii or UTF8
  ;#    mode.i  Desired key format #PB_Uniocde, #PB_Ascii, #PB_UTF8  
  ;#    
  ;#  returns the value or subnode        
  ;#  example    
  ;#     x = squintGetNode(sq,0,@"cars:toyota:")   subtrie = root, the key = "cars:toyota"  
  ;#     x = squintGetNode(sq,*toyota,@"Corolla")  subtrie = *toyota the key evaluates to = "cars:toyota:corolla"   
  ;#     or via interface 
  ;#     x = sq\get(0,@"cars:toyota:")  subtrie = root, the key = "cars:toyota"    
  ;################################################################################## 
  
  Procedure SquintGetNode(*this.squint,*subtrie,*key,mode=#PB_Unicode,bval=1)
    
    Protected *node.squint_Node,idx,offset,nodecount,vchar.l,vret.l,count,*out
    
    If *subtrie = 0
      XCHG_(@*node,(*this\root & #Squint_Pmask))
    Else 
      XCHG_(@*node,(*subtrie & #Squint_Pmask))
    EndIf 
    _CONVERTUTF8()
    
    If *node\vertex
      
      While vchar
        
        l1:
        If Not (*node & 1) 
          
          offset = (*node\squint >> ((vchar & $f0) >> 2 )) & $f
          _GETNODECOUNT()
          If offset < nodecount
            XCHG_(@*node,(*node\Vertex\e[offset] & #Squint_Pmask))
          Else
            ProcedureReturn 0
          EndIf
        Else 
          Delay(0)
          Goto l1  
        EndIf  
        
        l2:
        If Not (*node & 1) 
          
          offset = (*node\squint >> ((vchar & $0f) << 2)) & $f
          _GETNODECOUNT()
          If offset < nodecount
            XCHG_(@*node,(*node\Vertex\e[offset] & #Squint_Pmask))
          Else
            ProcedureReturn 0
          EndIf
        Else 
          Delay(0)
          Goto l2  
        EndIf 
        
        vchar >> 8
        count+1
        If vchar = 0
          *key+2
          _MODECHECK()
        EndIf
        
      Wend
      
      *out = *node 
      offset = *node\squint & $f
      _GETNODECOUNT()
      
      If offset <= nodecount
        XCHG_(@*node,(*node\Vertex\e[offset] & #Squint_Pmask)) 
        If bval 
          ProcedureReturn *node\value
        Else 
          ProcedureReturn *out  
        EndIf   
      Else
        ProcedureReturn 0
      EndIf
      
    EndIf 
    
  EndProcedure 
  
  Procedure SquintSetCursor(*this.squint,*key,*cursor) 
    
    Protected *node 
    *node = SquintGetNode(*this,0,*key,#PB_Unicode,0) 
    If *node 
      SquintSetNumeric(*this\cursor,*node,*cursor) 
    EndIf  
    *cursor = *node 
    
  EndProcedure  
   
  
  ;##################################################################################
  ;#    Resets a keys value to 0 or deletes the childen of the node freeing up memory     
  ;#    *this.squint instance from SquintNew() 
  ;#    *subtrie 0 Or the addess of a previously stored node retuned from this function 
  ;#    *key     address of a null terminated string can be unicode ascii or UTF8
  ;#    mode.i   Desired key format 
  ;#    returns  the value or 0
  ;#    example  
  ;#    x = SquintDeleteNode(sq,*cars,@"Toyota:",1)  subnode = *cars, the key evals to "cars:toyota" prune =1 So it deletes the child nodes corrola And camery  
  ;#    x = SquintDeleteNode(sq,0,@"cars:toyota:corolla") subtrie = root, the full key = "cars:toyota:corolla" prune=0 so it set the value to 0  
  ;#    via inteface  
  ;#    sq\delete(0,@"cars:toyota:corolla")     
  ;################################################################################## 
  
  Procedure SquintDeleteNode(*this.squint,*subtrie,*key.Unicode,prune=0,mode=#PB_Unicode)
    
    Protected *node.squint_node,idx,*mem.Character,offset,nodecount,vchar.l,vret.l,count,*out
    If *subtrie = 0
      *node = *this\root & #Squint_Pmask
    Else
      *node = *subtrie  & #Squint_Pmask 
    EndIf 
    _CONVERTUTF8()
    While vchar
      offset = (*node\squint >> ((vchar & $f0) >> 2 )) & $f
      If *node\vertex
        _GETNODECOUNT()
        If (offset <> 15 Or nodecount = 16)
          *node = *node\Vertex\e[offset] & #Squint_Pmask
        EndIf
      Else
        ProcedureReturn 0
      EndIf
      If *node
        offset = (*node\squint >> ((vchar & $0f) << 2)) & $f
        If *node\vertex
          _GETNODECOUNT()
          If (offset <> 15 Or nodecount = 16)
            *node = *node\Vertex\e[offset] & #Squint_Pmask
          EndIf
        Else
          ProcedureReturn 0
        EndIf
      EndIf
      vchar >> 8
      If vchar = 0
        *key+2
        _MODECHECK()
      EndIf
    Wend
    If prune
      ISquintFree(*this,*node)
      If (*node\vertex & #Squint_Pmask) = 0
        *node\squint = 0
      EndIf
    Else
      offset = *node\squint & $f
      _GETNODECOUNT()
      If offset <= nodecount
        *node = (*node\Vertex\e[offset] & #Squint_Pmask)
        If (*node\vertex & #Squint_Pmask) = 0
          *node\squint = 0
        EndIf
      Else
        ProcedureReturn 0
      EndIf
    EndIf
  EndProcedure
  
  Procedure IEnum(*this.squint,*node.squint_Node,depth,*pfn.squint_CB,*outkey,*userdata=0)
    Protected a.i,offset,nodecount,*mem.Ascii
    
    If Not *node
      ProcedureReturn 0
    EndIf
    
    For a =0 To 15
      
      offset = (*node\squint >> (a<<2)) & $f
      If (*node\vertex And *node\squint)
        _GETNODECOUNT()
        If (offset <> 15 Or nodecount = 16)
          _POKENHL(*outkey,depth,a)
          If IEnum(*this,(*node\Vertex\e[offset] & #Squint_Pmask),depth+1,*pfn,*outkey,*userdata) = 0 
            Break 
          EndIf  
        EndIf
        
      EndIf
    Next
    
    If *node\vertex=0
      If *pfn
        PokeA(*outkey+((depth>>1)),0)
        If *pfn(*outkey,*node\value,*userdata) = 0 
          ProcedureReturn 0
        EndIf   
      EndIf
    EndIf
    ProcedureReturn *node
    
  EndProcedure
  
  ;##################################################################################
  ;#  Enumerates the Trie from a given key   
  ;#    *this.squint instance from SquintNew() 
  ;#    *subtrie 0 Or the addess of a previously stored node       
  ;#    *key address of a null terminated string can be unicode ascii Or UTF8
  ;#     mode.i  Desired key format #PB_Uniocde, #PB_Ascii, #PB_UTF8  
  ;#    *pfn.squint_CB address of callback function as Squint_CB(*key,*value=0,*userdata=0) 
  ;#        where *key is pointer to the key *value is pointer to the *value, *userDate      
  ;# example    
  ;#     squintEnum(sq,*subtrie,@"cars:toyota:",@MyCallback())       
  ;#  or via interface 
  ;#     sq\Enum@"cars:toyota:",@MyCallback())   
  ;################################################################################## 
  
  Procedure SquintEnumNode(*this.squint,*subtrie,*key,*pfn.squint_CB,*userdata=0,mode=#PB_Unicode)  
    
    Protected *node.squint_Node,idx,*mem.Ascii,offset,nodecount,depth,vchar.l,vret.l,count,*out
    Protected *old.squint,*new.squint,bnmerge
    Protected outkey.s{1024} 
    
    _LockMutex(*this\menum)
    
    *new = SquintNew()     
   
    XCHG_(@*this\merge,*new) 
    
    If *subtrie = 0
       XCHG_(@*node,(*this\root & #Squint_Pmask))
    Else 
       XCHG_(@*node ,(*subtrie & #Squint_Pmask))
    EndIf 
    _CONVERTUTF8()
    
    If *node\vertex
      
      While vchar
        
        l1:
        If Not (*node & 1)
          
          offset = (*node\squint >> ((vchar & $f0) >> 2 )) & $f
          _GETNODECOUNT()
          If offset < nodecount
            XCHG_(@*node,(*node\Vertex\e[offset] & #Squint_Pmask))
          Else
            bnmerge = 1
            Break 
          EndIf
        Else 
          Delay(0)
          Goto l1  
        EndIf  
        
        l2:
        If Not (*node & 1)
         
          offset = (*node\squint >> ((vchar & $0f) << 2)) & $f
          _GETNODECOUNT()
          If offset < nodecount
            XCHG_(@*node,(*node\Vertex\e[offset] & #Squint_Pmask))
          Else
            bnmerge = 1 
            Break 
          EndIf
        Else 
          Delay(0)
          Goto l2
        EndIf 
        
        vchar >> 8
        count+1
        If vchar = 0
          *key+2
          _MODECHECK()
        EndIf
        
      Wend
      
      If bnmerge = 0 
        
        l3: 
        If Not (*node & 1)
          IEnum(*this,*node,depth,*pfn,@outkey,*userdata)
        Else 
          Delay(0)
          Goto l3 
        EndIf   
        
        _LockMutex(*this\mwrite)  
        
        *old = *this\merge
        XCHG_(@*this\merge,0)               
        SquintMerge(*old,*this)
        
        _UnlockMutex(*this\mwrite)
        
        SquintFree(*old)
        
      Else 
        
        _LockMutex(*this\mwrite)  
        *old = *this\merge
        XCHG_(@*this\merge,0)    
        
        _UnlockMutex(*this\mwrite)
        SquintFree(*old)
        
      EndIf 
      
    EndIf 
    
    _UnlockMutex(*this\menum) 
    
    
  EndProcedure
  
  ;##################################################################################
  ;#  Enumerates the Trie from a given key   
  ;#    *this.squint instance from SquintNew() 
  ;#    *key   address of a null terminated string can be unicode ascii or UTF8
  ;#     mode.i  Desired key format #PB_Uniocde, #PB_Ascii, #PB_UTF8  
  ;#    *pfn.squint_CB address of callback function as Squint_CB(*key,*value=0,*userdata=0) 
  ;#        where *key is pointer to the key *value is pointer to the *value, *userDate      
  ;# example    
  ;#     squintEnum(sq,@"cars:toyota:",@MyCallback())       
  ;#  or via interface 
  ;#     sq\Enum@"cars:toyota:",@MyCallback())   
  ;################################################################################## 
  
  Procedure SquintEnum(*this.squint,*key,*pfn.squint_CB,*userdata=0,mode=#PB_Unicode)
    
    SquintEnumNode(*this,0,*key,*pfn,*userdata,mode) 
    
  EndProcedure   
  
  ;##################################################################################
  ;# Walks the entire trie    
  ;#    *this.squint instance from SquintNew() 
  ;#    *pfn.squint_CB address of callback function as Squint_CB(*key,*value=0,*userdata=0) 
  ;#       where *key is pointer to the key *value is pointer to the *value, *userDate      
  ;# example    
  ;#     squintWalk(sq,@MyCallback())       
  ;#  or via interface 
  ;#     sq\Walk(@MyCallback())   
  ;################################################################################## 
  
  Procedure SquintWalk(*this.squint,*pfn.squint_CB,*userdata=0) 
    
    Protected *node, *old.squint,*new.squint, outkey.s{#SQUINT_MAX_KEY} 
    
    _LockMutex(*this\menum)
    
    *new = SquintNew()     
    XCHG_(@*this\merge,*new) 
    
    *node = *this\root & #Squint_Pmask
    
    IEnum(*this,*node,0,*pfn,@outkey,*userdata)
    
    _LockMutex(*this\mwrite)  
    
    *old = *this\merge
    XCHG_(@*this\merge,0)               
    SquintMerge(*old,*this) 
    
    _UnlockMutex(*this\mwrite)
    
    SquintFree(*old)
    
    _UnlockMutex(*this\menum) 
    
  EndProcedure
  
  ;##################################################################################
  ;# Walks from a subtrie    
  ;#    *this.squint instance from SquintNew() 
  ;#    *subtrie 0 Or the addess of a previously stored node  
  ;#    *pfn.squint_CB address of callback function As Squint_CB(*key,*value=0,*userdata=0) 
  ;#          
  ;# example    
  ;#     squintWalkNode(sq,*cars,@MyCallback())       
  ;#  or via interface 
  ;#     sq\Walk(*cars,@MyCallback())   
  ;################################################################################## 
  
  Procedure SquintWalkNode(*this.squint,*subtrie,*pfn.squint_CB,*userdata=0)   
    
    Protected *node, *old.squint,*new.squint, outkey.s{#SQUINT_MAX_KEY}    
    
    _LockMutex(*this\menum)
    
    *new = SquintNew()     
    XCHG_(@*this\merge,*new) 
    
    If *subtrie = 0
      *node = *this\root & #Squint_Pmask 
    Else
      *node = *subtrie  & #Squint_Pmask 
    EndIf 
    
    IEnum(*this,*node,0,*pfn,@outkey,*userdata)
    
    _LockMutex(*this\mwrite)  
    
    *old = *this\merge
    XCHG_(@*this\merge,0)               
    SquintMerge(*old,*this) 
    
    _UnlockMutex(*this\mwrite)
    
    SquintFree(*old)
    
    _UnlockMutex(*this\menum) 
    
  EndProcedure
  
  ;-Binaryfunctions operate the same as the string functions with no utf8 conversion   
  
  ;#################################################################################
  ;#    Set a Binary key  
  ;#    a Binary key is an address to memory and it's size in bytes 
  ;#    
  ;#    *this.squint instance from SquintNew() 
  ;#    *key   address of a variable or memory pointer 
  ;#    value.i non zero value or address of something  
  ;#    size.i required size in bytes    
  ;#  example     
  ;#     pt.point  
  ;#     pt\x = 100 
  ;#     pt\y = 200   
  ;#     SquintSetBinary(sq,@pt,1,SizeOf(point))       
  ;#  via interface  
  ;#     sq\setBinary(@pt,123435,SizeOf(point)))    
  ;################################################################################## 
  
  
  Procedure SquintSetBinary(*this.squint,*subtrie,*key,value.i,size)
    
    Protected *node.squint_node,idx,offset,nodecount,vchar.i,vret.i,count
    Protected bmerge,*old,*new.squint_node,sqindex,*akey.Ascii 
     
    
    _LockMutex(*this\mwrite)
    
    XCHG_(@bmerge,*this\merge) 
    If bmerge 
      *node = *this\merge\root & #Squint_Pmask
    Else 
      If *subtrie = 0
        *node = *this\root & #Squint_Pmask
      Else 
        *node = *subtrie & #Squint_Pmask
      EndIf
    EndIf 
    
    *akey = *key 
    
    While count <= size  
      idx = (*akey\a >> 4) & $f
      offset = (*node\squint >> (idx<<2)) & $f
      _SetNODE()
      idx = (*akey\a & $f)
      offset = (*node\squint >> (idx<<2)) & $f
      _SetNODE()
      *akey+1 
      count+1
    Wend
    
    If bmerge 
      *this\merge\count+1 
    Else 
      *this\count +1
    EndIf 
    
    If value 
      *node\value = value
    EndIf 
    
    _UnlockMutex(*this\mwrite)
    
    ProcedureReturn *node 
    
  EndProcedure
  
  ;##################################################################################
  ;#    Get a Binary node     
  ;#    *key   address of a variable Or memory pointer 
  ;#    size   number of bytes used for the key      
  ;#    #returns the value         
  ;#  example  
  ;#     pt.point  
  ;#     pt\x = 100 
  ;#     pt\y = 200   
  ;#     x = squintGetBinary(sq,@pt,sizeof(point))   
  ;#     or via interface 
  ;#     x = sq\getBinary(@pt,sizeof(point))        
  ;################################################################################## 
  
  Procedure SquintGetBinary(*this.squint,*subtrie,*key,size)
    
    Protected *node.squint_Node,idx,offset,nodecount,vchar.i,vret.i,count,*akey.Ascii,st  
    
    If *subtrie = 0
      *node = *this\root & #Squint_Pmask
    Else
      *node = *subtrie  & #Squint_Pmask 
    EndIf 
    
    *akey=*key 
    
    While count <= size  
      
      l1:
      If Not (*node & 1) 
        offset = (*node\squint >> ((*akey\a & $f0) >> 2 )) & $f
        _GETNODECOUNT()
        If offset < nodecount
          *node = (*node\Vertex\e[offset] & #Squint_Pmask)
        Else
          ProcedureReturn 0
        EndIf
      Else 
        Goto l1
      EndIf  
      
      l2:
      If Not (*node & 1) 
       offset = (*node\squint >> ((*akey\a & $0f) << 2)) & $f
        _GETNODECOUNT()
        If offset < nodecount
          *node = (*node\Vertex\e[offset] & #Squint_Pmask)
        Else
          ProcedureReturn 0
        EndIf
      Else 
        Goto l2
      EndIf  
      *akey+1
      count+1
    Wend
    
    ProcedureReturn *node\value
  EndProcedure
  
  ;##################################################################################
  ;#  Delete Binary resets the keys value to 0      
  ;#    *this.squint instance from SquintNew() 
  ;#    *key   address of a variable or memory pointer 
  ;#    size   number of bytes used to store the key    
  ;#  example  
  ;#     pt.point  
  ;#     pt\x = 100 
  ;#     pt\y = 200   
  ;#     x = SquintDeleteBinary(sq,@pt,SizeOf(point))   
  ;#     or via interface 
  ;#     x = sq\DeleteBinary(@pt,SizeOf(point))      
  ;################################################################################## 
  
  Procedure SquintDeleteBinary(*this.squint,*subtrie,*key,size,prune=0)    
    
    Protected *node.squint_node,idx,*mem.Ascii,*akey.Ascii,offset,nodecount,vchar.l,vret.l,count,*out
    If *subtrie = 0
      *node = *this\root & #Squint_Pmask
    Else
      *node = *subtrie  & #Squint_Pmask 
    EndIf 
    *akey=*key 
    
    While count <= size  
      offset = (*node\squint >> ((*akey\a & $f0) >> 2 )) & $f
      If *node\vertex
        _GETNODECOUNT()
        If (offset <> 15 Or nodecount = 16)
          *node = *node\Vertex\e[offset] & #Squint_Pmask
        EndIf
      Else
        ProcedureReturn 0
      EndIf
      If *node
        offset = (*node\squint >> ((*akey\a & $0f) << 2)) & $f
        If *node\vertex
          _GETNODECOUNT()
          If (offset <> 15 Or nodecount = 16)
            *node = *node\Vertex\e[offset] & #Squint_Pmask
          EndIf
        Else
          ProcedureReturn 0
        EndIf
      EndIf
      *akey+1
      count+1
    Wend
    
    If prune
      ISquintFree(*this,*node)
      If (*node\vertex & #Squint_Pmask) = 0
        *node\squint = 0
      EndIf
    Else
      offset = *node\squint & $f
      _GETNODECOUNT()
      If offset <= nodecount
        *node = (*node\Vertex\e[offset] & #Squint_Pmask)
        If (*node\vertex & #Squint_Pmask) = 0
          *node\squint = 0
        EndIf
      Else
        ProcedureReturn 0
      EndIf
    EndIf
  EndProcedure
  
  ;##################################################################################
  ;#  Enumerates the Trie from a given key   
  ;#    *this.squint instance from SquintNew() 
  ;#    *subtrie 0 Or the addess of a previously stored node       
  ;#    *key address 
  ;#     size the size of the key 
  ;#    *pfn.squint_CB address of callback function as Squint_CB(*key,*value=0,*userdata=0) 
  ;#        where *key is pointer to the key *value is pointer to the *value, *userDate      
  ;# example    
  ;#     pt.point     
  ;#     pt\x = 100 
  ;#     we want to search for all points where x = 100, size of the search key is 4 bytes    
  ;#     squintEnumBinary(sq,*subtrie,@pt,4,@MyCallback())       
  ;#  or via interface 
  ;#     sq\Enum@"cars:toyota:",@MyCallback())   
  ;################################################################################## 
  
  Procedure SquintEnumBinary(*this.squint,*subtrie,*key,size,*pfn.squint_CB,*userdata=0)       
    
    Protected *node.squint_Node,idx,*mem.Ascii,*akey.Ascii,offset,nodecount,depth,vchar.l,vret.l,count
    Protected bnmerge,*old.squint,*new.squint,outkey.s{1024} 
    
    _LockMutex(*this\menum)
    
    *new = SquintNew()     
    XCHG_(@*this\merge,*new) 
    
    If *subtrie = 0
      *node = *this\root
    Else
      *node = *subtrie  & #Squint_Pmask 
    EndIf 
    
    *akey = *key 
    
    While count <= size  
      
      offset = (*node\squint >> ((*akey\a & $f0) >> 2 )) & $f
      _GETNODECOUNT()
      If offset < nodecount
        *mem = @outkey+(depth>>1) 
        *mem\a = (*mem\a & $0f) | (((*akey\a >> 4) & $f)<<4)
        depth+1
        *node = (*node\Vertex\e[offset] & #Squint_Pmask)
      Else
        bnmerge=1
        Break 
      EndIf
      
      offset = (*node\squint >> ((*akey\a & $0f) << 2)) & $f
      _GETNODECOUNT()
      If offset < nodecount
        *mem = @outkey+(depth>>1) 
        *Mem\a = ((*Mem\a & $f0) | (*akey\a & $f))
        depth+1
        *node = (*node\Vertex\e[offset] & #Squint_Pmask)
      Else
        bnmerge=1  
        Break
      EndIf
      
      *akey+1
      count+1
      
    Wend
    
    If bnmerge = 0 
      
      IEnum(*this,*node,depth,*pfn,@outkey,*userdata)
      
      _LockMutex(*this\mwrite)  
      
      *old = *this\merge
      XCHG_(@*this\merge,0)               
      SquintMerge(*old,*this) 
      
      _UnlockMutex(*this\mwrite)
      
      SquintFree(*new)
      
    Else 
      
      *old = *this\merge
      XCHG_(@*this\merge,0)    
      SquintFree(*old)
      
    EndIf 
    
    _UnlockMutex(*this\menum) 
    
  EndProcedure
  
  Procedure SquintWalkBinary(*this.squint,*subtrie,*pfn.squint_CB,size,*userdata=0)    
    
    Protected *node, *old.squint,*new.squint, outkey.s{#SQUINT_MAX_KEY}    
    
    _LockMutex(*this\menum)
    
    *new = SquintNew()     
    XCHG_(@*this\merge,*new) 
    
    If *subtrie = 0
      *node = *this\root
    Else
      *node = *subtrie  & #Squint_Pmask 
    EndIf 
    
    IEnum(*this,*node,0,*pfn,@outkey,*userdata)
    
    _LockMutex(*this\mwrite)  
    
    *old = *this\merge
    XCHG_(@*this\merge,0)               
    SquintMerge(*old,*this) 
    
    _UnlockMutex(*this\mwrite)
    
    SquintFree(*old)
    
    _UnlockMutex(*this\menum) 
    
  EndProcedure   
  
  Procedure SquintSize(*this.squint) 
    ProcedureReturn *this\size 
  EndProcedure   
  
  Procedure SquintNumKeys(*this.squint)
    ProcedureReturn *this\count 
  EndProcedure   
  
  ;-Numeric functions operate the same as a map, keys can be anything that's serial  
  
  ;#################################################################################
  ;#    Set a numeric key  
  ;#    note you can use both numeric or string keys in the same trie  
  ;#    a numeric key is an address to a variable and the required size 4 or 8 bytes on x64 
  ;#    optionally you can use a hash use a hash when you don't want large keys 
  ;#
  ;#    *this.squint instance from SquintNew() 
  ;#    *key   address of a variable or memory pointer 
  ;#    value.i non zero value or address of something  
  ;#    size.i required size in bytes    
  ;#  example     
  ;#     ikey.l = 12345 
  ;#     SquintSetNumeric(sq,@ikey,1234567,4)  the key size is 4 bytes   
  ;#     pt.point  
  ;#     pt\x = 100 
  ;#     pt\y = 200   
  ;#     SquintSetNumeric(sq,@pt,1,SizeOf(point),#true) ;hashes the key         
  ;#  via interface  
  ;#     sq\setNumeric(@ikey,123435,4)    
  ;################################################################################## 
  
  Procedure SquintSetNumeric(*this.squint,*key,value.i,size=#Squint_Integer,bhash=0)
    
    Protected *node.squint_node,idx,offset,nodecount,vchar.i,vret.i,count,hash.q 
    Protected bmerge,*old,*new.squint_node,sqindex,*akey.Ascii 
      
    
    _LockMutex(*this\mwrite)
    
    XCHG_(@bmerge,*this\merge) 
    If bmerge 
      XCHG_(@*node,(*this\merge\root & #Squint_Pmask))
    Else 
      XCHG_(@*node,(*this\root & #Squint_Pmask))
    EndIf  
        
    If bhash 
      *akey=*key 
      hash = $D45E69F901E72147 ! bhash;
      Repeat 
        hash = $3631754B22FF2D5C * (count + *akey\a) ! (hash << 2) ! (hash >> 2);
        *akey + 1
        count+1 
      Until count >= size 
      count = 0 
      size = 8
      *akey = @hash+(#Squint_Integer-1)
    Else 
      *akey = *key+(size-1)
    EndIf 
    
    While count <= size  
      
      idx = (*akey\a >> 4) & $f
      offset = (*node\squint >> (idx<<2)) & $f
      _SetNODE()
      
      idx = (*akey\a & $f)
      offset = (*node\squint >> (idx<<2)) & $f
      _SetNODE()
      *akey-1 
      count+1
      Delay(0)
    Wend
    
    If bmerge 
      *this\merge\count+1 
    Else 
      *this\count +1
    EndIf 
    
    *node\value = value
            
    _UnlockMutex(*this\mwrite)
    
    ProcedureReturn *node
    
  EndProcedure
  
  ;##################################################################################
  ;#    Get a numeric node     
  ;#    *this.squint instance from SquintNew() 
  ;#    *key   address of a variable or memory pointer 
  ;#    size   number of bytes used to store the key 4 or 8 x64 or an arbitatry size if using the hash     
  ;#    bhash  set to #true if your hashing the key  
  ;#    #returns the value         
  ;#  example  
  ;#    key.l = 12345  
  ;#    x = squintGetNumeric(sq,@ikey,4)   
  ;#    or via interface 
  ;#    x = sq\get(@ikey,4)      
  ;################################################################################## 
  
  Procedure SquintGetNumeric(*this.squint,*key,size=#Squint_Integer,bhash=0)
    
    Protected *node.squint_Node,idx,offset,nodecount,vchar.i,vret.i,count,*akey.Ascii,hash.q,st  
    
    XCHG_(@*node,(*this\root & #Squint_Pmask))
    
    If bhash 
      *akey=*key 
      hash = $D45E69F901E72147 ! bhash;
      Repeat 
        hash = $3631754B22FF2D5C * (count + *akey\a) ! (hash << 2) ! (hash >> 2);
        *akey + 1
        count+1 
      Until count >= size 
      count = 0 
      size = 8
      *akey = @hash+(#Squint_Integer-1)
    Else 
      *akey = *key+(size-1)
    EndIf 
    
    While count <= size  
      
      l1:
      If Not (*node & 1) 
        
        XCHG_(@offset,*node\squint) 
        offset = (offset >> ((*akey\a & $f0) >> 2 )) & $f
        _GETNODECOUNT()
        If offset < nodecount
          XCHG_(@*node,(*node\Vertex\e[offset] & #Squint_Pmask))
        Else
          ProcedureReturn 0
        EndIf
      Else 
        Delay(0)
        Goto l1  
      EndIf  
      
      l2:
      If Not (*node & 1)  
        XCHG_(@offset,*node\squint) 
        offset = (offset >> ((*akey\a & $0f) << 2)) & $f
        _GETNODECOUNT()
        If offset < nodecount
          XCHG_(@*node,(*node\Vertex\e[offset] & #Squint_Pmask)) 
        Else
          ProcedureReturn 0
        EndIf
      Else 
        Delay(0)
        Goto l2  
      EndIf  
      *akey-1
      count+1
    Wend
    
    ProcedureReturn *node\value
  EndProcedure
  
  ;##################################################################################
  ;#  Delete Numeric resets the keys value to 0      
  ;#    *this.squint instance from SquintNew() 
  ;#    *key   address of a variable or memory pointer 
  ;#    size   number of bytes used to store the key    
  ;#  example  
  ;#     key.l = 12345  
  ;#     x = SquintDeleteNumeric(sq,@ikey,4)   
  ;#     or via interface 
  ;#     x = sq\DeleteNumeric(@ikey,4)      
  ;################################################################################## 
  
  Procedure SquintDeleteNumeric(*this.squint,*key,size=#Squint_Integer,bhash=0)    
    Protected *node.squint_node,idx,*mem.Character,offset,nodecount,vchar.i,vret.i,count,*akey.Ascii,hash.q 
    *node = *this\root & #Squint_Pmask
    
    If bhash 
      *akey=*key 
      hash = $D45E69F901E72147 ! bhash;
      Repeat 
        hash = $3631754B22FF2D5C * (count + *akey\a) ! (hash << 2) ! (hash >> 2);
        *akey + 1
        count+1 
      Until count >= size 
      count = 0 
      size = 8
      *akey = @hash+(#Squint_Integer-1)
    Else 
      *akey = *key+(size-1)
    EndIf 
    
    While count <= size 
      offset = (*node\squint >> ((*akey\a & $f0) >> 2 )) & $f
      _GETNODECOUNT()
      If offset < nodecount
        *node = (*node\Vertex\e[offset] & #Squint_Pmask)
      Else
        ProcedureReturn 0
      EndIf
      offset = (*node\squint >> ((*akey\a & $0f) << 2)) & $f
      _GETNODECOUNT()
      If offset < nodecount
        *node = (*node\Vertex\e[offset] & #Squint_Pmask)
      Else
        ProcedureReturn 0
      EndIf
      *akey-1
      count+1
    Wend
    If (*node\vertex & #Squint_Pmask) = 0
      *node\squint = 0
    EndIf
  EndProcedure
  
  Procedure IEnumNumeric(*this.squint,*node.squint_Node,depth,*pfn.squint_CB,*outkey.integer,size,*userdata=0)
    Protected a.i,offset,nodecount,*mem.Ascii,vchar.i,vret.i 
    
    If Not *node
      ProcedureReturn 0
    EndIf
    
    For a = 0 To 15 
      offset = (*node\squint >> (a<<2)) & $f
      If (*node\vertex And *node\squint)
        _GETNODECOUNT()
        If (offset <> 15 Or nodecount = 16)
          _POKENHL(*outkey,depth,a)
          IEnumNumeric(*this,*node\Vertex\e[offset] & #Squint_Pmask,depth+1,*pfn,*outkey,size,*userdata)
        EndIf
      EndIf
    Next
    
    If *node\vertex=0
      vchar = PeekI(*outkey) 
      CompilerIf #PB_Compiler_Backend = #PB_Backend_C 
        CompilerIf #PB_Compiler_Processor = #PB_Processor_x64  
          !v_vchar = __builtin_bswap64(v_vchar);    
        CompilerElse 
          !v_vchar = __builtin_bswap32(v_vchar);     
        CompilerEndIf
      CompilerElse 
        EnableASM
        mov rax, vchar
        bswap rax;
        mov vchar,rax
        DisableASM 
      CompilerEndIf 
      
      CompilerIf #PB_Compiler_Processor = #PB_Processor_x64  
        If size = 4 
          vchar >> 32 
        EndIf
      CompilerEndIf   
      
      If *node\value
        If *pfn   
          *pfn(@vchar,*node\value,*userdata)
        EndIf
      EndIf 
    EndIf
    
    ProcedureReturn *node
  EndProcedure
  
  ;##################################################################################
  ;# Walks whole trie. note it's not thread safe yet you can only walk one thread at a time with same trie    
  ;#    *this.squint instance from SquintNew() 
  ;#    *pfn.squint_CB address of callback function as Squint_CB(*key,*value=0,*userdata=0) 
  ;#     where *key is pointer to the key *value is pointer to the *value, *userDate      
  ;# example    
  ;#     squintWalkNumeric(sq,@MyCallback())       
  ;#  or via interface 
  ;#     sq\WalkNumeric(@MyCallback())   
  ;################################################################################## 
  
  Procedure SquintWalkNumeric(*this.squint,*pfn.squint_CB,size=#Squint_Integer,*userdata=0)       
    
    Protected depth,*node.squint_node,*new.squint,*old.squint,out.i,outkey.s{#SQUINT_MAX_KEY}        
    
    _LockMutex(*this\menum)
    
    *new = SquintNew()     
     
    XCHG_(@*this\merge,*new) 
    
    *node = *this\root & #Squint_Pmask
       
    CompilerIf #PB_Compiler_Processor = #PB_Processor_x64  
      If size > 8 
        IEnum(*this,*node,0,*pfn,@outkey,*userdata)
      Else 
        IEnumNumeric(*this,*node,depth,*pfn,@out,size,*userdata)
      EndIf   
    CompilerElse 
      If size > 4 
        IEnum(*this,*node,0,*pfn,@outkey,*userdata)
      Else 
        IEnumNumeric(*this,*node,depth,*pfn,@out,size,*userdata)
      EndIf   
      
    CompilerEndIf  
    
    _LockMutex(*this\mwrite)  
       
    *old = *this\merge
    XCHG_(@*this\merge,0)               
    SquintMerge(*old,*this,0,1) 
    
    _UnlockMutex(*this\mwrite)
           
    SquintFree(*old)
    
    _UnlockMutex(*this\menum) 
    
  EndProcedure