Snippet Linked List Module

Kenny

Back for now.
Reaction score
202
Linked List Module
By Kenny
Version 3.0.0

Description:

This module is a very powerful tool for structs. It enables users to create a linked list using a struct instance as the list itself, allowing for multiple lists in the one struct. It is simple to use and generates a very intuitive and basic interface that is easy to follow and understand. A linked list can be used to store struct instances instead of using the 'struct stack' method, and can also be used to attached a list to units and so on. When used appropriately it can give great functionality to users.​

Requirements:

Script:

JASS:
//------------------------------------------------------------------------------------\\
//                            Linked List Module [v3.0.0]                             \\
//                               By Kenny & Jesus4Lyf.                                \\
//                              Constructed using vJASS.                              \\
//                                Requires: NewGen WE.                                \\
//------------------------------------------------------------------------------------\\
//                                                                                    \\
//------------------------------------------------------------------------------------\\
//  DESCRIPTION:                                                                      \\
// ¯¯¯¯¯¯¯¯¯¯¯¯¯                                                                      \\
//    This module is a very powerful tool for structs. It enables users to create a   \\
//    linked list using a struct instance as the list itself, allowing for multiple   \\
//    lists in the one struct. It is simple to use and generates a very intuitive and \\
//    basic interface that is easy to follow and understand. A linked list can be     \\
//    used to store struct instances instead of using the 'struct stack' method, and  \\
//    can also be used to attached a list to units and so on. When used appropriately \\
//    it can give great functionality to users.                                       \\
//                                                                                    \\
//  METHODS:                                                                          \\
// ¯¯¯¯¯¯¯¯¯                                                                          \\
//    There are several methods available to you when you use this module, they       \\
//    include:                                                                        \\
//                                                                                    \\
//      Static methods:                                                               \\
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯                                                               \\
//        - .createList()   - Creates a list using a struct instance as its 'base'.   \\
//                          - Returns thistype. Retuns the list itself.               \\
//                                                                                    \\
//      Non-static methods:                                                           \\
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯                                                           \\
//        - .searchList()   - Searches a list for a given instance of a struct type.  \\
//                          - Returns thistype.                                       \\
//                                                                                    \\
//        - .destroyList()  - Destroys each link in the list, as well as the list.    \\
//                          - Returns nothing.                                        \\
//                                                                                    \\
//        - .addToStart()   - Adds a struct instance to the start of the list.        \\
//                          - Returns thistype. Returns the parameter.                \\
//                                                                                    \\
//        - .addToEnd()     - Adds a struct instance to the end of the list.          \\
//                          - Returns thistype. Returns the parameter.                \\
//                                                                                    \\
//        - .detachHead()   - Removes the first link from the list.                   \\
//                          - Returns thistype. Returns the first link.               \\
//                                                                                    \\
//        - .detachTail()   - Removes the last link from the list.                    \\
//                          - Returns thistype. Returns the last link.                \\
//                                                                                    \\
//        - .detachThis()   - Removes the current link from the list.                 \\
//                          - Returns thistype. Returns the current link.             \\
//                                                                                    \\
//        - .destroyHead()  - Removes the first link from the list and calls the      \\
//                            .destroy() method.                                      \\
//                          - Returns nothing.                                        \\
//                                                                                    \\
//        - .destroyTail()  - Removes the last link from the list and calls the       \\
//                            .destroy() method.                                      \\
//                          - Returns nothing.                                        \\
//                                                                                    \\
//        - .destroyThis()  - Removes the current link from the list and call the     \\
//                            .destroy() method.                                      \\
//                          - Returns nothing.                                        \\
//                                                                                    \\
//  MEMBERS:                                                                          \\
// ¯¯¯¯¯¯¯¯¯                                                                          \\
//    There are several members that users can access using this module, these        \\
//    include:                                                                        \\
//                                                                                    \\
//      Readonly members:                                                             \\
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯                                                             \\
//        - .head           - Retrieves the first link in the list and returns it.    \\ 
//                          - Returns thistype.                                       \\
//                                                                                    \\
//        - .next           - Retrieves the next link in the list and returns it.     \\
//                          - Returns thistype. Returns the next link.                \\
//                                                                                    \\
//        - .hasNext        - Checks to see if the current link has a next link.      \\
//                          - Returns boolean. Returns true is next link is there.    \\
//                                                                                    \\
//        - .tail           - Retrieves the last link in the list and returns it.     \\
//                          - Returns thistype. Returns the last link.                \\
//                                                                                    \\
//        - .prev           - Retrieves the prev link in the list and returns it.     \\
//                          - Returns thistype. Returns the previous link.            \\
//                                                                                    \\
//        - .hasPrev        - Checks to see if the current link has a next link.      \\
//                          - Returns boolean. Returns true if prev link is there.    \\ 
//                                                                                    \\
//        - .size           - Retrieves the current size of a list (Number of links). \\
//                          - Returns integer. Returns the number of current links.   \\
//                                                                                    \\
//        - .empty          - Checks to see if a given list is empty or not.          \\
//                          - Returns boolean. Returns true if list is empty.         \\
//                                                                                    \\
//        - .isList         - Checks to see if a given struct instance is a list.     \\
//                          - Returns boolean. Returns true if an instance is a list. \\ 
//                                                                                    \\
//  USAGE/EXAMPLES:                                                                   \\
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯                                                                   \\
//    To use this module within a struct you must implement it using the following:   \\
//                                                                                    \\
//      private struct Data                                                           \\
//          implement LinkedList                                                      \\
//                                                                                    \\
//          Do stuff here using the module.                                           \\
//      endstruct                                                                     \\
//                                                                                    \\
//    It is easiest to implement it right under struct declaration.                   \\
//                                                                                    \\
//    There are only three methods available which use parameters. Usage for these    \\
//    three methods are as follows:                                                   \\
//                                                                                    \\
//      call .addToStart(thistype value)                                              \\
//      call .addToEnd(thistype value)                                                \\
//      call .searchList(thistype value)                                              \\
//                                                                                    \\
//    The above take one parameter. The parameter must be a thistype value. Meaning   \\
//    it takes a struct instance as the parameter.                                    \\   
//                                                                                    \\
//  PROS & CONS:                                                                      \\
// ¯¯¯¯¯¯¯¯¯¯¯¯¯                                                                      \\
//    As this module is just a simplification of struct stack syntax, there are not   \\
//    many negative points for it. However, just for the sake of it:                  \\
//                                                                                    \\
//      Pros:                                                                         \\
//     ¯¯¯¯¯¯                                                                         \\
//        - Simplifies syntax a fair bit. Makes it easier to read.                    \\
//        - Allows for multiple linked lists within a single struct, generating       \\
//          multiple storage components.                                              \\
//        - Reduces time spent developing spells/scripts and reduces lines.           \\
//        - There is also a -possible- efficiency gain over the normal struct stack.  \\
//          But this I am not sure of.                                                \\
//                                                                                    \\
//      Cons:                                                                         \\
//     ¯¯¯¯¯¯                                                                         \\
//        - A single node can only exist in one list at a time.                       \\
//                                                                                    \\
//  IMPORTING:                                                                        \\
// ¯¯¯¯¯¯¯¯¯¯¯                                                                        \\
//    Simply create a new trigger, name it LinkedList or something along those lines. \\
//    Then convert it to custom text, and paste this in its place and save. Done.     \\
//                                                                                    \\
//  THANKS/CREDITS:                                                                   \\
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯                                                                   \\
//    - Jesus4Lyf - For basically re-inventing the module to make it far more useful  \\
//                  and dynamic. Also for helping me understand linked lists better   \\
//                  and helping to develop the script further. Major props to him.    \\
//                                                                                    \\
//------------------------------------------------------------------------------------\\
library ListModule
    
    module LinkedList
    
        private thistype nextx = 0
        private thistype prevx = 0
        private thistype listx = 0
        private boolean  aList = false

        method operator head takes nothing returns thistype
            debug if not this.aList then
                debug call BJDebugMsg("Linked List Module (head): Struct instance is not a list.")
                debug return 0
            debug endif
            return this.nextx
        endmethod
        
        method operator next takes nothing returns thistype
            return this.nextx
        endmethod
        
        method operator hasNext takes nothing returns boolean
            return this.nextx != 0
        endmethod
        
        method operator tail takes nothing returns thistype
            debug if not this.aList then
                debug call BJDebugMsg("Linked List Module (last): Struct instance is not a list.")
                debug return 0
            debug endif
            return this.prevx
        endmethod
        
        method operator prev takes nothing returns thistype
            return this.prevx
        endmethod
        
        method operator hasPrev takes nothing returns boolean
            return this.prevx != 0
        endmethod
        
        method operator size takes nothing returns integer
            debug if not this.aList then
                debug call BJDebugMsg("Linked List Module (size/empty): Struct instance is not a list.")
                debug return 0
            debug endif
            return integer(this.listx)
        endmethod
        
        method operator empty takes nothing returns boolean
            return this.size == 0
        endmethod
        
        method operator isList takes nothing returns boolean    
            return this.aList
        endmethod
        
        method operator[] takes integer index returns thistype
            loop
                set this = this.nextx
                set index = index - 1
                exitwhen index == 0
            endloop
            return this
        endmethod
        
        method destroyThis takes nothing returns nothing
            call this.detachThis().destroy()
        endmethod
        
        method destroyTail takes nothing returns nothing
            call this.detachTail().destroy()
        endmethod
        
        method destroyHead takes nothing returns nothing
            call this.detachHead().destroy()
        endmethod
        
        method detachThis takes nothing returns thistype
            debug if this.listx == 0 then
                debug call BJDebugMsg("Linked List Module (detachThis): Struct instance is not attached to a list.")
                debug return 0
            debug endif
            
            if this.listx.nextx == this then
                call this.listx.detachHead()
            elseif this.listx.prevx == this then
                call this.listx.detachTail()
            else
                set this.prevx.nextx = this.nextx
                set this.nextx.prevx = this.prevx
                set this.listx.listx = integer(this.listx.listx) - 1
                
                set this.nextx = 0
                set this.prevx = 0
                set this.listx = 0
            endif
            
            return this
        endmethod
        
        method detachTail takes nothing returns thistype
            local thistype tail = this.prevx
            
            debug if not this.aList then
                debug call BJDebugMsg("Linked List Module (detachLast): Struct instance is not a list.")
                debug return 0
            debug endif
            
            set this.prevx = this.prevx.prevx
            set this.prevx.nextx = 0
            set this.listx = integer(this.listx) - 1
            
            set tail.nextx = 0
            set tail.prevx = 0
            set tail.listx = 0
            
            if this.nextx == tail then
                set this.nextx = 0
            endif
            
            return tail
        endmethod
        
        method detachHead takes nothing returns thistype
            local thistype head = this.nextx
            
            debug if not this.aList then
                debug call BJDebugMsg("Lniked List Module (detachHead): Struct instance is not a list.")
                debug return 0
            debug endif
            
            set this.nextx = this.nextx.nextx
            set this.nextx.prevx = 0
            set this.listx = integer(this.listx) - 1
            
            set head.nextx = 0
            set head.prevx = 0
            set head.listx = 0
            
            if this.prevx == head then
                set this.prevx = 0
            endif
            
            return head
        endmethod
        
        method addToEnd takes thistype toAdd returns thistype
            debug if not this.aList then
                debug call BJDebugMsg("Linked List Module (addToEnd): Struct instance is not a list.")
                debug return 0
            debug endif
            
            set this.prevx.nextx = toAdd
            set toAdd.prevx = this.prevx
            set this.prevx = toAdd
            
            if this.nextx == 0 then
                set this.nextx = toAdd
            endif
            
            set toAdd.listx = this
            set this.listx  = integer(this.listx) + 1
            
            return toAdd
        endmethod
        
        method addToStart takes thistype toAdd returns thistype
            debug if not this.aList then
                debug call BJDebugMsg("Linked List Module (addToStart): Struct instance is not a list.")
                debug return 0
            debug endif
            
            set this.nextx.prevx = toAdd
            set toAdd.nextx = this.nextx
            set this.nextx = toAdd
            
            if this.prevx == 0 then
                set this.prevx = toAdd
            endif
            
            set toAdd.listx = this
            set this.listx  = integer(this.listx) + 1
            
            return toAdd
        endmethod
        
        method destroyList takes nothing returns nothing
            debug if not this.aList then
                debug call BJDebugMsg("Linked List Module (destroyList): Struct instance is not a list.")
                debug return
            debug endif
            
            loop
                if this.aList then
                    call this.deallocate()
                else
                    call this.destroy()
                endif
                set this = this.nextx
                exitwhen this == 0
            endloop
        endmethod
        
        method searchList takes thistype toSearch returns thistype
            debug if not this.aList then
                debug call BJDebugMsg("Linked List Module (searchList): Struct instance is not a list.")
                debug return 0
            debug endif
            
            loop
                set this = this.nextx
                if this == toSearch then
                    return this
                endif
                exitwhen this == 0
            endloop
            
            return 0
        endmethod
        
        static method createList takes nothing returns thistype
            local thistype this = thistype.allocate()
            
            set this.aList = true
            
            return this
        endmethod
        
    endmodule
    
