Here's my 20 cents worth - singly-linked bidirectional Linked List arrays...
- hope ya like it :)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Notes from the Author;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;The following Procedures were coded by EvilHomer at 3:54 in the morning.
;They are all that is required for basic management of
;multiple simultaneous Linked Lists,
;provided all entries are of the same type (one type of Entry, one type of List).
;If you like this code, we can improve it so that
;it can take another param for the type of LinkedObject (type of List).
;
;AddEntry - input param lpPrev is pointer to last entry before the new one
; - ie which entry to insert or append the new one behind...
; - For a new list, theres no Parent, so you can use NULL
; - Procedure handles insertions as well as appending.
; - Return value is pointer to the new entry,
; - Return value NULL indicates failure.
;
;KillEntry- input param lpThis is pointer to entry to be deleted. Simple.
; - Procedure handles link patching intelligently.
; - No return value.
;
;-------------------------------------------------------------------
;Structure of an Entry in a Linked List
;-------------------------------------------------------------------

LinkedObject STRUCT ;Example structure is minimal - add some more fields to it :)
pPrev DWORD ? ;Pointer to my daddy if I have one (previous)
pNext DWORD ? ;Pointer to my child if I have one (next)
pLock DWORD ? ;handle for freeing this memory
LinkedObject ENDS

;-------------------------------------------------------------------
;KillEntry Procedure
;-Removes an entry from a Linked-List.
;-Examines Parent<--<THIS>-->Child links and
;-Patches- Parent<-->Child (Bypassing Self).
;-Also detects and patches NewRoot and NewLast nodes.
;-Releases the allocated memory used by the killed entry.
;-In other words, flawless and transparent removal
;-of a single entry in our List.
;-------------------------------------------------------------------

KillEntry PROC lpThis:PTR LinkedObject ;pointer to entry to be deleted

mov esi,[lpThis].pPrev ;(Fetch possible Parent)
.if esi !=0 ;I have a Parent and thus am not Root..
mov edi,[lpThis].pNext ;(Fetch possible Child)
.if esi !=0 ;..and I also have a Child..
push edi ;(ChildPointer)
pop [esi].lpNext ;link Parent to Child, bypassing me
push esi ;(ParentPointer)
pop [edi].lpPrev ;link Child to Parent, bypassing me
.else ;..and I have no Child..
mov [esi].lpNext,NULL ;Kill Parent's link to me
.endif ;(setting it as Last)

.else ;I am Root and have no Parent..
mov edi,[lpThis].pNext ;(Fetch possible Child)
.if esi !=0 ;..but I do have a Child
mov [edi].lpPrev,NULL ;Kill Child's link to Parent
.endif ;(setting it as Root)
.endif ; (no parent and no child? alone? nothing to repair then)
mov eax,[lpThis].pLock ;This bit happens regardless...
push eax ;(handle to memory object)
invoke GlobalUnlock,eax ;Unlock this memory
pop eax ;(handle to memory object)
invoke GlobalFree,eax ;Release this memory
return TRUE ;cya
KillEntry ENDP

;-------------------------------------------------------------------
;NewEntry Procedure
;-Adds an entry to a Linked-List...
;-Allocates memory for a new entry,
;-Examines Parent<--->Child links and
;-Patches- Parent<--<THIS>-->Child (Inserting Self).
;-Bidirection links are preserved.
;-------------------------------------------------------------------
NewEntry PROC lpPrev:PTR LinkedObject ;Pointer to Previous entry
LOCAL lpThis,lpOldChild:PTR LinkedObject
LOCAL hMem:DWORD

szText szGAE,"GlobalAlloc err #%lu"
szText szGLE,"GlobalLock err #%lu"

invoke GlobalAlloc,GHND,sizeof LinkedObject
mov hMem,eax
.if eax != NULL
invoke GlobalLock,hMem
.if eax != NULL
mov lpThis,eax
push hMem
pop [lpThis].pLock ;Remember my unlock handle
mov esi,lpPrev
push [esi].lpNext
pop lpOldChild ;store possible child
.if esi != NULL ;I have a Parent and thus am not Root
push lpThis
pop [esi].lpNext ;Tell Parent hes my new daddy- APPENDING
push lpPrev
pop [lpThis].lpPrev ;Tell Myself I have a Parent
.if lpOldChild != NULL ;and that Parent had a Child - INSERTING!
push lpThis
pop [lpOldChild].lpPrev ;Tell Child I'm their new sugardaddy
push lpOldChild
pop [lpThis].lpNext ;Tell Myself I have a Child
.endif ;I have no kids to worry about or
.endif ;I am Root with No Parent and No Child
return lpThis ;Return pointer to the new Object in EAX
.else ;GlobalLock failed...
invoke GetLastError
invoke wsprintf,addr ErrBuf,addr szGLE,eax
invoke MessageBox,addr szGLE,addr szDisplayName,MB_OK+MB_ICONERROR
invoke GlobalFree,hMem ;Free the memory we Failed to Lock
.endif
.else ;GlobalAlloc failed...
invoke GetLastError
invoke wsprintf,addr ErrBuf,addr szGAE,eax
invoke MessageBox,addr szGAE,addr szDisplayName,MB_OK+MB_ICONERROR
.endif
xor eax,eax
ret ;Return ERROR in eax since we have Failed

