This code is moderately tested. I'd appreciate it if anybody would take a look at it/poke at it before i put it up on the rosetta code list.
With some inspiration and ideas from animeaime's
Class library, I made this.
I'd certainly love any suggestions to make it better.
Code:
; http://rosettacode.org/wiki/Doubly-Linked_List
;======================================+
; DOUBLY LINKED LIST FUNCTIONS |
;================================================================================
; Create new doubly linked list
dll_new()
{
dll := HeapAlloc(8)
NumPut(dll_node(""), dll+0, 0)
NumPut(dll_node(""), dll+0, 4)
dll_node_setnext(dll_head(dll), dll_tail(dll))
dll_node_setprev(dll_tail(dll), dll_head(dll))
return dll
}
; Return the head node of the list
dll_head(dll)
{
return NumGet(dll+0,0)
}
; Return the tail node of the list
dll_tail(dll)
{
return NumGet(dll+4,0)
}
; Insert node after prevnode
dll_insertafter(node, prevnode)
{
dll_node_setnext(node, dll_node_getnext(prevnode))
dll_node_setprev(node, prevnode)
dll_node_setprev(dll_node_getnext(prevnode), node)
dll_node_setnext(prevnode, node)
}
; Insert node before nextnode
dll_insertbefore(node, nextnode)
{
dll_node_setprev(node, dll_node_getprev(nextnode))
dll_node_setnext(node, nextnode)
dll_node_setnext(dll_node_getprev(nextnode), node)
dll_node_setprev(nextnode, node)
}
; Insert node at the beginning of dll
dll_insertfirst(dll, node)
{
dll_insertafter(node, dll_head(dll))
}
; Insert node at the end of dll
dll_insertlast(dll, node)
{
dll_insertbefore(node, dll_tail(dll))
}
; Remove node from dll
dll_remove(node)
{
prevnode := dll_node_getprev(node)
nextnode := dll_node_getnext(node)
dll_node_setnext(prevnode, nextnode)
dll_node_setprev(nextnode, prevnode)
HeapFree(node)
}
; Return a comma-delimited list of all values in dll
dll_dump(dll)
{
node := dll_head(dll)
While ((node := dll_node_getnext(node)) != dll_tail(dll))
dll_dump .= dll_node_getdata(node) ","
StringTrimRight, dll_dump, dll_dump, 1
return dll_dump
}
;========================+
; NODE FUNCTIONS |
;================================================================================
; Create and return a node
dll_node(data, prev=0, next=0)
{
; allocate memory for the node
data .= A_Space ; append space so numbers will be treated as strings
node := HeapAlloc(8 + StrLen(data))
; fill the node
NumPut(prev, node+0, 0)
NumPut(next, node+0, 4)
lstrcpy(node+8, data)
return node
}
; Return the previous node
dll_node_getprev(node)
{
return NumGet(node+0, 0)
}
; Return the next node
dll_node_getnext(node)
{
return NumGet(node+0, 4)
}
; Return the node data
dll_node_getdata(node)
{
s := stratadr(node+8)
StringTrimRight, s, s, 1 ; remove space we added before
return s
}
; Set the previous node
dll_node_setprev(node, newval)
{
NumPut(newval, node+0, 0)
}
; Set the next node
dll_node_setnext(node, newval)
{
NumPut(newval, node+0, 4)
}
;==========================+
; HELPER FUNCTIONS |
;================================================================================
; Allocate <size> bytes in the default process heap and return the address
HeapAlloc(size)
{
static HeapAlloc
HeapAlloc := HeapAlloc ? HeapAlloc : DllCall("GetProcAddress", uint, DllCall("GetModuleHandle", str, "Kernel32"), str, "HeapAlloc")
return DllCall(HeapAlloc, uint, hProcessHeap(), uint, 0x8, uint, size)
}
; Free the memory in the default process heap starting at <adr>
HeapFree(adr)
{
static HeapFree
HeapFree := HeapFree ? HeapFree : DllCall("GetProcAddress", uint, DllCall("GetModuleHandle", str, "Kernel32"), str, "HeapFree")
return DllCall(HeapFree, uint, hProcessHeap(), uint, 0, uint, adr)
}
; Return a handle to the default process heap
hProcessHeap()
{
static hProcessHeap
return hProcessHeap ? hProcessHeap : hProcessHeap := DllCall("GetProcessHeap")
}
; Copy string <s> to the block of memory starting at address <dest>
lstrcpy(dest, s)
{
static lstrcpy
lstrcpy := lstrcpy ? lstrcpy : DllCall("GetProcAddress", uint, DllCall("GetModuleHandle", str, "Kernel32"), str, "lstrcpy")
return DllCall(lstrcpy, uint, dest, str, s)
}
; Return the string starting at address <adr>
; stratadr MulDiv trick by Laszlo of the AHK forum:
; http://www.autohotkey.com/forum/viewtopic.php?t=20349&postdays=0&postorder=asc&start=11
stratadr(adr)
{
static Muldiv
MulDiv := MulDiv ? MulDiv : DllCall("GetProcAddress", uint, DllCall("GetModuleHandle", str, "Kernel32"), str, "MulDiv")
Return DllCall(MulDiv, int, adr, int, 1, int, 1, str)
}