• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] Linked list

Status
Not open for further replies.
Level 5
Joined
Jun 5, 2007
Messages
73
EDIT: Revamped the old post.

This is a new version of my linked list. It allows you to.... well, store structs in a linked-fashion :)
It doesn't produce memory-leaks (if you use it right) and it's fast!

JASS:
//LinkedList for vJass
//Copyright (c) 2008, E.Sandberg (Risc)
//Free for public use.

library LinkedList
    
    function H2I takes handle h returns integer
        return h
        return 0
    endfunction
    
    function H2N takes handle h returns Node
        return h
        return 0
    endfunction
    
    function N2H takes Node n returns handle
        return n
        return null
    endfunction
    
    //Modify this struct to anything you like.
    //Remember to modify the dispose-method to work with your struct (to prevent memory leaks)
    struct Data
        public string name
        public unit u
        
        public method dispose takes nothing returns nothing
            //this is just an example
            //change this to fit your fields
            call RemoveUnit(this.u)
            set this.u = null
            set this.name = null
        endmethod
    endstruct
    
    struct Node
        public handle next
        public Data data
        public boolean IsTail = false
        
        public method dispose takes nothing returns nothing
            call this.data.dispose()
            call this.data.destroy()
            set this.data = 0
            call this.destroy()
        endmethod
    endstruct

    struct List
        private Node head
        private Node tail
        private Node current
        public integer count
        
        static method create takes nothing returns List
            local List ldummy = List.allocate()
            set ldummy.head = Node.create()
            set ldummy.tail = Node.create()
            set ldummy.tail.IsTail = true
            set ldummy.head.next = N2H(ldummy.tail)
            return ldummy
        endmethod
        
        public method dispose takes nothing returns nothing
            //clear list
            call this.Clear()
            call this.head.destroy()
            call this.tail.destroy()
            call this.current.destroy()
            set this.head = 0
            set this.tail = 0
            set this.current = 0
            set this = 0
        endmethod
        
        public method First takes nothing returns Node
            return H2N(this.head.next)
        endmethod
        
        public method Add takes Data data returns Node
            local Node n = Node.create()
            local Node temp = this.head
            //find last node
            loop
            exitwhen H2N(temp.next) == this.tail
                set temp = H2N(temp.next)
            endloop
            
            set n.data = data
            set n.next = N2H(this.tail)
            set temp.next = N2H(n)
            set this.count = this.count + 1
            //--- Debug ---
            //call BJDebugMsg("Handle to this object is " + I2S(H2I(N2H(n))))
            //call BJDebugMsg("Handle to previous object is " + I2S(H2I(N2H(temp))))
            return n
        endmethod
        
        public method RemoveAndEnumNext takes Node n returns Node
            local Node temp = this.head
            
            loop
            exitwhen temp.next == N2H(n)
                set temp = H2N(temp.next)
            endloop
            
            set temp.next = n.next
            set this.current = H2N(this.current.next)
            set this.count = this.count - 1
            call n.dispose()
            return this.current
        endmethod
        
        public method Clear takes nothing returns nothing
            local Node temp = H2N(this.head.next)
            //find last node
            loop
            exitwhen temp.IsTail == true
                call temp.data.dispose()
                set temp = this.RemoveAndEnumNext(temp)
            endloop
            set this.head.next = N2H(this.tail)
            set this.count = 0
        endmethod
        
        public method Remove takes Node n returns nothing
            local Node temp = this.head
            
            loop
            exitwhen temp.next == N2H(n)
                set temp = H2N(temp.next)
            endloop
            
            set temp.next = n.next
            if this.current == n then
                set this.current = H2N(this.current.next)
            endif
            set this.count = this.count - 1
            call n.dispose()
        endmethod
        
        public method Enum takes nothing returns Node
            set this.current = H2N(this.head.next)
            return this.current
        endmethod
        
        public method EnumNext takes nothing returns Node
            set this.current = H2N(this.current.next)
            return this.current
        endmethod
    endstruct
endlibrary
 
Last edited:
Level 12
Joined
Apr 27, 2008
Messages
1,228
The example is in the first post ...
What is in the second(the double post) is an example map.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
The example is in the first post ...
What is in the second(the double post) is an example map.
Sorry but not, the first post is the link list "system".
This is an example an only in the example map :