AddEntry ENDP

;-------------------------------------------------------------------

Any thoughts on this ever-popular topic?

added [ code][ /code] block - scronty
Posted on 2002-08-15 01:31:24 by Homer
Afternoon, EvilHomer2k.

Attached is an example based upon the code you posted.

I've also added a new proc (KillEntryPlusChildren) which, as you can see by the name, deletes the given node, plus its children.

It'll be interesting to see how this progresses. There're linked-list examples in other forums here, so we might as well make this one more Game Programming related.

Cheers,
Scronty
Posted on 2002-08-15 08:37:29 by Scronty
Nice idea, a good addition, killing children recursively...
heres the code from later that day after I'd had some sleep...
It is much better as it can handle objects yet to be defined,
and can handle objects of differing sizes within a single list.
Also I cleared up those lil typo's due to tiredness..


;;;;;;;;;;;;;;;;;;;;;;;
;Notes from the Author;
;;;;;;;;;;;;;;;;;;;;;;;
;
;The following Procedures were coded by EvilHomer at 3:54 in the morning of August 15 2002.
;They were first modified at 9:00 pm of the same day.
;References to false LinkedObject fields corrected.
;Code in AddEntry altered to include an ObjectSize param for new entries,
;and to use that rather than sizeof LinkedObject.

;Since the functions provided here assumes that the Object they are
;creating or destroying is a LinkedObject and make no OTHER assumptions
;about the true nature of the Object they are creating or destroying,
;if we simply ensure that all our Objects begin with a LinkedObject as
;a Header, then any Object Pointer can become a Linked List!!
;Make sure that all Objects to be stored this way have a Structure Definition
;which begins with a LinkedObject entity.
;This means we can basically treat AddEntry in the same way as
;a C++ coder would use the "new" directive.

;AddEntry - input param lpPrev is pointer to last entry before the new one
; - ie which entry to insert or append the new one behind...
; - For a new list, theres no Parent, so you can use NULL
; - Procedure handles insertions as well as appending.
; - Return value is pointer to the new entry.
;
;KillEntry- input param lpThis is pointer to entry to be deleted. Simple.
; - Procedure handles link patching intelligently.
; - No return value.
;

;-------------------------------------------------------------------
;Structure of an Entry in a Linked List
;-------------------------------------------------------------------

LinkedObject STRUCT ;Example structure is minimal - add some more fields to it :)
pPrev DWORD ? ;Pointer to my daddy if I have one (previous)
pNext DWORD ? ;Pointer to my child if I have one (next)
pLock DWORD ? ;handle for freeing this memory
LinkedObject ENDS

;-------------------------------------------------------------------
;KillEntry Procedure
;-Removes an entry from a Linked-List.
;-Examines Parent<--<THIS>-->Child links and
;-Patches- Parent<-->Child (Bypassing Self).
;-Also detects and patches NewRoot and NewLast nodes.
;-Releases the allocated memory used by the killed entry.
;-In other words, flawless and transparent removal
;-of a single entry in our List.
;-------------------------------------------------------------------

KillEntry PROC lpThis:PTR LinkedObject ;pointer to entry to be deleted

mov esi,[lpThis].pPrev ;(Fetch possible Parent)
.if esi !=0 ;I have a Parent and thus am not Root..
mov edi,[lpThis].pNext ;(Fetch possible Child)
.if esi !=0 ;..and I also have a Child..
push edi ;(ChildPointer)
pop [esi].pNext ;link Parent to Child, bypassing me
push esi ;(ParentPointer)
pop [edi].pPrev ;link Child to Parent, bypassing me
.else ;..and I have no Child..
mov [esi].pNext,NULL ;Kill Parent's link to me
.endif ;(setting it as Last)

.else ;I am Root and have no Parent..
mov edi,[lpThis].pNext ;(Fetch possible Child)
.if esi !=0 ;..but I do have a Child
mov [edi].pPrev,NULL ;Kill Child's link to Parent
.endif ;(setting it as Root)
.endif ; (no parent and no child? alone? nothing to repair then)
mov eax,[lpThis].pLock ;This bit happens regardless...
push eax ;(handle to memory object)
invoke GlobalUnlock,eax ;Unlock this memory
pop eax ;(handle to memory object)
invoke GlobalFree,eax ;Release this memory
return TRUE ;cya
KillEntry ENDP

;-------------------------------------------------------------------
;NewEntry Procedure
;-Adds an entry to a Linked-List...
;-Allocates memory for a new entry,
;-Examines Parent<--->Child links and
;-Patches- Parent<--<THIS>-->Child (Inserting Self).
;-Bidirection links are preserved.
;-------------------------------------------------------------------
NewEntry PROC lpPrev:PTR LinkedObject, ObjectSize:DWORD
LOCAL lpThis,lpOldChild:PTR LinkedObject
LOCAL hMem:DWORD

