Warcraft III: MapsModelsSkinsIconsSpellsToolsTutorials
WC3 JASS: Code SnippetsJASS and vJASS Spells and SystemsJass Tutorials
Chat @Discord

vJASS & Zinc Documentation
For the latest documentation about how it works vJASS and Zinc language layers for Warcraft III, please follow these links:
Jasshelper documentation - Zinc documentation - WC3 Optimizer documentation

Author Topic: coding efficient vjass structs  (Read 487 times)

  • Newbie - level 2
  • **
  • Posts: 23
  • WC3 Models: 0
  • WC3 Tutorials: 0
  • WC3 Tools: 0
  • WC3 Maps: 0
  • WC3 Skins: 0
  • WC3 Icons: 0
  • WC3 Spells: 0
  • Reputation: 20
  • User
    • View Profile
coding efficient vjass structs
« on: April 14, 2012, 09:05:37 AM »
Many people continue to ask me what the difference is between struct Hello and struct Hello extends array is.

In vJASS, regular structs create some extra code in the background to make themselves work.

Code: jass  [Select]
  1. struct a
  2. endstruct
  3.  

outputs

Code: jass  [Select]
  1. constant integer si__a=1
  2. integer si__a_F=0
  3. integer si__a_I=0
  4. integer array si__a_V
  5.  
  6. //Generated allocator of a
  7. function s__a__allocate takes nothing returns integer
  8.  local integer this=si__a_F //first node on recycle stack
  9.     if (this!=0) then
  10.         set si__a_F=si__a_V[this] //set stack to next node (like stack.next)
  11.     else
  12.         set si__a_I=si__a_I+1
  13.         set this=si__a_I
  14.     endif
  15.     if (this>8190) then //protection against too many structs
  16.         return 0
  17.     endif
  18.  
  19.     set si__a_V[this]=-1 //set stack to -1 (stack.next = -1)
  20.  return this
  21. endfunction
  22.  
  23. //Generated destructor of a
  24. function s__a_deallocate takes integer this returns nothing
  25.     if this==null then //don't deallocate null instance
  26.         return
  27.     elseif (si__a_V[this]!=-1) then //double free protection
  28.         return
  29.     endif
  30.     set si__a_V[this]=si__a_F //set this.next = stack
  31.     set si__a_F=this //set stack = this
  32. endfunction
  33.  

Code: jass  [Select]
  1. struct b extends a
  2. endstruct
  3.  

outputs

Code: jass  [Select]
  1. constant integer si__a=1
  2. integer si__a_F=0
  3. integer si__a_I=0
  4. integer array si__a_V
  5. constant integer si__b=2
  6. integer array si__a_type
  7. trigger array st__a_onDestroy //Trigger array?!?!
  8. integer f__arg_this
  9.  
  10. //Generated allocator of a
  11. function s__a__allocate takes nothing returns integer
  12.  local integer this=si__a_F
  13.     if (this!=0) then
  14.         set si__a_F=si__a_V[this]
  15.     else
  16.         set si__a_I=si__a_I+1
  17.         set this=si__a_I
  18.     endif
  19.     if (this>8190) then
  20.         return 0
  21.     endif
  22.  
  23.     set si__a_type[this]=1
  24.     set si__a_V[this]=-1
  25.  return this
  26. endfunction
  27.  
  28. //Generated destructor of a
  29. function sc__a_deallocate takes integer this returns nothing
  30.     if this==null then
  31.         return
  32.     elseif (si__a_V[this]!=-1) then
  33.         return
  34.     endif
  35.     set f__arg_this=this
  36.     call TriggerEvaluate(st__a_onDestroy[si__a_type[this]]) //AHH!!
  37.     set si__a_V[this]=si__a_F
  38.     set si__a_F=this
  39. endfunction
  40.  
  41. //Generated allocator of b
  42. function s__b__allocate takes nothing returns integer
  43.  local integer this=s__a__allocate()
  44.  local integer kthis //why??
  45.     if(this==0) then
  46.         return 0
  47.     endif
  48.     set si__a_type[this]=2
  49.     set kthis=this //... doesn't actually do anything
  50.  
  51.  return this
  52. endfunction
  53.  

