• Welcome to Theos PowerBasic Museum 2017.

PB9 Linked List (Problem destroying objects)

Started by Paul Squires, August 31, 2008, 01:20:36 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Paul Squires

Hi Everyone,

I have finally dove into the PB9 object world. I am loving it so far! It is really easy to model what I want to do using the COM objects. I decided to try building an object oriented single linked list in order to help my learning. I have run into a bit of trouble when I try to remove all nodes in the linked list. It appears (to me anyway) that the nodes are not being set to NOTHING and therefore I can still iterate the list even though there should be no valid nodes available to iterate.

The current state of the code is listed below. If anyone can spot the problem then I would be very grateful for advice to fix it. This is my first shot at PB9 objects so don't laugh if it looks stupid!  ;D

'//
'//  PB9 OOP Single Linked List
'//

#Include Once "win32api.inc"



'//
'//  The definition of each node in the Linked List
'//
Class cLinkedListNode
   Instance m_sKey  As String
   Instance m_sData As String
   Instance m_nData As Long

   Interface LinkedListNodeInterface: Inherit IUnknown     
   
      ' Property to Get/Set the 'Key' for the item
      Property Get sKey() As String
         Property = m_sKey
      End Property
      Property Set sKey( ByVal sKey As String )
         m_sKey = sKey
      End Property
 
 
      ' Property to Get/Set the string 'Data' for the item (when UseStrings is TRUE)
      Property Get sData() As String
         Property = m_sData
      End Property
      Property Set sData( ByVal sData As String )
         m_sData = sData
      End Property
 
 
      ' Property to Get/Set the numeric 'Data' for the item (when UseStrings is FALSE)
      Property Get nData() As Long   
         Property = m_nData
      End Property
      Property Set nData( ByVal nData As Long )
         m_nData = nData
      End Property

   End Interface

End Class



'//
'//  The main Linked List class. An instance of this class should
'//  be made in the user's code and will be used to manipulate the
'//  various nodes in the list.
'//
Class cLinkedList
   ' Private instance variables
   Instance m_pChildNodes()   As LinkedListNodeInterface
   Instance m_nCurrentNodeNum As Long
   Instance m_nIncreaseSize   As Long
   Instance m_nUseStrings     As Long
   Instance m_IsEndOfList     As Long
   Instance m_nCount          As Long
   Instance m_zPtr            As Asciiz Ptr
   
   Class Method AddNewNode( ByVal nPosition As Long ) As Long
      Local y As Long
     
      ' Create a new node instance at the end of the linked list
      ' Do we need to make our array bigger?
      If m_nCount + 1 > UBound(m_pChildNodes) Then
         If m_nIncreaseSize = 0 Then m_nIncreaseSize = 100
         ReDim Preserve m_pChildNodes( UBound(m_pChildNodes) + m_nIncreaseSize )
      End If
     
      ' Determine if we need to insert into the array or simply
      ' add at the end of the array.
      If nPosition <= m_nCount Then
         Dim nArray(UBound(m_pChildNodes)) As Dword At VarPtr(m_pChildNodes(0))
         Array Insert nArray(nPosition)
      End If   
     
      If nPosition < 1 Then nPosition = 1
      m_pChildNodes(nPosition) = Class "cLinkedListNode"
      m_nCurrentNodeNum = nPosition
   End Method
     
   
   Class Method SetCurrentNodeData( ByVal sKey  As String, _
                                    ByVal nData As Long _
                                    ) As Long

      m_pChildNodes(m_nCurrentNodeNum).sKey  = sKey
     
      If m_nUseStrings Then
         m_zPtr = nData
         m_pChildNodes(m_nCurrentNodeNum).sData = @m_zPtr
      Else
         m_pChildNodes(m_nCurrentNodeNum).nData = nData
      End If
   
   End Method

   

   ' Main interface
   Interface LinkedListInterface: Inherit IUnknown     
   
      Property Get IsEndOfList() As Long
         Property = m_IsEndOfList
      End Property

      Property Get GetCount() As Long
         Property = m_nCount
      End Property

      Property Get UseStrings() As Long
         Property = m_nUseStrings
      End Property
      Property Set UseStrings( ByVal nTrueFalse As Long )
         m_nUseStrings = nTrueFalse
      End Property
     
      Property Get IncreaseSize() As Long
         Property = m_nIncreaseSize
      End Property
      Property Set IncreaseSize( ByVal nIncreaseSize As Long )
         If m_nIncreaseSize <= 0 Then m_nIncreaseSize = 10
         m_nIncreaseSize = nIncreaseSize
      End Property

      Property Get sKey() As String
         Property = m_pChildNodes(m_nCurrentNodeNum).sKey
      End Property
 
      Property Get sData() As String
         Property = m_pChildNodes(m_nCurrentNodeNum).sData
      End Property

      Property Get nData() As Long
         Property = m_pChildNodes(m_nCurrentNodeNum).nData
      End Property

      Property Get CurrentPosition() As Long
         Property = m_nCurrentNodeNum
      End Property

     
      '//
      '//  Add an item to the Linked List
      '//
      Method AddItem( ByVal sKey  As String, _
                      ByVal nData As Long _
                      ) As Long
         ' Create a new node instance at the end of the linked list
         Incr m_nCount
         Me.AddNewNode( m_nCount )
         Me.SetCurrentNodeData( sKey, nData )
      End Method
     
     
      '//
      '//  Add an item to the Linked List before the specified item
      '//
      Method AddItemBefore( ByVal nPosition As Long, _
                            ByVal sKey  As String, _
                            ByVal nData As Long _
                            ) As Long
         Me.AddNewNode( nPosition )
         Me.SetCurrentNodeData( sKey, nData )
         Incr m_nCount
      End Method


      '//
      '//  Add an item to the Linked List after the specified item
      '//
      Method AddItemAfter( ByVal nPosition As Long, _
                           ByVal sKey  As String, _
                           ByVal nData As Long _
                           ) As Long
         Me.AddNewNode( nPosition + 1 )
         Me.SetCurrentNodeData( sKey, nData )
         Incr m_nCount
      End Method


      '//
      '//  Move an item up one position in the Linked List
      '//
      Method MoveUp( ByVal nPosition As Long ) As Long
         If nPosition <= 1 Then Exit Method
         Local pTempNode As LinkedListNodeInterface
         pTempNode = m_pChildNodes(nPosition)
         m_pChildNodes(nPosition) = m_pChildNodes(nPosition-1)
         m_pChildNodes(nPosition-1) = pTempNode
         m_nCurrentNodeNum = nPosition - 1
      End Method


      '//
      '//  Move an item down one position in the Linked List
      '//
      Method MoveDown( ByVal nPosition As Long ) As Long
         If nPosition >= m_nCount Then Exit Method
         Local pTempNode As LinkedListNodeInterface
         pTempNode = m_pChildNodes(nPosition)
         m_pChildNodes(nPosition) = m_pChildNodes(nPosition+1)
         m_pChildNodes(nPosition+1) = pTempNode
         m_nCurrentNodeNum = nPosition + 1
      End Method


      '//
      '//  Find an item based on the Key (case insensitive)
      '//
      Method FindByKey( ByVal sKey As String ) As Long
         Local y As Long
         For y = 1 To m_nCount
            If lstrcmpi( ByCopy m_pChildNodes(y).sKey, ByCopy sKey ) = 0 Then
               m_nCurrentNodeNum = y
               Method = %TRUE
               Exit For
            End If
         Next
      End Method


      '//
      '//  Find an item based on the nData
      '//
      Method FindByData( ByVal nData As Long ) As Long
         Local y As Long
         For y = 1 To m_nCount
            If m_pChildNodes(y).nData = nData Then
               m_nCurrentNodeNum = y
               Method = %TRUE
               Exit For
            End If
         Next
      End Method


      '//
      '//  Remove all items from the Linked List.
      '//
      Method RemoveAll() As Long
         If m_nCount = 0 Then Exit Method
         
         Local y As Long
         
         For y = 1 To UBound(m_pChildNodes)
            Set m_pChildNodes(y) = Nothing
         Next
         
         m_nCount = 0
      End Method
     
     
      '//
      '//  Get the first item in the Linked List
      '//
      Method GetFirst() As Long
         ' Set the current node to the first node in the list
         m_IsEndOfList = %FALSE
         If m_nCount = 0 Then
            m_IsEndOfList = %TRUE
         Else
            m_nCurrentNodeNum = 1
         End If   
      End Method

   
      '//
      '//  Get the next item in the Linked List
      '//
      Method GetNext() As Long
         ' Set the current node to the next node in the list
         If m_nCurrentNodeNum + 1 > m_nCount Then
            m_IsEndOfList = %TRUE
         Else
            Incr m_nCurrentNodeNum
         End If   
      End Method


      '//
      '//  Get the last item in the Linked List
      '//
      Method GetLast() As Long
         ' Set the current node to the last node in the list
         m_IsEndOfList = %FALSE
         If m_nCount = 0 Then
            m_IsEndOfList = %TRUE
         Else
            m_nCurrentNodeNum = m_nCount
         End If   
      End Method


      '//
      '//  Get the previous item in the Linked List
      '//
      Method GetPrevious() As Long
         ' Set the current node to the previous node in the list
         If m_nCurrentNodeNum - 1 < 1 Then
            m_IsEndOfList = %TRUE
         Else
            Decr m_nCurrentNodeNum
         End If   
      End Method



   End Interface

