[Snippet] QueueQueue

A tutorial for understanding the QueueQueue

JASS:
library QueueQueue /* v2.2.6.5
*******************************************************************
*
*   To best understand this data structure, think of a list and then
*   imagine that every node on that list can have a list inside of it
*   and so on. It's also pretty much a tree.
*
*******************************************************************
*
*   API
*
*******************************************************************
*
*   module QueueQueue
*       readonly thistype parent
*       readonly boolean pointer
*       boolean skips
*
*       static method allocate takes nothing returns thistype
*       method deallocate takes nothing returns nothing
*
*       method add takes nothing returns thistype
*       method point takes integer head returns thistype
*       method operator next takes nothing returns thistype
*       method operator in takes nothing returns thistype
*
*   Loop macros
*       //! textmacro QUEUE_QUEUE_HEADER takes STRUCT
*       //! textmacro QUEUE_QUEUE_START_LOOP takes THIS
*       //! textmacro QUEUE_QUEUE_END_LOOP
*       //! textmacro QUEUE_QUEUE_HEADER_B takes STRUCT
*       //! textmacro QUEUE_QUEUE_START_LOOP_B takes THIS
*       //! textmacro QUEUE_QUEUE_END_LOOP_B
*
*   module QueueQueueLoop
*       readonly thistype get
*       readonly thistype skip
*       readonly thistype depthPointer
*       readonly thistype depthNode
*       integer id
*       method start takes nothing returns thistype
*       method end takes nothing returns nothing
*
*******************************************************************
*
*   module QueueQueue
*
*******************************************************************
*
*   readonly thistype next
*       -   Next node
*   readonly thistype in
*       -   Inner node (any given node can have nodes inside of it)
*   readonly thistype parent
*       -   The node that the node is contained inside of.
*   readonly boolean pointer
*       -   This determines whether the node is a pointer or not. Pointers are
*       -   the first node on the QueueQueue (a special pointer called a head, only
*       -   generated with allocate) and nodes made through the point method. Pointers
*       -   are automatically skipped, however their skip option can be set with the
*       -   skips property.
*   boolean skips
*       -   This determines whether or not to skip a pointer. Pointers that are skipped
*       -   are not looped over in loops. This is useful for systems that want to read
*       -   values inside of pointers to see if a pointer's contents should be skipped
*       -   over or not.
*
*   static method allocate takes nothing returns thistype
*       -   Returns the head for the entire object.
*   method deallocate takes nothing returns nothing
*       -   Destroys the entire structure given the head
*
*   method add takes nothing returns thistype
*       -   Adds a cell to the cell. Cells generated in this fashion
*       -   are entirely local to the QueueQueue they were added to, meaninng
*       -   that they can't be pointed to.
*   method point takes integer head returns thistype
*       -   Points a node to a head. Any node allocated with the allocate
*       -   method is a head. Pointers can't point to anything other than the head.
*
********************************************************************
*
*   Loop macros
*
*       A loop macro used for looping through a QueueQueue.
*
*******************************************************************
*
*   Regular loop (looped in right order)
*       //! textmacro QUEUE_QUEUE_HEADER takes STRUCT
*           -   Place at top of the method/function.
*           -
*           -   STRUCT:             Refers to the struct type to loop for.
*       //! textmacro QUEUE_QUEUE_START_LOOP takes THIS
*           -   Place where the loop should start
*           -
*           -   THIS:               Refers to where to start the loop from and also
*           -                       used to store current node inside of for reading.
*           -                       THIS must be a variable, and it is not recommended
*           -                       that the this variable be used.
*       //! textmacro QUEUE_QUEUE_END_LOOP
*           -   Place where the loop should end
*
*   Deep first postorder loop macros (inner before outer, backwards)
*       //! textmacro QUEUE_QUEUE_HEADER_B takes STRUCT
*       //! textmacro QUEUE_QUEUE_START_LOOP_B takes THIS
*       //! textmacro QUEUE_QUEUE_END_LOOP_B
*
*   ---------------------------------------------------------------------
*   -                     
*   -   Example       
*   -                     
*   -   //both are used the same way
*   -   function Test takes QueueQueue q returns nothing
*   -       //header
*   -       //! runtextmacro QUEUE_QUEUE_HEADER("QueueQueue")
*   -
*   -       local QueueQueue node = q      //make a copy
*   -
*   -       //loop
*   -       //! runtextmacro QUEUE_QUEUE_START_LOOP("node")
*   -           //code
*   -           call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, I2S(node))
*   -       //endloop
*   -       //! runtextmacro QUEUE_QUEUE_END_LOOP
*   -   endfunction
*   -
*   ---------------------------------------------------------------------
*
*********************************************************************
*
*   module QueueQueueLoop
*
*       A module that provides methods for looping through a 
*       QueueQueue given an instanced looper.
*
*******************************************************************
*
*   readonly thistype get
*       -   Retrieves the next value in the QueueQueue given a looper.
*   readonly thistype skip
*       -   Skips inner values of the current node and returns next node.
*   readonly thistype depthPointer
*       -   Returns pointer of current depth of loop that stores node. Depth
*       -   pointers are a stack, so depthPointer.depthPointer would go up one.
*   readonly thistype depthNode
*       -   Returns the node stored within the depth pointer.
*   integer id
*       -   For referencing a depth pointer to something. Depth pointers can be recycled
*       -   en masse w/o the user's knowledge, meaning that depth pointers should not be used
*       -   as references for values. It is best to reference the id of a depth pointer.
*
*   method start takes nothing returns thistype
*       -   Creates a new looper for the QueueQueue.
*   method end takes nothing returns nothing
*       -   Destroys a looper for a QueueQueue. Only used when not looping
*       -   through the entire QueueQueue. The looper is automatically destroyed
*       -   if the entire QueueQueue is looped through. This could be useful for value
*       -   searches where looping through the rest of the QueueQueue is pointles.
*
*   ---------------------------------------------------------------------
*   -                     
*   -   Example       
*   -            
*   -   function Test takes QueueQueue q returns nothing
*   -       local QueueQueue looper = q.start()     //create a new looper
*   -       local QueueQueue node
*   -
*   -       loop
*   -           set node = looper.get       //get the next node
*   -           exitwhen node == 0          //exitwhen the node is null
*   -
*   -           //code
*   -           call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, I2S(node))
*   -       endloop
*   -   endfunction
*   -
*   ---------------------------------------------------------------------
*
*******************************************************************/
    module QueueQueue
        private static integer array nc         //next column
        private static integer array nr         //next row
        private static integer array lr         //last row
        private static integer ic=0             //column count
        private static integer array rc         //position recycler
        debug private static boolean array a    //is node allocated
        debug private static integer array rs   //references
        private static boolean array h
        readonly boolean pointer
        readonly thistype parent
        private boolean z
        method operator skips takes nothing returns boolean
            return z
        endmethod
        method operator skips= takes boolean b returns nothing
            debug if (pointer) then
                set z=b
            debug else
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE ERROR: ATTEMPTED TO MANIPULATE SKIP OPTION FOR NON POINTER")
            debug endif
        endmethod
        //can only add rows to current object
        static method allocate takes nothing returns thistype
            local thistype this
            //allocate
            if (0==rc[0]) then
                set this=ic+1
                set ic=this
            else
                set this=rc[0]
                set rc[0]=rc[this]
            endif
            debug set a[this]=true
            set nc[this]=0          //next column is 0
            set nr[this]=0          //next row is 0
            set pointer=true        //is a pointer
            set z=true
            set parent=0
            //is head
            debug set h[this]=true
            return this
        endmethod
        method add takes nothing returns thistype
            local thistype n
            debug if (a[this] and (not pointer or h[this])) then
                //allocate
                if (0==rc[0]) then
                    set n=ic+1
                    set ic=n
                else
                    set n=rc[0]
                    set rc[0]=rc[n]
                endif
                debug set a[n]=true
                if (0==nc[this]) then
                    //if nothing to the right, expand
                    set nc[this]=n
                    set lr[this]=n
                else
                    //otherwise, add
                    set nr[lr[this]]=n
                    set lr[this]=n
                endif
                set nr[n]=0         //next row is 0
                set nc[n]=0         //next column is 0
                set n.parent=this
                return n
            debug else
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE ERROR: ATTEMPTED TO MANIPULATE NULL NODE")
            debug endif
            debug return 0
        endmethod
        //special add that adds an existing cell
        method point takes integer p returns thistype
            local thistype n
            //if allocated and not a shadowed pointer (hidden)
            debug if (a[this] and (not pointer or h[this]) and h) then
                //allocate
                if (0==rc[0]) then
                    set n=ic+1
                    set ic=n
                else
                    set n=rc[0]
                    set rc[0]=rc[n]
                endif
                debug set a[n]=true
                //add
                if (0==nc[this]) then
                    //if nothing to the right, expand
                    set nc[this]=n
                    set lr[this]=n
                else
                    //otherwise, add
                    set nr[lr[this]] = n
                    set lr[this] = n
                endif
                //expand and point to p
                set nc[n]=p
                set nr[n]=0
                set n.pointer=true
                set n.z=true
                set n.parent=this
                debug if (h) then
                    debug set rs=rs+1
                debug endif
                return n
            debug else
                debug if (not h) then
                    debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE ERROR: ATTEMPTED TO POINT TO NON HEAD")
                debug elseif (a[this]) then
                    debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE ERROR: ATTEMPTED TO MANIPULATE NON HEAD POINTER")
                debug else
                    debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE ERROR: ATTEMPTED TO MANIPULATE NULL NODE")
                debug endif
            debug endif
            return 0
        endmethod
        method operator next takes nothing returns thistype
            return nr[this]
        endmethod
        method operator in takes nothing returns thistype
            return nc[this]
        endmethod
        method deallocate takes nothing returns nothing
            local thistype array r  //first row on column
            local thistype c = -1   //column
            local thistype n = this //node
            local boolean p = false
            debug if (h[n] and 0==rs[n]) then
                debug set h[n]=false
                debug set a[n]=false
                set rc[n]=rc[0]
                set rc[0]=n
                set pointer=false
                set z=false
                loop
                    if (p) then
                        debug if (h[nc[n]]) then
                            debug set rs[nc[n]]=rs[nc[n]]-1
                        debug endif
                        set n.pointer=false
                        set n.z=false
                        loop
                            //go left until can go down or all the way left
                            exitwhen 0!=nr[n] or 0==c
                            set c=c-1
                            set n=r[c]
                        endloop
                        set n=nr[n]
                        set r[c]=n
                    else
                        if (0==nc[n]) then
                            //if there is nothing to the right, then go down
                            loop
                                //go left until can go down or all the way left
                                exitwhen 0!=nr[n] or 0==c
                                set c=c-1
                                set n=r[c]
                            endloop
                            set n=nr[n]
                            set r[c]=n
                        else
                            //go right
                            set c=c+1       //go to next column
                            set n=nc[n]
                            set r[c]=n      //update next column
                        endif
                    endif
                    exitwhen 0==n
                    set p=n.pointer
                    debug set a[n]=false
                    //destroy
                    set rc[n]=rc[0]
                    set rc[0]=n
                endloop
            debug else
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE ERROR: ATTEMPT TO DESTROY NON HEAD "+I2S(n))
            debug endif
        endmethod
    endmodule
    //! textmacro QUEUE_QUEUE_HEADER_B takes STRUCT
        local boolean array d_1
        local $STRUCT$ array r_1
        local $STRUCT$ c_1
        local $STRUCT$ n_1
    //! endtextmacro
    //! textmacro QUEUE_QUEUE_START_LOOP_B takes THIS
        set n_1=$THIS$
        set c_1=0
        if (0!=n_1.in) then
            loop
                //go to lowest position
                loop
                    exitwhen d_1[c_1] or (0==n_1.next and 0==n_1.in)
                    set d_1[c_1]=true
                    //first go down, then right
                    if (0!=n_1.in) then
                        set c_1=c_1+1
                        set r_1[c_1]=n_1
                        if (0!=n_1.next) then
                            set c_1=c_1+1
                            set r_1[c_1]=n_1.in
                            set n_1=n_1.next
                        else
                            set n_1=n_1.in
                        endif
                    elseif (0!=n_1.next) then
                        set c_1=c_1+1
                        set r_1[c_1]=n_1
                        set n_1=n_1.next
                    endif
                endloop
                if (not n_1.skips) then
                    set $THIS$=n_1
    //! endtextmacro
    
    //! textmacro QUEUE_QUEUE_END_LOOP_B
                endif
                //go up 1
                set d_1[c_1]=false
                set n_1=r_1[c_1]
                set c_1=c_1-1
                exitwhen 0==n_1
            endloop
        endif
    //! endtextmacro
    //! textmacro QUEUE_QUEUE_HEADER takes STRUCT
        local $STRUCT$ array r_1
        local $STRUCT$ c_1
        local $STRUCT$ n_1
    //! endtextmacro
    //! textmacro QUEUE_QUEUE_START_LOOP takes THIS
        set n_1=$THIS$
        set c_1=-1
        loop
            if (not n_1.skips) then
                set $THIS$=n_1
    //! endtextmacro
    
    //! textmacro QUEUE_QUEUE_END_LOOP
            endif
            if (0==n_1.in) then
                //if there is nothing to the right, then go down
                loop
                    //go left until can go down or all the way left
                    exitwhen 0!=n_1.next or 0==c_1
                    set c_1=c_1-1
                    set n_1=r_1[c_1]
                endloop
                set n_1=n_1.next
                set r_1[c_1]=n_1
            else
                //go right
                set c_1=c_1+1       //go to next column
                set n_1=n_1.in
                set r_1[c_1]=n_1    //update next column
            endif
            exitwhen 0==n_1
        endloop
    //! endtextmacro
    module QueueQueueLoop
        private thistype c
        private thistype n
        private boolean e
        private boolean s
        integer id
        debug private boolean o
        private static thistype array rr //recyler
        private static thistype rc=0    //instance count
        method operator depthNode takes nothing returns thistype
            return n
        endmethod
        method operator depthPointer takes nothing returns thistype
            local thistype h=c
            loop
                exitwhen not h.n.skips
                set h=h.c
            endloop
            if (h==this) then
                return 0
            endif
            return h
        endmethod
        method operator skip takes nothing returns thistype
            local thistype n=c.n
            debug if (o) then
                //first, skip the node
                loop
                    //go left until can go down or all the way left
                    exitwhen 0!=n.next or c.e
                    //destroy
                    set rr[c]=rr[0]
                    set rr[0]=c
                    set c=c.c
                    set n=c.n
                endloop
                set n=n.next
                set c.n=n
                //then find a node that doesn't skip
                loop
                    exitwhen not n.skips
                    if (0==n.in) then
                        //if there is nothing to the right, then go down
                        loop
                            //go left until can go down or all the way left
                            exitwhen 0!=n.next or c.e
                            //destroy
                            set rr[c]=rr[0]
                            set rr[0]=c
                            set c=c.c
                            set n=c.n
                        endloop
                        set n=n.next
                        set c.n=n
                    else
                        //go right
                        if (0==rr[0]) then
                            set rc=rc+1
                            set rc.c=c
                            set c=rc
                        else
                            set rr[0].c=c
                            set c=rr[0]
                            set rr[0]=rr[c]
                        endif
                        set c.id=0
                        set n=n.in
                        set c.n=n
                    endif
                endloop
                if (0==n) then
                    debug set o=false
                    set s=false
                    set e=false
                    set rr[this]=rr[0]
                    set rr[0]=this
                else
                    set c.id=0
                endif
                return n
            debug else
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE LOOP ERROR: LOOP NOT OPEN")
            debug endif
            debug return 0
        endmethod
        method operator get takes nothing returns thistype
            local thistype n=c.n
            local string es=""
            debug if (o) then
                if (s) then
                    set s=false
                    if (not n.skips) then
                        return n
                    endif
                endif
                loop
                    if (0==n.in) then
                        //if there is nothing to the right, then go down
                        loop
                            //go left until can go down or all the way left
                            exitwhen 0!=n.next or c.e
                            //destroy
                            set rr[c]=rr[0]
                            set rr[0]=c
                            set c=c.c
                            set n=c.n
                        endloop
                        set n=n.next
                        set c.n=n
                    else
                        //go right
                        if (0==rr[0]) then
                            set rc=rc+1
                            set rc.c=c
                            set c=rc
                        else
                            set rr[0].c=c
                            set c=rr[0]
                            set rr[0]=rr[c]
                        endif
                        set c.id=0
                        set n=n.in
                        set c.n=n
                    endif
                    exitwhen not n.skips
                endloop
                if (0==n) then
                    debug set o=false
                    set s=false
                    set e=false
                    set rr[this]=rr[0]
                    set rr[0]=this
                else
                    set c.id=0
                endif
                return n
            debug else
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE LOOP ERROR: LOOP NOT OPEN")
            debug endif
            debug return 0
        endmethod
        method start takes nothing returns thistype
            local thistype t
            if (0==rr[0]) then
                set rc=rc+1
                set t=rc
            else
                set t=rr[0]
                set rr[0]=rr[t]
            endif
            set t.id=0
            set t.s=true
            set t.c=t
            set t.e=true
            set t.n=this
            debug set t.o=true
            return t
        endmethod
        method end takes nothing returns nothing
            local thistype c=this.c
            debug if (o) then
                debug set o=false
                loop
                    exitwhen c.e
                    set rr[c]=rr[0]
                    set rr[0]=c
                    set c=c.c
                endloop
                set s=false
                set e=false
                set rr[c]=rr[0]
                set rr[0]=c
            debug else
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE LOOP ERROR: LOOP NOT OPEN")
            debug endif
        endmethod
    endmodule