szText szGAE,"GlobalAlloc err #%lu"
szText szGLE,"GlobalLock err #%lu"

invoke GlobalAlloc,GHND,ObjectSize
mov hMem,eax
.if eax != NULL
invoke GlobalLock,hMem
.if eax != NULL
mov lpThis,eax
push hMem
pop [lpThis].pLock ;Remember my unlock handle
mov esi,lpPrev
push [esi].pNext
pop lpOldChild ;store possible child
.if esi != NULL ;I have a Parent and thus am not Root
push lpThis
pop [esi].pNext ;Tell Parent hes my new daddy- APPENDING
push lpPrev
pop [lpThis].pPrev ;Tell Myself I have a Parent
.if lpOldChild != NULL ;and that Parent had a Child - INSERTING!
push lpThis
pop [lpOldChild].pPrev ;Tell Child I'm their new sugardaddy
push lpOldChild
pop [lpThis].pNext ;Tell Myself I have a Child
.endif ;I have no kids to worry about or
.endif ;I am Root with No Parent and No Child
return lpThis ;Return pointer to the new Object in EAX
.else ;GlobalLock failed...
invoke GetLastError
invoke wsprintf,addr ErrBuf,addr szGLE,eax
invoke MessageBox,addr szGLE,addr szDisplayName,MB_OK+MB_ICONERROR
invoke GlobalFree,hMem ;Free the memory we Failed to Lock
.endif
.else ;GlobalAlloc failed...
invoke GetLastError
invoke wsprintf,addr ErrBuf,addr szGAE,eax
invoke MessageBox,addr szGAE,addr szDisplayName,MB_OK+MB_ICONERROR
.endif
xor eax,eax
ret ;Return ERROR in eax since we have Failed Like Foo


AddEntry ENDP

;-------------------------------------------------------------------

added [ code][ /code] block, and changed the expletive to "foo" - Scronty
Posted on 2002-08-15 11:15:29 by Homer
I have implemented it similarly to the "new" directive in C++
I can invoke NewEntry,pSpaceShips,sizeof SpaceShip for example.
Since Linked Lists have bad access-time symmetry, I implement multiple Lists
to keep Bullets, Enemies, etc.
This way I can perform faster searches and reduce linear access times.
Posted on 2002-08-15 11:23:02 by Homer
Please omit and excuse the obscenity in the final comments.
Posted on 2002-08-15 11:35:34 by Homer
Afternoon, EvilHomer2k.

Attached is the example proggy with the adjusted AddEntry proc (ObjectSize).

I've also added Sibling fieldnames in the LINKEDOBJECT structure. No procs for them yet.
With Siblings, you can have your Bullets/Power/Shields/etc included inside the same main object, and search each Siblings' list individually.

Also added is a couple of Application-Specific fields. These are fields which would be different from application-to-application.
The fields are pName and hNameLock, following the convention of the other fields.
The NewName and KillName procs are implemented and working.
I've placed the KillName calls inside the Kill* procs for the nodes themselves, so that the cleanup process is less visible (i.e. with a few fieldnames, it'd be awkward to have to call each Kill<fieldname> for each field).

The NewName proc will have to be adjusted so that it takes into account any prior allocated Name memory.

NOTE: I've changed the "lock" fields to use a prepended 'h' instead of 'p', as these are handles, and not necessarily memory pointers (though they sometimes seem to be the same thing).

For faster search qualities, there could be an option to have an index structure as the root, which holds pointers to each Child or Sibling.
The idea being, that a "level" or "object" would be generated before the gamelevel begins.

Cheers,
Scronty
Posted on 2002-08-15 20:47:02 by Scronty
Bidirectional siblings, eh?
Nice one !!
Very powerful feature, basically our LinkedList just became a rudimentary Neural Network !!

My interpretation of the Siblings approach would be to actually keep different types of Objects in the main Tree, and to have each list of Siblings represent similar Objects in that Group, which could in turn be Parented to an Owner or Creator...

example .. particles emitted by a particle emitter would have other particles from that emitter as siblings, would have the emitter as parent, and then we could use the child to indicate a subparticle owned by the particle.

Players would have a bunch of weapons but only have one equipped at a time.
That weapon would be the player's child weapon, and its siblings would include all the other weapons available to the player. All those siblings are owned by the same parent, and in the same way we can parent flying bullets to their creators/originators so that a bullet "knows who fired it".

I would have assumed that the unique address of a given instanced object would be enough of a unique identifier, but the strings approach would sure make a game-editor much clearer :)

ok since we are going down the track of multilinkig (siblings) we may as well go the whole hog and implement the parent/child links as pointers to two lists of N parents and N children, giving us the full power of a Neural Network array, as older/younger siblings are basically a secondary parent/child set.
This way an object may be Owned by N objects, and may in turn Own N objects.