End Class





'//
'// 
'//
Function PBMain() As Long

   Local st As String

   ' Create an instance of the list and add items to it.
   Dim cList As LinkedListInterface
   cList = Class "cLinkedList"

   ' Tell the class that nData is a 32-bit number rather
   ' than a pointer to a string.
   cList.UseStrings = %FALSE
   ' Tell the class how much to increase the list when
   ' it needs to be resized
   cList.IncreaseSize = 100

   
   cList.AddItem "Paul",  5
   cList.AddItem "Tammy", 100
   cList.AddItem "Bob",   200
   cList.AddItem "Mark",  555
   

   ? "List Count =" & Str$(cList.GetCount) & $CrLf & _
     "UseStrings =" & Str$(cList.UseStrings)

   ' Find a key that we know exists (the search is case insensitive)
   If cList.FindByKey( "bob" ) Then
      ? "Found key: " & cList.sKey
   Else
      ? "'bob' Key not found"
   End If   

   ' Look for a key that we know does not exist
   If cList.FindByKey( "somebody" ) Then
      ? "Found key: " & cList.sKey
   Else
      ? "'somebody' Key not found"
   End If   


   ' Look for an item based on nData that we know exists
   If cList.FindByData( 555 ) Then
      ? "Found data: " & Str$(cList.nData)
   Else
      ? "'555' data not found"
   End If   

   ' Look for an item based on nData that we know does not exist
   If cList.FindByData( 999 ) Then
      ? "Found data: " & Str$(cList.nData)
   Else
      ? "'999' data not found"
   End If   



   st = "BEFORE MOVING ITEM" & $CrLf
   
   cList.GetFirst
   Do Until cList.IsEndOfList
      st = st & cList.sKey & "   " & Str$(cList.nData) & $CrLf
      cList.GetNext
   Loop

   st = st & $CrLf & $CrLf & "AFTER MOVING FIRST ITEM DOWN ONE SLOT" & $CrLf
   cList.MoveDown 1
   cList.GetFirst
   Do Until cList.IsEndOfList
      st = st & cList.sKey & "   " & Str$(cList.nData) & $CrLf
      cList.GetNext
   Loop
   
   ? st
   

   st = "AFTER MOVE CURRENT ITEM '" & cList.sKey &  "' UP ONE SLOT" & $CrLf
   cList.MoveUp cList.CurrentPosition
   cList.GetFirst
   Do Until cList.IsEndOfList
      st = st & cList.sKey & "   " & Str$(cList.nData) & $CrLf
      cList.GetNext
   Loop
   
   ? st


   ' Remove all items from the linked list
   cList.RemoveAll


   ? "AFTER REMOVE" & $CrLf & _
     "List Count =" & Str$(cList.GetCount)


   
   ' Tell the class that nData is a 32-bit number rather
   ' than a pointer to a string.
   cList.UseStrings = %TRUE 

   st = "Squires":   cList.AddItem "Paul",  StrPtr(st)
   st = "Poirier":   cList.AddItem "Tammy", StrPtr(st)
   st = "Zale":      cList.AddItem "Bob",   StrPtr(st)
   st = "Tobin":     cList.AddItem "Mark",  StrPtr(st)

   
   ? "List Count =" & Str$(cList.GetCount) & $CrLf & _
     "UseStrings =" & Str$(cList.UseStrings)
   
   st = "Position":      cList.AddItemBefore 1, "New First",  StrPtr(st)
   st = "Position":      cList.AddItemAfter  5, "New Last",   StrPtr(st)

   st = "AFTER ADDING ITEM AT START AND AT END OF LIST" & $CrLf
   cList.GetFirst
   Do Until cList.IsEndOfList
      st = st & cList.sKey & "   " & cList.sData & $CrLf
      cList.GetNext
   Loop

   ? st
   


ExitOut:   

   ? "Completed."

End Function




Paul Squires
FireFly Visual Designer SQLitening Database System JellyFish Pro Editor
http://www.planetsquires.com

José Roca

#1
 
Setting an object to NOTHING doesn't destroy it, just decrements its reference count by 1. The object destroys himself when the reference count is 0.

When you create the Node1, it has a reference count of 1, but when you create Node2 and set a reference to Node1 with m_pCurrentNode.SetNextNode = m_pFirstNode, now Node1 has a reference count of 2. Therefore, to destroy Node1, your have to destroy Node2 first. But if there is a Node3, with a reference to Node2, then you can't destroy Node2 and Node1 until you destroy Node3 first, and so on.

IMO you have chosen an inadequate subject for your first try. Imagine that you want to have two references, PreviousNode and NextNode, to be able to traverse the list forward and backward. As Node1 will hold a reference to Node2, and Node2 to Node1, there is no way to destroy them.

Paul Squires

It was pretty easy to switch to using a dynamic object array within the class. :)


'//
'//  PB9 OOP Single Linked List
'//

%TRUE  = 1
%FALSE = 0

'//
'//  The definition of each node in the Linked List
'//
Class cLinkedListNode
   Instance m_sKey  As String
   Instance m_sData As String
   Instance m_nData As Long

   Interface LinkedListNodeInterface: Inherit IUnknown     
   
      ' Property to Get/Set the 'Key' for the item
      Property Get sKey() As String
         Property = m_sKey
      End Property
      Property Set sKey( ByVal sKey As String )
         m_sKey = sKey
      End Property
 
 
      ' Property to Get/Set the string 'Data' for the item (when UseStrings is TRUE)
      Property Get sData() As String
         Property = m_sData
      End Property
      Property Set sData( ByVal sData As String )
         m_sData = sData
      End Property
 
 
      ' Property to Get/Set the numeric 'Data' for the item (when UseStrings is FALSE)
      Property Get nData() As Long   
         Property = m_nData
      End Property
      Property Set nData( ByVal nData As Long )
         m_nData = nData
      End Property

   End Interface

End Class