endlibrary


Updates:

  • Version 1.0.0 - Initial release. [23rd June, 2009].
  • Version 2.0.0 - Major update. Total re-write of script to allow for greater functionality. Thanks to Jesus4Lyf. [10th July, 2009].
  • Version 3.0.0 - Major update. Another re-write of the script, making it much neater and easier to use. [26th Feb. 2010].
 

Jesus4Lyf

Good Idea™
Reaction score
397
Hate to be unfair, but this isn't necessary... Periodic Module does this in a much simpler way, doesn't it?

Why did you make this a struct-stack timer system? They're the one thing that doesn't need a linked list... But if you ever write a struct-stack faster than Periodic Module, be sure to give us a yell. :D

JASS:
private boolean  link = false        // If link is added to list.

Surely you can remove this field... What's it do?
 

Kenny

Back for now.
Reaction score
202
Hate to be unfair, but this isn't necessary... Periodic Module does this in a much simpler way.

Criticism is always welcome, I don't mind. I have just never really looked at periodic module before.

Why did you make this a struct-stack timer system? They're the one thing that doesn't need a linked list...

Actually its not a "timer" system, its just a simpler way to index structs. I just added the timer because they are needed the majority of timers that you use struct stacks. And this thing isn't about speed, just a nicer interface to use. This module does not have to be used in conjunction with timers.

