mirror of
https://github.com/KevinMidboe/linguist.git
synced 2025-10-29 09:40:21 +00:00
369 lines
8.0 KiB
BlitzBasic
369 lines
8.0 KiB
BlitzBasic
|
|
; Double-linked list container class
|
|
;====================================
|
|
|
|
; with thanks to MusicianKool, for concept and issue fixes
|
|
|
|
|
|
Type LList
|
|
Field head_.ListNode
|
|
Field tail_.ListNode
|
|
End Type
|
|
|
|
Type ListNode
|
|
Field pv_.ListNode
|
|
Field nx_.ListNode
|
|
Field Value
|
|
End Type
|
|
|
|
Type Iterator
|
|
Field Value
|
|
Field l_.LList
|
|
Field cn_.ListNode, cni_
|
|
End Type
|
|
|
|
|
|
;Create a new LList object
|
|
Function CreateList.LList()
|
|
Local l.LList = New LList
|
|
|
|
l\head_ = New ListNode
|
|
l\tail_ = New ListNode
|
|
|
|
l\head_\nx_ = l\tail_ ;End caps
|
|
l\head_\pv_ = l\head_ ;These make it more or less safe to iterate freely
|
|
l\head_\Value = 0
|
|
|
|
l\tail_\nx_ = l\tail_
|
|
l\tail_\pv_ = l\head_
|
|
l\tail_\Value = 0
|
|
|
|
Return l
|
|
End Function
|
|
|
|
;Free a list and all elements (not any values)
|
|
Function FreeList(l.LList)
|
|
ClearList l
|
|
Delete l\head_
|
|
Delete l\tail_
|
|
Delete l
|
|
End Function
|
|
|
|
;Remove all the elements from a list (does not free values)
|
|
Function ClearList(l.LList)
|
|
Local n.ListNode = l\head_\nx_
|
|
While n <> l\tail_
|
|
Local nx.ListNode = n\nx_
|
|
Delete n
|
|
n = nx
|
|
Wend
|
|
l\head_\nx_ = l\tail_
|
|
l\tail_\pv_ = l\head_
|
|
End Function
|
|
|
|
;Count the number of elements in a list (slow)
|
|
Function ListLength(l.LList)
|
|
Local i.Iterator = GetIterator(l), elems
|
|
While EachIn(i)
|
|
elems = elems + 1
|
|
Wend
|
|
Return elems
|
|
End Function
|
|
|
|
;Return True if a list contains a given value
|
|
Function ListContains(l.LList, Value)
|
|
Return (ListFindNode(l, Value) <> Null)
|
|
End Function
|
|
|
|
;Create a linked list from the intvalues in a bank (slow)
|
|
Function ListFromBank.LList(bank)
|
|
Local l.LList = CreateList()
|
|
Local size = BankSize(bank), p
|
|
|
|
For p = 0 To size - 4 Step 4
|
|
ListAddLast l, PeekInt(bank, p)
|
|
Next
|
|
|
|
Return l
|
|
End Function
|
|
|
|
;Create a bank containing all the values in a list (slow)
|
|
Function ListToBank(l.LList)
|
|
Local size = ListLength(l) * 4
|
|
Local bank = CreateBank(size)
|
|
|
|
Local i.Iterator = GetIterator(l), p = 0
|
|
While EachIn(i)
|
|
PokeInt bank, p, i\Value
|
|
p = p + 4
|
|
Wend
|
|
|
|
Return bank
|
|
End Function
|
|
|
|
;Swap the contents of two list objects
|
|
Function SwapLists(l1.LList, l2.LList)
|
|
Local tempH.ListNode = l1\head_, tempT.ListNode = l1\tail_
|
|
l1\head_ = l2\head_
|
|
l1\tail_ = l2\tail_
|
|
l2\head_ = tempH
|
|
l2\tail_ = tempT
|
|
End Function
|
|
|
|
;Create a new list containing the same values as the first
|
|
Function CopyList.LList(lo.LList)
|
|
Local ln.LList = CreateList()
|
|
Local i.Iterator = GetIterator(lo) : While EachIn(i)
|
|
ListAddLast ln, i\Value
|
|
Wend
|
|
Return ln
|
|
End Function
|
|
|
|
;Reverse the order of elements of a list
|
|
Function ReverseList(l.LList)
|
|
Local n1.ListNode, n2.ListNode, tmp.ListNode
|
|
|
|
n1 = l\head_
|
|
n2 = l\head_\nx_
|
|
|
|
While n1 <> l\tail_
|
|
n1\pv_ = n2
|
|
tmp = n2\nx_
|
|
n2\nx_ = n1
|
|
n1 = n2
|
|
n2 = tmp
|
|
Wend
|
|
|
|
tmp = l\head_
|
|
l\head_ = l\tail_
|
|
l\tail_ = tmp
|
|
|
|
l\head_\pv_ = l\head_
|
|
l\tail_\nx_ = l\tail_
|
|
End Function
|
|
|
|
;Search a list to retrieve the first node with the given value
|
|
Function ListFindNode.ListNode(l.LList, Value)
|
|
Local n.ListNode = l\head_\nx_
|
|
|
|
While n <> l\tail_
|
|
If n\Value = Value Then Return n
|
|
n = n\nx_
|
|
Wend
|
|
|
|
Return Null
|
|
End Function
|
|
|
|
;Append a value to the end of a list (fast) and return the node
|
|
Function ListAddLast.ListNode(l.LList, Value)
|
|
Local n.ListNode = New ListNode
|
|
|
|
n\pv_ = l\tail_\pv_
|
|
n\nx_ = l\tail_
|
|
n\Value = Value
|
|
|
|
l\tail_\pv_ = n
|
|
n\pv_\nx_ = n
|
|
|
|
Return n
|
|
End Function
|
|
|
|
;Attach a value to the start of a list (fast) and return the node
|
|
Function ListAddFirst.ListNode(l.LList, Value)
|
|
Local n.ListNode = New ListNode
|
|
|
|
n\pv_ = l\head_
|
|
n\nx_ = l\head_\nx_
|
|
n\Value = Value
|
|
|
|
l\head_\nx_ = n
|
|
n\nx_\pv_ = n
|
|
|
|
Return n
|
|
End Function
|
|
|
|
;Remove the first occurence of the given value from a list
|
|
Function ListRemove(l.LList, Value)
|
|
Local n.ListNode = ListFindNode(l, Value)
|
|
If n <> Null Then RemoveListNode n
|
|
End Function
|
|
|
|
;Remove a node from a list
|
|
Function RemoveListNode(n.ListNode)
|
|
n\pv_\nx_ = n\nx_
|
|
n\nx_\pv_ = n\pv_
|
|
Delete n
|
|
End Function
|
|
|
|
;Return the value of the element at the given position from the start of the list,
|
|
;or backwards from the end of the list for a negative index
|
|
Function ValueAtIndex(l.LList, index)
|
|
Local n.ListNode = ListNodeAtIndex(l, index)
|
|
If n <> Null Then Return n\Value : Else Return 0
|
|
End Function
|
|
|
|
;Return the ListNode at the given position from the start of the list, or backwards
|
|
;from the end of the list for a negative index, or Null if invalid
|
|
Function ListNodeAtIndex.ListNode(l.LList, index)
|
|
Local e, n.ListNode
|
|
|
|
If index >= 0
|
|
n = l\head_
|
|
For e = 0 To index
|
|
n = n\nx_
|
|
Next
|
|
If n = l\tail_ Then n = Null ;Beyond the end of the list - not valid
|
|
|
|
Else ;Negative index - count backward
|
|
n = l\tail_
|
|
For e = 0 To index Step -1
|
|
n = n\pv_
|
|
Next
|
|
If n = l\head_ Then n = Null ;Before the start of the list - not valid
|
|
|
|
EndIf
|
|
|
|
Return n
|
|
End Function
|
|
|
|
;Replace a value at the given position (added by MusicianKool)
|
|
Function ReplaceValueAtIndex(l.LList,index,value)
|
|
Local n.ListNode = ListNodeAtIndex(l,index)
|
|
If n <> Null Then n\Value = value:Else Return 0
|
|
End Function
|
|
|
|
;Remove and return a value at the given position (added by MusicianKool)
|
|
Function RemoveNodeAtIndex(l.LList,index)
|
|
Local n.ListNode = ListNodeAtIndex(l,index),tval
|
|
If n <> Null Then tval = n\Value:RemoveListNode(n):Return tval:Else Return 0
|
|
End Function
|
|
|
|
;Retrieve the first value from a list
|
|
Function ListFirst(l.LList)
|
|
If l\head_\nx_ <> l\tail_ Then Return l\head_\nx_\Value
|
|
End Function
|
|
|
|
;Retrieve the last value from a list
|
|
Function ListLast(l.LList)
|
|
If l\tail_\pv_ <> l\head_ Then Return l\tail_\pv_\Value
|
|
End Function
|
|
|
|
;Remove the first element from a list, and return its value
|
|
Function ListRemoveFirst(l.LList)
|
|
Local val
|
|
If l\head_\nx_ <> l\tail_
|
|
val = l\head_\nx_\Value
|
|
RemoveListNode l\head_\nx_
|
|
EndIf
|
|
Return val
|
|
End Function
|
|
|
|
;Remove the last element from a list, and return its value
|
|
Function ListRemoveLast(l.LList)
|
|
Local val
|
|
If l\tail_\pv_ <> l\head_
|
|
val = l\tail_\pv_\Value
|
|
RemoveListNode l\tail_\pv_
|
|
EndIf
|
|
Return val
|
|
End Function
|
|
|
|
;Insert a value into a list before the specified node, and return the new node
|
|
Function InsertBeforeNode.ListNode(Value, n.ListNode)
|
|
Local bef.ListNode = New ListNode
|
|
|
|
bef\pv_ = n\pv_
|
|
bef\nx_ = n
|
|
bef\Value = Value
|
|
|
|
n\pv_ = bef
|
|
bef\pv_\nx_ = bef
|
|
|
|
Return bef
|
|
End Function
|
|
|
|
;Insert a value into a list after the specified node, and return then new node
|
|
Function InsertAfterNode.ListNode(Value, n.ListNode)
|
|
Local aft.ListNode = New ListNode
|
|
|
|
aft\nx_ = n\nx_
|
|
aft\pv_ = n
|
|
aft\Value = Value
|
|
|
|
n\nx_ = aft
|
|
aft\nx_\pv_ = aft
|
|
|
|
Return aft
|
|
End Function
|
|
|
|
;Get an iterator object to use with a loop
|
|
;This function means that most programs won't have to think about deleting iterators manually
|
|
;(in general only a small, constant number will be created)
|
|
Function GetIterator.Iterator(l.LList)
|
|
Local i.Iterator
|
|
|
|
If l = Null Then RuntimeError "Cannot create Iterator for Null"
|
|
|
|
For i = Each Iterator ;See if there's an available iterator at the moment
|
|
If i\l_ = Null Then Exit
|
|
Next
|
|
|
|
If i = Null Then i = New Iterator ;If there wasn't, create one
|
|
|
|
i\l_ = l
|
|
i\cn_ = l\head_
|
|
i\cni_ = -1
|
|
i\Value = 0 ;No especial reason why this has to be anything, but meh
|
|
|
|
Return i
|
|
End Function
|
|
|
|
;Use as the argument to While to iterate over the members of a list
|
|
Function EachIn(i.Iterator)
|
|
|
|
i\cn_ = i\cn_\nx_
|
|
|
|
If i\cn_ <> i\l_\tail_ ;Still items in the list
|
|
i\Value = i\cn_\Value
|
|
i\cni_ = i\cni_ + 1
|
|
Return True
|
|
|
|
Else
|
|
i\l_ = Null ;Disconnect from the list, having reached the end
|
|
i\cn_ = Null
|
|
i\cni_ = -1
|
|
Return False
|
|
|
|
EndIf
|
|
End Function
|
|
|
|
;Remove from the containing list the element currently pointed to by an iterator
|
|
Function IteratorRemove(i.Iterator)
|
|
If (i\cn_ <> i\l_\head_) And (i\cn_ <> i\l_\tail_)
|
|
Local temp.ListNode = i\cn_
|
|
|
|
i\cn_ = i\cn_\pv_
|
|
i\cni_ = i\cni_ - 1
|
|
i\Value = 0
|
|
|
|
RemoveListNode temp
|
|
|
|
Return True
|
|
Else
|
|
Return False
|
|
EndIf
|
|
End Function
|
|
|
|
;Call this before breaking out of an EachIn loop, to disconnect the iterator from the list
|
|
Function IteratorBreak(i.Iterator)
|
|
i\l_ = Null
|
|
i\cn_ = Null
|
|
i\cni_ = -1
|
|
i\Value = 0
|
|
End Function
|
|
|
|
|
|
;~IDEal Editor Parameters:
|
|
;~F#5#A#10#18#2A#32#3E#47#4C#58#66#6F#78#8F#9B#A9#B7#BD#C5#CC
|
|
;~F#E3#E9#EF#F4#F9#103#10D#11B#12B#13F#152#163
|
|
;~C#Blitz3D |