'//
'//  The main Linked List class. An instance of this class should
'//  be made in the user's code and will be used to manipulate the
'//  various nodes in the list.
'//
Class cLinkedList
   ' Private instance variables
   Instance m_pChildNodes()   As LinkedListNodeInterface
   Instance m_nCurrentNodeNum As Long
   Instance m_nUseStrings     As Long
   Instance m_IsEndOfList     As Long
   Instance m_nCount          As Long
   Instance m_zPtr            As Asciiz Ptr
   
   ' Main interface
   Interface LinkedListInterface: Inherit IUnknown     
   
      Property Get IsEndOfList() As Long
         Property = m_IsEndOfList
      End Property

      Property Get GetCount() As Long
         Property = m_nCount
      End Property

      Property Get UseStrings() As Long
         Property = m_nUseStrings
      End Property
      Property Set UseStrings( ByVal nTrueFalse As Long )
         m_nUseStrings = nTrueFalse
      End Property
     
      Property Get sKey() As String
         Property = m_pChildNodes(m_nCurrentNodeNum).sKey
      End Property
 
      Property Get sData() As String
         Property = m_pChildNodes(m_nCurrentNodeNum).sData
      End Property

      Property Get nData() As Long
         Property = m_pChildNodes(m_nCurrentNodeNum).nData
      End Property


      '//
      '//  Add an item to the Linked List
      '//
      Method AddItem( ByVal sKey  As String, _
                      ByVal nData As Long _
                      ) As Long
         
         ' Create a new node instance at the end of the linked list
         ' Do we need to make our array bigger?
         If m_nCount + 1 > UBound(m_pChildNodes) Then
            ReDim Preserve m_pChildNodes( UBound(m_pChildNodes) + 10 )
         End If
         
         Incr m_nCount
         m_pChildNodes(m_nCount) = Class "cLinkedListNode"
         
         m_nCurrentNodeNum = m_nCount
         
         m_pChildNodes(m_nCurrentNodeNum).sKey  = sKey
         
         If m_nUseStrings Then
            m_zPtr = nData
            m_pChildNodes(m_nCurrentNodeNum).sData = @m_zPtr
         Else
            m_pChildNodes(m_nCurrentNodeNum).nData = nData
         End If
         
      End Method
     
     
      '//
      '//  Remove all items from the Linked List.
      '//
      Method RemoveAll() As Long
         If m_nCount = 0 Then Exit Method
         
         Local y As Long
         
         For y = 1 To UBound(m_pChildNodes)
            Set m_pChildNodes(y) = Nothing
         Next
         
         m_nCount = 0
      End Method
     
     
      '//
      '//  Get the first item in the Linked List
      '//
      Method GetFirst() As Long
         ' Set the current node to the first node in the list
         m_IsEndOfList = %FALSE
         If m_nCount = 0 Then
            m_IsEndOfList = %TRUE
         Else
            m_nCurrentNodeNum = 1
         End If   
      End Method

   
      '//
      '//  Get the next item in the Linked List
      '//
      Method GetNext() As Long
         ' Set the current node to the next node in the list
         If m_nCurrentNodeNum + 1 > m_nCount Then
            m_IsEndOfList = %TRUE
         Else
            Incr m_nCurrentNodeNum
         End If   
      End Method


   End Interface

End Class




'//
'//  Sample code to test Linked List
'//
Function PBMain() As Long

   ' Create an instance of the list and add items to it.
   Dim cList As LinkedListInterface
   cList = Class "cLinkedList"
   
   ' Tell the class that nData is a 32-bit number rather
   ' than a pointer to a string.
   cList.UseStrings = %FALSE
   
   cList.AddItem "Paul",  5
   cList.AddItem "Tammy", 100
   cList.AddItem "Bob",   200
   cList.AddItem "Mark",  555
   

   ? "List Count =" & Str$(cList.GetCount) & $CrLf & _
     "UseStrings =" & Str$(cList.UseStrings)

   cList.GetFirst
   Do Until cList.IsEndOfList
      ? cList.sKey & $CrLf & Str$(cList.nData)
      cList.GetNext
   Loop

   ' Remove all items from the linked list
   cList.RemoveAll


   ? "AFTER REMOVE" & $CrLf & _
     "List Count =" & Str$(cList.GetCount)


   Local st As String
   
   ' Tell the class that nData is a 32-bit number rather
   ' than a pointer to a string.
   cList.UseStrings = %TRUE 

   st = "Squires":   cList.AddItem "Paul",  StrPtr(st)
   st = "Poirier":   cList.AddItem "Tammy", StrPtr(st)
   st = "Zale":      cList.AddItem "Bob",   StrPtr(st)
   st = "Tobin":     cList.AddItem "Mark",  StrPtr(st)

   
   ? "List Count =" & Str$(cList.GetCount) & $CrLf & _
     "UseStrings =" & Str$(cList.UseStrings)
   
   cList.GetFirst
   Do Until cList.IsEndOfList
      ? cList.sKey & $CrLf & cList.sData
      cList.GetNext
   Loop
   

   ? "Completed."

End Function





   
Paul Squires
FireFly Visual Designer SQLitening Database System JellyFish Pro Editor
http://www.planetsquires.com

Theo Gottwald

I think this is a direction, where the new objects can be most useful.
They can use dynamic strings inside, which was not possible before, using UDT's.

Now is much more easy to define complex User Data structures, including dynamic strings.

Paul Squires

Exactly Theo - being able to have dynamic strings and dynamic arrays in the Class is a HUGE advantage for my style of programming. No more will I have to manually allocate/deallocate strings in TYPE's. I have been working with Classes all day and I love it. Bob and Co. have done an outstanding job implementing this. Once I get the basics down then hopefully I can move into areas of COM that Jose plays with all the time.

Paul Squires
FireFly Visual Designer SQLitening Database System JellyFish Pro Editor
http://www.planetsquires.com

James C. Fuller

Paul,
  Did you look at the IDictionary sample I posted on the PB site comparing it to your hash table? It's faster up to about 25k items ( according to José).
http://www.powerbasic.com/support/pbforums/showthread.php?t=38402&page=2

I think it might be an area to investigate instead of dynamic allocation? And you can store anything include COM Objects.

James

Theo Gottwald

Maybe you can also post it here, together with an explanation?

I have looked at it, but it was no way clear to me.

If I define my own Data-Structure in an Object the result is very clear.


James C. Fuller

Here's a simple one that can be useful for debugging callback messages.

James

'=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
'SED_PBWIN
'=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
'Dictionary Example
'Good for checking message #'s with string name
'******************************************************************************
'                                    James C. Fuller
'                                    August 8, 2008
'                                 jcfuller@jcfuller.com
'******************************************************************************
#COMPILE EXE
#INCLUDE ONCE "Windows.inc"
#INCLUDE ONCE "SCRRUN.INC"

FUNCTION CreateDict() AS IDictionary
LOCAL oDic AS IDictionary
LOCAL v1,v2 AS VARIANT
oDic = NEWCOM $PROGID_ScriptingDictionary
    IF ISNOTHING(oDic) THEN EXIT FUNCTION

