Double Linked Struct Module

Hello Everyone,
I hope you're all good

I found that thread, talking about efficiently loop on structs iterations (other than with an array)

I tried below to create a concrete struct that is called by a trigger.
Using what @Nestharus wrote on the thread.

I want to know if this could be intersting.

The main goal is to put all the non-functional code into a module.

vJASS:
/*********************************************************************************************
*  These struct are created with a random countMax [1, 10]
*  This count is increased by 1 every second.
*  Struct is destroyed when the count reaches the countMax
*
*  The structs are chained with the attaributes prev/next
*  The method processNode is useful to process every structs
*
*  HOW TO IMPORT
*   - 1
*  call initTest() // in initialization of the map
*
*   - 2
*  call Test.create()  // in a trigger for example when a player Escape Cinematic Sequense
*
*   - 3
*   DONE
*********************************************************************************************/
scope Test
  globals
    private constant real INTERVAL = 1

    // the Struct Number only useful to log
    private integer STRUCT_NUM
  endglobals

struct Test extends array
  // useful to generate new struct Test
  private static integer instanceCount = 0
  // the previous struct recycled
  private static integer array recycle

  // useful to know if I must start/stop a timer
  static integer countStructsTotal
  // the first struct of the chain
  static thistype first = 0
  // the last struct of the chain
  static thistype last = 0
  static timer T = null

  // the next struct Test
  thistype next
  // the previous struct Test
  thistype prev
  integer num
  integer count
  integer countMax

  private method destroy takes nothing returns nothing
    set recycle[this] = recycle[0]
    set recycle[0] = this
  endmethod

  // when a struct should be removed from the chain
  private method remove takes nothing returns nothing
call BJDebugMsg("REMOVE " + I2S(.num))

    // we chain the previous and next node together
    set .prev.next = .next
    set .next.prev = .prev

call BJDebugMsg(I2S(.prev.num) + " > " + I2S(.num) + " > " + I2S(.next.num))

    // the current node is the first one
    if .first == this then
      set .first = .next
    endif

    // the current node is the last one
    if .next == 0 then
call BJDebugMsg("IS LAST")
      set .last = .prev
    endif

    set .countStructsTotal = .countStructsTotal - 1

    // No more struct in the chain
    if .countStructsTotal <= 0 then
call BJDebugMsg("PAUSE TIMER")
      call PauseTimer(.T)
      set .first = 0
      set .countStructsTotal = 0
    endif

    call .destroy()
  endmethod

  // A new struct has been add, after the last node
  private method addNext takes thistype node returns nothing
call BJDebugMsg("ADD " + I2S(.num))

    set .next = node
    set node.prev = this

call BJDebugMsg(I2S(.prev.num) + " > " + I2S(.num) + " > " + I2S(.next.num))
  endmethod

  // method increase the count by 1 until it reaches the countMax
  private method increaseCount takes nothing returns nothing
    set .count = .count + R2I(INTERVAL)

    if .count >= .countMax then
      call .remove()
    endif
  endmethod

  // method call herself with the next node of each node
  static method processNode takes thistype node returns nothing
    if node != 0 then
call BJDebugMsg(I2S(node.num))
      call node.increaseCount()

      // if the node has a next, we call the method with the next node
      call .processNode(node.next)
    else
call BJDebugMsg("NO MORE NODE")
    endif
  endmethod

  static method timerExpires takes nothing returns nothing
    call BJDebugMsg("\nTIMER EXPIRES")

    // we just call the ùethod for the first node
    call .processNode(.first)
  endmethod

  // MEthod called each time a player press Esc
  static method create takes nothing returns thistype
    local thistype this = recycle[0]

    if this == 0 then
call BJDebugMsg("STRUCT CREATED")
      set this = instanceCount + 1
      set instanceCount = this
    else
call BJDebugMsg("STRUCT RECYCLED")
      set recycle[0] = recycle[this]
    endif

// call BJDebugMsg(I2S(instanceCount))

    // useful for logging
    set STRUCT_NUM = STRUCT_NUM + 1

    set this.next = 0
    set this.prev = 0
    set this.num = STRUCT_NUM
    set this.count = 0
    set this.countMax = GetRandomInt(1, 10)

    // no struct before, we start the timer
    if .countStructsTotal == 0 then
      set .first = this

      // The timer is started
      call TimerStart(.T, INTERVAL, true, function thistype.timerExpires)
    else
      // method to add the last node in the chain
      call .last.addNext(this)
    endif

    set .countStructsTotal = .countStructsTotal + 1
    set .last = this

    return this
  endmethod
endstruct

// INIT Function called on Init of the map
function initTest takes nothing returns nothing
  set Test.T = CreateTimer()
  set Test.countStructsTotal = 0
  set STRUCT_NUM = 0
endfunction

endscope

I have a few questions about the create and destroy method
1/ what means the
vJASS:
thistype(0)
is it the first instance? because it extends Array

2/
vJASS:
    local thistype this = recycle[0]

    if this == 0 then
      set this = instanceCount + 1
      set instanceCount = this
    else
      set recycle[0] = recycle[this]
    endif

In that code how the given instance of our struct is just an integer + 1, in the case we did not found any instance in the recycler
And why are we doing 'set recycle[0] = recycle[this]' in case where there is an instance found in the recycle array?