Surely you can remove this field... What's it do?

An attempt to stop user stupidity? Just in case they try to link the same struct more than once. Which is highly unlikely. If you think it should be removed, then so be it.

Thanks for your comments, I was wondering if you would give this a look over. Your "black magic" kind of inspired me to learn something about linked lists :p.
 

Jesus4Lyf

Good Idea™
Reaction score
397
>Thanks for your comments, I was wondering if you would give this a look over. Your "black magic" kind of inspired me to learn something about linked lists :p.

After a bit of a look over, I have to suggest a couple of things...

You've constructed this quite specifically for timers. I'd like to suggest that instead of making a struct type into a single linked list, you allow users to create linked lists of structs.

So your module implements the methods:
  • static createList() --> thistype (a dummy node to contain the list)
  • destroyList()
  • getFirst() --> thistype
  • getNext() --> thistype
  • getLast() --> thistype
  • getPrevious() --> thistype
  • addToStart(thistype)
  • addToEnd(thistype)
  • hasNext(thistype) --> boolean (compares next to 0)
  • hasPrevious(thistype) --> boolean (compares prev to 0)
  • detachFirst()
  • detachLast()
  • destroyFirst()
  • destroyLast()
(Of course you can add more to this list if you like...)

One node can only be in one list, but you can have many separate lists. For the dummy node, you can reuse the next and previous fields as "first" and "last". These can be invisible to the end user. Get it? :p

Then this becomes very user friendly and also very dynamic. So the only thing users must understand is that thistype becomes either a list or a single node of that type, and not to confuse the two in their use. Then you can attach lists of nodes to a unit, instead of a single node, for example. Suddenly this module is POWERFUL! :D Heh...

Oh, and remove that random static timer variable, ey? <_< It's doing you no favors. :)
 

Kenny

Back for now.
Reaction score
202
You've constructed this quite specifically for timers.

That was initially the point of this, but i see how this could become better if I change it according to what you said. Unfortunately, I don't think I am experienced enough yet to do it. I learnt most of this from wikipedia, lol.

Oh, and remove that random static timer variable, ey? <_< It's doing you no favors.

Will do, once I figure out how to do the changes you specified.

This is currently still a utility module for struct stacks until I see fit to actually updae it with changes.
 

Jesus4Lyf

Good Idea™
Reaction score
397
Untested, but I just punched this out as fast as I could before I have to go. :)

JASS:
library Linked
    
    public module List
        
        // For each struct...
        private thistype next = 0            // Next node link.
        private thistype prev = 0            // Prev node link.
        private thistype list = 0            // Which list this node belongs to.

        // For list structs...
        // define next: first                // First node in a list.
        // define prev: last                 // Last node in a list.
        // Could add... define list: count... But I don&#039;t see why. <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite1" alt=":)" title="Smile    :)" loading="lazy" data-shortname=":)" /> - Jesus4Lyf.
        
        static method createList takes nothing returns thistype
            return thistype.allocate()
        endmethod
        
        method destroyList takes nothing returns nothing
            loop
                call this.destroy()
                set this=this.next
                exitwhen this==0
            endloop
        endmethod
        
        method getFirst takes nothing returns thistype
            return this.next // return this.first
        endmethod
        
        method getNext takes nothing returns thistype
            return this.next
        endmethod
        
        method getLast takes nothing returns thistype
            return this.prev // return this.last
        endmethod
        
        method getPrevious takes nothing returns thistype
            return this.prev
        endmethod
        
        method addToStart takes thistype toAdd returns nothing
            set this.next.prev=toAdd // set this.first.prev=toAdd
            set toAdd.next=this.next // set toAdd.next=this.first
            set this.next=toAdd // set this.first=toAdd
            
            set toAdd.list=this
        endmethod
        
        method addToEnd takes thistype toAdd returns nothing
            set this.prev.next=toAdd // set this.last.next=toAdd
            set toAdd.prev=this.prev // set toAdd.prev=this.last
            set this.prev=toAdd // set this.last=toAdd
            
            set toAdd.list=this
        endmethod
        
        method hasNext takes nothing returns boolean
            return this.next!=0
        endmethod
        
        method hasPrevious takes nothing returns boolean
            return this.prev!=0
        endmethod
        
        method detachFirst takes nothing returns thistype
            // Get the first
            local thistype first=this.next // local thistype last=this.first
            // Set first to the one after first.
            set this.next=this.next.next // set this.first=this.first.next
            set this.next.prev=0 // set this.first.prev=0
            
            set first.next=0
            set first.prev=0
            set first.list=0
            
            if this.prev==first then // if this.last==first then
                set this.prev=0 // set this.last=0
            endif
            
            return first
        endmethod
        
        method detachLast takes nothing returns thistype
            // Get the last
            local thistype last=this.prev // local thistype last=this.last
            // Set last to the one before last.
            set this.prev=this.prev.prev // set this.last=this.last.prev
            set this.prev.next=0 // set this.last.next=0
            
            set last.next=0
            set last.prev=0
            set last.list=0
            
            if this.next==last then // if this.first==last then
                set this.next=0 // set this.first=0
            endif
            
            return last
        endmethod
        
        method detach takes nothing returns nothing
            if this.list.next==this then // if this.list.first==this then
                call this.list.detachFirst()
            elseif this.list.last==this then // if this.list.last==this then
                call this.list.detachLast()
            else
                set this.next.prev=this.prev
                set this.prev.next=this.next
                set this.next=0
                set this.prev=0
                set this.list=0
            endif
        endmethod
        
        method destroyFirst takes nothing returns nothing
            call this.detachFirst().destroy()
        endmethod
        
        method destroyLast takes nothing returns nothing
            call this.detachLast().destroy()
        endmethod
        
    endmodule
    