v1 = %WM_USER : v2 = "%WM_USER"
oDic.Add(v1,v2)
v1 = %WM_CREATE : v2 = "%WM_CREATE"
oDic.Add(v1,v2)
v1 = %WM_DESTROY : v2 = "%WM_DESTROY"
oDic.Add(v1,v2)
v1 = %WM_ENABLE : v2 = "%WM_ENABLE"
oDic.Add(v1,v2)
v1 = %WM_MOVE : v2 = "%WM_MOVE"
oDic.Add(v1,v2)
v1 = %WM_SIZE : v2 = "%WM_SIZE"
oDic.Add(v1,v2)
v1 = %WM_ACTIVATE : v2 = "%WM_ACTIVATE"
oDic.Add(v1,v2)
v1 = %WM_SHOWWINDOW : v2 = "%WM_SHOWWINDOW"
oDic.Add(v1,v2)
v1 = %WM_SETFOCUS : v2 = "%WM_SETFOCUS"
oDic.Add(v1,v2)
v1 = %WM_KILLFOCUS : v2 = "%WM_KILLFOCUS"
oDic.Add(v1,v2)
v1 = %WM_SETREDRAW : v2 = "%WM_SETREDRAW"
oDic.Add(v1,v2)
v1 = %WM_SETTEXT : v2 = "%WM_SETTEXT"
oDic.Add(v1,v2)
v1 = %WM_GETTEXT : v2 = "%WM_GETTEXT"
oDic.Add(v1,v2)
v1 = %WM_GETTEXTLENGTH : v2 = "%WM_GETTEXTLENGTH"
oDic.Add(v1,v2)
v1 = %WM_PAINT : v2 = "%WM_PAINT"
oDic.Add(v1,v2)
v1 = %WM_CLOSE : v2 = "%WM_CLOSE"
oDic.Add(v1,v2)
v1 = %WM_QUERYENDSESSION : v2 = "%WM_QUERYENDSESSION"
oDic.Add(v1,v2)
v1 = %WM_QUIT : v2 = "%WM_QUIT"
oDic.Add(v1,v2)
v1 = %WM_QUERYOPEN : v2 = "%WM_QUERYOPEN"
oDic.Add(v1,v2)
v1 = %WM_ERASEBKGND : v2 = "%WM_ERASEBKGND"
oDic.Add(v1,v2)
v1 = %WM_SYSCOLORCHANGE : v2 = "%WM_SYSCOLORCHANGE"
oDic.Add(v1,v2)
v1 = %WM_ENDSESSION : v2 = "%WM_ENDSESSION"
oDic.Add(v1,v2)
v1 = %WM_WININICHANGE : v2 = "%WM_WININICHANGE"
oDic.Add(v1,v2)
v1 = %WM_SETTINGCHANGE : v2 = "%WM_SETTINGCHANGE"
oDic.Add(v1,v2)
v1 = %WM_DEVMODECHANGE : v2 = "%WM_DEVMODECHANGE"
oDic.Add(v1,v2)
v1 = %WM_ACTIVATEAPP : v2 = "%WM_ACTIVATEAPP"
oDic.Add(v1,v2)
v1 = %WM_FONTCHANGE : v2 = "%WM_FONTCHANGE"
oDic.Add(v1,v2)
v1 = %WM_TIMECHANGE : v2 = "%WM_TIMECHANGE"
oDic.Add(v1,v2)
v1 = %WM_CANCELMODE : v2 = "%WM_CANCELMODE"
oDic.Add(v1,v2)
v1 = %WM_SETCURSOR : v2 = "%WM_SETCURSOR"
oDic.Add(v1,v2)
v1 = %WM_HELP : v2 = "%WM_HELP"
oDic.Add(v1,v2)
v1 = %WM_MOUSEACTIVATE : v2 = "%WM_MOUSEACTIVATE"
oDic.Add(v1,v2)
v1 = %WM_CHILDACTIVATE : v2 = "%WM_CHILDACTIVATE"
oDic.Add(v1,v2)
v1 = %WM_QUEUESYNC : v2 = "%WM_QUEUESYNC"
oDic.Add(v1,v2)
v1 = %WM_GETMINMAXINFO : v2 = "%WM_GETMINMAXINFO"
oDic.Add(v1,v2)
v1 = %WM_PAINTICON : v2 = "%WM_PAINTICON"
oDic.Add(v1,v2)
v1 = %WM_ICONERASEBKGND : v2 = "%WM_ICONERASEBKGND"
oDic.Add(v1,v2)
v1 = %WM_NEXTDLGCTL : v2 = "%WM_NEXTDLGCTL"
oDic.Add(v1,v2)
v1 = %WM_SPOOLERSTATUS : v2 = "%WM_SPOOLERSTATUS"
oDic.Add(v1,v2)
v1 = %WM_DRAWITEM : v2 = "%WM_DRAWITEM"
oDic.Add(v1,v2)
v1 = %WM_MEASUREITEM : v2 = "%WM_MEASUREITEM"
oDic.Add(v1,v2)
v1 = %WM_DELETEITEM : v2 = "%WM_DELETEITEM"
oDic.Add(v1,v2)
v1 = %WM_VKEYTOITEM : v2 = "%WM_VKEYTOITEM"
oDic.Add(v1,v2)
v1 = %WM_CHARTOITEM : v2 = "%WM_CHARTOITEM"
oDic.Add(v1,v2)
v1 = %WM_SETFONT : v2 = "%WM_SETFONT"
oDic.Add(v1,v2)
v1 = %WM_GETFONT : v2 = "%WM_GETFONT"
oDic.Add(v1,v2)
v1 = %WM_SETHOTKEY : v2 = "%WM_SETHOTKEY"
oDic.Add(v1,v2)
v1 = %WM_GETHOTKEY : v2 = "%WM_GETHOTKEY"
oDic.Add(v1,v2)
v1 = %WM_QUERYDRAGICON : v2 = "%WM_QUERYDRAGICON"
oDic.Add(v1,v2)
v1 = %WM_COMPAREITEM : v2 = "%WM_COMPAREITEM"
oDic.Add(v1,v2)
v1 = %WM_COMPACTING : v2 = "%WM_COMPACTING"
oDic.Add(v1,v2)
v1 = %WM_OTHERWINDOWCREATED : v2 = "%WM_OTHERWINDOWCREATED"
oDic.Add(v1,v2)
v1 = %WM_OTHERWINDOWDESTROYED : v2 = "%WM_OTHERWINDOWDESTROYED"
oDic.Add(v1,v2)
v1 = %WM_COMMNOTIFY : v2 = "%WM_COMMNOTIFY"
oDic.Add(v1,v2)
v1 = %WM_WINDOWPOSCHANGING : v2 = "%WM_WINDOWPOSCHANGING"
oDic.Add(v1,v2)
v1 = %WM_WINDOWPOSCHANGED : v2 = "%WM_WINDOWPOSCHANGED"
oDic.Add(v1,v2)
v1 = %WM_POWER : v2 = "%WM_POWER"
oDic.Add(v1,v2)
v1 = %WM_COPYDATA : v2 = "%WM_COPYDATA"
oDic.Add(v1,v2)
v1 = %WM_CANCELJOURNAL : v2 = "%WM_CANCELJOURNAL"
oDic.Add(v1,v2)
v1 = %WM_NOTIFY : v2 = "%WM_NOTIFY"
oDic.Add(v1,v2)
v1 = %WM_INPUTLANGUAGECHANGEREQUEST : v2 = "%WM_INPUTLANGUAGECHANGEREQUEST"
oDic.Add(v1,v2)
v1 = %WM_INPUTLANGUAGECHANGE : v2 = "%WM_INPUTLANGUAGECHANGE"
oDic.Add(v1,v2)
v1 = %WM_TCARD : v2 = "%WM_TCARD"
oDic.Add(v1,v2)
v1 = %WM_USERCHANGED : v2 = "%WM_USERCHANGED"
oDic.Add(v1,v2)
v1 = %WM_NOTIFYFORMAT : v2 = "%WM_NOTIFYFORMAT"
oDic.Add(v1,v2)
v1 = %WM_CONTEXTMENU : v2 = "%WM_CONTEXTMENU"
oDic.Add(v1,v2)
v1 = %WM_STYLECHANGING : v2 = "%WM_STYLECHANGING"
oDic.Add(v1,v2)
v1 = %WM_STYLECHANGED : v2 = "%WM_STYLECHANGED"
oDic.Add(v1,v2)
v1 = %WM_DISPLAYCHANGE : v2 = "%WM_DISPLAYCHANGE"
oDic.Add(v1,v2)
v1 = %WM_GETICON : v2 = "%WM_GETICON"
oDic.Add(v1,v2)
v1 = %WM_SETICON : v2 = "%WM_SETICON"
oDic.Add(v1,v2)
v1 = %WM_NCCREATE : v2 = "%WM_NCCREATE"
oDic.Add(v1,v2)
v1 = %WM_NCDESTROY : v2 = "%WM_NCDESTROY"
oDic.Add(v1,v2)
v1 = %WM_NCCALCSIZE : v2 = "%WM_NCCALCSIZE"
oDic.Add(v1,v2)
v1 = %WM_NCHITTEST : v2 = "%WM_NCHITTEST"
oDic.Add(v1,v2)
v1 = %WM_NCPAINT : v2 = "%WM_NCPAINT"
oDic.Add(v1,v2)
v1 = %WM_NCACTIVATE : v2 = "%WM_NCACTIVATE"
oDic.Add(v1,v2)
v1 = %WM_GETDLGCODE : v2 = "%WM_GETDLGCODE"
oDic.Add(v1,v2)
v1 = %WM_NCMOUSEMOVE : v2 = "%WM_NCMOUSEMOVE"
oDic.Add(v1,v2)
v1 = %WM_NCLBUTTONDOWN : v2 = "%WM_NCLBUTTONDOWN"
oDic.Add(v1,v2)
v1 = %WM_NCLBUTTONUP : v2 = "%WM_NCLBUTTONUP"
oDic.Add(v1,v2)
v1 = %WM_NCLBUTTONDBLCLK : v2 = "%WM_NCLBUTTONDBLCLK"
oDic.Add(v1,v2)
v1 = %WM_NCRBUTTONDOWN : v2 = "%WM_NCRBUTTONDOWN"
oDic.Add(v1,v2)
v1 = %WM_NCRBUTTONUP : v2 = "%WM_NCRBUTTONUP"
oDic.Add(v1,v2)
v1 = %WM_NCRBUTTONDBLCLK : v2 = "%WM_NCRBUTTONDBLCLK"
oDic.Add(v1,v2)
v1 = %WM_NCMBUTTONDOWN : v2 = "%WM_NCMBUTTONDOWN"
oDic.Add(v1,v2)
v1 = %WM_NCMBUTTONUP : v2 = "%WM_NCMBUTTONUP"
oDic.Add(v1,v2)
v1 = %WM_NCMBUTTONDBLCLK : v2 = "%WM_NCMBUTTONDBLCLK"
oDic.Add(v1,v2)
v1 = %WM_KEYDOWN : v2 = "%WM_KEYDOWN"
oDic.Add(v1,v2)
v1 = %WM_KEYFIRST : v2 = "%WM_KEYFIRST"
oDic.Add(v1,v2)
v1 = %WM_KEYUP : v2 = "%WM_KEYUP"
oDic.Add(v1,v2)
v1 = %WM_CHAR : v2 = "%WM_CHAR"
oDic.Add(v1,v2)
v1 = %WM_DEADCHAR : v2 = "%WM_DEADCHAR"
oDic.Add(v1,v2)
v1 = %WM_SYSKEYDOWN : v2 = "%WM_SYSKEYDOWN"
oDic.Add(v1,v2)
v1 = %WM_SYSKEYUP : v2 = "%WM_SYSKEYUP"
oDic.Add(v1,v2)
v1 = %WM_SYSCHAR : v2 = "%WM_SYSCHAR"
oDic.Add(v1,v2)
v1 = %WM_SYSDEADCHAR : v2 = "%WM_SYSDEADCHAR"
oDic.Add(v1,v2)
v1 = %WM_KEYLAST : v2 = "%WM_KEYLAST"
oDic.Add(v1,v2)
v1 = %WM_INITDIALOG : v2 = "%WM_INITDIALOG"
oDic.Add(v1,v2)
v1 = %WM_COMMAND : v2 = "%WM_COMMAND"
oDic.Add(v1,v2)
v1 = %WM_SYSCOMMAND : v2 = "%WM_SYSCOMMAND"
oDic.Add(v1,v2)
v1 = %WM_TIMER : v2 = "%WM_TIMER"
oDic.Add(v1,v2)
v1 = %WM_HSCROLL : v2 = "%WM_HSCROLL"
oDic.Add(v1,v2)
v1 = %WM_VSCROLL : v2 = "%WM_VSCROLL"
oDic.Add(v1,v2)
v1 = %WM_INITMENU : v2 = "%WM_INITMENU"
oDic.Add(v1,v2)
v1 = %WM_INITMENUPOPUP : v2 = "%WM_INITMENUPOPUP"
oDic.Add(v1,v2)
v1 = %WM_MENUSELECT : v2 = "%WM_MENUSELECT"
oDic.Add(v1,v2)
v1 = %WM_MENUCHAR : v2 = "%WM_MENUCHAR"
oDic.Add(v1,v2)
v1 = %WM_ENTERIDLE : v2 = "%WM_ENTERIDLE"
oDic.Add(v1,v2)
v1 = %WM_CTLCOLORMSGBOX : v2 = "%WM_CTLCOLORMSGBOX"
oDic.Add(v1,v2)
v1 = %WM_CTLCOLOREDIT : v2 = "%WM_CTLCOLOREDIT"
oDic.Add(v1,v2)
v1 = %WM_CTLCOLORLISTBOX : v2 = "%WM_CTLCOLORLISTBOX"
oDic.Add(v1,v2)
v1 = %WM_CTLCOLORBTN : v2 = "%WM_CTLCOLORBTN"
oDic.Add(v1,v2)
v1 = %WM_CTLCOLORDLG : v2 = "%WM_CTLCOLORDLG"
oDic.Add(v1,v2)
v1 = %WM_CTLCOLORSCROLLBAR : v2 = "%WM_CTLCOLORSCROLLBAR"
oDic.Add(v1,v2)
v1 = %WM_CTLCOLORSTATIC : v2 = "%WM_CTLCOLORSTATIC"
oDic.Add(v1,v2)
v1 = %WM_MOUSEMOVE : v2 = "%WM_MOUSEMOVE"
oDic.Add(v1,v2)
v1 = %WM_MOUSEFIRST : v2 = "%WM_MOUSEFIRST"
oDic.Add(v1,v2)
v1 = %WM_LBUTTONDOWN : v2 = "%WM_LBUTTONDOWN"
oDic.Add(v1,v2)
v1 = %WM_LBUTTONUP : v2 = "%WM_LBUTTONUP"
oDic.Add(v1,v2)
v1 = %WM_LBUTTONDBLCLK : v2 = "%WM_LBUTTONDBLCLK"
oDic.Add(v1,v2)
v1 = %WM_RBUTTONDOWN : v2 = "%WM_RBUTTONDOWN"
oDic.Add(v1,v2)
v1 = %WM_RBUTTONUP : v2 = "%WM_RBUTTONUP"
oDic.Add(v1,v2)
v1 = %WM_RBUTTONDBLCLK : v2 = "%WM_RBUTTONDBLCLK"
oDic.Add(v1,v2)
v1 = %WM_MBUTTONDOWN : v2 = "%WM_MBUTTONDOWN"
oDic.Add(v1,v2)
v1 = %WM_MBUTTONUP : v2 = "%WM_MBUTTONUP"
oDic.Add(v1,v2)
v1 = %WM_MBUTTONDBLCLK : v2 = "%WM_MBUTTONDBLCLK"
oDic.Add(v1,v2)
v1 = %WM_MOUSEWHEEL : v2 = "%WM_MOUSEWHEEL"
oDic.Add(v1,v2)
v1 = %WM_MOUSELAST : v2 = "%WM_MOUSELAST"
oDic.Add(v1,v2)
v1 = %WM_PARENTNOTIFY : v2 = "%WM_PARENTNOTIFY"
oDic.Add(v1,v2)
v1 = %WM_ENTERMENULOOP : v2 = "%WM_ENTERMENULOOP"
oDic.Add(v1,v2)
v1 = %WM_EXITMENULOOP : v2 = "%WM_EXITMENULOOP"
oDic.Add(v1,v2)
v1 = %WM_SIZING : v2 = "%WM_SIZING"
oDic.Add(v1,v2)
v1 = %WM_CAPTURECHANGED : v2 = "%WM_CAPTURECHANGED"
oDic.Add(v1,v2)
v1 = %WM_MOVING : v2 = "%WM_MOVING"
oDic.Add(v1,v2)
v1 = %WM_POWERBROADCAST : v2 = "%WM_POWERBROADCAST"
oDic.Add(v1,v2)
v1 = %WM_DEVICECHANGE : v2 = "%WM_DEVICECHANGE"
oDic.Add(v1,v2)
v1 = %WM_MDICREATE : v2 = "%WM_MDICREATE"
oDic.Add(v1,v2)
v1 = %WM_MDIDESTROY : v2 = "%WM_MDIDESTROY"
oDic.Add(v1,v2)
v1 = %WM_MDIACTIVATE : v2 = "%WM_MDIACTIVATE"
oDic.Add(v1,v2)
v1 = %WM_MDIRESTORE : v2 = "%WM_MDIRESTORE"
oDic.Add(v1,v2)
v1 = %WM_MDINEXT : v2 = "%WM_MDINEXT"
oDic.Add(v1,v2)
v1 = %WM_MDIMAXIMIZE : v2 = "%WM_MDIMAXIMIZE"
oDic.Add(v1,v2)
v1 = %WM_MDITILE : v2 = "%WM_MDITILE"
oDic.Add(v1,v2)
v1 = %WM_MDICASCADE : v2 = "%WM_MDICASCADE"
oDic.Add(v1,v2)
v1 = %WM_MDIICONARRANGE : v2 = "%WM_MDIICONARRANGE"
oDic.Add(v1,v2)
v1 = %WM_MDIGETACTIVE : v2 = "%WM_MDIGETACTIVE"
oDic.Add(v1,v2)
v1 = %WM_MDISETMENU : v2 = "%WM_MDISETMENU"
oDic.Add(v1,v2)
v1 = %WM_DROPFILES : v2 = "%WM_DROPFILES"
oDic.Add(v1,v2)
v1 = %WM_MDIREFRESHMENU : v2 = "%WM_MDIREFRESHMENU"
oDic.Add(v1,v2)
v1 = %WM_MOUSEHOVER : v2 = "%WM_MOUSEHOVER"
oDic.Add(v1,v2)
v1 = %WM_MOUSELEAVE : v2 = "%WM_MOUSELEAVE"
oDic.Add(v1,v2)
v1 = %WM_CUT : v2 = "%WM_CUT"
oDic.Add(v1,v2)
v1 = %WM_COPY : v2 = "%WM_COPY"
oDic.Add(v1,v2)
v1 = %WM_PASTE : v2 = "%WM_PASTE"
oDic.Add(v1,v2)
v1 = %WM_CLEAR : v2 = "%WM_CLEAR"
oDic.Add(v1,v2)
v1 = %WM_UNDO : v2 = "%WM_UNDO"
oDic.Add(v1,v2)
v1 = %WM_RENDERFORMAT : v2 = "%WM_RENDERFORMAT"
oDic.Add(v1,v2)
v1 = %WM_RENDERALLFORMATS : v2 = "%WM_RENDERALLFORMATS"
oDic.Add(v1,v2)
v1 = %WM_DESTROYCLIPBOARD : v2 = "%WM_DESTROYCLIPBOARD"
oDic.Add(v1,v2)
v1 = %WM_DRAWCLIPBOARD : v2 = "%WM_DRAWCLIPBOARD"
oDic.Add(v1,v2)
v1 = %WM_PAINTCLIPBOARD : v2 = "%WM_PAINTCLIPBOARD"
oDic.Add(v1,v2)
v1 = %WM_VSCROLLCLIPBOARD : v2 = "%WM_VSCROLLCLIPBOARD"
oDic.Add(v1,v2)
v1 = %WM_SIZECLIPBOARD : v2 = "%WM_SIZECLIPBOARD"
oDic.Add(v1,v2)
v1 = %WM_ASKCBFORMATNAME : v2 = "%WM_ASKCBFORMATNAME"
oDic.Add(v1,v2)
v1 = %WM_CHANGECBCHAIN : v2 = "%WM_CHANGECBCHAIN"
oDic.Add(v1,v2)
v1 = %WM_HSCROLLCLIPBOARD : v2 = "%WM_HSCROLLCLIPBOARD"
oDic.Add(v1,v2)
v1 = %WM_QUERYNEWPALETTE : v2 = "%WM_QUERYNEWPALETTE"
oDic.Add(v1,v2)
v1 = %WM_PALETTEISCHANGING : v2 = "%WM_PALETTEISCHANGING"
oDic.Add(v1,v2)
v1 = %WM_PALETTECHANGED : v2 = "%WM_PALETTECHANGED"
oDic.Add(v1,v2)
v1 = %WM_HOTKEY : v2 = "%WM_HOTKEY"
oDic.Add(v1,v2)
v1 = %WM_PRINTCLIENT : v2 = "%WM_PRINTCLIENT"
oDic.Add(v1,v2)
v1 = %WM_PENWINFIRST : v2 = "%WM_PENWINFIRST"
oDic.Add(v1,v2)
v1 = %WM_PENWINLAST : v2 = "%WM_PENWINLAST"
oDic.Add(v1,v2)
v1 = %WM_ENTERSIZEMOVE : v2 = "%WM_ENTERSIZEMOVE"
oDic.Add(v1,v2)
v1 = %WM_EXITSIZEMOVE : v2 = "%WM_EXITSIZEMOVE"
oDic.Add(v1,v2)
v1 = %WM_NULL : v2 = "%WM_NULL"
oDic.Add(v1,v2)
v1 = %WM_IME_STARTCOMPOSITION : v2 = "%WM_IME_STARTCOMPOSITION"
oDic.Add(v1,v2)
v1 = %WM_IME_ENDCOMPOSITION : v2 = "%WM_IME_ENDCOMPOSITION"
oDic.Add(v1,v2)
v1 = %WM_IME_COMPOSITION : v2 = "%WM_IME_COMPOSITION"
oDic.Add(v1,v2)
v1 = %WM_IME_KEYLAST : v2 = "%WM_IME_KEYLAST"
oDic.Add(v1,v2)
v1 = %WM_IME_SETCONTEXT : v2 = "%WM_IME_SETCONTEXT"
oDic.Add(v1,v2)
v1 = %WM_IME_NOTIFY : v2 = "%WM_IME_NOTIFY"
oDic.Add(v1,v2)
v1 = %WM_IME_CONTROL : v2 = "%WM_IME_CONTROL"
oDic.Add(v1,v2)
v1 = %WM_IME_COMPOSITIONFULL : v2 = "%WM_IME_COMPOSITIONFULL"
oDic.Add(v1,v2)
v1 = %WM_IME_SELECT : v2 = "%WM_IME_SELECT"
oDic.Add(v1,v2)
v1 = %WM_IME_CHAR : v2 = "%WM_IME_CHAR"
oDic.Add(v1,v2)
v1 = %WM_IME_REQUEST : v2 = "%WM_IME_REQUEST"
oDic.Add(v1,v2)
v1 = %WM_IME_KEYDOWN : v2 = "%WM_IME_KEYDOWN"
oDic.Add(v1,v2)
v1 = %WM_IME_KEYUP : v2 = "%WM_IME_KEYUP"
oDic.Add(v1,v2)
FUNCTION = oDic
END FUNCTION
'==============================================================================
FUNCTION PBMAIN() AS LONG
LOCAL oDic AS IDictionary
LOCAL v1,v2 AS VARIANT