What u think?
Posted on 2002-08-16 03:32:23 by Homer
We don't need more parent branches, but N children would be nice.

Here's another couple of procs,
one for the LinkedList include, and one for the GameObjects include...
FindYoungestSibling PROC lpThis:LPLINKEDOBJECT

mov esi,lpThis
assume esi:ptr LinkedObject
.while [esi].pYoungerSibling ;while there's a younger sibling
mov esi,[esi].pYoungerSibling ;walk to that younger sibling
.endw
assume esi:nothing
return esi ;return the address of the youngest sibling
FindYoungestSibling ENDP

AddPlayer PROC lpPlayers:DWORD,lpPlayerName:DWORD
LOCAL lpThis:PTR LinkedPlayerObject
invoke FindYoungestSibling,lpPlayers ;Ensure we are Appending
invoke NewEntry,eax,sizeof LinkedPlayerObject ;create memory object for Player
mov lpThis,eax
invoke NewName,lpThis,lpPlayerName ;Set Name in Linked PlayerObject
m2m [lpThis].Weapon,lpDefaultWeapon ;Initialize new Player further
m2m [lpThis].Score,NULL ;prolly need more here
inc NumPlayers
return TRUE
AddPlayer ENDP
Posted on 2002-08-16 11:13:49 by Homer
Afternoon, EvilHomer2k.

I've begun implementing the Sibling code.
Also implemented is the FindYoungestSibling proc (which is used in the appending of new Siblings).

Attached is a zip of the EXE only, since the code is still in the middle of development.

I've had to split the AddEntry proc into two procs. One for Appending, and one for Insertion. This is because (as you already realise) there isn't any fundamental difference between a Parent/Child relationship and an OlderSibling/YoungerSibling relationship.

The way the Append proc works is, if the given Parent hasn't got a Child, then a Child is appended. If the Parent already has a Child, then a Sibling of that Child is appended.
The Insertion proc hasn't been built yet. However this, I would imagine, would require a param which told the proc whether a Child or a Sibling is being Inserted.

An Update proc will also be required, so that a current Sibling could be made a Child, or a current Child could be made into a Sibling.

As you can see by the proggy, I've also begun a visual representation of the linked list.
It displays the whole list correctly (i.e. every object in the list can be displayed), however I still have to build some kind of "auto-alignment" proc for drawing the text. Any Siblings are offset to the right by 100 pixels. This means that any Siblings of Mesh1 will overwrite the text to the right of it.

Cheers,
Scronty
Posted on 2002-08-17 08:25:52 by Scronty
I have a complete linked list here http://www.asmcommunity.net/board/index.php?topic=3179&highlight=linked+list

I did a little coding on state and process management based on the concept of stacked linked list.

I hope this will help. :alright:
Posted on 2002-08-17 17:12:17 by stryker
Here's my version:



; #########################################################################
; LinkedList.inc
; The following code is for educational purposes only.
; However, since linkedlists are a fundamental part of programming,
; feel free to use this file as you please.
; #########################################################################
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Initial Linkedlist Code:
; KillEntry, AddEntry, plus initial structure
; EvilHomer2k, 15 August 2002, 3:54 in the morning.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Initial Example Program:
; bug fixes, and the addition of KillEntryPlusChildren
; Scronty, 15 August 2002, 11:24pm.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Initial Linkedlist Code Update:
; References to false LinkedObject fields corrected.
; Code in AddEntry altered to include an ObjectSize param for
; new entries.
; EvilHomer2k, 15 August 2002, 9:00 pm.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Example Program Update:
; Implemented EvilHomer2ks altered AddEntry param (ObjectSize).
; Added Sibling fieldnames in LINKEDOBJECT struct (no procs).
; Added Application-Specific fieldnames in LINKEDOBJECT
; struct (NAME).
; Added NewName and KillName procs for the NAME fieldnames.
; Scronty, 16 August 2002, 11:08am.
; --------
; Changed name of AddEntry procedure to AddChildEntry.
; Added procedure: AddSiblingEntry
; Added procedure: KillEntryPlusYoungerSiblings
; Modified procedure: KillEntry to also patch Sibling links.
; EvilHomer, 18 August 2002, 11:02pm.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Current Table of Procedures:
; ============================
; -AddChildEntry
; -AddSiblingEntry
; -NewName
; -KillName
; -KillEntry (not recursive)(Checks all links)
; -KillEntryPlusChildren (recursive)(does not check Sibling links)
; -KillEntryPlusYoungerSiblings (recursive)(does not check Parent-Child links)
;
;-------------------------------------------------------------------
;Structure of an Entry in a Linked List
;-------------------------------------------------------------------

_LINKEDOBJECT STRUCT ;Example structure is minimal - add some more fields to it