3/ how many running instance can be managed by warcraft III in maximum?

If you have suggestions you can tell me,
If this could interest someone. Maybe putting it in the spell section.
 

Attachments

  • DoubleLinkedStructs.w3m
    20.3 KB · Views: 5
Hello
Here is a new version with a module

Here is the module
vJASS:
library LinkedStruct
module LinkedStruct
  // useful to generate new struct Test
  private static integer instanceCount = 0
  // the previous struct recycled
  private static integer array recycle

  // the first struct of the chain
  static thistype first = 0
  // the last struct of the chain
  static thistype last = 0
  // the next struct Test
  thistype next
  // the previous struct Test
  thistype prev

  private method destroy takes nothing returns nothing
    set recycle[this] = recycle[0]
    set recycle[0] = this
  endmethod

  // when a struct should be removed from the chain
  method remove takes nothing returns nothing
call BJDebugMsg("REMOVE " + I2S(.num))
    // we chain the previous and next node together
    set .prev.next = .next
    set .next.prev = .prev
call BJDebugMsg(I2S(.prev.num) + " > " + I2S(.num) + " > " + I2S(.next.num))

    // the current node is the first one
    if .first == this then
      set .first = .next
    endif

    // the current node is the last one
    if .next == 0 then
call BJDebugMsg("IS LAST")
      set .last = .prev
    endif

    // No more struct in the chain
    if .first == 0 then
call BJDebugMsg("PAUSE TIMER")
      call PauseTimer(.T)
      set .first = 0
    endif

    call .destroy()
  endmethod

  // method call herself with the next node of each node
  static method processNode takes thistype node returns nothing
    if node != 0 then
call BJDebugMsg(I2S(node.num))
      call node.manageStruct()
      // if the node has a next, we call the method with the next node
      call .processNode(node.next)
    else
call BJDebugMsg("NO MORE NODE")
    endif
  endmethod

  static method timerExpires takes nothing returns nothing
    call BJDebugMsg("\nTIMER EXPIRES")
    // we just call the method for the first node
    call .processNode(.first)
  endmethod

  // A new struct has been add, after the last node
  private method addNext takes thistype node returns nothing
call BJDebugMsg("ADD " + I2S(.num))
    set .next = node
    set node.prev = this
call BJDebugMsg(I2S(.prev.num) + " > " + I2S(.num) + " > " + I2S(.next.num))
  endmethod

  // Method called each time a player press Esc
  static method create takes nothing returns thistype
    local thistype this = recycle[0]
    if this == 0 then
call BJDebugMsg("STRUCT CREATED")
      set this = instanceCount + 1
      set instanceCount = this
    else
call BJDebugMsg("STRUCT RECYCLED")
      set recycle[0] = recycle[this]
    endif
// call BJDebugMsg(I2S(instanceCount))
    set this.next = 0
    set this.prev = 0

    // no struct before, we start the timer
    if .first == 0 then
      set .first = this
    else
      // method to add the last node in the chain
      call .last.addNext(this)
    endif

    set .last = this
    return this
  endmethod
endmodule
endlibrary

Here is the struct
vJASS:
/*********************************************************************************************
*  These struct are created with a random countMax [1, 10]
*  This count is increased by 1 every second.
*  Struct is destroyed when the count reaches the countMax
*
*  The structs are chained with the attaributes prev/next
*  The method processNode is useful to process every structs
*
*  HOW TO IMPORT
*   - 1
*  create file LinkedStruct with the code
*
*   - 2
*  create your struct and implement your LinkedStruct
*
*   - 3
*  call thistype.create()  to create a linked struct instance
*
*   - 4
*  your timer must call thistype.timerExpires // this will be call after expiration for each struct
*
*   - 5
*  you can code in a method manageStruct
*
*   - 6
*  call remove method when a struct should be deleted
*
*   - 7
*   DONE
*********************************************************************************************/
scope Test
  globals
    private constant real INTERVAL = 1
    // the Struct Number only useful to log
    private integer STRUCT_NUM
  endglobals

struct Test extends array
  static timer T = null
  integer num
  integer count
  integer countMax
  implement LinkedStruct
  // method increase the count by 1 until it reaches the countMax
  private method increaseCount takes nothing returns nothing
    set .count = .count + R2I(INTERVAL)
    if .count >= .countMax then
      call .remove()
    endif
  endmethod

  // method increase the count by 1 until it reaches the countMax
  private method manageStruct takes nothing returns nothing
    call .increaseCount()
  endmethod

  // Method called each time a player press Esc
  static method addTest takes nothing returns nothing
    local thistype test = thistype.create()
    // useful for logging
    set STRUCT_NUM = STRUCT_NUM + 1
    set test.num = STRUCT_NUM
    set test.count = 0
    set test.countMax = GetRandomInt(1, 10)

    if test.prev == 0 then
      call TimerStart(.T, INTERVAL, true, function thistype.timerExpires)
    endif
  endmethod
endstruct

// INIT Function called on Init of the map
function initTest takes nothing returns nothing
  set Test.T = CreateTimer()
  set STRUCT_NUM = 0
endfunction

endscope

What do you think about that
Is it interesting?
Is there some optimizations @Nestharus

I hope this can help
Have a nice day
 

Attachments

  • DoubleLinkedStructs.w3m
    21.7 KB · Views: 6
Top