• 🏆 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!

[Solved] Question with Indexing (Structs)

Status
Not open for further replies.
I wonder how this will behave (indexing). Am I doing something wrong with indexing this?

JASS:
private struct lolStruct extends array
        private static integer count = 0
        private static thistype recycle = 0
        private thistype recNext
       
        private static thistype first    =    0
        private static thistype last    =    0
        private thistype next
        private thistype prev
       
        method destroy takes nothing returns nothing
            set recNext = recycle
            set recycle = this
            if this.prev == 0 then
                set first = this.next
            else
                set this.prev.next = this.next
            endif
            if this.next == 0 then
                set last = this.prev
            else
                set this.next.prev = this.prev
            endif
        endmethod
       
        static method create takes nothing returns thistype
            local thistype this
            if recycle == 0 then
                set count = count + 1
                set this = count
            else
                set this = recycle
                set recycle = recycle.recNext
            endif
            return this
        endmethod
       
        method push takes nothing returns nothing
            if recycle == 0 then
                set first = this
                set last = this
                set this.next = 0
                set this.prev = 0
            else
                set this.next = first
                set this.prev = 0
                set first.prev = this
                set first = this
            endif
        endmethod
       
        method queue takes nothing returns nothing
            if recycle == 0 then
                set first = this
                set last = this
                set this.next = 0
                set this.prev = 0
            else
                set this.prev = last
                set this.next = 0
                set last.next = this
                set last = this
            endif
        endmethod
       
    endstruct
 
Last edited:
Level 22
Joined
Feb 6, 2014
Messages
2,466
@MyPad What exactly are you asking here, the allocation method you used or the function of "struct LearnData"?

Am I doing something wrong with indexing this?
Why extends array if you're gonna override it with your own allocation method anyways? You could argue for less generated script but it would be much more efficient (in terms of coding speed) to put your allocation method in a module and just implement it every time instead of rewriting the attributes and function for each struct.
 
@Flux I wanted to ask about how the allocation method will behave. I wanted to know that what I wrote is the correct way.

JASS:
set this.next = thistype(0).next
set thistype(0).next = this

I would like to add its' previous and next, but I don't know exactly how to do it.

EDIT:

Never mind the next portion. I think I figured it out.
 
Last edited:
@KILLCIDE

I'll try to understand the logic first. I'll reply later.

EDIT:

I removed set this.next = 0 because I found it redundant to define.

These are my observations...

JASS:
set thistype(0).prev.next = this    //next[prev[0]] == next[0] = 1, next[prev[0]] == next[1] = 2
set this.prev = thistype(0).prev    //prev[1] = prev[0] = 0, prev[2] = prev[0] = 1
set thistype(0).prev = this            //prev[0] = 1, prev[0] = 2
 
Last edited:
Level 22
Joined
Feb 6, 2014
Messages
2,466
This is how I do my queued circular doubly linked list
JASS:
set this.next = 0
set this.prev = thistype(0).prev
set this.prev.next = this
set this.next.prev = this

You can pick all using
JASS:
local thistype this = thistype(0).next
loop
    exitwhen this == 0
    //Do stuffs on this
    set this = this.next
endloop
^That will pick instances by order they are added (sometimes it matters sometimes it does not). That list also happens to be circular so when you removed the "exitwhen", it will go back to thistype(0) after the last node. It's simple, only need 4 lines for "push", 2 for "pop", only utilizes 2 arrays (some list algorithms I see here on hive uses an extra non-array variable usually called head or first) and at the same time queued and circular.

The "pop" from the list is exactly the same as yours.
 
This is how I do my queued circular doubly linked list
JASS:
set this.next = 0
set this.prev = thistype(0).prev
set this.prev.next = this
set this.next.prev = this

You can pick all using
JASS:
local thistype this = thistype(0).next
loop
    exitwhen this == 0
    //Do stuffs on this
    set this = this.next
endloop
^That will pick instances by order they are added (sometimes it matters sometimes it does not). That list also happens to be circular so when you removed the "exitwhen", it will go back to thistype(0) after the last node. It's simple, only need 4 lines for "push", 2 for "pop", only utilizes 2 arrays (some list algorithms I see here on hive uses an extra non-array variable usually called head or first) and at the same time queued and circular.

The "pop" from the list is exactly the same as yours.

Woah, thanks for that. Now, I can have a nice alternative to hashtables. :thumbs_up:
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
The only problem is that this is not instanced.

Push
JASS:
if (isEmpty()) then
    set p__first = element
    set p__last = element
    set element.p__next = 0
    set element.p__prev = 0
