New lib xHash (w/ Updated xList)

Share your advanced PureBasic knowledge/code with the community.
PolyVector
Enthusiast
Enthusiast
Posts: 499
Joined: Wed Sep 17, 2003 9:17 pm
Location: Southern California
Contact:

New lib xHash (w/ Updated xList)

Post by PolyVector »

Code updated For 5.20+

Update: I fixed up xList.pb and xHash.pb to have far more extensive thread-safety... Both libraries are fully thread-safe now...
To make sure that your xList programs are safe, you can now call xLockList(List) and xUnlockList(List) before modifying the contents of an element... You don't need to Lock or Unlock a list to use xList commands, eg. xDeleteElement()... This is already done for you...


My conversion/hash code was a little out of date so I wrote a new library based on xList calld xHash....
It's basicly an easy way to setup conversions between numbers or strings... All commands in xHash are thread safe. Yeah, I thought you'd like that 8)

A practical use for this library is to keep track of conversions between a GadgetID and it's Windows handle... You could use it in your message handler to find out which gadget number the hWnd is refering to :)

Here's a test program: (I'll post the libraries below)

Code: Select all

 XIncludeFile "xHash.pb"

Debug "********* NUMERIC *********"
Converter=xNewConverter()
xAddConversion(Converter,1,123)
xAddConversion(Converter,2,246)
xAddConversion(Converter,3,369)

Debug xConvertFromLeft(Converter,1);/Output: 123
Debug xConvertFromLeft(Converter,2);/Output: 246
Debug xConvertFromLeft(Converter,3);/Output: 369

Debug xConvertFromRight(Converter,123);/Output: 1
Debug xConvertFromRight(Converter,246);/Output: 2
Debug xConvertFromRight(Converter,369);/Output: 3

xDelConverter(Converter)

Debug "********* STRINGS *********"

HashConverter=xNewHashConverter()
xAddHashConversion(HashConverter,"a","apple")
xAddHashConversion(HashConverter,"b","bananna")
xAddHashConversion(HashConverter,"c","carrot")

Debug xHashConvertFromLeft(HashConverter,"a");/Output: "apple"
Debug xHashConvertFromLeft(HashConverter,"b");/Output: "bananna"
Debug xHashConvertFromLeft(HashConverter,"c");/Output: "carrot"

Debug xHashConvertFromRight(HashConverter,"apple");/Output: "a"
Debug xHashConvertFromRight(HashConverter,"bananna");/Output: "b"
Debug xHashConvertFromRight(HashConverter,"carrot");/Output: "c"

xDelHashConverter(HashConverter)
Last edited by PolyVector on Mon Nov 29, 2004 7:57 am, edited 5 times in total.
PolyVector
Enthusiast
Enthusiast
Posts: 499
Joined: Wed Sep 17, 2003 9:17 pm
Location: Southern California
Contact:

New lib xHash (w/ Updated xList)

Post by PolyVector »

Here is "xList.pb"

Code: Select all

Structure xList
  ElementCount.l
  *First.xElement
  *Last.xElement
  DataSize.l
  UserData.l
  Mutex.l
  ConstructorProc.l
  DestructorProc.l
  AutoSortProc.l
  SortReversed.l
  ListMemoryIsManual.l
  ElementMemoryIsManual.l
EndStructure

Structure xElement
  *Parent.xList
  *Forward.xElement
  *Backward.xElement
EndStructure

