.DestroyAllNthPosition(ByVal destroy As Sub(ByVal p As Any Ptr) = 0)
Test code with the file to include modified accordingly:
Code: Select all
' DynamicArrayList.bi modified
#if __FB_VERSION__ < "1.10"
Type DoublyLinkedNode
Dim As DoublyLinkedNode Ptr prevNodePtr '' previous node pointer
Dim As Any Ptr userPtr '' user pointer
Dim As DoublyLinkedNode Ptr nextNodePtr '' next node pointer
End Type
#endif
Type DynamicArrayList
Public:
Declare Function InsertInNthPosition(ByVal p As Any Ptr, ByVal n As Integer) As Any Ptr
Declare Function SuppressTheNthPosition(ByVal n As Integer) As Any Ptr
Declare Function ReturnFromNthPosition(ByVal n As Integer) As Any Ptr
Declare Function UpdateTheNthPosition(ByVal p As Any Ptr, ByVal n As Integer) As Any Ptr
Declare Function SwapNthPthPosition(ByVal n1 As Integer, ByVal n2 As Integer) As Integer
Declare Function ShiftTheNthPosition(ByVal n As Integer, ByVal offset As Integer) As Integer
Declare Function ReverseOrderOfPosition() As Integer
Declare Function ReturnArrayFromPosition(array() As Any Ptr) As Integer
Declare Function LoadArrayIntoPosition(array() As Any Ptr) As Integer
Declare Function SearchForNthPosition(ByVal compare As Function(ByVal p As Any Ptr) As Boolean, ByVal startPosition As Integer = 1) As Integer
Declare Sub DestroyAllNthPosition(ByVal destroy As Sub(ByVal p As Any Ptr) = 0)
Declare Function ReturnNumberOfPosition() As Integer
Declare Constructor()
Declare Destructor()
Private:
#if __FB_VERSION__ >= "1.10"
Type DoublyLinkedNode
Dim As DoublyLinkedNode Ptr prevNodePtr '' previous node pointer
Dim As Any Ptr userPtr '' user pointer
Dim As DoublyLinkedNode Ptr nextNodePtr '' next node pointer
End Type
#endif
Declare Function SearchNthPositionNode(ByVal n1 As Integer) As DoublyLinkedNode Ptr
Dim As DoublyLinkedNode dummyNode '' dummy node
Dim As Integer nbrUserNode '' number of user node
Dim As Integer recent1NodeIndex '' recent #1 node index (position)
Dim As DoublyLinkedNode Ptr recent1NodePtr '' recent #1 node pointer
Dim As Integer recent2NodeIndex '' recent #2 node index (position)
Dim As DoublyLinkedNode Ptr recent2NodePtr '' recent #2 node pointer
End Type
Function DynamicArrayList.InsertInNthPosition(ByVal p As Any Ptr, ByVal n As Integer) As Any Ptr
' Returns 0 on error, otherwise the value of the provided user pointer
' Converts index into positive index
Dim As Integer posNodeIndex = IIf(n <= 0, This.nbrUserNode + n + 1, n)
' Tests index validity
If (posNodeIndex < 1) Or (posNodeIndex > This.nbrUserNode + 1) Then Return 0
' Allocates memory for new node
Dim As DoublyLinkedNode Ptr newNodePtr = CAllocate(1, SizeOf(DoublyLinkedNode))
If newNodePtr = 0 Then Return 0
' Copies user pointer value in new node
newNodePtr->userPtr = p
' Searches for node below insertion
Dim As DoublyLinkedNode Ptr searchNodePtr = This.SearchNthPositionNode(posNodeIndex)
' Updates pointers of previous, inserted, and next nodes
newNodePtr->nextNodePtr = searchNodePtr
newNodePtr->prevNodePtr = searchNodePtr->prevNodePtr
searchNodePtr->prevNodePtr = newNodePtr
newNodePtr->prevNodePtr->nextNodePtr = newNodePtr
' Increments the number of user nodes
This.nbrUserNode +=1
' Updates the recent visited node data
If posNodeIndex > This.recent1NodeIndex Then
This.recent2NodeIndex = posNodeIndex
This.recent2NodePtr = newNodePtr
Else
This.recent1NodeIndex = posNodeIndex
This.recent1NodePtr = newNodePtr
This.recent2NodeIndex += 1 ' recent #2 node position shifted by the insertion
End If
Return p
End Function
Function DynamicArrayList.SuppressTheNthPosition(ByVal n As Integer) As Any Ptr
' Returns 0 on error, otherwise the value of the provided user pointer
' Converts index into positive index
Dim As Integer posNodeIndex = IIf(n <= 0, This.nbrUserNode + n + 1, n)
' Tests index validity
If (posNodeIndex < 1) Or (posNodeIndex > This.nbrUserNode) Then Return 0
' Searches for node to suppress
Dim As DoublyLinkedNode Ptr searchNodePtr = This.SearchNthPositionNode(posNodeIndex)
' Updates of previous and next nodes
searchNodePtr->prevNodePtr->nextNodePtr = searchNodePtr->nextNodePtr
searchNodePtr->nextNodePtr->prevNodePtr = searchNodePtr->prevNodePtr
' Updates the recent visited node data
If (posNodeIndex < This.nbrUserNode) And (posNodeIndex <> This.recent2NodeIndex) Then
If posNodeIndex > This.recent1NodeIndex Then
This.recent2NodeIndex = posNodeIndex
This.recent2NodePtr = searchNodePtr->nextNodePtr
Else
This.recent1NodeIndex = posNodeIndex
This.recent1NodePtr = searchNodePtr->nextNodePtr
This.recent2NodeIndex -= 1 ' recent #2 node position shifted by the suppression
End If
Else
' Resets the recent visited node data
This.recent1NodePtr = @This.dummyNode
This.recent1NodeIndex = 0
This.recent2NodePtr = @This.dummyNode
This.recent2NodeIndex = 0
End If
' Saves user pointer of the node
Dim As Any Ptr searchUserPtr = searchNodePtr->userPtr
' Deallocates memory for the node
Deallocate(searchNodePtr)
' Decrements the number of user nodes
This.nbrUserNode -= 1
Return searchUserPtr
End Function
Function DynamicArrayList.ReturnFromNthPosition(ByVal n As Integer) As Any Ptr
' Returns 0 on error, otherwise the value of the provided user pointer
' Converts index into positive index
Dim As Integer posNodeIndex = IIf(n <= 0, This.nbrUserNode + n + 1, n)
' Tests index validity
If (posNodeIndex < 1) Or (posNodeIndex > This.nbrUserNode) Then Return 0
' Searches for user node
Dim As DoublyLinkedNode Ptr searchNodePtr = This.SearchNthPositionNode(posNodeIndex)
' Updates the recent visited node data
If posNodeIndex > This.recent1NodeIndex Then
This.recent2NodeIndex = posNodeIndex
This.recent2NodePtr = searchNodePtr
Else
This.recent1NodeIndex = posNodeIndex
This.recent1NodePtr = searchNodePtr
End If
Return searchNodePtr->userPtr
End Function
Function DynamicArrayList.UpdateTheNthPosition(ByVal p As Any Ptr, ByVal n As Integer) As Any Ptr
' Returns 0 on error, otherwise the value of the provided user pointer
' Converts index into positive index
Dim As Integer posNodeIndex = IIf(n <= 0, This.nbrUserNode + n + 1, n)
' Tests index validity
If (posNodeIndex < 1) Or (posNodeIndex > This.nbrUserNode) Then Return 0
' Searches for user node
Dim As DoublyLinkedNode Ptr searchNodePtr = This.SearchNthPositionNode(posNodeIndex)
' Updates user pointer of the node
searchNodePtr->userPtr = p
' Updates the recent visited node data
If posNodeIndex > This.recent1NodeIndex Then
This.recent2NodeIndex = posNodeIndex
This.recent2NodePtr = searchNodePtr
Else
This.recent1NodeIndex = posNodeIndex
This.recent1NodePtr = searchNodePtr
End If
Return p
End Function
Function DynamicArrayList.SwapNthPthPosition(ByVal n1 As Integer, ByVal n2 As Integer) As Integer
' Returns 0 on error, otherwise -1
' Converts indexes into positive indexes
Dim As Integer posNodeIndex1 = IIf(n1 <= 0, This.nbrUserNode + n1 + 1, n1)
Dim As Integer posNodeIndex2 = IIf(n2 <= 0, This.nbrUserNode + n2 + 1, n2)
' Tests index validity
If (posNodeIndex1 < 1) Or (posNodeIndex1 > This.nbrUserNode) Or (posNodeIndex2 < 1) Or (posNodeIndex2 > This.nbrUserNode) Then Return 0
' search for the 2 user nodes
Dim As DoublyLinkedNode Ptr searchNodePtr1 = This.SearchNthPositionNode(posNodeIndex1)
Dim As DoublyLinkedNode Ptr searchNodePtr2 = This.SearchNthPositionNode(posNodeIndex2)
' swaps the 2 user pointers
Swap searchNodePtr1->userPtr, searchNodePtr2->userPtr
' Updates the recent visited node data
If posNodeIndex2 > posNodeIndex1 Then
This.recent1NodeIndex = posNodeIndex1
This.recent1NodePtr = searchNodePtr1
This.recent2NodeIndex = posNodeIndex2
This.recent2NodePtr = searchNodePtr2
Else
This.recent1NodeIndex = posNodeIndex2
This.recent1NodePtr = searchNodePtr2
This.recent2NodeIndex = posNodeIndex1
This.recent2NodePtr = searchNodePtr1
End If
Return -1
End Function
Function DynamicArrayList.ShiftTheNthPosition(ByVal n As Integer, ByVal offset As Integer) As Integer
' Returns 0 on error, otherwise -1
' Converts index into positive index
Dim As Integer posNodeIndex = IIf(n <= 0, This.nbrUserNode + n + 1, n)
' Tests index and offset validity
If (posNodeIndex < 1) Or (posNodeIndex > This.nbrUserNode) Or (posNodeIndex + offset < 1) Or (posNodeIndex + offset > This.nbrUserNode) Then Return 0
' search for the user node
Dim As DoublyLinkedNode Ptr nodePtr2 = This.SearchNthPositionNode(posNodeIndex)
Dim As DoublyLinkedNode Ptr nodePtr1
' Updates the recent visited node data
If offset > 0 Then
This.recent1NodeIndex = posNodeIndex
This.recent1NodePtr = nodePtr2
Else
This.recent2NodeIndex = posNodeIndex
This.recent2NodePtr = nodePtr2
End If
' Shifts the user pointer by using a repeated swapping process
If offset > 0 Then
For I As Integer = 1 To Offset
nodePtr1 = nodePtr2
nodePtr2 = nodePtr2->nextNodePtr
Swap nodePtr1->userPtr, nodePtr2->userPtr
Next I
Else
For I As Integer = -1 To Offset Step -1
nodePtr1 = nodePtr2
nodePtr2 = nodePtr2->prevNodePtr
Swap nodePtr1->userPtr, nodePtr2->userPtr
Next I
End If
' Updates the recent visited node data
If offset > 0 Then
This.recent2NodeIndex = posNodeIndex + offset
This.recent2NodePtr = nodePtr2
Else
This.recent1NodeIndex = posNodeIndex + offset
This.recent1NodePtr = nodePtr2
End If
Return -1
End Function
Function DynamicArrayList.ReverseOrderOfPosition() As Integer
' Returns 0 on empty list, otherwise -1
' Tests empty list
If This.nbrUserNode = 0 Then Return 0
' Swaps user pointers from the ends up to the middle
Dim As DoublyLinkedNode Ptr leftNodePtr = @This.dummyNode, rightNodePtr = @This.dummyNode
For I As Integer = 1 To This.nbrUserNode \ 2
leftNodePtr = leftNodePtr->nextNodePtr
rightNodePtr = rightNodePtr->prevNodePtr
Swap rightNodePtr->userPtr, leftNodePtr->userPtr
Next I
Return -1
End Function
Function DynamicArrayList.ReturnArrayFromPosition(array() As Any Ptr) As Integer
' Returns the number of elements
If This.nbrUserNode = 0 Then Return 0
Dim As DoublyLinkedNode Ptr nodePtr = @This.dummyNode
' sizes the passed array
Redim array(1 To This.nbrUserNode)
' fills in the array with the user pointers
For I As Integer = 1 To This.nbrUserNode
nodePtr = nodePtr->nextNodePtr
array(I) = nodePtr->userPtr
Next I
Return This.nbrUserNode
End Function
Function DynamicArrayList.LoadArrayIntoPosition(array() As Any Ptr) As Integer
' Return 0 if the list is not empty, otherwise returns the number of loaded elements
If This.nbrUserNode > 0 Then Return 0
Dim As DoublyLinkedNode Ptr nodePtr = @This.dummyNode
For I As Integer = Lbound(array) To Ubound(array)
' Allocates memory for new node
Dim As DoublyLinkedNode Ptr newNodePtr = CAllocate(1, SizeOf(DoublyLinkedNode))
If newNodePtr = 0 Then Return This.nbrUserNode
' Copies user pointer value in new node
newNodePtr->userPtr = array(I)
' Updates pointers of previous and inserted nodes
nodePtr->nextNodePtr = newNodePtr
newNodePtr->prevNodePtr = nodePtr
' Inserted node becomes previous node
nodePtr = newNodePtr
' Increments the number of user nodes
This.nbrUserNode += 1
Next I
' Updates pointer of last node and dummy node
nodePtr->nextNodePtr = @This.dummyNode
This.dummyNode.prevNodePtr = nodePtr
Return This.nbrUserNode
End Function
Function DynamicArrayList.SearchForNthPosition(ByVal compare As Function(ByVal p As Any Ptr) As Boolean, ByVal startPosition As Integer = 1) As Integer
' Return 0 if the search failed, otherwise returns the position index of the first occurence found
' If startPosition > 0 (set of positive index used), the search begins at the startPosition index then continues in the increasing index order
' If startPosition < 0 (set of negative index used), the search begins at the startPosition index then continues in the decreasing index order (reverse order)
' The returned index uses the same set (positive or negative) of index than the one used for startPosition
If compare = 0 Then Return 0
Dim As DoublyLinkedNode Ptr nodePtr
' set of positive index used
If (startPosition >= 1) And (startPosition <= This.nbrUserNode) Then
' search start node
nodePtr = This.SearchNthPositionNode(startPosition)
For I As Integer = startPosition To This.nbrUserNode
If compare(nodePtr->userPtr) = True Then Return I
' next node
nodePtr = nodePtr->nextNodePtr
Next I
' set of negative index used
ElseIf (startPosition <= -1) And (startPosition >= -This.nbrUserNode) Then
' search start node
nodePtr = This.SearchNthPositionNode(This.nbrUserNode + startPosition + 1)
For I As Integer = startPosition To -This.nbrUserNode Step -1
If compare(nodePtr->userPtr) = True Then Return I
' previous node
nodePtr = nodePtr->prevNodePtr
Next I
End If
Return 0
End Function
Sub DynamicArrayList.DestroyAllNthPosition(ByVal destroy As Sub(ByVal p As Any Ptr) = 0)
' Deallocates memory used by user nodes one by one by transverse access, including user data in the loop if destroy <> 0 is passed
Dim As DoublyLinkedNode Ptr nodePtr = This.dummyNode.nextNodePtr
If destroy <> 0 Then
For I As Integer = 1 To This.nbrUserNode
nodePtr = nodePtr->nextNodePtr
destroy(nodePtr->prevNodePtr->userPtr)
Deallocate(nodePtr->prevNodePtr)
Next I
Else
For I As Integer = 1 To This.nbrUserNode
nodePtr = nodePtr->nextNodePtr
Deallocate(nodePtr->prevNodePtr)
Next I
End If
' Clears the number of user nodes
This.nbrUserNode = 0
' Loops the dummy node on itself
This.dummyNode.nextNodePtr = @This.dummyNode
This.dummyNode.prevNodePtr = @This.dummyNode
' Initializes the two recent visited nodes memory with the dummy node
This.recent1NodeIndex = 0
This.recent1NodePtr = @This.dummyNode
This.recent2NodeIndex = 0
This.recent2NodePtr = @This.dummyNode
End Sub
Function DynamicArrayList.ReturnNumberOfPosition() As Integer
Return This.nbrUserNode
End Function
Function DynamicArrayList.SearchNthPositionNode(ByVal posNodeIndex As Integer) As DoublyLinkedNode Ptr
Dim As DoublyLinkedNode Ptr nodePtr
' The node (among these 3) memorized closest to the targeted position
' is chosen as starting point of the iteration (forward or backward) through the nodes
' (3 * 2 = 6 cases)
If posNodeIndex < This.recent1NodeIndex Then
If posNodeIndex <= This.recent1NodeIndex - posNodeIndex Then
' dummy node closest to targeted position
nodePtr = @This.dummyNode
For I As Integer = 1 To posNodeIndex ' forward iteration
nodePtr = nodePtr->nextNodePtr
Next I
Else
' recent #1 visited node closest to targeted position
nodePtr = This.recent1NodePtr
For I As Integer = This.recent1NodeIndex - 1 To posNodeIndex Step -1 ' backward iteration
nodePtr = nodePtr->prevNodePtr
Next I
End If
ElseIf posNodeIndex < This.recent2NodeIndex Then
If posNodeIndex - This.recent1NodeIndex <= This.recent2NodeIndex - posNodeIndex Then
' recent #1 visited node closest to targeted position
nodePtr = This.recent1NodePtr
For I As Integer = This.recent1NodeIndex + 1 To posNodeIndex ' forward iteration
nodePtr = nodePtr->nextNodePtr
Next I
Else
' recent #2 visited node closest to targeted position
nodePtr = This.recent2NodePtr
For I As Integer = This.recent2NodeIndex - 1 To posNodeIndex Step -1 ' backward iteration
nodePtr = nodePtr->prevNodePtr
Next I
End If
Else
If posNodeIndex - This.recent2NodeIndex <= This.nbrUserNode + 1 - posNodeIndex Then
' recent #2 visited node closest to targeted position
nodePtr = This.recent2NodePtr
For I As Integer = This.recent2NodeIndex + 1 To posNodeIndex ' forward iteration
nodePtr = nodePtr->nextNodePtr
Next I
Else
' dummy node closest to targeted position
nodePtr = @This.dummyNode
For I As Integer = This.nbrUserNode To posNodeIndex Step -1 ' backward iteration
nodePtr = nodePtr->prevNodePtr
Next I
End If
End If
Return nodePtr
End Function
Constructor DynamicArrayList()
' Loops the dummy node on itself
This.dummyNode.nextNodePtr = @This.dummyNode
This.dummyNode.prevNodePtr = @This.dummyNode
' Initializes the two recent visited nodes memory with the dummy node
This.recent1NodePtr = @This.dummyNode
This.recent2NodePtr = @This.dummyNode
End Constructor
Destructor DynamicArrayList()
' Deallocates memory used by user nodes one by one by transverse access
This.DestroyAllNthPosition()
End Destructor
Sub PrintList(Byref dal As DynamicArrayList)
Print " ";
For I As Integer = 1 To 5
Print *Cptr(Long Ptr, dal.ReturnFromNthPosition(I));
Next I
Print " .....";
For I As Integer = dal.ReturnNumberOfPosition() - 4 To dal.ReturnNumberOfPosition()
Print *Cptr(Long Ptr, dal.ReturnFromNthPosition(I));
Next I
Print
End Sub
Sub destroy(ByVal p As Any Ptr)
Delete Cptr(Long Ptr, p)
End Sub
Sub test(Byval N As Integer)
Dim As Double t
Dim As Integer position
Dim As DynamicArrayList dal1
Dim As DynamicArrayList dal2
Print "Two Dynamic ArrayLists pointing to """ & N & """ dynamic integers :"
For I As Integer = 1 To N
dal1.InsertInNthPosition(New Long(I), 0)
Next I
PrintList(dal1)
For I As Integer = 1 To N
dal2.InsertInNthPosition(New Long(I), 0)
Next I
PrintList(dal2)
Print
Print " Time to destroy all elements + the dynamic user data :"
Print " - by using a user loop for the first Dynamic ArrayList :"
t = Timer
For I As Integer = 1 To N
Delete Cptr(Long Ptr, dal1.SuppressTheNthPosition(1))
Next i
Print " " & Timer - t & " s"
Print " - by using the member method for the second Dynamic ArrayList :"
t = Timer
dal2.DestroyAllNthPosition(@destroy)
Print " " & Timer - t & " s"
End Sub
Test(1000000)
Print "--------------------------------------------------------------------"
Test(3000000)
Print "--------------------------------------------------------------------"
Test(5000000)
Print "--------------------------------------------------------------------"
Test(7000000)
Print "--------------------------------------------------------------------"
Test(9000000)
Sleep
- Output example:
Code: Select all
Two Dynamic ArrayLists pointing to "1000000" dynamic integers : 1 2 3 4 5 ..... 999996 999997 999998 999999 1000000 1 2 3 4 5 ..... 999996 999997 999998 999999 1000000 Time to destroy all elements + the dynamic user data : - by using a user loop for the first Dynamic ArrayList : 0.1290565999519799 s - by using the member method for the second Dynamic ArrayList : 0.08200879994598154 s -------------------------------------------------------------------- Two Dynamic ArrayLists pointing to "3000000" dynamic integers : 1 2 3 4 5 ..... 2999996 2999997 2999998 2999999 3000000 1 2 3 4 5 ..... 2999996 2999997 2999998 2999999 3000000 Time to destroy all elements + the dynamic user data : - by using a user loop for the first Dynamic ArrayList : 0.3774869000394574 s - by using the member method for the second Dynamic ArrayList : 0.2655347000473967 s -------------------------------------------------------------------- Two Dynamic ArrayLists pointing to "5000000" dynamic integers : 1 2 3 4 5 ..... 4999996 4999997 4999998 4999999 5000000 1 2 3 4 5 ..... 4999996 4999997 4999998 4999999 5000000 Time to destroy all elements + the dynamic user data : - by using a user loop for the first Dynamic ArrayList : 0.6417374999850267 s - by using the member method for the second Dynamic ArrayList : 0.4314474999961249 s -------------------------------------------------------------------- Two Dynamic ArrayLists pointing to "7000000" dynamic integers : 1 2 3 4 5 ..... 6999996 6999997 6999998 6999999 7000000 1 2 3 4 5 ..... 6999996 6999997 6999998 6999999 7000000 Time to destroy all elements + the dynamic user data : - by using a user loop for the first Dynamic ArrayList : 0.8864024000415611 s - by using the member method for the second Dynamic ArrayList : 0.6022076999993828 s -------------------------------------------------------------------- Two Dynamic ArrayLists pointing to "9000000" dynamic integers : 1 2 3 4 5 ..... 8999996 8999997 8999998 8999999 9000000 1 2 3 4 5 ..... 8999996 8999997 8999998 8999999 9000000 Time to destroy all elements + the dynamic user data : - by using a user loop for the first Dynamic ArrayList : 1.11212479997738 s - by using the member method for the second Dynamic ArrayList : 0.7666473000202814 s
I would prefer to add this member method to the DynamicArrayList structure, which makes it easier for the user to manually destroy the list elements and its associated data if necessary.