endlibrary

Textmacro Demo
JASS:
scope ttt

//remove the _B to see loop forward and add the _B to see loop backward
private module HeadLoop
    //! runtextmacro QUEUE_QUEUE_HEADER_B("thistype")
endmodule
private module StartLoop
    //! runtextmacro QUEUE_QUEUE_START_LOOP_B("node")
endmodule
private module EndLoop
    //! runtextmacro QUEUE_QUEUE_END_LOOP_B()
endmodule
private struct ttt extends array
    //the first node on the QueueQueue does not actually have to be a head
    //as only the entire QueueQueue structure can be destroyed.
    //
    //keep in mind that only heads can be pointed to*
    private static constant boolean SHOW_HEAD = true

    implement QueueQueue
    string v        //represent values in node, shows positioning
    integer id      //depth for spacing
    
    private method test takes nothing returns nothing
        local thistype node = this
        local string s = ""
        local integer i = 0
        //first create the header. The header takes the struct type
        implement HeadLoop
        //next, start the loop. Pass node in to the loop (this)
        //node is overwritten, so don't actually pass in this unless you
        //don't need it
        implement StartLoop
            set s = ""
            //mumbo jumbo for spacing
            //notice that I am just reading the node variable here as it's automatically set
            //by the macro
            if (SHOW_HEAD) then
                set i = node.id-1
            else
                set i = node.id-2
            endif
            loop
                exitwhen i == 0
                set s = s + "            "
                set i = i - 1
            endloop
            set s = s + node.v
            call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, s)
        //end the loop
        implement EndLoop
    endmethod
    
    /****************************************
    *
    *   Looping Forwards
    *
    *****************************************
    *
    *   1
    *       1.1
    *       1.2
    *           1.2.1
    *               1.2.1.1
    *           1.2.2
    *           1.2.3
    *       1.3
    *       1.4
    *   2
    *       2.1
    *       2.2
    *           2.2.1
    *               2.2.1.1
    *           2.2.2
    *           2.2.3
    *       2.3
    *       2.4
    *
    ****************************************/
    
    /****************************************
    *
    *   Looping Backwards
    *
    *****************************************
    *
    *   	2.4
	*       2.3	
    *           2.2.3
    *           2.2.2	
    *               2.2.1.1
    *           2.2.1
	*       2.2
	*       2.1
    *   2	
	*       1.4
	*       1.3	
    *           1.2.3
    *           1.2.2	
    *               1.2.1.1
    *           1.2.1
	*       1.2
	*       1.1
    *   1
    *
    ****************************************/
    private static method run takes nothing returns nothing
        local thistype this = thistype.allocate()
        local thistype r1 = add()
        local thistype r1_r1 = r1.add()
        local thistype r1_r2 = r1.add()
        local thistype r1_r2_r1 = r1_r2.add()
        local thistype r1_r2_r1_r1 = r1_r2_r1.add()
        local thistype r1_r2_r2 = r1_r2.add()
        local thistype r1_r2_r3 = r1_r2.add()
        local thistype r1_r3 = r1.add()
        local thistype r1_r4 = r1.add()
        local thistype r2 = add()
        local thistype r2_r1 = r2.add()
        local thistype r2_r2 = r2.add()
        local thistype r2_r2_r1 = r2_r2.add()
        local thistype r2_r2_r1_r1 = r2_r2_r1.add()
        local thistype r2_r2_r2 = r2_r2.add()
        local thistype r2_r2_r3 = r2_r2.add()
        local thistype r2_r3 = r2.add()
        local thistype r2_r4 = r2.add()
        
        set skips = not SHOW_HEAD
        set id = 1
        set v = "head"
        
        set r1.id = 2
        set r1_r1.id = 3
        set r1_r2.id = 3
        set r1_r2_r1.id = 4
        set r1_r2_r1_r1.id = 5
        set r1_r2_r2.id = 4
        set r1_r2_r3.id = 4
        set r1_r3.id = 3
        set r1_r4.id = 3
        set r2.id = 2
        set r2_r1.id = 3
        set r2_r2.id = 3
        set r2_r2_r1.id = 4
        set r2_r2_r1_r1.id = 5
        set r2_r2_r2.id = 4
        set r2_r2_r3.id = 4
        set r2_r3.id = 3
        set r2_r4.id = 3
        
        set r1.v = "1"
        set r1_r4.v = "1.4"
        set r1_r3.v = "1.3"
        set r1_r2.v = "1.2"
        set r1_r2_r3.v = "1.2.3"
        set r1_r2_r2.v = "1.2.2"
        set r1_r2_r1_r1.v = "1.2.1.1"
        set r1_r2_r1.v = "1.2.1"
        set r1_r1.v = "1.1"
        set r2.v = "2"
        set r2_r4.v = "2.4"
        set r2_r3.v = "2.3"
        set r2_r2.v = "2.2"
        set r2_r2_r3.v = "2.2.3"
        set r2_r2_r2.v = "2.2.2"
        set r2_r2_r1_r1.v = "2.2.1.1"
        set r2_r2_r1.v = "2.2.1"
        set r2_r1.v = "2.1"

        call test()
        call deallocate()
        
        call DestroyTimer(GetExpiredTimer())
    endmethod
    
    private static method onInit takes nothing returns nothing
        call TimerStart(CreateTimer(), 0, false, function thistype.run)
    endmethod
