# WC3 JASS.com"The Jass Vault" plus vJASS and Zinc

 Warcraft III: Maps Models Skins Icons Spells / Systems Tools Tutorials vJASS & Zinc DocumentationFor 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

### coding efficient vjass structs Jass Tutorials

Started by
moyack

0 Members and 1 Guest are viewing this topic.

##### 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
1. struct a
2. endstruct
3.

outputs

Code: jass
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
1. struct b extends a
2. endstruct
3.

outputs

Code: jass
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
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
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
1. private static thistype recycle = 0 //next recycled instance
2. private thistype recycleNext //recycled stack
3.

Code: jass
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
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
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
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
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
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
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 »

 Started by moyack Replies: 2Views: 6324 WC3 Editing Tools Started by Magtheridon96 Replies: 3Views: 12153 Jass Tutorials Started by Wareditor Replies: 7Views: 20421 Rejected Codes & Snippets Started by Troll-Brain Replies: 8Views: 22439 Codes & Snippets