Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
This is a little struct attachment system that I made which I called RAS (Reborns Attachment System). It is very easy to use I think.
Since I'm not a pro in vJass there might be some bugs or something.
Here's the code:
JASS:
library RAS
private function H2I takes handle h returns integer
return h
return 0
endfunction
globals
private constant integer size = 13600
private constant integer size2 = 3
endglobals
globals
private integer array stru [size][size2]
endglobals
function GetAttachedStruct takes handle h, integer slot returns integer
return stru[H2I(h) - 0x100000][slot]
endfunction
function AttachStruct takes handle h, integer dat, integer slot returns nothing
set stru[H2I(h) - 0x100000][slot] = dat
endfunction
endlibrary
To attach a struct to a handle you just use this: call AttachStruct(WHICH_HANDLE, THE_STRUCT, SLOT1)
And to retrieve the struct you use this: call GetAttachedStruct(WHICH_HANDLE, SLOT1)
v1.0 -- Initial Release.
v1.1 -- Changed some things to make it safer.
v2.0 -- Changed the code (I found some bugs) It also uses textmacros now.
v2.0b -- Inlined the functions.
v3.0 -- Changed the code. No longer uses textmacros.
v3.0b -- The code from v3.0 didn't work for some reason (I think it's fixed now. It is no longer a 3D array.
You don't need the ifs. And I would like you to test this vs TimerUtils and CSData. And this method isn't really new, but I must say the test results are impressing.
Yeah, I know. That's why I added it . I was surprised when I saw the results, because I thought that HSAS was fastest, but both DAS, RAS and CSData was faster than it.
Edit: I have done another benchmark test now, and I've tested: CSData, RAS, TimerUtils Red Flavour and DAS.
Here's the result:
EDIT3: The code is changed so the results might be wrong!
No, but the system has to be tweaked a little bit.
I am testing somethings at the moment. I will give a more detailed comment later.
It seemed to do more
Well I will put it like this for now:
cache[max1][max2]
The maximum numbers that can go in there are:
max1=8//Not to sure at the moment
max2=1023
Bigger, and data gets confused, but no game errors(crashes) occur.
JASS:
library RAS initializer Init
private function H2I takes handle h returns integer
return h
return 0
endfunction
private type int extends integer array [1000][1000]//useless, actually an error, but the compiler doesn't recognize it, i guess
private type int2 extends int array [1000]
globals
private int2 cache
endglobals
private function Init takes nothing returns nothing
local integer i = 1//wrong
set cache = int2.create()
loop
exitwhen i == 1000
set cache[i] = int2.create()//wrong, but doesn't matter
set i = i + 1
endloop
endfunction
function GetAttachedStruct takes handle h, integer dat returns integer
local integer i = H2I(h)
local integer i2 = i - 0x100000
if i2 < 1000 then//what about dat?
return cache[i2][dat]
endif
return 0
endfunction
function AttachStruct takes handle h, integer dat, integer str returns nothing
local integer i = H2I(h)
local integer i2 = i - 0x100000
if i2 < 1000 then//what about dat?
set cache[i2][dat] = str
endif
endfunction
endlibrary
So the corrected code would look like this:
JASS:
library RAS initializer Init
private function H2I takes handle h returns integer
return h
return 0
endfunction
private type int extends integer array [1023]
private type int2 extends int array [1023]
globals
private int2 cache
endglobals
private function Init takes nothing returns nothing
local integer i = 0
set cache = int2.create()
loop
exitwhen i == int2.size//note this
set cache[i] = int.create()
set i = i + 1
endloop
endfunction
function GetAttachedStruct takes handle h, integer dat returns integer
local integer i = H2I(h)
local integer i2 = i - 0x100000
if i2 < int2.size and dat<int.size then//but this check reduces performance
return cache[i2][dat]
endif
return 0
endfunction
function AttachStruct takes handle h, integer dat, integer str returns nothing
local integer i = H2I(h)
local integer i2 = i - 0x100000
if i2 < int2.size and dat<int.size then//same
set cache[i2][dat] = str
endif
endfunction
endlibrary
But how do you compare it to the other attachment systems?
(I know you use the benchmark system)
But they all work for handle indexes >1000 and the code you posted does not.
I suggest using this:
JASS:
library RAS initializer Init
private function H2I takes handle h returns integer
return h
return 0
endfunction
private type int extends integer array [1023]
private type int2 extends int array [1023]
globals
private int2 cache
private integer i=0
endglobals
private function Init takes nothing returns nothing
set cache = int2.create()
loop
exitwhen i == int2.size
set cache[i]=int.create()
set i = i + 1
endloop
endfunction
function GetAttachedStruct takes handle h returns integer
set i=H2I(h) - 0x100000
return cache[R2I(i/5191)][i - (i / 5191) * 5191]
endfunction
function AttachStruct takes handle h, integer str returns nothing
set i=H2I(h) - 0x100000
set cache[R2I(i/5191)][i - (i / 5191) * 5191]=str
endfunction
endlibrary
You can say it is faster than HSAS, but slightly. Those things depend on a lot of factors. For instance, on my HDD and with WC3 1.22 Game cache is the fastest. I think Blizzard modified the game optimizing the game cache so that Dota Allstars can run smother. However, this will only work indexes up to 8191. To make it work for bigger indexes you should change the line:
private type int extends integer array [1023]
to
private type int extends integer array [1023,409550]
This way it will work up to 409550 indexes, but at the cost of performance, big cost. Even with lower maximum instances speed is drastically reduced.
To attach more than 1 struct to the same handle I suggest doing this the same way as HSAS(with text macros). Something like this:
JASS:
library RAS initializer blah
private function H2I takes handle h returns integer
return h
return 0
endfunction
private type int extends integer array [1023,409550]
private type int2 extends int array [1023,10230]
globals
private integer i
endglobals
//! textmacro RAS takes IDENTIFIER
globals
private int2 cache$IDENTIFIER$
endglobals
private function Init$IDENTIFIER$ takes nothing returns nothing
local integer j = 0
set cache$IDENTIFIER$ = int2.create()
loop
exitwhen j == int2.size
set cache$IDENTIFIER$[j]=int.create()
set j = j + 1
endloop
endfunction
function GetAttachedStruct$IDENTIFIER$ takes handle h returns integer
set i=H2I(h) - 0x100000
return cache$IDENTIFIER$[R2I(i/5191)][i - (i / 5191) *5191]
endfunction
function AttachStruct$IDENTIFIER$ takes handle h, integer str returns nothing
set i=H2I(h) - 0x100000
set cache$IDENTIFIER$[R2I(i/5191)][i - (i / 5191) * 5191]=str
endfunction
//! endtextmacro
//! runtextmacro RAS("")
//! runtextmacro RAS("RAS1")
//! runtextmacro RAS("RAS2")
//! runtextmacro RAS("RAS3")
private function blah takes nothing returns nothing
call Init()
call InitRAS1()
call InitRAS2()
call InitRAS3()
endfunction
endlibrary
I would have suggested like this, but I found out it does not work:
JASS:
library RAS initializer Init
private function H2I takes handle h returns integer
return h
return 0
endfunction
private type int extends integer array [1023,409550]
private type int2 extends int array [1023,10230]
globals
private int2 array cache [8]
private integer i
endglobals
private function Init takes nothing returns nothing
local integer ij = 0
local integer j = 0
loop
exitwhen j==8
set cache[j] = int2.create()
loop
exitwhen ij == int2.size
set cache[j][ij]=int.create()
set ij = ij + 1
endloop
set j=j+1
endloop
endfunction
function GetAttachedStruct takes handle h,integer dat returns integer
set i=H2I(h) - 0x100000
return cache[dat][R2I(i/1023)][i - (i / 1023) * 1023]//here dat may cause a problem, but checking it would reduce performance
endfunction
function AttachStruct takes handle h, integer dat, integer str returns nothing
set i=H2I(h) - 0x100000
set cache[dat][R2I(i/5191)][i - (i / 5191) * 5191]=str//here dat may cause a problem, but checking it would reduce performance
endfunction
endlibrary
I will do some more tests
P.s. And whatever I did, I could not make a 3D array(working).
Edit: I suppose some of this is just junk, but some of it is not
For instance, on my HDD and with WC3 1.22 Game cache is the fastest. I think Blizzard modified the game optimizing the game cache so that Dota Allstars can run smother.
Code is from the implemented benchmark system in the the test map from here
Only editing I did was changing the script from testing ABC to testing RAS.
Those 2 are the results I got before 1.22
As you can see at that time my HDD performed well vs HSAS but could not beat it. And it is not a high performance one - Seagate 250GB 7200 RPM 16 MB cache. On the market there are hdds that are way faster than this.
And here are the 1.22 results
After the patch, Gama cache beats HSAS. And After I did the last optimization I thought of to RAS it's performance improved a little bit, so that is why it has such a lead over Game cache in the Single Struct Attachment Speed Test.
The exact RAS code I used for the last result is in my previous post in the Suggestion.
Anyway, the benchmark system only check speed and not data integrity.
id like to see the testmaps you used (especially the one for 1.22, 'cause i cant seem to get JAPI working in 1.22). And by the looks of it, CSData should be a LOT faster, once you change MAX_HANDLE_ID_COUNT to 8190 or less. Problem is: CSData can only attach one struct to a handle (solution: textmacros) (btw: who needs more than one? I can only think of units, where you can use PUI just as well).
After carefully testing every aspect(speed and safety) I can safely say that dynamical arrays just wont work nicely for a struct attachment system.
Static arrays are just more fun
JASS:
library Blah
public function H2I takes handle h returns integer
return h
return 0
endfunction
globals
private integer array structs [100000]
private integer i
endglobals
function GetAttachedStruct takes handle h returns integer
set i=H2I(h) - 0x100000
return structs[i]
endfunction
function AttachStruct takes handle h, integer str returns nothing
set i=H2I(h) - 0x100000
set structs[i]=str
endfunction
endlibrary
//a part of the code
private type int extends integer array [1000][40000]
private type int2 extends int array [1000]
function AttachStruct takes handle h, integer dat, integer str returns nothing
local integer i = H2I(h) - 0x100000
if i < size and dat < 1000 then
set cache[dat][i] = str
endif
endfunction
It is normal that you missed it in my posts , but this thread made me study and test dynamic arrays a lot.
In the above case, the maximum index you can enter as i is 999, and for dat -> 7.
As I said, [1000][40000] should be a syntax error, but Vexorian missed that
That is why the compiler does not find the [size] error - you can't enter variables as array sizes unless they are constant.
The correct syntax of that would be:
[1000,size] (with size being a constant)
or [1000,40000]
Now the limits would be 999 for i and 39 for dat.
You are better off using a 2D array(supported by JNGP v5b), it is simpler, but has roughly the same speeds. Only problem is that normal arrays can't take higher then their max indexes( I think) and this can. When that happens, dynamic arrays, presume you are using its maximum index. For instance, if you use cache[599696][5845845748] that will be the same as cache[7][999] and would store both on the same place(with the code from the first post).
I just got really enthusiastic about the possibility of something so simple and short being faster than anything else, that I tested and tested and learned Got really disappointed with the results though
P.s. Since the maximum indexes you can enter are so low, when you test it using the benchmark system, you do almost nothing, as the index the benchmark passes to RAS is >8191 so it is interpretated as 999.
As I said, the benchmark tests only speed, not data integrity.
function GetAttachedStruct$DAT$ takes handle h returns integer
set i = H2I(h) - 0x100000
return struct$DAT$[i]
endfunction
function AttachStruct$DAT$ takes handle h, integer dat returns nothing
set i = H2I(h) - 0x100000
set struct$DAT$[i] = dat
endfunction
Do that :
JASS:
function GetAttachedStruct$DAT$ takes handle h returns integer
return struct$DAT$[H2I(h) - 0x100000]
endfunction
function AttachStruct$DAT$ takes handle h, integer dat returns nothing
set struct$DAT$[H2I(h) - 0x100000] = dat
endfunction
If you deactivate the debug mode theses functions will be inlined when you will save.
When I benchmarked it I used the HSAS map and just replaced the game cache with my system, but the results I got are wrong now, because the code is updated.
What's the difference between this and CSData/Timerutils/HSAS? They all use the same method (The set <someglobalarray>[H2I(Handle) - 0x100000] = <Struct passed> way). This is really a copy of CSData but instead of only the need of typing "requires CSData" you now need to do "requiers RAS" and //! runtextmacro RAS("MyID") really, I see nothing better in this than any other system, rather this is worse.
//a part of the code
private type int extends integer array [1000][40000] //Here is the syntax error (NewGen doesn't find it)
private type int2 extends int array [1000]
function AttachStruct takes handle h, integer dat, integer str returns nothing
local integer i = H2I(h) - 0x100000
if i < size and dat < 1000 then
set cache[dat][i] = str
endif
endfunction
You can extend arrays of any type, even of custom types (structs, interfaces, other dynamic arrays) thus making a dynamic array of dynamic arrays, a matrix like syntax is possible:
JASS:
type iar extends integer array[3]
type iar_ar extends iar array[3]
function test takes nothing returns arsample
local iar_ar r=iar_ar.create()
local integer i=0
local integer j
loop
exitwhen i==iar_ar.size //holds size of the array type
set r[i]=iar.create()
set j=0
loop
exitwhen j==iar.size
set r[i][j]=j*i
set j=j+1
endloop
set i=i+1
endloop
return r
endfunction
Not necessarily. It's a lot slower to use arrays of size > 8192 (ie: big arrays). Custom multidimensional arrays of less size than that are actually as fast as doing multidimensional arrays by hand. The size is the max indexes multiplied together, so often will go over that and become big arrays, which are far slower than arrays (~2 the speed of GC, even in worst case senario though).
But still: I will quote the Jass Helper Manual again.
JASS:
Dynamic arrays with more index space
Dynamic arrays already use [] to specify the size for each instance, but what if you want to specify the maximum storage space? I was forced to add a comma:
type myDyArray extends integer array [200] //a normal dynamic array type of size 200
//max 40 instances
type myDyArray extends integer array [200,40000] //an enhanced dynamic array type of size 200
//max 200 instances
JASS:
private type int extends integer array [1000][40000] //Here is the syntax error (NewGen doesn't find it)
private type int2 extends int array [1000]
What, you want to create a 3d array?
All it does is creating a 2d array. So the [40000] part is useless or am I wrong o.0
So, if it does absolutely nothing, meaning Jasshelper does nothing with it and it has not been "thought" what to do with it. But from what JH makes out of it, it is has no syntax errors.
P.s. I seem unable to find anything in the JH manual that states you can extend 2d arrays
Do us a favor and read the manual, like I did during my posts from page 1 up to now.
A quick improvement from sized arrays, is the ability to have two-dimensional arrays, n-dimensional arrays are not implemented, if you really need it very hard, contact me.
Two dimensional arrays in vJass, since vJass is implemented on top of Jass, are just normal arrays in disguise, using a multiplication trick to convert 2-dimension indexes into a one-dimension one. The way to declare one of these arrays is: <type> array name[width][height], notice the real size of the array is width*height, this size suffers the same limitations as normal array's size, it cannot go above approximately 40800, and if this size is bigger than 8191, you will be using slower function calls instead of array lookups and multiple arrays in the final script, etc.
The field size would return this total size we are talking about, the fields height and width return the ones we used to declare the array. As with sized arrays, you can use constants for the width and size.
globals
integer array HandleAttachArray
integer array HandleAttachArrayA
integer array HandleAttachArrayB
integer array HandleAttachArrayC
integer array HandleAttachArrayD
integer array HandleAttachArrayE
endglobals
function SetHandleInteger takes handle h, integer i returns nothing
local integer hashnumber = h2i(h)-0x100000
local integer index = R2I(hashnumber/8192)
//call Debug("handle has size " + I2S(hashnumber) + "+0x100000")
set hashnumber = hashnumber - index*8192
//call Debug("Stored to [" + I2S(index) + "][" + I2S(hashnumber) + "]")
if ( index == 0 ) then
set HandleAttachArray[hashnumber] = i
elseif ( index == 1 ) then
set HandleAttachArrayA[hashnumber] = i
elseif ( index == 2 ) then
set HandleAttachArrayB[hashnumber] = i
elseif ( index == 3 ) then
set HandleAttachArrayC[hashnumber] = i
elseif ( index == 4 ) then
set HandleAttachArrayD[hashnumber] = i
elseif ( index == 5 ) then
set HandleAttachArrayE[hashnumber] = i
else
call Debug ("HandleAttachment System is too full.")
endif
endfunction
function GetHandleInteger takes handle h returns integer
local integer hashnumber = h2i(h)-0x100000
local integer index = R2I(hashnumber/8192)
set hashnumber = hashnumber - index*8192
if ( index == 0 ) then
return HandleAttachArray[hashnumber]
elseif ( index == 1 ) then
return HandleAttachArrayA[hashnumber]
elseif ( index == 2 ) then
return HandleAttachArrayB[hashnumber]
elseif ( index == 3 ) then
return HandleAttachArrayC[hashnumber]
elseif ( index == 4 ) then
return HandleAttachArrayD[hashnumber]
elseif ( index == 5 ) then
return HandleAttachArrayE[hashnumber]
else
call Debug ("HandleAttachment System is too full.")
endif
return -1
endfunction
function RemoveHandleInteger takes handle h returns nothing
local integer hashnumber = h2i(h)-0x100000
local integer index = R2I(hashnumber/8192)
set hashnumber = hashnumber - index*8192
if ( index == 0 ) then
set HandleAttachArray[hashnumber] = 0
elseif ( index == 1 ) then
set HandleAttachArrayA[hashnumber] = 0
elseif ( index == 2 ) then
set HandleAttachArrayB[hashnumber] = 0
elseif ( index == 3 ) then
set HandleAttachArrayC[hashnumber] = 0
elseif ( index == 4 ) then
set HandleAttachArrayD[hashnumber] = 0
elseif ( index == 5 ) then
set HandleAttachArrayE[hashnumber] = 0
else
call Debug ("HandleAttachment System is too full.")
endif
endfunction
easy math.
Handle has size 12989 + 0x100000
local integer hashnumber = 12989
local integer index = 1
set hashnumber = 4797
set Bla[1][4797] = integer to store
EDIT3: Some of you might wonder about this part: [(H2I(h) - 0x100000) / 8191] which actually doesn't do anything useful.
The reason is that I just wanted to add something ^^
If you don't require it to be inlinefriendly you may actually use it for something by changing some stuff, making the code like this:
JASS:
library RAS
private function H2I takes handle h returns integer
return h
return 0
endfunction
globals
private constant integer size = 408000
private constant integer size2 = 1000
private constant integer size3 = 100
endglobals
//! textmacro RAS takes ID
private struct $ID$str
integer array $ID$struct[size]
endstruct
globals
private $ID$str array $ID$stru [size2][size3]
endglobals
function GetAttachedStruct$ID$ takes handle h, integer slot returns integer
local integer hid = H2I(h) - 0x100000
local integer i = (hid) / 8191
return $ID$stru[i][slot].$ID$struct[hid - (8192 * i)]
endfunction
function AttachStruct$ID$ takes handle h, integer dat, integer slot returns nothing
local integer hid = H2I(h) - 0x100000
local integer i = (hid) / 8191
set $ID$stru[i][slot].$ID$struct[hid - (8192 * i)] = dat
endfunction
//! endtextmacro
//! runtextmaro RAS("1")
//! runtextmaro RAS("2")
//! runtextmaro RAS("3")
endlibrary
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.