endlibrary

Epic useful, if it works. ;)
 

Kenny

Back for now.
Reaction score
202
Untested, but I just punched this out as fast as I could before I have to go.

Lol, I spent ages reading and researching to come up with something "similar" to what you did in probably no time at all, and by similar i mean no where near as good :).

JASS:
method getFirst takes nothing returns thistype
    return this.next // return this.first
endmethod
        
method getNext takes nothing returns thistype
    return this.next
endmethod


Whoa... tricky.

I will test it out when I can (everything seems to be okay, reading over it). However the interface seems to be lacking with it, just doesn't seem as intuitive... But maybe thats just me.
 

Jesus4Lyf

Good Idea™
Reaction score
397
I actually constructed it that way on purpose, by the way, so you can have a loop that starts with the linked list, then the first line of the loop is set to .next, then exitwhen==0, and then your stuff. So you don't need to get the first node before you start your loop, you can just start with the linked list struct. ;)

Mine doesn't convert a struct type into a linked list. It allows users to create linked lists of a struct type. Which is much more flexible, and well, just as fast, really.

>However the interface seems to be lacking with it, just doesn't seem as intuitive...
Can you elaborate? What's lacking? :D
 

Kenny

Back for now.
Reaction score
202
>However the interface seems to be lacking with it, just doesn't seem as intuitive...
Can you elaborate? What's lacking?

Sorry, lacking was the wrong word :p. I think there was just one thing i thought was weird. To add a link to the list, you use a non-static method, does that mean if i wanted to add the current struct instance it would look something like:

JASS:
d.addToStart(d)


?

Im just a little lost i guess, mind revamping my example with your version of the list, so I can see where I got lost?
 

Jesus4Lyf

Good Idea™
Reaction score
397
JASS:
    private struct Shadow2
        implement Linked_List // This replaces the necessary variables for a struct stack

        static timer t = CreateTimer()
        static thistype timer_list
        
        unit    shadow = null
        integer alpha  = 0
        integer anim   = 0
        integer id     = 0

        static method create takes unit caster, integer id, integer animation, real angle, real timescale, real x, real y returns thistype
            local thistype s2 = thistype.allocate()

            set s2.id     = id
            set s2.anim   = animation
            set s2.alpha  = ALPHA_START
            set s2.shadow = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),s2.id,x,y,GetUnitFacing(caster))

            call SetUnitColor(s2.shadow,GetPlayerColor(GetOwningPlayer(caster)))
            call SetUnitVertexColor(s2.shadow,RED,GREEN,BLUE,s2.alpha)
            call SetUnitAnimationByIndex(s2.shadow,s2.anim)
            call SetUnitTimeScale(s2.shadow,timescale)
            call UnitAddAbility(s2.shadow,LOCUST_ID)
            call SetUnitPathing(s2.shadow,false)
            
            call SetUnitX(s2.shadow,x + OFFSET * Cos(angle))
            call SetUnitY(s2.shadow,y + OFFSET * Sin(angle))
            
            if GetUnitFlyHeight(caster) &gt; 1.00 then
                call UnitAddAbility(s2.shadow,CROW_ID)
                call UnitRemoveAbility(s2.shadow,CROW_ID)
                call SetUnitFlyHeight(s2.shadow,GetUnitFlyHeight(caster),0.00)
            endif
            
            call thistype.timer_list.addToEnd(s2)
            if thistype.timer_list.getFirst() == s2 then
                call TimerStart(thistype.t,INTERVAL,function thistype.update)
            endif
            
            return s2
        endmethod
        
        static method update takes nothing returns nothing
            local thistype s2 = thistype.timer_list.getFirst() // No need for extra local variable. Simple.
            
            loop
                exitwhen s2 == 0 // Comparison

                if s2.alpha &lt;= 0 then
                    call s2.detach()
                    call s2.destroy()
                else
                    call SetUnitVertexColor(s2.shadow,RED,GREEN,BLUE,s2.alpha)
                    call SetUnitAnimationByIndex(s2.shadow,s2.anim)
                    
                    set s2.alpha = s2.alpha - ALPHA_MINUS
                endif
                
                set s2 = s2.getNext() // Gets the next node in the list, simple
            endloop
            
            if thistype.timer_list.getFirst() == 0 then
                call PauseTimer(thistype.t) // Simplification of function
            endif
        endmethod
        
        method onDestroy takes nothing returns nothing
            call RemoveUnit(.shadow)
            set .shadow = null
        endmethod
        
        static method onInit takes nothing returns nothing
            set thistype.timer_list=thistype.createList()
        endmethod
        
    endstruct
There can be more than one list, remember that...