; Everything between the "~~~~" lines are mandatory.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pParent DWORD ? ;Pointer to my parent if I have one (Parent)
pChild DWORD ? ;Pointer to my child if I have one (Child)
pOlderSibling DWORD ? ;Pointer to my older sibling if I have one (Older Sibling)
pYoungerSibling DWORD ? ;Pointer to my younger sibling if I have one (Younger Sibling)
hLock DWORD ? ;Handle for freeing this memory
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; Add Application-Specific fields here
;_____________________________________
; NAME
pName DWORD ? ;Pointer to the name of this object (Name)
hNameLock DWORD ? ;Handle for freeing the Names' memory
;_____________________________________

_LINKEDOBJECT ENDS
LINKEDOBJECT TYPEDEF _LINKEDOBJECT
LPLINKEDOBJECT TYPEDEF PTR _LINKEDOBJECT

; #########################################################################

; macros:
; CTEXT macro
; eg.
; invoke MessageBox, NULL, CTEXT("Hello World!"), NULL, MB_OK
CTEXT macro y:vararg
local sym

const segment

ifidni <y>, <>
sym db 0
else
sym db y, 0
endif
const ends
exitm <offset sym>
endm
;## 'return' Macro ##
return MACRO returnvalue
mov eax, returnvalue
ret
ENDM

; #########################################################################
.data

ERRbuff db 128 DUP (0)

; #########################################################################
.code
KillName PROC lpThis:PTR LINKEDOBJECT
push edi

mov eax, lpThis
mov edi, eax

.if [edi].LINKEDOBJECT.hNameLock != NULL ;I have a Name
mov eax,[edi].LINKEDOBJECT.hNameLock ;This bit happens regardless...
invoke GlobalUnlock,eax ;Unlock this memory
mov eax,[edi].LINKEDOBJECT.hNameLock ;Grab the handle to this memory
invoke GlobalFree,eax ;Release this memory
;_____________________________________
;Null-out Name fields
mov [edi].LINKEDOBJECT.pName, NULL
mov [edi].LINKEDOBJECT.hNameLock, NULL
;_____________________________________

invoke MessageBox,NULL,CTEXT("Killed Name!"),CTEXT("Success!"),MB_OK
.endif

pop edi

return TRUE
KillName ENDP

NewName PROC lpThis:PTR LINKEDOBJECT, pszNewName:DWORD
LOCAL dwSize:DWORD

push edi
push esi

mov eax, lpThis
mov edi, eax

;________________________________
;Get the string length
mov eax, pszNewName
@@:
mov dl, [eax]
inc eax
cmp dl, 0
jne @B
sub eax, pszNewName
dec eax ; correct count
mov dwSize, eax
;________________________________
mov eax, dwSize
inc eax
invoke GlobalAlloc,GPTR,eax ;Allocate memory for name
mov [edi].LINKEDOBJECT.hNameLock, eax ;Remember the unlock handle
.if eax != NULL
invoke GlobalLock,[edi].LINKEDOBJECT.hNameLock
mov [edi].LINKEDOBJECT.pName, eax
.if eax != NULL
;________________________________
;Copy name into allocated memory
cld
mov esi, [pszNewName]
mov eax, [edi].LINKEDOBJECT.pName
mov edi, eax
mov ecx, dwSize

shr ecx, 2
rep movsd

mov ecx, dwSize
and ecx, 3
rep movsb
inc edi
mov BYTE PTR [edi], 0 ;Appended a 0
;________________________________

mov eax, lpThis
invoke MessageBox,NULL,CTEXT("Added Name!"),[eax].LINKEDOBJECT.pName,MB_OK

;Return the node-pointer back to the caller
mov eax, lpThis
pop esi
pop edi
return eax ;Return pointer to the new Object in EAX
.else ;GlobalLock failed...
invoke GetLastError
invoke wsprintf,addr ERRbuff,CTEXT("GlobalLock err #%lu"),eax
invoke MessageBox,NULL, addr ERRbuff,CTEXT("Error!"),MB_OK+MB_ICONERROR
invoke GlobalFree,[edi].LINKEDOBJECT.hNameLock ;Free the memory we Failed to Lock
mov [edi].LINKEDOBJECT.hNameLock, NULL
.endif
.else ;GlobalAlloc failed...
invoke GetLastError
invoke wsprintf,addr ERRbuff,CTEXT("GlobalAlloc err #%lu"),eax
invoke MessageBox,NULL,addr ERRbuff,CTEXT("Error!"),MB_OK+MB_ICONERROR
.endif

pop esi
pop edi

xor eax,eax
ret ;Return ERROR in eax since we have Failed

NewName ENDP


;-------------------------------------------------------------------
;KillEntry Procedure
;-Removes an entry from a Linked-List.
;-Revised to handle parent-child and/or sibling links.
;-Examines Parent<--<THIS>-->Child links and
;-Patches- Parent<-->Child (Bypassing Self).
;-Examines OlderSibling<--<THIS>--YoungerSibling links and
;-Patches- OlderSibling<-->YoungerSibling (Bypassing Self).
;-Also detects and patches NewRoot and NewLast nodes.
;-Releases the allocated memory used by the killed entry.
;-In other words, flawless and transparent removal
;-of a single entry in our List.
;-------------------------------------------------------------------
KillEntry PROC lpThis:PTR LinkedObject ;pointer to entry to be deleted
push edi
push esi