oDic = CreateDict
IF ISNOTHING(oDic) THEN
?" No oDic"
EXIT FUNCTION
END IF

v1 = %WM_IME_KEYUP
IF oDic.Exists(v1) = 0 THEN
? "No Entry"
ELSE
v2 = oDic.Item(v1)
?  "v2 = " + VARIANT$(v2)
END IF

END FUNCTION



Theo Gottwald

What Limitations daoes it have per element?
Maximum Lenght?
Only NULL-Termianted?

Or would it eat a String up to 2 GB if I set "v2" to this string?
And will I get this string back?

Or is this just for short strings?

Paul Squires

Here is the code to the linked list that I completed yesterday. It works well but I'm not sure if I would use it over my existing linked list code - maybe someone will find use for it.


'//
'//  PB9 OOP Single Linked List
'//

#Include Once "win32api.inc"



'//
'//  The definition of each node in the Linked List
'//
Class cLinkedListNode
   Instance m_sKey  As String
   Instance m_sData As String
   Instance m_nData As Long

   Interface LinkedListNodeInterface: Inherit IUnknown     
   
      ' Property to Get/Set the 'Key' for the item
      Property Get sKey() As String
         Property = m_sKey
      End Property
      Property Set sKey( ByVal sKey As String )
         m_sKey = sKey
      End Property
 
 
      ' Property to Get/Set the string 'Data' for the item (when UseStrings is TRUE)
      Property Get sData() As String
         Property = m_sData
      End Property
      Property Set sData( ByVal sData As String )
         m_sData = sData
      End Property
 
 
      ' Property to Get/Set the numeric 'Data' for the item (when UseStrings is FALSE)
      Property Get nData() As Long   
         Property = m_nData
      End Property
      Property Set nData( ByVal nData As Long )
         m_nData = nData
      End Property

   End Interface