endstruct

endscope

Module Demo
JASS:
scope ttt

private module HeadLoop
    local thistype looper = start()
    loop
endmodule
private module StartLoop
        set node = looper.get
        exitwhen node == 0
endmodule
private module EndLoop
    endloop
endmodule
private struct ttt extends array
    //the first node on the QueueQueue does not actually have to be a head
    //as only the entire QueueQueue structure can be destroyed.
    //
    //keep in mind that only heads can be pointed to*
    private static constant boolean SHOW_HEAD = false

    implement QueueQueue
    implement QueueQueueLoop
    string v        //represent values in node, shows positioning
    integer id      //depth for spacing
    
    private method test takes nothing returns nothing
        local thistype node = this
        local string s = ""
        local integer i = 0
        //first create the header. The header takes the struct type
        implement HeadLoop
        //next, start the loop. Pass node in to the loop (this)
        //node is overwritten, so don't actually pass in this unless you
        //don't need it
        implement StartLoop
            set s = ""
            //mumbo jumbo for spacing
            //notice that I am just reading the node variable here as it's automatically set
            //by the macro
            if (SHOW_HEAD) then
                set i = node.id-1
            else
                set i = node.id-2
            endif
            loop
                exitwhen i == 0
                set s = s + "            "
                set i = i - 1
            endloop
            set s = s + node.v
            call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, s)
        //end the loop
        implement EndLoop
    endmethod
    
    /****************************************
    *
    *   Looping Forwards
    *
    *****************************************
    *
    *   1
    *       1.1
    *       1.2
    *           1.2.1
    *               1.2.1.1
    *           1.2.2
    *           1.2.3
    *       1.3
    *       1.4
    *   2
    *       2.1
    *       2.2
    *           2.2.1
    *               2.2.1.1
    *           2.2.2
    *           2.2.3
    *       2.3
    *       2.4
    *
    ****************************************/
    
    /****************************************
    *
    *   Looping Backwards
    *
    *****************************************
    *
    *   	2.4
	*       2.3	
    *           2.2.3
    *           2.2.2	
    *               2.2.1.1
    *           2.2.1
	*       2.2
	*       2.1
    *   2	
	*       1.4
	*       1.3	
    *           1.2.3
    *           1.2.2	
    *               1.2.1.1
    *           1.2.1
	*       1.2
	*       1.1
    *   1
    *
    ****************************************/
    private static method run takes nothing returns nothing
        local thistype this = thistype.allocate()
        local thistype r1 = add()
        local thistype r1_r1 = r1.add()
        local thistype r1_r2 = r1.add()
        local thistype r1_r2_r1 = r1_r2.add()
        local thistype r1_r2_r1_r1 = r1_r2_r1.add()
        local thistype r1_r2_r2 = r1_r2.add()
        local thistype r1_r2_r3 = r1_r2.add()
        local thistype r1_r3 = r1.add()
        local thistype r1_r4 = r1.add()
        local thistype r2 = add()
        local thistype r2_r1 = r2.add()
        local thistype r2_r2 = r2.add()
        local thistype r2_r2_r1 = r2_r2.add()
        local thistype r2_r2_r1_r1 = r2_r2_r1.add()
        local thistype r2_r2_r2 = r2_r2.add()
        local thistype r2_r2_r3 = r2_r2.add()
        local thistype r2_r3 = r2.add()
        local thistype r2_r4 = r2.add()
        
        set skips = not SHOW_HEAD
        set id = 1
        set v = "head"
        
        set r1.id = 2
        set r1_r1.id = 3
        set r1_r2.id = 3
        set r1_r2_r1.id = 4
        set r1_r2_r1_r1.id = 5
        set r1_r2_r2.id = 4
        set r1_r2_r3.id = 4
        set r1_r3.id = 3
        set r1_r4.id = 3
        set r2.id = 2
        set r2_r1.id = 3
        set r2_r2.id = 3
        set r2_r2_r1.id = 4
        set r2_r2_r1_r1.id = 5
        set r2_r2_r2.id = 4
        set r2_r2_r3.id = 4
        set r2_r3.id = 3
        set r2_r4.id = 3
        
        set r1.v = "1"
        set r1_r4.v = "1.4"
        set r1_r3.v = "1.3"
        set r1_r2.v = "1.2"
        set r1_r2_r3.v = "1.2.3"
        set r1_r2_r2.v = "1.2.2"
        set r1_r2_r1_r1.v = "1.2.1.1"
        set r1_r2_r1.v = "1.2.1"
        set r1_r1.v = "1.1"
        set r2.v = "2"
        set r2_r4.v = "2.4"
        set r2_r3.v = "2.3"
        set r2_r2.v = "2.2"
        set r2_r2_r3.v = "2.2.3"
        set r2_r2_r2.v = "2.2.2"
        set r2_r2_r1_r1.v = "2.2.1.1"
        set r2_r2_r1.v = "2.2.1"
        set r2_r1.v = "2.1"

        call test()
        call deallocate()
        
        call DestroyTimer(GetExpiredTimer())
    endmethod
    
    private static method onInit takes nothing returns nothing
        call TimerStart(CreateTimer(), 0, false, function thistype.run)
    endmethod