mov eax, lpThis
mov edi, eax

;Kill any Name for this node
invoke KillName, edi

.if ([edi].LINKEDOBJECT.pParent != NULL) || ([edi].LINKEDOBJECT.pOlderSibling != NULL) ;I have a Parent and thus am not Root..
.if [edi].LINKEDOBJECT.pChild != NULL ;..and I also have a Child..
mov eax, [edi].LINKEDOBJECT.pParent ;(fetch ParentPointer)
mov esi, eax
mov eax, [edi].LINKEDOBJECT.pChild ;(fetch ChildPointer)
mov [esi].LINKEDOBJECT.pChild, eax ;link Parent to Child, bypassing me
mov eax, [edi].LINKEDOBJECT.pChild ;(ChildPointer)
mov esi, eax
mov eax, [edi].LINKEDOBJECT.pParent ;(ParentPointer)
mov [esi].LINKEDOBJECT.pParent, eax ;link Child to Parent, bypassing me
.else ;..and I have no Child..
mov eax, [edi].LINKEDOBJECT.pParent
mov esi, eax
mov [esi].LINKEDOBJECT.pChild,NULL ;Kill Parent's link to me
.endif
;----------
.if [edi].LINKEDOBJECT.pYoungerSibling !=NULL ;..and I have a younger sibling
mov eax, [edi].LINKEDOBJECT.pOlderSibling
mov esi,eax
mov eax,[edi].LINKEDOBJECT.pYoungerSibling
mov [esi].LINKEDOBJECT.pYoungerSibling,eax
mov eax,[edi].LINKEDOBJECT.pYoungerSibling
mov esi,eax
mov eax,[edi].LINKEDOBJECT.pOlderSibling
mov [esi].LINKEDOBJECT.pOlderSibling,eax
.else ;..I have no younger sibling..
mov eax, [edi].LINKEDOBJECT.pOlderSibling
mov esi, eax
mov [esi].LINKEDOBJECT.pYoungerSibling,NULL ;Kill Parent's link to me
.endif ;(setting it as Last)
invoke MessageBox,NULL,CTEXT("killed Child!"),CTEXT("Success!"),MB_OK

.else ;I am Root and have no Parent..
.if [edi].LINKEDOBJECT.pChild != NULL ;..but I do have a Child
mov eax, [edi].LINKEDOBJECT.pChild
mov esi, eax
mov [esi].LINKEDOBJECT.pParent,NULL ;Kill Child's link to Parent
.endif ;(setting it as Root)
.if [edi].LINKEDOBJECT.pYoungerSibling != NULL ;..but I do have a Child
mov eax, [edi].LINKEDOBJECT.pYoungerSibling
mov esi, eax
mov [esi].LINKEDOBJECT.pOlderSibling,NULL ;Kill Child's link to Parent
.endif ;(setting it as Root)

invoke MessageBox,NULL,CTEXT("killed Root!"),CTEXT("Success!"),MB_OK
.endif

; (no parent and no child? alone? nothing to repair then)

mov eax,[edi].LINKEDOBJECT.hLock ;This bit happens regardless...
invoke GlobalUnlock,eax ;Unlock this memory
mov eax,[edi].LINKEDOBJECT.hLock ;Grab the handle to this memory
invoke GlobalFree,eax ;Release this memory

pop esi
pop edi

return TRUE ;cya
KillEntry ENDP

;-------------------------------------------------------------------
;AddChildEntry Procedure
;-Adds an entry to a Linked-List...
;-Allocates memory for a new entry,
;-Examines Parent<--->Child links and
;-Patches- Parent<--<THIS>-->Child (Inserting Self).
;-Bidirection links are preserved.
;-------------------------------------------------------------------
AddChildEntry PROC lpParent:PTR LINKEDOBJECT, ObjectSize:DWORD
LOCAL lpOldChild:PTR LINKEDOBJECT
LOCAL hMem:DWORD
push edi
push esi

mov eax, lpParent
mov esi, eax

invoke GlobalAlloc,GPTR,ObjectSize
mov hMem,eax
.if eax != NULL
invoke GlobalLock,hMem
mov edi, eax
.if eax != NULL
mov eax, hMem
mov [edi].LINKEDOBJECT.hLock, eax ;Remember my unlock handle
.if esi != NULL ;I have a Parent and thus am not Root
mov eax, [esi].LINKEDOBJECT.pChild
mov lpOldChild, eax ;store possible child
mov [esi].LINKEDOBJECT.pChild, edi ;Tell Parent hes my new daddy- APPENDING
mov [edi].LINKEDOBJECT.pParent, esi ;Tell Myself I have a Parent
mov eax, lpOldChild
.if eax != NULL ;and that Parent had a Child - INSERTING!
mov eax, lpOldChild
mov esi, eax
mov [esi].LINKEDOBJECT.pParent, edi ;Tell Child I'm their new sugardaddy
mov [edi].LINKEDOBJECT.pChild, esi ;Tell Myself I have a Child
invoke MessageBox,NULL,CTEXT("Child Inserted!"),CTEXT("Success!"),MB_OK
.else
mov [edi].LINKEDOBJECT.pChild, NULL
invoke MessageBox,NULL,CTEXT("Child Appended!"),CTEXT("Success!"),MB_OK
.endif ;I have no kids to worry about or
.else ;I am Root with No Parent and No Child
mov [edi].LINKEDOBJECT.pParent, NULL
mov [edi].LINKEDOBJECT.pChild, NULL
mov [edi].LINKEDOBJECT.pOlderSibling, NULL
mov [edi].LINKEDOBJECT.pYoungerSibling, NULL
invoke MessageBox,NULL,CTEXT("Added Root!"),CTEXT("Success!"),MB_OK
.endif