End Class



'//
'//  The main Linked List class. An instance of this class should
'//  be made in the user's code and will be used to manipulate the
'//  various nodes in the list.
'//
Class cLinkedList
   ' Private instance variables
   Instance m_pChildNodes()   As LinkedListNodeInterface
   Instance m_nCurrentNodeNum As Long
   Instance m_nIncreaseSize   As Long
   Instance m_nUseStrings     As Long
   Instance m_IsEndOfList     As Long
   Instance m_nCount          As Long
   Instance m_zPtr            As Asciiz Ptr
   
   Class Method AddNewNode( ByVal nPosition As Long ) As Long
      Local y As Long
     
      ' Create a new node instance at the end of the linked list
      ' Do we need to make our array bigger?
      If m_nCount + 1 > UBound(m_pChildNodes) Then
         If m_nIncreaseSize = 0 Then m_nIncreaseSize = 100
         ReDim Preserve m_pChildNodes( UBound(m_pChildNodes) + m_nIncreaseSize )
      End If
     
      ' Determine if we need to insert into the array or simply
      ' add at the end of the array.
      If nPosition <= m_nCount Then
         Dim nArray(UBound(m_pChildNodes)) As Dword At VarPtr(m_pChildNodes(0))
         Array Insert nArray(nPosition)
      End If   
     
      If nPosition < 1 Then nPosition = 1
      m_pChildNodes(nPosition) = Class "cLinkedListNode"
      m_nCurrentNodeNum = nPosition
   End Method
     
   
   Class Method SetCurrentNodeData( ByVal sKey  As String, _
                                    ByVal nData As Long _
                                    ) As Long

      m_pChildNodes(m_nCurrentNodeNum).sKey  = sKey
     
      If m_nUseStrings Then
         m_zPtr = nData
         m_pChildNodes(m_nCurrentNodeNum).sData = @m_zPtr
      Else
         m_pChildNodes(m_nCurrentNodeNum).nData = nData
      End If
   
   End Method

   

   ' Main interface
   Interface LinkedListInterface: Inherit IUnknown     
   
      Property Get IsEndOfList() As Long
         Property = m_IsEndOfList
      End Property

      Property Get GetCount() As Long
         Property = m_nCount
      End Property

      Property Get UseStrings() As Long
         Property = m_nUseStrings
      End Property
      Property Set UseStrings( ByVal nTrueFalse As Long )
         m_nUseStrings = nTrueFalse
      End Property
     
      Property Get IncreaseSize() As Long
         Property = m_nIncreaseSize
      End Property
      Property Set IncreaseSize( ByVal nIncreaseSize As Long )
         If m_nIncreaseSize <= 0 Then m_nIncreaseSize = 10
         m_nIncreaseSize = nIncreaseSize
      End Property

      Property Get sKey() As String
         Property = m_pChildNodes(m_nCurrentNodeNum).sKey
      End Property
 
      Property Get sData() As String
         Property = m_pChildNodes(m_nCurrentNodeNum).sData
      End Property

      Property Get nData() As Long
         Property = m_pChildNodes(m_nCurrentNodeNum).nData
      End Property

      Property Get CurrentPosition() As Long
         Property = m_nCurrentNodeNum
      End Property

     
      '//
      '//  Add an item to the Linked List
      '//
      Method AddItem( ByVal sKey  As String, _
                      ByVal nData As Long _
                      ) As Long
         ' Create a new node instance at the end of the linked list
         Incr m_nCount
         Me.AddNewNode( m_nCount )
         Me.SetCurrentNodeData( sKey, nData )
      End Method
     
     
      '//
      '//  Add an item to the Linked List before the specified item
      '//
      Method AddItemBefore( ByVal nPosition As Long, _
                            ByVal sKey  As String, _
                            ByVal nData As Long _
                            ) As Long
         Me.AddNewNode( nPosition )
         Me.SetCurrentNodeData( sKey, nData )
         Incr m_nCount
      End Method


      '//
      '//  Add an item to the Linked List after the specified item
      '//
      Method AddItemAfter( ByVal nPosition As Long, _
                           ByVal sKey  As String, _
                           ByVal nData As Long _
                           ) As Long
         Me.AddNewNode( nPosition + 1 )
         Me.SetCurrentNodeData( sKey, nData )
         Incr m_nCount
      End Method


      '//
      '//  Move an item up one position in the Linked List
      '//
      Method MoveUp( ByVal nPosition As Long ) As Long
         If nPosition <= 1 Then Exit Method
         Local pTempNode As LinkedListNodeInterface
         pTempNode = m_pChildNodes(nPosition)
         m_pChildNodes(nPosition) = m_pChildNodes(nPosition-1)
         m_pChildNodes(nPosition-1) = pTempNode
         m_nCurrentNodeNum = nPosition - 1
      End Method


      '//
      '//  Move an item down one position in the Linked List
      '//
      Method MoveDown( ByVal nPosition As Long ) As Long
         If nPosition >= m_nCount Then Exit Method
         Local pTempNode As LinkedListNodeInterface
         pTempNode = m_pChildNodes(nPosition)
         m_pChildNodes(nPosition) = m_pChildNodes(nPosition+1)
         m_pChildNodes(nPosition+1) = pTempNode
         m_nCurrentNodeNum = nPosition + 1
      End Method


      '//
      '//  Find an item based on the Key (case insensitive)
      '//
      Method FindByKey( ByVal sKey As String ) As Long
         Local y As Long
         For y = 1 To m_nCount
            If lstrcmpi( ByCopy m_pChildNodes(y).sKey, ByCopy sKey ) = 0 Then
               m_nCurrentNodeNum = y
               Method = %TRUE
               Exit For
            End If
         Next
      End Method


      '//
      '//  Find an item based on the nData
      '//
      Method FindByData( ByVal nData As Long ) As Long
         Local y As Long
         For y = 1 To m_nCount
            If m_pChildNodes(y).nData = nData Then
               m_nCurrentNodeNum = y
               Method = %TRUE
               Exit For
            End If
         Next
      End Method


      '//
      '//  Remove all items from the Linked List.
      '//
      Method RemoveAll() As Long
         If m_nCount = 0 Then Exit Method
         
         Local y As Long
         
         For y = 1 To UBound(m_pChildNodes)
            Set m_pChildNodes(y) = Nothing
         Next
         
         m_nCount = 0
      End Method
     
     
      '//
      '//  Get the first item in the Linked List
      '//
      Method GetFirst() As Long
         ' Set the current node to the first node in the list
         m_IsEndOfList = %FALSE
         If m_nCount = 0 Then
            m_IsEndOfList = %TRUE
         Else
            m_nCurrentNodeNum = 1
         End If   
      End Method

   
      '//
      '//  Get the next item in the Linked List
      '//
      Method GetNext() As Long
         ' Set the current node to the next node in the list
         If m_nCurrentNodeNum + 1 > m_nCount Then
            m_IsEndOfList = %TRUE
         Else
            Incr m_nCurrentNodeNum
         End If   
      End Method


      '//
      '//  Get the last item in the Linked List
      '//
      Method GetLast() As Long
         ' Set the current node to the last node in the list
         m_IsEndOfList = %FALSE
         If m_nCount = 0 Then
            m_IsEndOfList = %TRUE
         Else
            m_nCurrentNodeNum = m_nCount
         End If   
      End Method


      '//
      '//  Get the previous item in the Linked List
      '//
      Method GetPrevious() As Long
         ' Set the current node to the previous node in the list
         If m_nCurrentNodeNum - 1 < 1 Then
            m_IsEndOfList = %TRUE
         Else
            Decr m_nCurrentNodeNum
         End If   
      End Method



   End Interface