else
    set element.p__next = p__first
    set element.p__prev = 0
    set p__first.p__prev = element
    set p__first = element
endif

Enqueue
JASS:
if (isEmpty()) then
    set p__first = element
    set p__last = element
    set element.p__next = 0
    set element.p__prev = 0
else
    set element.p__prev = p__last
    set element.p__next = 0
    set p__last.p__next = element
    set p__last = element
endif

Remove
JASS:
if (element.p__prev == 0) then
    set p__first = element.p__next
else
    set element.p__prev.p__next = element.p__next
endif
if (element.p__next == 0) then
    set p__last = element.p__prev
else
    set element.p__next.p__prev = element.p__prev
endif
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
The only problem is that this is not instanced.

Push
JASS:
if (isEmpty()) then
    set p__first = element
    set p__last = element
    set element.p__next = 0
    set element.p__prev = 0
else
    set element.p__next = p__first
    set element.p__prev = 0
    set p__first.p__prev = element
    set p__first = element
endif

Enqueue
JASS:
if (isEmpty()) then
    set p__first = element
    set p__last = element
    set element.p__next = 0
    set element.p__prev = 0
else
    set element.p__prev = p__last
    set element.p__next = 0
    set p__last.p__next = element
    set p__last = element
endif

Remove
JASS:
if (element.p__prev == 0) then
    set p__first = element.p__next
else
    set element.p__prev.p__next = element.p__next
endif
if (element.p__next == 0) then
    set p__last = element.p__prev
else
    set element.p__next.p__prev = element.p__prev
endif
Yeah but if you will only have 1 list just for the purpose of picking all instances (like most Spells), then thistype(0) can serve as the "universal" head.
 
The only problem is that this is not instanced.

Push
JASS:
if (isEmpty()) then
    set p__first = element
    set p__last = element
    set element.p__next = 0
    set element.p__prev = 0
else
    set element.p__next = p__first
    set element.p__prev = 0
    set p__first.p__prev = element
    set p__first = element
endif

Enqueue
JASS:
if (isEmpty()) then
    set p__first = element
    set p__last = element
    set element.p__next = 0
    set element.p__prev = 0
else
    set element.p__prev = p__last
    set element.p__next = 0
    set p__last.p__next = element
    set p__last = element
endif

Remove
JASS:
if (element.p__prev == 0) then
    set p__first = element.p__next
else
    set element.p__prev.p__next = element.p__next
endif
if (element.p__next == 0) then
    set p__last = element.p__prev
else
    set element.p__next.p__prev = element.p__prev
endif

At this point, I'm just learning unique ways with indexing certain elements. Thanks for you help: :grin:

By the way, I have updated the code above. I just need a bit of clarification with this:

(isEmpty())

Is it recycle == 0, or is it something else entirely?

EDIT:

I think that the create method should be combined with either the push or the queue. Maybe I might be wrong on this...
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
JASS:
public method isEmpty takes nothing returns boolean
    return p__first.isNull
endmethod

public method operator isNull takes nothing returns boolean
    return this == 0
endmethod


Create is not combined with push or enqueue. Create creates the collection. Push/enqueue create nodes.

JASS:
public static method create takes nothing returns thistype
    return createCollection()
endmethod

public method destroy takes nothing returns nothing
    static if DEBUG_MODE and LIBRARY_ErrorMessage then
        call AssertCollection("destroy", this, p__collection)
    endif

    call destroyCollection()
endmethod

JASS:
public method enqueueCollection takes nothing returns thistype
    local thistype element = createElement(this)

    if (isEmpty()) then
        set p__first = element
        set p__last = element
        set element.p__next = 0
        set element.p__prev = 0
    else
        set element.p__prev = p__last
        set element.p__next = 0
        set p__last.p__next = element
        set p__last = element
    endif

    return element
endmethod

JASS:
method enqueue takes nothing returns thistype
   static if DEBUG_MODE and LIBRARY_ErrorMessage then
      call AssertCollection("enqueue", this, p__collection)
   endif

   return enqueueCollection()
endmethod

On top of this, the allocation for nodes is a little bit unique to save on variables. Note that p__next is used as the recycler. Also, note that in this example nodes use a different allocator from the collection itself. This means that this module has 2 allocators. They can also share the same allocator. I still like to use p__next for nodes and p__first for collections for my allocators : ). This means that I use extends array on my structs.

JASS:
            local thistype this = thistype(0).p__next

            if (p__next == 0) then
                set thistype(0).p__next = this + 1
            else
                set thistype(0).p__next = p__next
            endif

            set p__next = 0
 
Last edited:
Level 7
Joined
Oct 19, 2015
Messages
286
With regards to the code currently posted in the first post, the create method lacks the following line: set this.next = thistype(0)
 