;_____________________________________
;Null-out Application-Specific fields
mov [edi].LINKEDOBJECT.pName, NULL
mov [edi].LINKEDOBJECT.hNameLock, NULL
;_____________________________________
mov eax, edi
pop esi
pop edi
return eax ;Return pointer to the new Object in EAX
.else ;GlobalLock failed...
invoke GetLastError
invoke wsprintf,addr ERRbuff,CTEXT("GlobalLock err #%lu"),eax
invoke MessageBox,NULL, addr ERRbuff,CTEXT("Error!"),MB_OK+MB_ICONERROR
invoke GlobalFree,hMem ;Free the memory we Failed to Lock
.endif
.else ;GlobalAlloc failed...
invoke GetLastError
invoke wsprintf,addr ERRbuff,CTEXT("GlobalAlloc err #%lu"),eax
invoke MessageBox,NULL,addr ERRbuff,CTEXT("Error!"),MB_OK+MB_ICONERROR
.endif

pop esi
pop edi

xor eax,eax
ret ;Return ERROR in eax since we have Failed

AddChildEntry ENDP




;-------------------------------------------------------------------
;AddSiblingEntry Procedure
;-Adds an entry to a Linked-List...
;-Allocates memory for a new entry,
;-Examines OlderSibling<--->YoungerSibling links and
;-Patches- Parent<--<THIS>-->Child (Inserting Self).
;-Bidirection links are preserved.
;-------------------------------------------------------------------
AddSiblingEntry PROC lpParent:PTR LINKEDOBJECT, ObjectSize:DWORD
LOCAL lpOldChild:PTR LINKEDOBJECT
LOCAL hMem:DWORD
push edi
push esi

mov eax, lpParent
mov esi, eax

invoke GlobalAlloc,GPTR,ObjectSize
mov hMem,eax
.if eax != NULL
invoke GlobalLock,hMem
mov edi, eax
.if eax != NULL
mov eax, hMem
mov [edi].LINKEDOBJECT.hLock, eax ;Remember my unlock handle
.if esi != NULL ;I have a Parent and thus am not Root
mov eax, [esi].LINKEDOBJECT.pYoungerSibling
mov lpOldChild, eax ;store possible child
mov [esi].LINKEDOBJECT.pYoungerSibling, edi ;Tell Parent hes my new daddy- APPENDING
mov [edi].LINKEDOBJECT.pOlderSibling, esi ;Tell Myself I have a Parent
mov eax, lpOldChild
.if eax != NULL ;and that Parent had a Child - INSERTING!
mov eax, lpOldChild
mov esi, eax
mov [esi].LINKEDOBJECT.pOlderSibling, edi ;Tell Child I'm their new sugardaddy
mov [edi].LINKEDOBJECT.pYoungerSibling, esi ;Tell Myself I have a Child
invoke MessageBox,NULL,CTEXT("Sibling Inserted!"),CTEXT("Success!"),MB_OK
.else
mov [edi].LINKEDOBJECT.pChild, NULL
invoke MessageBox,NULL,CTEXT("Sibling Appended!"),CTEXT("Success!"),MB_OK
.endif ;I have no kids to worry about or
.else ;I am Root with No Parent and No Child
mov [edi].LINKEDOBJECT.pParent, NULL
mov [edi].LINKEDOBJECT.pChild, NULL
mov [edi].LINKEDOBJECT.pOlderSibling, NULL
mov [edi].LINKEDOBJECT.pYoungerSibling, NULL
invoke MessageBox,NULL,CTEXT("Added Root!"),CTEXT("Success!"),MB_OK
.endif

;_____________________________________
;Null-out Application-Specific fields
mov [edi].LINKEDOBJECT.pName, NULL
mov [edi].LINKEDOBJECT.hNameLock, NULL
;_____________________________________
mov eax, edi
pop esi
pop edi
return eax ;Return pointer to the new Object in EAX
.else ;GlobalLock failed...
invoke GetLastError
invoke wsprintf,addr ERRbuff,CTEXT("GlobalLock err #%lu"),eax
invoke MessageBox,NULL, addr ERRbuff,CTEXT("Error!"),MB_OK+MB_ICONERROR
invoke GlobalFree,hMem ;Free the memory we Failed to Lock
.endif
.else ;GlobalAlloc failed...
invoke GetLastError
invoke wsprintf,addr ERRbuff,CTEXT("GlobalAlloc err #%lu"),eax
invoke MessageBox,NULL,addr ERRbuff,CTEXT("Error!"),MB_OK+MB_ICONERROR
.endif