End Class





'//
'// 
'//
Function PBMain() As Long

   Local st As String

   ' Create an instance of the list and add items to it.
   Dim cList As LinkedListInterface
   cList = Class "cLinkedList"

   ' Tell the class that nData is a 32-bit number rather
   ' than a pointer to a string.
   cList.UseStrings = %FALSE
   ' Tell the class how much to increase the list when
   ' it needs to be resized
   cList.IncreaseSize = 100

   
   cList.AddItem "Paul",  5
   cList.AddItem "Tammy", 100
   cList.AddItem "Bob",   200
   cList.AddItem "Mark",  555
   

   ? "List Count =" & Str$(cList.GetCount) & $CrLf & _
     "UseStrings =" & Str$(cList.UseStrings)

   ' Find a key that we know exists (the search is case insensitive)
   If cList.FindByKey( "bob" ) Then
      ? "Found key: " & cList.sKey
   Else
      ? "'bob' Key not found"
   End If   

   ' Look for a key that we know does not exist
   If cList.FindByKey( "somebody" ) Then
      ? "Found key: " & cList.sKey
   Else
      ? "'somebody' Key not found"
   End If   


   ' Look for an item based on nData that we know exists
   If cList.FindByData( 555 ) Then
      ? "Found data: " & Str$(cList.nData)
   Else
      ? "'555' data not found"
   End If   

   ' Look for an item based on nData that we know does not exist
   If cList.FindByData( 999 ) Then
      ? "Found data: " & Str$(cList.nData)
   Else
      ? "'999' data not found"
   End If   



   st = "BEFORE MOVING ITEM" & $CrLf
   
   cList.GetFirst
   Do Until cList.IsEndOfList
      st = st & cList.sKey & "   " & Str$(cList.nData) & $CrLf
      cList.GetNext
   Loop

   st = st & $CrLf & $CrLf & "AFTER MOVING FIRST ITEM DOWN ONE SLOT" & $CrLf
   cList.MoveDown 1
   cList.GetFirst
   Do Until cList.IsEndOfList
      st = st & cList.sKey & "   " & Str$(cList.nData) & $CrLf
      cList.GetNext
   Loop
   
   ? st
   

   st = "AFTER MOVE CURRENT ITEM '" & cList.sKey &  "' UP ONE SLOT" & $CrLf
   cList.MoveUp cList.CurrentPosition
   cList.GetFirst
   Do Until cList.IsEndOfList
      st = st & cList.sKey & "   " & Str$(cList.nData) & $CrLf
      cList.GetNext
   Loop
   
   ? st


   ' Remove all items from the linked list
   cList.RemoveAll


   ? "AFTER REMOVE" & $CrLf & _
     "List Count =" & Str$(cList.GetCount)


   
   ' Tell the class that nData is a 32-bit number rather
   ' than a pointer to a string.
   cList.UseStrings = %TRUE 

   st = "Squires":   cList.AddItem "Paul",  StrPtr(st)
   st = "Poirier":   cList.AddItem "Tammy", StrPtr(st)
   st = "Zale":      cList.AddItem "Bob",   StrPtr(st)
   st = "Tobin":     cList.AddItem "Mark",  StrPtr(st)

   
   ? "List Count =" & Str$(cList.GetCount) & $CrLf & _
     "UseStrings =" & Str$(cList.UseStrings)
   
   st = "Position":      cList.AddItemBefore 1, "New First",  StrPtr(st)
   st = "Position":      cList.AddItemAfter  5, "New Last",   StrPtr(st)

   st = "AFTER ADDING ITEM AT START AND AT END OF LIST" & $CrLf
   cList.GetFirst
   Do Until cList.IsEndOfList
      st = st & cList.sKey & "   " & cList.sData & $CrLf
      cList.GetNext
   Loop

   ? st
   