As can be seen, trigger evaluations pop up and useless variables get generated.

Code: jass  [Select]
  1. struct a extends array
  2. endstruct
  3.  

generates

constant integer si__a=1

Not bad, but this means that this sort of thing will no longer work
Code: jass  [Select]
  1. local a myStruct = a.create()
  2. call myStruct.destroy()
  3.  

meaning that the allocation and deallocation of structs is left up to the coders.

So let's look on how structs are actually allocated (getting rid of the virtually useless double free protection and getting rid of allocate/deallocate as they might as well be put into create and destroy).

As structs are created, the total number of structs generated continues to increase. A counter is needed in order to track how many structs have been created.

private static integer instanceCount = 0

As structs are destroyed, their instances need to be recycled.

Code: jass  [Select]
  1. private static thistype recycle = 0 //next recycled instance
  2. private thistype recycleNext //recycled stack
  3.  

Code: jass  [Select]
  1. struct MyStruct extends array
  2.     private static integer instanceCount = 0
  3.     private static thistype recycle = 0
  4.     private thistype recycleNext
  5.  
  6.     static method create takes nothing returns thistype
  7.         local thistype this
  8.  
  9.         //first check to see if there are any structs waiting to be recycled
  10.         if (recycle == 0) then
  11.             //if recycle is 0, there are no structs, so increase instance count
  12.             set instanceCount = instanceCount + 1
  13.             set this = instanceCount
  14.         else
  15.             //a struct is waiting to be recycled, so use it
  16.             set this = recycle
  17.             set recycle = recycle.recycleNext
  18.         endif
  19.  
  20.         //perform creation code
  21.  
  22.         return this
  23.     endmethod
  24.  
  25.     method destroy takes nothing returns nothing
  26.         //add to recycle stack
  27.         set recycleNext = recycle
  28.         set recycle = this
  29.     endmethod
  30. endstruct
  31.  

Code output from above (does same thing as first example w/o double free protection)

Code: jass  [Select]
  1. constant integer si__MyStruct=1
  2. integer s__MyStruct_instanceCount= 0
  3. integer s__MyStruct_recycle= 0
  4. integer array s__MyStruct_recycleNext
  5.  
  6. function s__MyStruct_create takes nothing returns integer
  7.     local integer this
  8.     if ( s__MyStruct_recycle == 0 ) then
  9.         set s__MyStruct_instanceCount=s__MyStruct_instanceCount + 1
  10.         set this=s__MyStruct_instanceCount
  11.     else
  12.         set this=s__MyStruct_recycle
  13.         set s__MyStruct_recycle=s__MyStruct_recycleNext[s__MyStruct_recycle]
  14.     endif
  15.     return this
  16. endfunction
  17.  
  18. function s__MyStruct_destroy takes integer this returns nothing
  19.     set s__MyStruct_recycleNext[this]=s__MyStruct_recycle
  20.     set s__MyStruct_recycle=this
  21. endfunction
  22.  

A bit more work, but a bit more optimal. What about extending structs?

Extending structs is done with delegates (also allows members to be overriden).

Code: jass  [Select]
  1. struct Mystruct2 extends array
  2.     //delegate stores pointers to parent struct
  3.     //this means that one can extend off of multiple structs
  4.     private delegate MyStruct MyStruct
  5.    
  6.     static method create takes nothing returns thistype
  7.         //base instance off of parent struct
  8.         local thistype this = MyStruct.create()
  9.         //store pointer into delegate
  10.         set MyStruct = this
  11.        
  12.         return this
  13.     endmethod
  14.    
  15.     method destroy takes nothing returns nothing
  16.         //simply destroy
  17.         call MyStruct.destroy()
  18.     endmethod
  19. endstruct
  20.  