pop esi
pop edi

xor eax,eax
ret ;Return ERROR in eax since we have Failed

AddSiblingEntry ENDP


;-------------------------------------------------------------------
;KillEntryPlusChildren Procedure
;-Removes an entry from a Linked-List.
;-Examines Parent<--<THIS>-->Child links and
;-Patches- Parent (Deleting Self).
;-Also detects Child links and recursively removes them.
;-Releases the allocated memory used by the killed entry.
;-In other words, flawless and transparent removal
;-of a single entry in our List.
;-------------------------------------------------------------------
KillEntryPlusChildren PROC lpThis:PTR LinkedObject ;pointer to entry to be deleted
push edi
push esi

mov eax, lpThis
mov edi, eax

.if [edi].LINKEDOBJECT.pParent != NULL ;I have a Parent and thus am not Root..
mov eax, [edi].LINKEDOBJECT.pParent
mov esi, eax
mov [esi].LINKEDOBJECT.pChild,NULL ;Kill Parent's link to me
.if [edi].LINKEDOBJECT.pChild !=NULL ;..and I also have a Child..
invoke KillEntryPlusChildren, [edi].LINKEDOBJECT.pChild ; Kill Child
;Kill any Name for this node
invoke KillName, lpThis
invoke MessageBox,NULL,CTEXT("killed Child Node!"),CTEXT("Success!"),MB_OK
.else
;Kill any Name for this node
invoke KillName, lpThis
invoke MessageBox,NULL,CTEXT("killed End Node!"),CTEXT("Success!"),MB_OK
.endif

.else ;I am Root with No Parent
.if [edi].LINKEDOBJECT.pChild != NULL ;..and I also have a Child..
invoke KillEntryPlusChildren, [edi].LINKEDOBJECT.pChild ; Kill Child
.endif
;Kill any Name for this node
invoke KillName, lpThis
invoke MessageBox,NULL,CTEXT("Killed Root!"),CTEXT("Success!"),MB_OK

.endif

invoke GlobalUnlock,[edi].LINKEDOBJECT.hLock ;Unlock this memory
invoke GlobalFree,[edi].LINKEDOBJECT.hLock ;Release this memory

pop esi
pop edi

return TRUE ;cya
KillEntryPlusChildren ENDP


;-------------------------------------------------------------------
;KillEntryPlusYoungerSiblings Procedure
;-Removes an entry from a Linked-List.
;-Examines OlderSibling<--<THIS>-->YoungerSibling links and
;-Patches- OlderSibling<-->YoungerSibling (Deleting Self).
;-Also detects Child links and recursively removes them.
;-Releases the allocated memory used by the killed entry.
;-In other words, flawless and transparent removal
;-of a single entry in our List plus its Younger Siblings.
;-------------------------------------------------------------------
KillEntryPlusYoungerSiblings PROC lpThis:PTR LinkedObject ;pointer to entry to be deleted
push edi
push esi

mov eax, lpThis
mov edi, eax

.if [edi].LINKEDOBJECT.pOlderSibling != NULL ;I have a Parent and thus am not Root..
mov eax, [edi].LINKEDOBJECT.pOlderSibling
mov esi, eax
mov [esi].LINKEDOBJECT.pYoungerSibling,NULL ;Kill Parent's link to me
.if [edi].LINKEDOBJECT.pYoungerSibling !=NULL ;..and I also have a Child..
invoke KillEntryPlusYoungerSiblings, [edi].LINKEDOBJECT.pYoungerSibling; Kill Child
;Kill any Name for this node
invoke KillName, lpThis
invoke MessageBox,NULL,CTEXT("killed Child Sibling Node!"),CTEXT("Success!"),MB_OK
.else
;Kill any Name for this node
invoke KillName, lpThis
invoke MessageBox,NULL,CTEXT("killed End Sibling Node!"),CTEXT("Success!"),MB_OK
.endif

.else ;I am Root with No Parent
.if [edi].LINKEDOBJECT.pChild != NULL ;..and I also have a Child..
invoke KillEntryPlusYoungerSiblings [edi].LINKEDOBJECT.pYoungerSibling ; Kill Child
.endif
;Kill any Name for this node
invoke KillName, lpThis
invoke MessageBox,NULL,CTEXT("Killed Root!"),CTEXT("Success!"),MB_OK

.endif

invoke GlobalUnlock,[edi].LINKEDOBJECT.hLock ;Unlock this memory
invoke GlobalFree,[edi].LINKEDOBJECT.hLock ;Release this memory

pop esi
pop edi

return TRUE ;cya
KillEntryPlusYoungerSiblings ENDP
Posted on 2002-08-18 08:06:06 by Homer