ExitOut:   

   ? "Completed."

End Function





   
Paul Squires
FireFly Visual Designer SQLitening Database System JellyFish Pro Editor
http://www.planetsquires.com

James C. Fuller

Quote from: Theo Gottwald on September 01, 2008, 10:15:12 AM
What Limitations daoes it have per element?
Maximum Lenght?
Only NULL-Termianted?

Or would it eat a String up to 2 GB if I set "v2" to this string?
And will I get this string back?

Or is this just for short strings?

Theo,
  I just realized José had not spoken up on this. I have no idea and would like to know myself.

José??

James

José Roca

 
These are questions whose answer you can find by yourselves. Just try it. Build an string of the wanted size and assign it to a variant to see if it works. I'm not so crazy as to build a dictionary with 2GB strings (4GB when converted to unicode) :)

Theo Gottwald

#13
My problem with these API/Windows system functions is mostly, that first i am depending on their reliability, and second, i do not know which limitations they have.
If I use pure PB, i know the Limitations, the weaknesses. And I know they are reliable.

A dictionary is not much more then a two-dimensional Array. Can even be two one-dimensional dynamic string arrays where the elements have the same index.
Actually something like this can quickly built with the new objects and dynamic strings.
And then I know each element can at least have 2 GB in the worst case and all runs at full speed.

This reminds me of something ... i think the new dynamic strings in PB 4 can even have up to 4 GB .-).

James C. Fuller

Theo,
  You'll never match the speed using Arrays. It's even faster than Paul's hash table.

James