Outputs
Code: jass  [Select]
  1. constant integer si__MyStruct=1
  2. integer s__MyStruct_instanceCount= 0
  3. integer s__MyStruct_recycle= 0
  4. integer array s__MyStruct_recycleNext
  5. constant integer si__Mystruct2=2
  6. integer array s__Mystruct2_MyStruct
  7.  
  8. function s__MyStruct_create takes nothing returns integer
  9.         local integer this
  10.         if ( s__MyStruct_recycle == 0 ) then
  11.                 set s__MyStruct_instanceCount=s__MyStruct_instanceCount + 1
  12.                 set this=s__MyStruct_instanceCount
  13.         else
  14.                 set this=s__MyStruct_recycle
  15.                 set s__MyStruct_recycle=s__MyStruct_recycleNext[s__MyStruct_recycle]
  16.         endif
  17.         return this
  18. endfunction
  19.  
  20. function s__MyStruct_destroy takes integer this returns nothing
  21.         set s__MyStruct_recycleNext[this]=s__MyStruct_recycle
  22.         set s__MyStruct_recycle=this
  23. endfunction
  24.  
  25. function s__Mystruct2_create takes nothing returns integer
  26.         local integer this= s__MyStruct_create()
  27.         set s__Mystruct2_MyStruct[this]=this
  28.         return this
  29. endfunction
  30.  
  31. function s__Mystruct2_destroy takes integer this returns nothing
  32.         call s__MyStruct_destroy(s__Mystruct2_MyStruct[this])
  33. endfunction
  34.  

No trigger arrays, no trigger evaluations, and no wasted local variables. It even allows you to make one struct extend off of multiple structs.

Multi-Struct Extension
Code: jass  [Select]
  1. struct MyStruct extends array
  2.     private static integer instanceCount = 0
  3.     private static thistype recycle = 0
  4.     private thistype recycleNext
  5.  
  6.     static method create takes nothing returns thistype
  7.         local thistype this
  8.         if (recycle == 0) then
  9.             set instanceCount = instanceCount + 1
  10.             set this = instanceCount
  11.         else
  12.             set this = recycle
  13.             set recycle = recycle.recycleNext
  14.         endif
  15.         return this
  16.     endmethod
  17.  
  18.     method destroy takes nothing returns nothing
  19.         set recycleNext = recycle
  20.         set recycle = this
  21.     endmethod
  22. endstruct
  23.  
  24. struct MyStruct2 extends array
  25.     private static integer instanceCount = 0
  26.     private static thistype recycle = 0
  27.     private thistype recycleNext
  28.  
  29.     static method create takes nothing returns thistype
  30.         local thistype this
  31.         if (recycle == 0) then
  32.             set instanceCount = instanceCount + 1
  33.             set this = instanceCount
  34.         else
  35.             set this = recycle
  36.             set recycle = recycle.recycleNext
  37.         endif
  38.         return this
  39.     endmethod
  40.  
  41.     method destroy takes nothing returns nothing
  42.         set recycleNext = recycle
  43.         set recycle = this
  44.     endmethod
  45. endstruct
  46.  
  47. struct Mystruct3 extends array
  48.     private delegate MyStruct MyStruct
  49.     private delegate MyStruct2 MyStruct2
  50.    
  51.     static method create takes nothing returns thistype
  52.         local thistype this = MyStruct.create()
  53.         set MyStruct = this
  54.        
  55.         //use first pointer as current struct's instance
  56.         set MyStruct2 = MyStruct2.create()
  57.        
  58.         //creation code
  59.        
  60.         return this
  61.     endmethod
  62.    
  63.     method destroy takes nothing returns nothing
  64.         //destroy both structs
  65.         call MyStruct.destroy()
  66.         call MyStruct2.destroy()
  67.     endmethod
  68. endstruct
  69.  

