• 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!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[vJASS] Structs with more index space

Status
Not open for further replies.
Level 15
Joined
Aug 7, 2013
Messages
1,338
Hi,

From the JassHelper manual:

For some reason, the 8190 instances limit is not enough for us, we need 10000 instances ! so:


struct X[10000]
integer a
integer b
endstruct

It appears to have more structs than JASS_MAX_ARRAY_SIZE, we simply write in the number we want as if it were an array besides the struct name declaration.

However, what are the penalties for doing this? Would I expect a very serious performance penalty? Or will not even be noticeable in most cases?

Also, what is the highest value that can be put there, i.e.

JASS:
struct A[N]
…

How big can N be?

Also, from the same manual:

Not to be confused with an instance limit improvement, it is an improvement for index space, both terms are usually equivalent unless there are array members involved

So here is a struct of mine, which is a fancy wrapper around a rect.

JASS:
struct Quad
    rect r
    real maxX
    real minX
    real maxY
    real minY
    real area
    lightning array bolts[BOLTS_PER_RECT]
    Quad array subQuads[MAX_QUADS]
    …
endstruct

where MAX_QUADS = 5, and BOLTS_PER_RECT = 4.

With 8190 index, space, this means that I can have at most 8190 / 5 = 1638 instances of a Quad struct. Considering the recursive nature of this struct, would I be able to increase the instance limit by doing

JASS:
struct Quad[50000]
    …
endstruct

So now I could have 10,000 instances of a Quad struct?
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
IIRC, that creates/makes use of multiple arrays which utilize a binary search if-then conditional blocks to set and read data, so there will be some overhead when doing such operations. I guess it is okay if you don't intend to use it on high-frequency operations.
 
You can find out how generated code looks by yourself using currentmapscript.j file found within logs folder of your JNPG folder.

And here, you can see what Nestharus and chobibo were telling you:
JASS:
integer array si__Quad_V
integer array si__Quad_2V
integer array si__Quad_3V
integer array si__Quad_4V
integer array si__Quad_5V
integer array si__Quad_6V
integer array si__Quad_7V

//Generated allocator of Quad
function s__Quad__allocate takes nothing returns integer
 local integer this=si__Quad_F
    if (this!=0) then
        if(this<8191) then
            set si__Quad_F=si__Quad_V[this]
        elseif(this<32764) then
            if(this<16382) then
                set si__Quad_F=si__Quad_2V[this-8191]
            elseif(this<24573) then
                set si__Quad_F=si__Quad_3V[this-16382]
            else
                set si__Quad_F=si__Quad_4V[this-24573]
            endif
        elseif(this<40955) then
            set si__Quad_F=si__Quad_5V[this-32764]
        elseif(this<49146) then
            set si__Quad_F=si__Quad_6V[this-40955]
        else
            set si__Quad_F=si__Quad_7V[this-49146]
        endif
    else
        set si__Quad_I=si__Quad_I+1
        set this=si__Quad_I
    endif
    if (this>50000) then
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Unable to allocate id for an object of type: Quad")
        return 0
    endif

    if(this<8191) then
        set si__Quad_V[this]=-1
    elseif(this<32764) then
        if(this<16382) then
            set si__Quad_2V[this-8191]=-1
        elseif(this<24573) then
            set si__Quad_3V[this-16382]=-1
        else
            set si__Quad_4V[this-24573]=-1
        endif
    elseif(this<40955) then
        set si__Quad_5V[this-32764]=-1
    elseif(this<49146) then
        set si__Quad_6V[this-40955]=-1
    else
        set si__Quad_7V[this-49146]=-1
    endif
 return this
endfunction

//Generated destructor of Quad
function s__Quad_deallocate takes integer this returns nothing
 local integer used
    if this==null then
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Attempt to destroy a null struct of type: Quad")
        return
    else
        if(this<8191) then
            set used=si__Quad_V[this]
        elseif(this<32764) then
            if(this<16382) then
                set used=si__Quad_2V[this-8191]
            elseif(this<24573) then
                set used=si__Quad_3V[this-16382]
            else
                set used=si__Quad_4V[this-24573]
            endif
        elseif(this<40955) then
            set used=si__Quad_5V[this-32764]
        elseif(this<49146) then
            set used=si__Quad_6V[this-40955]
        else
            set used=si__Quad_7V[this-49146]
        endif
        if (used!=-1) then
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Double free of type: Quad")
            return
        endif
    endif
    if(this<8191) then
        set si__Quad_V[this]=si__Quad_F
    elseif(this<32764) then
        if(this<16382) then
            set si__Quad_2V[this-8191]=si__Quad_F
        elseif(this<24573) then
            set si__Quad_3V[this-16382]=si__Quad_F
        else
            set si__Quad_4V[this-24573]=si__Quad_F
        endif
    elseif(this<40955) then
        set si__Quad_5V[this-32764]=si__Quad_F
    elseif(this<49146) then
        set si__Quad_6V[this-40955]=si__Quad_F
    else
        set si__Quad_7V[this-49146]=si__Quad_F
    endif
    set si__Quad_F=this