thistype can either be a struct of thistype, or a list of thistype... My only dislike of it now is actually that onDestroy gets called for lists as well... which is kind of not right. :( lol

Oh, and not bad, only one error in my code that I saw...
JASS:
elseif this.list.last==this then // if this.list.last==this then

in detach, should be...
JASS:
elseif this.list.prev==this then // if this.list.last==this then
 

Kenny

Back for now.
Reaction score
202
There can be more than one list, remember that...

Haha, forgot about that. This is still above my level of intelligence in regards to linked lists. It took me a bit to get my head around it.

thistype can either be a struct of thistype, or a list of thistype... My only dislike of it now is actually that onDestroy gets called for lists as well... which is kind of not right. lol

I may be wrong, but that doesn't seem like it would be a massive deal.

Oh, and not bad, only one error in my code that I saw...

Already picked up on that when i copied into a map to test it :D.

Thanks for all the help with all that.

EDIT:

Finished testing, it doesn't seem to work correctly. This part:

JASS:
call thistype.timer_list.addToEnd(s2)
if thistype.timer_list.getFirst() == s2 then
    call TimerStart(thistype.t,INTERVAL,function thistype.update)
endif


Doesn't seem to work. The timer never starts.

thistype.timer_list.getFirst() always returns 0 in that situation.
 

Jesus4Lyf

Good Idea™
Reaction score
397
Hey thanks for the debugging. Made it easy.
JASS:
library Linked
    
    public module List
        
        // For each struct...
        private thistype next = 0            // Next node link.
        private thistype prev = 0            // Prev node link.
        private thistype list = 0            // Which list this node belongs to.

        // For list structs...
        // define next: first                // First node in a list.
        // define prev: last                 // Last node in a list.
        // Could add... define list: count... But I don&#039;t see why. <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite1" alt=":)" title="Smile    :)" loading="lazy" data-shortname=":)" /> - Jesus4Lyf.
        
        static method createList takes nothing returns thistype
            return thistype.allocate()
        endmethod
        
        method destroyList takes nothing returns nothing
            loop
                call this.destroy()
                set this=this.next
                exitwhen this==0
            endloop
        endmethod
        
        method getFirst takes nothing returns thistype
            return this.next // return this.first
        endmethod
        
        method getNext takes nothing returns thistype
            return this.next
        endmethod
        
        method getLast takes nothing returns thistype
            return this.prev // return this.last
        endmethod
        
        method getPrevious takes nothing returns thistype
            return this.prev
        endmethod
        
        method addToStart takes thistype toAdd returns nothing
            set this.next.prev=toAdd // set this.first.prev=toAdd
            set toAdd.next=this.next // set toAdd.next=this.first
            set this.next=toAdd // set this.first=toAdd
            
            if this.prev==0 then // if this.last==0 then
                set this.prev=toAdd // set this.last=toAdd
            endif
            
            set toAdd.list=this
        endmethod
        
        method addToEnd takes thistype toAdd returns nothing
            set this.prev.next=toAdd // set this.last.next=toAdd
            set toAdd.prev=this.prev // set toAdd.prev=this.last
            set this.prev=toAdd // set this.last=toAdd
            
            if this.next==0 then // if this.first==0 then
                set this.next=toAdd // set this.first=toAdd
            endif
            
            set toAdd.list=this
        endmethod
        
        method hasNext takes nothing returns boolean
            return this.next!=0
        endmethod
        
        method hasPrevious takes nothing returns boolean
            return this.prev!=0
        endmethod
        
        method detachFirst takes nothing returns thistype
            // Get the first
            local thistype first=this.next // local thistype last=this.first
            // Set first to the one after first.
            set this.next=this.next.next // set this.first=this.first.next
            set this.next.prev=0 // set this.first.prev=0
            
            set first.next=0
            set first.prev=0
            set first.list=0
            
            if this.prev==first then // if this.last==first then
                set this.prev=0 // set this.last=0
            endif
            
            return first
        endmethod
        
        method detachLast takes nothing returns thistype
            // Get the last
            local thistype last=this.prev // local thistype last=this.last
            // Set last to the one before last.
            set this.prev=this.prev.prev // set this.last=this.last.prev
            set this.prev.next=0 // set this.last.next=0
            
            set last.next=0
            set last.prev=0
            set last.list=0
            
            if this.next==last then // if this.first==last then
                set this.next=0 // set this.first=0
            endif
            
            return last
        endmethod
        
        method detach takes nothing returns nothing
            if this.list.next==this then // if this.list.first==this then
                call this.list.detachFirst()
            elseif this.list.last==this then // if this.list.last==this then
                call this.list.detachLast()
            else
                set this.next.prev=this.prev
                set this.prev.next=this.next
                set this.next=0
                set this.prev=0
                set this.list=0
            endif
        endmethod
        
        method destroyFirst takes nothing returns nothing
            call this.detachFirst().destroy()
        endmethod
        
        method destroyLast takes nothing returns nothing
            call this.detachLast().destroy()
        endmethod
        
    endmodule
    
endlibrary
I just wrote it in browser. *Shrugs* Try that, heh. My bad. :)
 

Kenny

Back for now.
Reaction score
202
Thanks, it works flawlessly now. I also added the .destroyCurrent(), just for kicks.

Also, about the debug boolean. Did you mean something like this:

JASS:
library Linked
    
    public module List
        
        private thistype next = 0            // Next node link.
        private thistype prev = 0            // Prev node link.
        private thistype list = 0            // Which list this node belongs to.
        
        debug private boolean isList = false

        static method createList takes nothing returns thistype
            debug local thistype this = .allocate()
            debug set .isList = true                   // Just setting the variable.
            debug return this
            return .allocate()
        endmethod
        
        method destroyList takes nothing returns nothing
            //--------------------------------\\
            // Is this what you talked about? \\
            //--------------------------------\\
            debug if not this.isList then
            debug     call BJDebugMsg(&quot;Struct instance is not a list.&quot;)
            debug     return
            debug endif
            loop
                call this.destroy()
                set this = this.next
                exitwhen this == 0
            endloop
        endmethod
        
        method getFirst takes nothing returns thistype
            return this.next
        endmethod
        
        method getNext takes nothing returns thistype
            return this.next
        endmethod
        
        method getLast takes nothing returns thistype
            return this.prev
        endmethod
        
        method getPrev takes nothing returns thistype
            return this.prev
        endmethod
        
        method addToStart takes thistype toAdd returns nothing
            set this.next.prev = toAdd
            set toAdd.next = this.next
            set this.next = toAdd
            
            if this.prev == 0 then
                set this.prev = toAdd
            endif
            
            set toAdd.list = this
        endmethod
        
        method addToEnd takes thistype toAdd returns nothing
            set this.prev.next = toAdd
            set toAdd.prev = this.prev
            set this.prev = toAdd
            
            if this.next == 0 then
                set this.next = toAdd
            endif
            
            set toAdd.list = this
        endmethod
        
        method hasNext takes nothing returns boolean
            return this.next != 0
        endmethod
        
        method hasPrev takes nothing returns boolean
            return this.prev != 0
        endmethod
        
        method detachFirst takes nothing returns thistype
            local thistype first = this.next

            set this.next = this.next.next
            set this.next.prev = 0
            
            set first.next = 0
            set first.prev = 0
            set first.list = 0
            
            if this.prev == first then
                set this.prev = 0
            endif
            
            return first
        endmethod
        
        method detachLast takes nothing returns thistype
            local thistype last = this.prev
            
            set this.prev = this.prev.prev
            set this.prev.next = 0
            
            set last.next = 0
            set last.prev = 0
            set last.list = 0
            
            if this.next == last then
                set this.next = 0
            endif
            
            return last
        endmethod
        
        method detachCurrent takes nothing returns thistype
            if this.list.next == this then
                call this.list.detachFirst()
            elseif this.list.prev == this then
                call this.list.detachLast()
            else
                set this.next.prev = this.prev
                set this.prev.next = this.next
                set this.next = 0
                set this.prev = 0
                set this.list = 0
            endif
            
            return this
        endmethod
        
        method destroyFirst takes nothing returns nothing
            call this.detachFirst().destroy()
        endmethod
        
        method destroyLast takes nothing returns nothing
            call this.detachLast().destroy()
        endmethod
        
        method destroyCurrent takes nothing returns nothing
            call this.detachCurrent().destroy()
        endmethod
        
    endmodule
    