Which happily outputs
Code: jass  [Select]
  1. constant integer si__MyStruct=1
  2. integer s__MyStruct_instanceCount= 0
  3. integer s__MyStruct_recycle= 0
  4. integer array s__MyStruct_recycleNext
  5. constant integer si__MyStruct2=2
  6. integer s__MyStruct2_instanceCount= 0
  7. integer s__MyStruct2_recycle= 0
  8. integer array s__MyStruct2_recycleNext
  9. constant integer si__Mystruct3=3
  10. integer array s__Mystruct3_MyStruct
  11. integer array s__Mystruct3_MyStruct2
  12.  
  13. function s__MyStruct_create takes nothing returns integer
  14.         local integer this
  15.         if ( s__MyStruct_recycle == 0 ) then
  16.                 set s__MyStruct_instanceCount=s__MyStruct_instanceCount + 1
  17.                 set this=s__MyStruct_instanceCount
  18.         else
  19.                 set this=s__MyStruct_recycle
  20.                 set s__MyStruct_recycle=s__MyStruct_recycleNext[s__MyStruct_recycle]
  21.         endif
  22.         return this
  23. endfunction
  24.  
  25. function s__MyStruct_destroy takes integer this returns nothing
  26.         set s__MyStruct_recycleNext[this]=s__MyStruct_recycle
  27.         set s__MyStruct_recycle=this
  28. endfunction
  29.  
  30.  
  31. function s__MyStruct2_create takes nothing returns integer
  32.         local integer this
  33.         if ( s__MyStruct2_recycle == 0 ) then
  34.                 set s__MyStruct2_instanceCount=s__MyStruct2_instanceCount + 1
  35.                 set this=s__MyStruct2_instanceCount
  36.         else
  37.                 set this=s__MyStruct2_recycle
  38.                 set s__MyStruct2_recycle=s__MyStruct2_recycleNext[s__MyStruct2_recycle]
  39.         endif
  40.         return this
  41. endfunction
  42.  
  43. function s__MyStruct2_destroy takes integer this returns nothing
  44.         set s__MyStruct2_recycleNext[this]=s__MyStruct2_recycle
  45.         set s__MyStruct2_recycle=this
  46. endfunction
  47.  
  48.  
  49. function s__Mystruct3_create takes nothing returns integer
  50.         local integer this= s__MyStruct_create()
  51.         set s__Mystruct3_MyStruct[this]=this
  52.         set s__Mystruct3_MyStruct2[this]=s__MyStruct2_create()
  53.         return this
  54. endfunction
  55.  
  56. function s__Mystruct3_destroy takes integer this returns nothing
  57.         call s__MyStruct_destroy(s__Mystruct3_MyStruct[this])
  58.         call s__MyStruct2_destroy(s__Mystruct3_MyStruct2[this])
  59. endfunction
  60.  
« Last Edit: December 15, 2017, 12:21:08 PM by moyack »

 

Illusion Editor v1.3 [vJass + GUI Support]

Started by AGDBoard Warcraft III Spells and Systems

Replies: 3
Views: 5399
Last post September 08, 2016, 07:38:01 AM
by AGD
[vJass] Rect Utils

Started by WareditorBoard Rejected Codes & Snippets

Replies: 7
Views: 17037
Last post August 31, 2015, 02:41:01 AM
by sankaku
[ vJASS ] About Spawn Unit

Started by LembidiZBoard Triggers & Scripting

Replies: 13
Views: 10651
Last post March 19, 2016, 06:30:06 AM
by LembidiZ
Which could be more efficient/better performance?

Started by 8uY_YoUBoard Coding Help

Replies: 5
Views: 11348
Last post February 23, 2015, 12:25:15 AM
by 8uY_YoU
Structs For Dummies

Started by Magtheridon96Board Jass Tutorials

Replies: 3
Views: 9173
Last post December 29, 2011, 09:34:13 PM
by Magtheridon96
Blizzard Modding Information Center Wacraft III Modding Information Center WC3JASS.com - The JASS Vault Chronicles of Darkness - A Warcraft III mod Jetcraft - A Starcraft II mod Troll Smash - A Warcraft III Arena Starcraft II Modding Information Center
  Mod DB - Change the Game Power of Corruption - A Warcraft III altered melee map Chaos Realm - The world of Game modders and wc3 addicts Follow us on Facebook!!