JASS:
library listTest initializer init_list
    globals
        List l
    endglobals
    
    function DebugLog takes string s returns nothing
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, s)
    endfunction
    
    function init_list takes nothing returns nothing
        set l = List.create()
    endfunction
    
    function testClearList takes nothing returns nothing
        call l.Clear()
    endfunction
    
    //stress-test of list
    function testAddPeasants takes nothing returns nothing
        local Data d
        local integer i = 1
        local real posX = 500
        local real posY = 3000
        //create 100 peasants and put them in the list
        loop
        exitwhen i == 100
            set d = Data.create()
            set posX = -posX
            set posY = posY - 100
            set d.u = CreateUnit(GetLocalPlayer(), 'hpea', posX, posY, 0)
            set d.name = "peasant"
            call l.Add(d)
            set i = i + 1
        endloop
    endfunction
    
    function testCircleAttackFrenzy takes nothing returns nothing
        local Node last = l.Enum()
        local Node n = l.EnumNext()
        loop
        exitwhen n.IsTail == true
            //order peasant to attack next peasant in list
            call IssueTargetOrder(n.data.u, "attack", last.data.u)
            call DebugLog("Ordering " + I2S(H2I(n.data.u)) + " to attack " + I2S(H2I(last.data.u)))
            set last = n
            set n = l.EnumNext()
        endloop
        //order first peasant to attack last peasant
        call IssueTargetOrder(l.First().data.u, "attack", last.data.u)
    endfunction
    
    function testSuicideFrenzy takes nothing returns nothing
        local Node n = l.Enum()
        loop
        exitwhen n.IsTail == true
            //order peasant to kill himself
            call KillUnit(n.data.u)
            set n = l.EnumNext()
        endloop
    endfunction
    
    function testBuildFarmFrenzy takes nothing returns nothing
        local Node n = l.Enum()
        loop
        exitwhen n.IsTail == true
            //order peasant to build a farm
            call IssueBuildOrder(n.data.u, "farm", GetUnitX(n.data.u), GetUnitY(n.data.u))
            set n = l.EnumNext()
        endloop
    endfunction
endlibrary

And the test trigger named "yo" :

JASS:
function Trig_yo_Actions takes nothing returns nothing
    call SetPlayerState(GetLocalPlayer(), PLAYER_STATE_RESOURCE_GOLD, 40000)
    call SetPlayerState(GetLocalPlayer(), PLAYER_STATE_RESOURCE_LUMBER, 40000)
    call testAddPeasants()
    call testCircleAttackFrenzy()
endfunction

//===========================================================================
function InitTrig_yo takes nothing returns nothing
    set gg_trg_yo = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( gg_trg_yo, Player(0), "yo", true )
    call TriggerAddAction( gg_trg_yo, function Trig_yo_Actions )
endfunction
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
Didn't get what's the point of the Data struct, you only need the nodes.

public handle next - Can't you make that public node next (never tried using this with Jass) ?

public boolean IsTail = false - normally you just check if node->next (the next pointer) is null instead of putting a boolean.

Instead of the "dispose" method, you can just put a onDestroy method (runs automatically when the struct is destroyed).

You might also add some documentary as you hardly commented it at all (and add the fact that it requires JNGP).
 
Level 5
Joined
Jun 5, 2007
Messages
73
[node]public boolean IsTail = false - normally you just check if node->next (the next pointer) is null instead of putting a boolean.[/node]
Doesn't work since it's never null. If you look at the inner-workings of the vJass preprocessor, you'll understand that all it does it reference a value in an array, which is never null; closets you'll get is 0, and that might be a structure in the list. That's why I would say it's not safe enough.

Instead of the "dispose" method, you can just put a onDestroy method (runs automatically when the struct is destroyed).
I might just do that if someone actually decides to use this.

You might also add some documentary as you hardly commented it at all (and add the fact that it requires JNGP).
It doesn't require JNGP. It requires a vJass preprocessor (JassHelper). Which isn't really the same thing.
 
Last edited:
Status
Not open for further replies.
Top