endlibrary

Also, just a question. For most of the methods, would you use this.isList for the boolean, or this.List.isList? Or could you even just compare if this.List != 0 or something? If isList is only being set to true for lists created using .createList(), then using this.isList for stuff like .detachLast() wouldn't work, as it is a node not a list. Or have I just got everything completely confused?
 

Jesus4Lyf

Good Idea™
Reaction score
397
Every list is meant to be created using createList(), or else it is not a list, it is a normal instance of the struct. :)
JASS:
        static method createList takes nothing returns thistype
            debug local thistype this = .allocate()
            debug set .isList = true                   // Just setting the variable.
            debug return this
            return .allocate()
        endmethod

Yep perfect, and the debug message looks right. Same stuff for detachFirst, detachLast, etc... :thup: Good work.

>would you use this.isList for the boolean, or this.List.isList?
this.list is a struct member which points to the list it belongs to. If the struct does -not- belong to a list, it will return 0 (or should), which does not make the struct a list, but still makes this.list==0 return true. So using this.list.isList is silly, and using this.list==0 doesn't work. :p
 

Kenny

Back for now.
Reaction score
202
this.list is a struct member which points to the list it belongs to. If the struct does -not- belong to a list, it will return 0 (or should), which does not make the struct a list, but still makes this.list==0 return true. So using this.list.isList is silly, and using this.list==0 doesn't work.

You should probably have just disregarded all of what I said. It was obviously too early for me to be thinking :p. I understand it all now.

Added more debug messages:

JASS:
library Linked
    
    public module List
        
        private thistype next = 0            // Next node link.
        private thistype prev = 0            // Prev node link.
        private thistype list = 0            // Which list this node belongs to.
        
       debug private boolean isList = false
        
        static method createList takes nothing returns thistype
           debug local thistype this = .allocate()
           debug set .isList = true
           debug return this
            return .allocate()
        endmethod
        
        method destroyList takes nothing returns nothing
           debug if not this.isList then
           debug     call BJDebugMsg(&quot;Linked List Module (destroyList): Struct instance is not a list.&quot;)
           debug     return
           debug endif
            
            loop
                call this.destroy()
                set this = this.next
                exitwhen this == 0
            endloop
        endmethod
        
        method getFirst takes nothing returns thistype
            return this.next
        endmethod
        
        method getNext takes nothing returns thistype
            return this.next
        endmethod
        
        method hasNext takes nothing returns boolean
            return this.next != 0
        endmethod
        
        method getLast takes nothing returns thistype
            return this.prev
        endmethod
        
        method getPrev takes nothing returns thistype
            return this.prev
        endmethod
        
        method hasPrev takes nothing returns boolean
            return this.prev != 0
        endmethod
        
        method addToStart takes thistype toAdd returns nothing
           debug if not this.isList then
           debug     call BJDebugMsg(&quot;Linked List Module (addToStart): Struct instance is not a list.&quot;)
           debug     return
           debug endif
            
            set this.next.prev = toAdd
            set toAdd.next = this.next
            set this.next = toAdd
            
            if this.prev == 0 then
                set this.prev = toAdd
            endif
            
            set toAdd.list = this
        endmethod
        
        method addToEnd takes thistype toAdd returns nothing
           debug if not this.isList then
           debug     call BJDebugMsg(&quot;Linked List Module (addToEnd): Struct instance is not a list.&quot;)
           debug     return 
           debug endif
            
            set this.prev.next = toAdd
            set toAdd.prev = this.prev
            set this.prev = toAdd
            
            if this.next == 0 then
                set this.next = toAdd
            endif
            
            set toAdd.list = this
        endmethod
        
        method detachFirst takes nothing returns thistype
            local thistype first = this.next
            
           debug if not this.isList then
           debug     call BJDebugMsg(&quot;Lniked List Module (detachFirst): Struct instance is not a list.&quot;)
           debug     return 0
           debug endif

            set this.next = this.next.next
            set this.next.prev = 0
            
            set first.next = 0
            set first.prev = 0
            set first.list = 0
            
            if this.prev == first then
                set this.prev = 0
            endif
            
            return first
        endmethod
        
        method detachLast takes nothing returns thistype
            local thistype last = this.prev
            
           debug if not this.isList then
           debug     call BJDebugMsg(&quot;Linked List Module (detachLast): Struct instance is not a list.&quot;)
           debug     return 0
           debug endif
            
            set this.prev = this.prev.prev
            set this.prev.next = 0
            
            set last.next = 0
            set last.prev = 0
            set last.list = 0
            
            if this.next == last then
                set this.next = 0
            endif
            
            return last
        endmethod
        
        method detachCurrent takes nothing returns thistype
           debug if not this.isList then
           debug     call BJDebugMsg(&quot;Linked List Module (detachCurrent): Struct instance is not a list.&quot;)
           debug     return 0
           debug endif
            
            if this.list.next == this then
                call this.list.detachFirst()
            elseif this.list.prev == this then
                call this.list.detachLast()
            else
                set this.next.prev = this.prev
                set this.prev.next = this.next
                set this.next = 0
                set this.prev = 0
                set this.list = 0
            endif
            
            return this
        endmethod
        
        method destroyFirst takes nothing returns nothing
            call this.detachFirst().destroy()
        endmethod
        
        method destroyLast takes nothing returns nothing
            call this.detachLast().destroy()
        endmethod
        
        method destroyCurrent takes nothing returns nothing
            call this.detachCurrent().destroy()
        endmethod
        
    endmodule
    
endlibrary

Few questions (once again):

1. Is there anyway to ensure that a struct created as a list does not use the onDestroy method? I was thinking about it this morning and couldn't come up with any ideas. However, I don't see this as an immediate problem.

2. Do the one-liner methods also need a debug message?

Back on topic:

This will probably be updated in the near future, to use the module developed by Jesus4Lyf. Just working on the documentation and examples now.

After testing the new module quite a bit, I found (as stated by Jesus4Lyf) that it is indeed quite a powerful tool for structs, and it can be very handy.
 

Jesus4Lyf

Good Idea™
Reaction score
397
>1. Is there anyway to ensure that a struct created as a list does not use the onDestroy method?
Nup. Not that I can think of, either. :p