endfunction
You don't want this.
 
Level 15
Joined
Aug 7, 2013
Messages
1,338
If I am only generating and manipulating the structs not very frequently, then would this performance penalty even matter?

Don't remember max number. Just use a table

Do you mean a table like Bribe's? That would result in 8190 instances for a much cheaper performance cost?
 
You missed the point of using Table, and yes, Nes meant the Table made by Bribe.

When your are dealing with indexes (arrays with size) less then 0x2000 you shouldnt be using Table at all. Instead, Table allows you to by pass that limits in convenient way, also it's pretty usefull when you want to get an instance of object via handle reference.

Since hashtable read/write op is slower than array read/write Table has worse performence if we talking about op cost.

Again, you use table, only when you need to.

Edit: however, you have to also consider that code such as yours, implements additional global arrays, thus instead of having one hashtable (Table), you have 7 arrays instead.
 
Last edited:
@sethmachine, you seen to be a bit confused. Nowhere is it said to avoid using struct - if we are dealing with object programming, we want to use objects, thus we implement classes/structs.

You need to understand exactly what you need, and adapt your approach to given goal i.e use certain tools.

About edo494' example - dont forget that each table instance has to be allocated (created) before you can use it.

You might even consider using global table instead of table array, again, depending on what u need.
 
Level 15
Joined
Aug 7, 2013
Messages
1,338
here, I gave you 8190 instances, and unlimited-size arrays for both lightnings and the Quads

This is what I asked/suggested in my previous post, though it is true that there is always at most 4 lightnings per Quad and at most 5 Quads per Quad.

Do you mean a table like Bribe's? That would result in 8190 instances for a much cheaper performance cost?

But apparently that is not what Bannar is suggesting as an option (or it's not the only option)?

You missed the point of using Table

So if Bannar is suggesting that the point isn't to replace all arrays with their own tables inside the struct to get the most instances (8190 / JASS_MAX_ARRAY_SIZE), then I am not sure what Bannar meant by me "missing the point of using the Table." Because I've used Table to replace arrays before inside structs to increase the number of instances.
 
Level 15
Joined
Aug 7, 2013
Messages
1,338
Why don't you try benchmarking both implementations so you can make an objective choice eh?

My last few posts are trying to figure out what Bannar was telling me, and which I did not understand.

No need for benchmarking since it's not like I'm writing a medical application where a second could make the difference between someone's life :p I do like the Table api too.

I'll most likely replace the arrays with Tables if it turns out I do really need more than ~1600 instances.
 
To clarify:

I doubt that you would be needing more than 8191 allocated instances of given class of objects.
Structs that extend array (which is the most common choice) in vJass are basically interpreted as arrays - global arrays of struct type.

Since we all know the defined within common.j MAX_ARRAY_SIZE constant, we can have a total of 8191 of instanciated struct objects, each possesing access to every of struct members. Thus:
JASS:
struct my extends array
    integer int
    boolean flag
endstruct
allows us to work with arrays int and flag as long as we dont do: flag[8192++] - that would fail.

In some cases, expecialy when dealing with handles, we want to store them via GetHandleId() - here we approach a problem with magnitude of hanleid (certainly its greater than 8191), so our previous array approach would fail. However, Table is a saviour in such cases, demolishing our troubles with ease.

Of couse, sometimes clever approach/algorithm can still allow us to work with arrays, yet its rather unlikeky and can be quite obscure.

Back to your "Quad 50000" -> I dont think you will really need 50000 instances of struct, its highly unlikely that you will even by pass 2000 instances. Rather, usually concentrate on struct members, and as suggested by edo, use table if one of such memebers troubles you.
 
Status
Not open for further replies.
Top