JASS:
public method isEmpty takes nothing returns boolean
    return p__first.isNull
endmethod

public method operator isNull takes nothing returns boolean
    return this == 0
endmethod


Create is not combined with push or enqueue. Create creates the collection. Push/enqueue create nodes.

JASS:
public static method create takes nothing returns thistype
    return createCollection()
endmethod

public method destroy takes nothing returns nothing
    static if DEBUG_MODE and LIBRARY_ErrorMessage then
        call AssertCollection("destroy", this, p__collection)
    endif

    call destroyCollection()
endmethod

JASS:
public method enqueueCollection takes nothing returns thistype
    local thistype element = createElement(this)

    if (isEmpty()) then
        set p__first = element
        set p__last = element
        set element.p__next = 0
        set element.p__prev = 0
    else
        set element.p__prev = p__last
        set element.p__next = 0
        set p__last.p__next = element
        set p__last = element
    endif

    return element
endmethod

JASS:
method enqueue takes nothing returns thistype
   static if DEBUG_MODE and LIBRARY_ErrorMessage then
      call AssertCollection("enqueue", this, p__collection)
   endif

   return enqueueCollection()
endmethod

On top of this, the allocation for nodes is a little bit unique to save on variables. Note that p__next is used as the recycler. Also, note that in this example nodes use a different allocator from the collection itself. This means that this module has 2 allocators. They can also share the same allocator. I still like to use p__next for nodes and p__first for collections for my allocators : ). This means that I use extends array on my structs.

JASS:
            local thistype this = thistype(0).p__next

            if (p__next == 0) then
                set thistype(0).p__next = this + 1
            else
                set thistype(0).p__next = p__next
            endif

            set p__next = 0

I updated parts of the code now. This is what it looks like:

JASS:
private struct lolStruct extends array
        private static integer count = 0
        private static thistype recycle = 0
        private thistype recNext
       
        private static thistype first    =    0
        private static thistype last    =    0
        private thistype next
        private thistype prev
       
        method operator Null takes nothing returns boolean
            return this == 0
        endmethod
       
        method Empty takes nothing returns boolean
            return first.Null
        endmethod
       
        static method create takes nothing returns thistype
            local thistype this
            if recycle.Null then
                set count = count + 1
                set this = count
            else
                set this = recycle
                set recycle = recycle.recNext
            endif
            return this
        endmethod
        
        //push and queue code...
        //destroy below...

        method destroy takes nothing returns nothing
            set recNext = recycle
            set recycle = this
            if this.prev == 0 then
                set first = this.next
            else
                set this.prev.next = this.next
            endif
            if this.next == 0 then
                set last = this.prev
            else
                set this.next.prev = this.prev
            endif
        endmethod
       
    endstruct

Which one of these is more acceptable?

This?

JASS:
method pushOne takes nothing returns thistype
        local thistype that = thistype(0).next
        if that.next.Null then
            set thistype(0).next = that + 1
        else
            set thistype(0).next = that.next
        endif
        set that.next = 0
        if Empty() then    //first == 0
            set first = that
            set last = that
            set that.next = 0
            set that.prev = 0
        else            //first != 0
            set that.next = first
            set that.prev = 0
            set first.prev = that
            set first = that
        endif
        return that
endmethod

or this?

JASS:
method pushTwo takes nothing returns thistype
        local thistype that = thistype.create()
        set that.next = 0
        if Empty() then    //first == 0
            set first = that
            set last = that
            set that.next = 0
            set that.prev = 0
        else            //first != 0
            set that.next = first
            set that.prev = 0
            set first.prev = that
            set first = that
        endif
        return that
endmethod
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
I don't know what your aim is.

Are you aiming for a static linked list or an instantiable linked list?


Static means that you may only have one list. Instantiable means that one struct can have N lists on it.

The following is instanced
JASS:
// two different lists from the same struct
local List listA = List.create()
local List listB = List.create()

// each has one node each
local List nodeA = listA.push() // retrieve the node pushed onto the first list
call listB.push()

call nodeA.remove() // now listA has no nodes on it. nodeA is destroyed.
call listB.clear() // now listB has no nodes on it

call listA.push()

call listA.destroy() // destroys listA. The node that was on listA is also destroyed.
call listB.destroy() // destroys listB.

The following is static

JASS:
local List nodeA = List.push() // notice that now push is static!

call List.clear()

set nodeA = List.enqueue()

call nodeA.remove()

// notice there is no destroy method
// clearing the list is all that needs to be done because the list is static



Which style are you aiming for?
 
Status
Not open for further replies.
Top