>2. Do the one-liner methods also need a debug message?
Yep. Well, GetFirst and GetLast do, but not GetNext and GetPrev. Those two work in a sensible kind of way for both lists and nodes. Lol. Well, in my books they do. :thup:

>it is indeed quite a powerful tool for structs
Yep. :D
 

Kenny

Back for now.
Reaction score
202
Thanks for the reply. I will be updating this when I can get WE up and running again, just got to add the debug messages to getFirst and getLast and update the documentation. I will be sure to give credits.
 

Jesus4Lyf

Good Idea™
Reaction score
397
Sounds good to me. This should be a nice module for people who bother to learn the function. :)

By the way, you could add a [index] operator to the struct to return node #index. It would be O(n) complexity, but that's not such an issue.

Also, I wouldn't have removed all the commented lines explaining the equivalents... lol.
 

Kenny

Back for now.
Reaction score
202
By the way, you could add a [index] operator to the struct to return node #index. It would be O(n) complexity, but that's not such an issue.

Lolwut? Haha, naa, I think I know where your comin from with that. But will it be that useful?

Also, I wouldn't have removed all the commented lines explaining the equivalents... lol.

Don't worry, they are still there in the 'official' release. Just gotta add some for the update you did.

JASS:
//------------------------------------------------------------------------------------\\
//                              Linked List Module [v2]                               \\
//                               By kenny! &amp; Jesus4Lyf                                \\
//                              Constructed using vJASS                               \\
//                                Requires: NewGen WE                                 \\
//------------------------------------------------------------------------------------\\
//                                                                                    \\
//------------------------------------------------------------------------------------\\
//  DESCRIPTION:                                                                      \\
// ¯¯¯¯¯¯¯¯¯¯¯¯¯                                                                      \\
//    This module is a very powerful tool for structs. It enables users to create a   \\
//    linked list using a struct instance as the list itself, allowing for multiple   \\
//    lists in the one struct. It is simple to use and generates a very intuitive and \\
//    basic interface that is easy to follow and understand. A linked list can be     \\
//    used to store struct instances instead of using the &#039;struct stack&#039; method, and  \\
//    can also be used to attached a list to units and so on. When used appropriately \\
//    it can give great functionality to users.                                       \\
//                                                                                    \\
//  METHODS:                                                                          \\
// ¯¯¯¯¯¯¯¯¯                                                                          \\
//    There are several methods available to you when you use this module, they       \\
//    include:                                                                        \\
//                                                                                    \\
//      Static methods:                                                               \\
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯                                                               \\
//        - .createList()     - Creates a list using a struct instance as its &#039;base&#039;. \\
//                            - Returns thistype. Retuns the list itself.             \\
//                                                                                    \\
//      Non-static methods:                                                           \\
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯                                                           \\
//        - .destroyList()    - Destroys each link in the list, as well as the list.  \\
//                            - Returns nothing.                                      \\
//                                                                                    \\
//        - .getFirst()       - Retrieves the first link in the list and returns it.  \\
//                            - Returns thistype. Returns the first link.             \\
//                                                                                    \\
//        - .getNext()        - Retrieves the next link in the list and returns it.   \\
//                            - Returns thistype. Returns the next link.              \\
//                                                                                    \\
//        - .hasNext()        - Checks to see if the current link has a next link.    \\
//                            - Returns boolean. Returns true is next link is there.  \\
//                                                                                    \\
//        - .getLast()        - Retrieves the last link in the list and returns it.   \\
//                            - Returns thistype. Returns the last link.              \\
//                                                                                    \\
//        - .getPrev()        - Retrieves the prev link in the list and returns it.   \\
//                            - Returns thistype. Returns the previous link.          \\
//                                                                                    \\
//        - .hasPrev()        - Checks to see if the current link has a next link.    \\
//                            - Returns boolean. Returns true if prev link is there.  \\
//                                                                                    \\
//        - .addToStart()     - Adds a struct instance to the start of the list.      \\
//                            - Returns thistype. Returns the parameter.              \\
//                                                                                    \\
//        - .addToEnd()       - Adds a struct instance to the end of the list.        \\
//                            - Returns thistype. Returns the parameter.              \\
//                                                                                    \\
//        - .detachFirst()    - Removes the first link from the list.                 \\
//                            - Returns thistype. Returns the first link.             \\
//                                                                                    \\
//        - .detachLast()     - Removes the last link from the list.                  \\
//                            - Returns thistype. Returns the last link.              \\
//                                                                                    \\
//        - .detachCurrent()  - Removes the current link from the list.               \\
//                            - Returns thistype. Returns the current link.           \\
//                                                                                    \\
//        - .destroyFirst()   - Removes the first link from the list and calls the    \\
//                              .destroy() method.                                    \\
//                            - Returns nothing.                                      \\
//                                                                                    \\
//        - .destroyLast()    - Removes the last link from the list and calls the     \\
//                              .destroy() method.                                    \\
//                            - Returns nothing.                                      \\
//                                                                                    \\
//        - .destroyCurrent() - Removes the current link from the list and call the   \\
//                              .destroy() method.                                    \\
//                            - Returns nothing.                                      \\
//                                                                                    \\
//  USAGE/EXAMPLES:                                                                   \\
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯                                                                   \\
//    To use this module within a struct you must implement it using the following:   \\
//                                                                                    \\
//      private struct Data                                                           \\
//          implement Linked_List                                                     \\
//                                                                                    \\
//          Do stuff here using the module.                                           \\
//      endstruct                                                                     \\
//                                                                                    \\
//    It is easiest to implement it right under struct declaration.                   \\
//                                                                                    \\
//    There are only two methods available which use parameters. Usage for these two  \\
//    methods are as follows:                                                         \\
//                                                                                    \\
//      call .addToStart(thistype value)                                              \\
//      call .addToEnd(thistype value)                                                \\
//                                                                                    \\
//    The above take one parameter. The parameter must be a thistype value. Meaning   \\
//    it takes a struct instance as the parameter.                                    \\   
//                                                                                    \\
//  PROS &amp; CONS:                                                                      \\
// ¯¯¯¯¯¯¯¯¯¯¯¯¯                                                                      \\
//    As this module is just a simplification of struct stack syntax, there are not   \\
//    many negative points for it. However, just for the sake of it:                  \\
//                                                                                    \\
//      Pros:                                                                         \\
//     ¯¯¯¯¯¯                                                                         \\
//        - Simplifies syntax a fair bit. Makes it easier to read.                    \\
//        - Allows for multiple linked lists within a single struct, generating       \\
//          multiple storage components.                                              \\
//        - Reduces time spent developing spells/scripts and reduces lines.           \\
//        - There is also a -possible- efficiency gain over the normal struct stack.  \\
//          But this I am not sure of.                                                \\
//                                                                                    \\
//      Cons:                                                                         \\
//     ¯¯¯¯¯¯                                                                         \\
//        - A single node can only exist in one list at a time.                       \\
//        - onDestroy gets called for list nodes.                                     \\
//                                                                                    \\
//  IMPORTING:                                                                        \\
// ¯¯¯¯¯¯¯¯¯¯¯                                                                        \\
//    Simply create a new trigger, name it LinkedList or something along those lines. \\
//    Then convert it to custom text, and paste this in its place and save. Done.     \\
//                                                                                    \\
//  THANKS/CREDITS:                                                                   \\
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯                                                                   \\
//    - Jesus4Lyf - For basically re-inventing the module to make it far more useful  \\
//                  and dynamic. Also for helping me understand linked lists better   \\
//                  and helping to develop the script further. Major props to him.    \\
//                                                                                    \\
//------------------------------------------------------------------------------------\\