Procedure _xNewList(DataSize.l,Buffer.l)
  Protected *List.xList
  If Buffer
    *List=Buffer
    *List\ListMemoryIsManual=#True
  Else
    *List=AllocateMemory(SizeOf(xList))
  EndIf
  
  *List\DataSize=DataSize
  *List\Mutex=CreateMutex_(#Null,#Null,"")
  ProcedureReturn *List
EndProcedure

Procedure xNewList(DataSize.l)
  ProcedureReturn _xNewList(DataSize,#Null)
EndProcedure

Procedure xLockList(*List.xList)
  WaitForSingleObject_(*List\Mutex,#INFINITE);/ 
EndProcedure

Procedure xUnlockList(*List.xList)
  ReleaseMutex_(*List\Mutex)
EndProcedure

Procedure xEnumElements(*List.xList,CallbackProc.l,Param.l)
  Protected *Element.xElement,*NextElement.xElement
  *Element=*List\first
  While *Element
    *NextElement=*Element\Forward
    If CallFunctionFast(CallbackProc,*Element+SizeOf(xElement),Param)=#Null
      ProcedureReturn #True
    EndIf
    *Element=*NextElement
  Wend
  ProcedureReturn #False
EndProcedure

Procedure xEnumElements_Reversed(*List.xList,CallbackProc.l,Param.l)
  Protected *Element.xElement
  *Element=*List\Last
  While *Element
    CallFunctionFast(CallbackProc,*Element+SizeOf(xElement),Param)
    *Element=*Element\Backward
  Wend
EndProcedure

Procedure xQuickSwapElement(*BaseElement.xElement)
  Protected *List.xList,*TopElement.xElement
  *List=*BaseElement\Parent
  *TopElement=*BaseElement\Forward
  If *TopElement
    If *BaseElement\Backward
      *BaseElement\Backward\Forward=*TopElement
    EndIf
    If *TopElement\Forward
      *TopElement\Forward\Backward=*BaseElement
    EndIf
    *BaseElement\Forward=*TopElement\Forward
    *TopElement\Backward=*BaseElement\Backward
    *BaseElement\Backward=*TopElement
    *TopElement\Forward=*BaseElement
    
    ;/List Cleanup:
    If *List\first=*BaseElement
      *List\first=*TopElement
    EndIf
    If *List\Last=*TopElement
      *List\Last=*BaseElement
    EndIf
    
    ProcedureReturn #True
  EndIf
  ProcedureReturn #False
EndProcedure

Procedure xSortList(*List.xList,SortProc.l)
  Protected *Element.xElement
  Protected I.l,MaxCount.l,Modified.l
  xLockList(*List)
  MaxCount=*List\ElementCount-1
  For I=1 To MaxCount
    Modified=#False
    *Element=*List\first
    While *Element And *Element\Forward
      If CallFunctionFast(SortProc,*Element+SizeOf(xElement),*Element\Forward+SizeOf(xElement))<>*List\SortReversed
        xQuickSwapElement(*Element)
        Modified=#True
      Else
        *Element=*Element\Forward
      EndIf
    Wend
    If Modified=#False
      Break
    EndIf
  Next
  xUnlockList(*List)
  ProcedureReturn #True
EndProcedure

Procedure xSortElement(*Element.xElement,SortProc.l)
  Protected *List.xList
  *Element-SizeOf(xElement)
  *List=*Element\Parent
  xLockList(*List)
  While *Element And *Element\Forward
    If CallFunctionFast(SortProc,*Element+SizeOf(xElement),*Element\Forward+SizeOf(xElement))<>*List\SortReversed
      xQuickSwapElement(*Element)
      Modified=#True
    Else
      *Element=*Element\Forward
    EndIf
    If Modified=#False
      Break
    EndIf
  Wend
  While *Element And *Element\Backward
    If CallFunctionFast(SortProc,*Element\Backward+SizeOf(xElement),*Element+SizeOf(xElement))<>*List\SortReversed
      xQuickSwapElement(*Element\Backward)
      Modified=#True
    Else
      *Element=*Element\Backward
    EndIf
    If Modified=#False
      Break
    EndIf
  Wend
  xUnlockList(*List)
EndProcedure

Procedure xGetList(*Element.xElement)
  *Element-SizeOf(xElement)
  ProcedureReturn *Element\Parent
EndProcedure

Procedure xFirstElement(*List.xList)
  If *List\first
    ProcedureReturn *List\first+SizeOf(xElement)
  EndIf
  ProcedureReturn #Null
EndProcedure

Procedure xLastElement(*List.xList)
  If *List\Last
    ProcedureReturn *List\Last+SizeOf(xElement)
  EndIf
  ProcedureReturn #Null
EndProcedure

Procedure xNextElement(*Element.xElement)
  *Element-SizeOf(xElement)
  If *Element\Forward
    ProcedureReturn *Element\Forward+SizeOf(xElement)
  EndIf
  ProcedureReturn #Null
EndProcedure

Procedure xPreviousElement(*Element.xElement)
  *Element-SizeOf(xElement)
  If *Element\Backward
    ProcedureReturn *Element\Backward+SizeOf(xElement)
  EndIf
  ProcedureReturn #Null
EndProcedure

Enumeration
  #FindByte
  #FindWord
  #FindLong
  #FindString
EndEnumeration
Structure FindElementStruct
  TypeOfData.l
  StructureOffset.l
  FindData.l
  *ElementMatch.xElement
EndStructure
Procedure _xFindElement(*Element.xElement,*FindElement.FindElementStruct)
  Protected ElementFound.l,FindDataPtr.l
  ElementFound=#False
  FindDataPtr=*Element+*FindElement\StructureOffset
  Select *FindElement\TypeOfData
    Case #FindByte
      If PeekB(FindDataPtr)=*FindElement\FindData
        ElementFound=#True
      EndIf
    Case #FindWord
      If PeekW(FindDataPtr)=*FindElement\FindData
        ElementFound=#True
      EndIf
    Case #FindLong
      If PeekL(FindDataPtr)=*FindElement\FindData
        ElementFound=#True
      EndIf
    Case #FindString
      If PeekS(FindDataPtr)=PeekS(*FindElement\FindData)
        ElementFound=#True
      EndIf
  EndSelect
  If ElementFound
    *FindElement\ElementMatch=*Element
    ProcedureReturn #False
  EndIf
  ProcedureReturn #True
EndProcedure

Procedure xFindElement(*List.xList,TypeOfData.l,StructureOffset.l,FindData.l)
  Protected FindElement.FindElementStruct
  FindElement\TypeOfData=TypeOfData
  FindElement\StructureOffset=StructureOffset
  FindElement\FindData=FindData
  FindElement\ElementMatch=#Null
  xEnumElements(*List,@_xFindElement(),@FindElement)
  ProcedureReturn FindElement\ElementMatch
EndProcedure






Procedure xCountList(*List.xList)
  ProcedureReturn *List\ElementCount
EndProcedure

Procedure xGetListUserData(*List.xList)
  ProcedureReturn *List\UserData
EndProcedure

Procedure xSetListUserData(*List.xList,UserData.l)
  xLockList(*List)
  *List\UserData=UserData
  xUnlockList(*List)
EndProcedure

Procedure xSetElementConstructor(*List.xList,ConstructorProc.l)
  xLockList(*List)
  *List\ConstructorProc=ConstructorProc
  xUnlockList(*List)
EndProcedure

Procedure xSetElementDestructor(*List.xList,DestructorProc.l)
  xLockList(*List)
  *List\DestructorProc=DestructorProc
  xUnlockList(*List)
EndProcedure

Procedure xSetElementAutoSortProc(*List.xList,SortProc.l)
  xLockList(*List)
  *List\AutoSortProc=SortProc
  xUnlockList(*List)
EndProcedure

Procedure xSetElementSortReversed(*List.xList,TrueFalse.l)
  xLockList(*List)
  *List\SortReversed=TrueFalse
  xUnlockList(*List)
EndProcedure

Procedure __xAddElement(*List.xList,Param.l,Buffer.l)
  Protected *Element.xElement,*NewIndexTable
  xLockList(*List)
  If Buffer
    *List\ElementMemoryIsManual=#True
    *Element=Buffer
  Else
    *Element=AllocateMemory(SizeOf(xElement)+*List\DataSize)
  EndIf
  *Element\Parent=*List
  *Element\Forward=#Null;/Safety First
  *Element\Backward=#Null;/Safety First
  If *List\ElementCount=#Null;/First Element
    *List\first=*Element
    *List\Last=*Element
  Else
    *List\Last\Forward=*Element
    *Element\Backward=*List\Last
    *List\Last=*Element
  EndIf
  *List\ElementCount+1
  If *List\ConstructorProc
    CallFunctionFast(*List\ConstructorProc,*Element+SizeOf(xElement),Param)
  EndIf
  If *List\AutoSortProc
    xSortElement(*Element+SizeOf(xElement),*List\AutoSortProc)
    ;xSortList(*List,*List\AutoSortProc)
  EndIf
  xUnlockList(*List)
  ProcedureReturn *Element+SizeOf(xElement) 
EndProcedure
Procedure _xAddElement(*List.xList,Param.l)
  ProcedureReturn __xAddElement(*List,Param,#Null)
EndProcedure
Procedure xAddElement(*List.xList)
  ProcedureReturn _xAddElement(*List,#Null)
EndProcedure

Procedure _xDeleteElement(*Element.xElement,QuickDelete.l)
  Protected *List.xList
  *List=*Element\Parent
  xLockList(*List)
  If *Element
    If QuickDelete=#False
      If *Element\Forward
        *Element\Forward\Backward=*Element\Backward
      Else
        *List\Last=*Element\Backward
      EndIf
      If *Element\Backward
        *Element\Backward\Forward=*Element\Forward
      Else
        *List\first=*Element\Forward
      EndIf
    EndIf
    If *List\DestructorProc
      CallFunctionFast(*List\DestructorProc,*Element+SizeOf(xElement))
    EndIf
    
    If *List\ElementMemoryIsManual=#False
      FreeMemory(*Element)
    EndIf
    
    *List\ElementCount-1
  EndIf
  xUnlockList(*List)
EndProcedure

Procedure xDeleteElement(*Element.xElement)
  If *Element
    *Element-SizeOf(xElement)
    _xDeleteElement(*Element,#False)
  EndIf
EndProcedure

Procedure _xDeleteList_Enum(*Element.xElement,Param.l)
  *Element-SizeOf(xElement)
  _xDeleteElement(*Element,#True)
  ProcedureReturn #True
EndProcedure
Procedure xDeleteList(*List.xList)
  xEnumElements(*List,@_xDeleteList_Enum(),0)
  *List\ElementCount=#Null
  *List\first=#Null
  *List\Last=#Null
  If *List\ListMemoryIsManual=#False
    xUnlockList(*List)
    CloseHandle_(*List\Mutex)
    FreeMemory(*List)
  EndIf
EndProcedure
###########################################################
You'll need the updated "xHash.pb"

Code: Select all

XIncludeFile "xList.pb"

#MaxHashStringLength=255;/The longest a Hash String can be...

Structure xConversion
  left.l
  right.l
EndStructure

Procedure xNewConverter()
  Protected Converter.l
  Converter=xNewList(SizeOf(xConversion))
  ProcedureReturn Converter
EndProcedure

Procedure xFindConversionFromLeft(Converter.l,left.l)
  ProcedureReturn xFindElement(Converter,#FindLong,OffsetOf(xConversion\left),left)
EndProcedure

Procedure xFindConversionFromRight(Converter.l,right.l)
  ProcedureReturn xFindElement(Converter,#FindLong,OffsetOf(xConversion\right),right)
EndProcedure

Procedure xAddConversion(Converter.l,left.l,right.l)
  Protected *Conversion.xConversion
  *Conversion=xFindConversionFromLeft(Converter,left);/Keeps All Left Values Unique
  If *Conversion=#Null
    ;*Conversion=xFindConversionFromRight(Converter,right);/Keeps All Right Values Unique
    ;If *Conversion=#Null
    *Conversion=xAddElement(Converter)
    ;EndIf
  EndIf
  If *Conversion
    xLockList(Converter)
    *Conversion\left=left
    *Conversion\right=right
    xUnlockList(Converter)
  EndIf
EndProcedure

Procedure xDelConversionFromLeft(Converter.l,left.l)
  Protected *Conversion.xConversion
  *Conversion=xFindConversionFromLeft(Converter,left)
  If *Conversion
    xDeleteElement(*Conversion)
  EndIf
EndProcedure

Procedure xDelConversionFromRight(Converter.l,right.l)
  Protected *Conversion.xConversion
  *Conversion=xFindConversionFromRight(Converter,right)
  If *Conversion
    xDeleteElement(*Conversion)
  EndIf
EndProcedure

Procedure xDelConverter(Converter.l)
  xDeleteList(Converter)
EndProcedure

Procedure _xCopyConverter(*Conversion.xConversion,NewConverter.l)
  xAddConversion(NewConverter,*Conversion\left,*Conversion\right)
  ProcedureReturn #True
EndProcedure

Procedure xCopyConverter(Converter.l)
  Protected NewConverter.l
  NewConverter=xNewList(SizeOf(xConversion))
  xEnumElements(Converter,@_xCopyConverter(),NewConverter)
  ProcedureReturn NewConverter
EndProcedure

Procedure xConvertFromLeft(Converter.l,left.l)
  Protected *Conversion.xConversion
  *Conversion=xFindConversionFromLeft(Converter,left)
  If *Conversion
    ProcedureReturn *Conversion\right
  EndIf
  ProcedureReturn #Null 
EndProcedure

Procedure xConvertFromRight(Converter.l,right.l)
  Protected *Conversion.xConversion
  *Conversion=xFindConversionFromRight(Converter,right)
  If *Conversion
    ProcedureReturn *Conversion\left
  EndIf
  ProcedureReturn #Null 
EndProcedure

;-------

Structure xHashConversion
  left.b[#MaxHashStringLength]
  right.b[#MaxHashStringLength]
EndStructure

Procedure xNewHashConverter()
  Protected HashConverter.l
  HashConverter=xNewList(SizeOf(xHashConversion))
  ProcedureReturn HashConverter
EndProcedure

Procedure xFindHashConversionFromLeft(HashConverter.l,left$)
  ProcedureReturn xFindElement(HashConverter,#FindString,OffsetOf(xHashConversion\left),@left$)
EndProcedure

Procedure xFindHashConversionFromRight(HashConverter.l,right$)
  ProcedureReturn xFindElement(HashConverter,#FindString,OffsetOf(xHashConversion\right),@right$)
EndProcedure

Procedure xAddHashConversion(HashConverter.l,left$,right$)
  Protected *HashConversion.xHashConversion
  *HashConversion=xFindHashConversionFromLeft(HashConverter,left$);/Keeps All Left Values Unique
  If *HashConversion=#Null
    ;*HashConversion=xFindHashConversionFromRight(HashConverter,right$);/Keeps All Right Values Unique
    ;If *HashConversion=#Null
    *HashConversion=xAddElement(HashConverter)
    ;EndIf
  EndIf
  If *HashConversion
    xLockList(HashConverter)
    PokeS(@*HashConversion\left,Left(left$,#MaxHashStringLength))
    PokeS(@*HashConversion\right,Left(right$,#MaxHashStringLength))
    xUnlockList(HashConverter)
  EndIf
EndProcedure

Procedure xDelHashConversionFromLeft(HashConverter.l,left$)
  Protected *HashConversion.xHashConversion
  *HashConversion=xFindHashConversionFromLeft(HashConverter,left$)
  If *HashConversion
    xDeleteElement(*HashConversion)
  EndIf
EndProcedure

Procedure xDelHashConversionFromRight(HashConverter.l,right$)
  Protected *HashConversion.xHashConversion
  *HashConversion=xFindHashConversionFromRight(HashConverter,right$)
  If *HashConversion
    xDeleteElement(*HashConversion)
  EndIf
EndProcedure

Procedure xDelHashConverter(HashConverter.l)
  xDelConverter(HashConverter)
EndProcedure

Procedure _xCopyHashConverter(*HashConversion.xHashConversion,NewHashConverter.l)
  xAddHashConversion(NewHashConverter,PeekS(@*HashConversion\left),PeekS(@*HashConversion\right))
  ProcedureReturn #True
EndProcedure

Procedure xCopyHashConverter(HashConverter.l)
  Protected NewHashConverter.l
  NewHashConverter=xNewList(SizeOf(xHashConversion))
  xEnumElements(HashConverter,@_xCopyHashConverter(),NewHashConverter)
  ProcedureReturn NewHashConverter
EndProcedure

Procedure.s xHashConvertFromLeft(HashConverter.l,left$)
  Protected *HashConversion.xHashConversion
  *HashConversion=xFindHashConversionFromLeft(HashConverter,left$)
  If *HashConversion
    ProcedureReturn PeekS(@*HashConversion\right)
  EndIf
  ProcedureReturn ""
EndProcedure

Procedure.s xHashConvertFromRight(HashConverter.l,right$)
  Protected *HashConversion.xHashConversion
  *HashConversion=xFindHashConversionFromRight(HashConverter,right$)
  If *HashConversion
    ProcedureReturn PeekS(@*HashConversion\left)
  EndIf
  ProcedureReturn "" 
EndProcedure


;-main--------------------
;         XIncludeFile "xHash.pb"

Debug "********* NUMERIC *********"
Converter=xNewConverter()
xAddConversion(Converter,1,123)
xAddConversion(Converter,2,246)
xAddConversion(Converter,3,369)

Debug xConvertFromLeft(Converter,1);/Output: 123
Debug xConvertFromLeft(Converter,2);/Output: 246
Debug xConvertFromLeft(Converter,3);/Output: 369

Debug xConvertFromRight(Converter,123);/Output: 1
Debug xConvertFromRight(Converter,246);/Output: 2
Debug xConvertFromRight(Converter,369);/Output: 3

xDelConverter(Converter)

Debug "********* STRINGS *********"

HashConverter=xNewHashConverter()
xAddHashConversion(HashConverter,"a","apple")
xAddHashConversion(HashConverter,"b","bananna")
xAddHashConversion(HashConverter,"c","carrot")

Debug xHashConvertFromLeft(HashConverter,"a");/Output: "apple"
Debug xHashConvertFromLeft(HashConverter,"b");/Output: "bananna"
Debug xHashConvertFromLeft(HashConverter,"c");/Output: "carrot"

Debug xHashConvertFromRight(HashConverter,"apple");/Output: "a"
Debug xHashConvertFromRight(HashConverter,"bananna");/Output: "b"
Debug xHashConvertFromRight(HashConverter,"carrot");/Output: "c"

xDelHashConverter(HashConverter)
Last edited by PolyVector on Tue Nov 30, 2004 4:42 am, edited 3 times in total.
Xombie
Addict
Addict
Posts: 898
Joined: Thu Jul 01, 2004 2:51 am
Location: Tacoma, WA
Contact:

Post by Xombie »

:cry: This is what I get for not searching the forums before I go off on my own. sigh. Well, at least I got to play around a little bit and learn a few things.

Your code is so much more professional looking ^_^ I'll let this be a lesson to me before I think something doesn't already exist here :oops:
PolyVector
Enthusiast
Enthusiast
Posts: 499
Joined: Wed Sep 17, 2003 9:17 pm
Location: Southern California
Contact:

Post by PolyVector »

Actually, I got in the mood to update xList and create xHash because of your code :D
It wouldn't have happend if you hadn't posted your list code 8)
User avatar
blueb
Addict
Addict
Posts: 1116
Joined: Sat Apr 26, 2003 2:15 pm
Location: Cuernavaca, Mexico

Post by blueb »

Xombie...

I think it's a really good idea to post ideas, etc on the forum, even if they aren't complete! One idea usually leads to another.

I love nothing better than playing with some code snippets, because I end up learning a lot... so: Keep it up!

--blueb
PolyVector
Enthusiast
Enthusiast
Posts: 499
Joined: Wed Sep 17, 2003 9:17 pm
Location: Southern California
Contact:

Post by PolyVector »

Update: I improved xList and xHash with some generic element searching routines... The code is a little smaller now, and cleaner...
Check out the new xFindElement() command... it's great :)
Post Reply