endstruct
endscope

Data
Code:
1
1.1
1.2
1.2.1
1.2.1.1
1.2.2
1.2.3
1.3
1.4
2
2.1
2.2
2.2.1
2.2.1.1
2.2.2
2.2.3
2.3
2.4

Looped over forwards
Code:
1
	1.1
	1.2
		1.2.1
			1.2.1.1
		1.2.2
		1.2.3
	1.3
	1.4
2
	2.1
	2.2
		2.2.1
			2.2.1.1
		2.2.2
		2.2.3
	2.3
	2.4


Looped over backwards
Code:
	2.4
	2.3	
		2.2.3
		2.2.2	
			2.2.1.1
		2.2.1
	2.2
	2.1
2	
	1.4
	1.3	1.2.3
		1.2.2	
			1.2.1.1
		1.2.1
	1.2
	1.1
1
 
Last edited:
This may match the computer - language term "snippet" (re-useable source code) but utterly defies the standard logic (being a small piece).

But putting things in perspective, this is meant as a piece of the Big Int library, the Scrambler library and other bits you've put development work into. Perhaps small in comparison to the whole. But definitely not small.

Do you think that 8190 values are large enough for all the nodes in a save/load system?
 
Made it so that loop macros and module support whether or not to skip pointers. Before, it always skipped pointers. The skip method in the module is really only useful when not automatically skipping over pointer nodes as skipping an entire pointer is normally determined by the data in the pointer node.

There is currently no way to skip over specific pointers (everything it points to and etc) in the macro.
 
Added depth support to the loop macro. Now depthPointer and depthNode can be used for ultimate traversal.

Example of retrieving current parent
set parent = looper.depthPointer.depthPointer.depthNode

Example of retrieving current parent given custom pointers
JASS:
set parent = looper.depthPointer
loop
    exitwhen not pointer[parent.depthNode]
    set parent = parent.depthPointer
endloop

Also added id integer field to the loop macro so that instances can be associated with depth pointers. Remember that nodes may be linked to multiple times, so nodes can't be used as a reference, but depth pointers are entirely unique, so they can be used.

The id is reset to 0 properly, so no worries about reading possibly wrong values.
 
Top