library Linked
    
    public module List
        
        private thistype next = 0            // Next node link.
        private thistype prev = 0            // Prev node link.
        private thistype list = 0            // Which list this node belongs to.
        
       debug private boolean isList = false  // For user safety. Won&#039;t allow list methods to
                                             // work for normal structs if debug mode is on.
        
        static method createList takes nothing returns thistype
           debug local thistype this = .allocate()
           debug set .isList = true
           debug return this
            return .allocate() // return struct created as a list
        endmethod
        
        method destroyList takes nothing returns nothing
           debug if not this.isList then
           debug     call BJDebugMsg(&quot;Linked List Module (destroyList): Struct instance is not a list.&quot;)
           debug     return
           debug endif
            loop
                call this.destroy()
                set this = this.next
                exitwhen this == 0
            endloop
        endmethod
        
        method getFirst takes nothing returns thistype
           debug if not this.isList then
           debug     call BJDebugMsg(&quot;Linked List Module (getFirst): Struct instance is not a list.&quot;)
           debug     return 0
           debug endif
            return this.next // return this.first
        endmethod
        
        method getNext takes nothing returns thistype
            return this.next
        endmethod
        
        method hasNext takes nothing returns boolean
            return this.next != 0
        endmethod
        
        method getLast takes nothing returns thistype
           debug if not this.isList then
           debug     call BJDebugMsg(&quot;Linked List Module (getLast): Struct instance is not a list.&quot;)
           debug     return 0
           debug endif
            return this.prev // return this.last
        endmethod
        
        method getPrev takes nothing returns thistype
            return this.prev
        endmethod
        
        method hasPrev takes nothing returns boolean
            return this.prev != 0
        endmethod
        
        method addToStart takes thistype toAdd returns thistype
           debug if not this.isList then
           debug     call BJDebugMsg(&quot;Linked List Module (addToStart): Struct instance is not a list.&quot;)
           debug     return 0
           debug endif
            set this.next.prev = toAdd  // set this.first.prev = toAdd
            set toAdd.next = this.next  // set toAdd.prev = this.last
            set this.next = toAdd       // set this.last = toAdd
            
            if this.prev == 0 then      // if this.last == 0 then
                set this.prev = toAdd   // set this.last = toAdd
            endif
            
            set toAdd.list = this
            
            return toAdd                // return toAdd for simplicity
        endmethod
    
        method addToEnd takes thistype toAdd returns thistype
           debug if not this.isList then
           debug     call BJDebugMsg(&quot;Linked List Module (addToEnd): Struct instance is not a list.&quot;)
           debug     return 0
           debug endif
            set this.prev.next = toAdd  // set this.last.next = toAdd
            set toAdd.prev = this.prev  // set toAdd.prev = this.last
            set this.prev = toAdd       // set this.last = toAdd
            
            if this.next == 0 then      // if this.first == 0 then
                set this.next = toAdd   // set this.first = toAdd
            endif
            
            set toAdd.list = this
            
            return toAdd                // return toAdd for simplicity
        endmethod
        
        method detachFirst takes nothing returns thistype
            local thistype first = this.next // local thistype first = this.first
            
           debug if not this.isList then
           debug     call BJDebugMsg(&quot;Lniked List Module (detachFirst): Struct instance is not a list.&quot;)
           debug     return 0
           debug endif
            set this.next = this.next.next   // set this.first = this.first.next
            set this.next.prev = 0           // set this.first.prev = 0
            
            set first.next = 0
            set first.prev = 0
            set first.list = 0
            
            if this.prev == first then       // if this.last == first then
                set this.prev = 0            // set this.last = 0
            endif
            
            return first
        endmethod
        
        method detachLast takes nothing returns thistype
            local thistype last = this.prev // local thistype last = this.last
            
           debug if not this.isList then
           debug     call BJDebugMsg(&quot;Linked List Module (detachLast): Struct instance is not a list.&quot;)
           debug     return 0
           debug endif
            set this.prev = this.prev.prev  // set this.last = this.last.prev
            set this.prev.next = 0          // set this.last.next = 0
            
            set last.next = 0
            set last.prev = 0
            set last.list = 0
            
            if this.next == last then       // if this.first == last then
                set this.next = 0           // set this.first = 0
            endif
            
            return last
        endmethod
        
        method detachCurrent takes nothing returns thistype
           debug if not this.list.isList then
           debug     call BJDebugMsg(&quot;Linked List Module (detachCurrent): Struct instance is not a list.&quot;)
           debug     return 0
           debug endif
            if this.list.next == this then      // if this.list.first == this then
                call this.list.detachFirst()
            elseif this.list.prev == this then  // if this.list.last == this then
                call this.list.detachLast()
            else
                set this.next.prev = this.prev
                set this.prev.next = this.next
                set this.next = 0
                set this.prev = 0
                set this.list = 0
            endif
            
            return this
        endmethod
        
        method destroyFirst takes nothing returns nothing
            call this.detachFirst().destroy()    // detach and destroy first link.
        endmethod
        
        method destroyLast takes nothing returns nothing
            call this.detachLast().destroy()     // detach and destroy last link.
        endmethod
        
        method destroyCurrent takes nothing returns nothing
            call this.detachCurrent().destroy()  // detach and destroy current link.
        endmethod
        
    endmodule
    
endlibrary
 

Kenny

Back for now.
Reaction score
202
Major update. The module is now far more powerful and dynamic. Has a wider variety of uses, and a pretty simple interface. It is also full of debug messages to make sure you don't do anything stupid.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top