• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] [Snippet] Dimensional-Array

Level 9
Joined
Jun 21, 2012
Messages
432
JASS:
library DimensionalArray/*
****************************************************************************************
*
*   DimensionalArray
*   ________________
*   v2.0.1.1
*   by Thelordmarshall
*
*                           ________
*                          /_/_/_/_/|
*                         /_/_/_/_/|/|
*                        /_/_/_/_/|/|/|
*                       /_/_/_/_/|/|/|/|
*                      |_|_|_|_|/|/|/|/ 
*                      |_|_|_|_|/|/|/
*                      |_|_|_|_|/|/
*                      |_|_|_|_|/ 
*        
*
*   Dimensional-Array is a tool that maximizes the use of the hashtable allowing 
*   the user to feel comfortable with their easy and complete interface.
*
*   Why use Dimensional-Array?
*   __________________________
*   
*       This resource was created for the purpose of having a multi-dimensional 
*       environment; in this case 4D. It should be noted that initially figured that use 
*       more than 4 dimensions were necessary, but in warcraft III is not.
*
*   API:
*   ___
*     
*   struct Array extends ArrayCore
*       - static method create takes nothing returns Array
*       - method destroy takes nothing returns nothing
*       - method flush takes nothing returns nothing
*       - method operator [] takes integer id returns ArrayDimensional
*       - method operator $TYPE$= takes $TYPE$ value returns nothing
*           - save handle, real, integer, boolean or string.
*       - method operator $TYPE$ takes nothing returns $TYPE$
*           - unit, player, integer, string, etc...
*       - method has$TYPE$ takes nothing returns boolean
*       - method remove$TYPE$ takes nothing returns nothing
*
*   Credits:
*   ________
*       - looking_for_help: for their suggestions.
*
****************************************************************************************/
    
    globals
        private hashtable h=InitHashtable()
        private integer key=0
        private integer size=0
        private integer keySize=0
        private string array keyId
    endglobals

    private struct ArrayCore
    
        private method operator hash takes nothing returns hashtable
            if(0<this)then
                set key=StringHash(keyId[keySize])
                set keyId[keySize]=""
                if(0<keySize)then
                    set keySize=keySize-1
                endif
                return h
            endif
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"[Dimensional-Array] error: attempted to save/get value from invalid Array instance: ("+I2S(this)+" )")
            return null
        endmethod
        
        //! textmacro ARRAY_OPERATOR takes OPERATOR,ARGUMENT,FUNC1,FUNC2
            method operator $OPERATOR$= takes $ARGUMENT$ value returns nothing
                call Save$FUNC1$(.hash,this,key,value)
            endmethod
            
            method has$FUNC2$ takes nothing returns boolean
                return HaveSaved$FUNC2$(.hash,this,key)
            endmethod
            
            method remove$FUNC2$ takes nothing returns nothing
                call RemoveSaved$FUNC2$(.hash,this,key)
            endmethod
        //! endtextmacro
        
        //! runtextmacro ARRAY_OPERATOR("boolean","boolean","Boolean","Boolean")
        //! runtextmacro ARRAY_OPERATOR("handle","agent","AgentHandle","Handle")
        //! runtextmacro ARRAY_OPERATOR("integer","integer","Integer","Integer")
        //! runtextmacro ARRAY_OPERATOR("real","real","Real","Real")
        //! runtextmacro ARRAY_OPERATOR("string","string","Str","String")
        
        //! textmacro ARRAY_TYPE takes TYPEA,TYPEB
            method operator $TYPEA$ takes nothing returns $TYPEA$
                return Load$TYPEB$(.hash,this,key)
            endmethod
        //! endtextmacro
        
        //       type list:
        //=========================|      Type            |       FuncType          |================
        //! runtextmacro ARRAY_TYPE(    "boolean",         "Boolean"                )
        //! runtextmacro ARRAY_TYPE(    "boolexpr",        "BooleanExprHandle"      )
        //! runtextmacro ARRAY_TYPE(    "button",          "ButtonHandle"           )
        //! runtextmacro ARRAY_TYPE(    "defeatcondition", "DefeatConditionHandle"  )
        //! runtextmacro ARRAY_TYPE(    "destructable",    "DestructableHandle"     )
        //! runtextmacro ARRAY_TYPE(    "dialog",          "DialogHandle"           )
        //! runtextmacro ARRAY_TYPE(    "effect",          "EffectHandle"           )
        //! runtextmacro ARRAY_TYPE(    "fogmodifier",     "FogModifierHandle"      )
        //! runtextmacro ARRAY_TYPE(    "fogstate",        "FogStateHandle"         )
        //! runtextmacro ARRAY_TYPE(    "force",           "ForceHandle"            )
        //! runtextmacro ARRAY_TYPE(    "group",           "GroupHandle"            )
        //! runtextmacro ARRAY_TYPE(    "hashtable",       "HashtableHandle"        )
        //! runtextmacro ARRAY_TYPE(    "image",           "ImageHandle"            )
        //! runtextmacro ARRAY_TYPE(    "integer",         "Integer"                )
        //! runtextmacro ARRAY_TYPE(    "item",            "ItemHandle"             )
        //! runtextmacro ARRAY_TYPE(    "itempool",        "ItemPoolHandle"         )
        //! runtextmacro ARRAY_TYPE(    "leaderboard",     "LeaderboardHandle"      )
        //! runtextmacro ARRAY_TYPE(    "lightning",       "LightningHandle"        )
        //! runtextmacro ARRAY_TYPE(    "location",        "LocationHandle"         )
        //! runtextmacro ARRAY_TYPE(    "multiboard",      "MultiboardHandle"       )
        //! runtextmacro ARRAY_TYPE(    "multiboarditem",  "MultiboardItemHandle"   )
        //! runtextmacro ARRAY_TYPE(    "player",          "PlayerHandle"           )
        //! runtextmacro ARRAY_TYPE(    "quest",           "QuestHandle"            )
        //! runtextmacro ARRAY_TYPE(    "questitem",       "QuestItemHandle"        )
        //! runtextmacro ARRAY_TYPE(    "real",            "Real"                   )
        //! runtextmacro ARRAY_TYPE(    "rect",            "RectHandle"             )
        //! runtextmacro ARRAY_TYPE(    "region",          "RegionHandle"           )
        //! runtextmacro ARRAY_TYPE(    "sound",           "SoundHandle"            )
        //! runtextmacro ARRAY_TYPE(    "string",          "Str"                    )
        //! runtextmacro ARRAY_TYPE(    "texttag",         "TextTagHandle"          )
        //! runtextmacro ARRAY_TYPE(    "timerdialog",     "TimerDialogHandle"      )
        //! runtextmacro ARRAY_TYPE(    "timer",           "TimerHandle"            )
        //! runtextmacro ARRAY_TYPE(    "trackable",       "TrackableHandle"        )
        //! runtextmacro ARRAY_TYPE(    "triggeraction",   "TriggerActionHandle"    )
        //! runtextmacro ARRAY_TYPE(    "triggercondition","TriggerConditionHandle" )
        //! runtextmacro ARRAY_TYPE(    "event",           "TriggerEventHandle"     )
        //! runtextmacro ARRAY_TYPE(    "trigger",         "TriggerHandle"          )
        //! runtextmacro ARRAY_TYPE(    "ubersplat",       "UbersplatHandle"        )
        //! runtextmacro ARRAY_TYPE(    "unit",            "UnitHandle"             )
        //! runtextmacro ARRAY_TYPE(    "unitpool",        "UnitPoolHandle"         )
        //! runtextmacro ARRAY_TYPE(    "widget",          "WidgetHandle"           )
    endstruct

    //! textmacro ARRAY_DIMENSIONAL takes NAME,RETURNS,EXTENDS
        private struct $NAME$ extends $EXTENDS$
            method operator [] takes integer id returns $RETURNS$
                set keyId[keySize]=keyId[keySize]+","+I2S(id)
                return this
            endmethod
        endstruct
    //! endtextmacro
    
    //! runtextmacro ARRAY_DIMENSIONAL("Array4D","ArrayCore","array")
    //! runtextmacro ARRAY_DIMENSIONAL("Array3D","Array4D","ArrayCore")
    //! runtextmacro ARRAY_DIMENSIONAL("Array2D","Array3D","ArrayCore")
    
    struct Array extends ArrayCore
        method operator [] takes integer id returns Array2D
            set keySize=keySize+1
            set keyId[keySize]=I2S(id)
            return this
        endmethod
        
        method flush takes nothing returns nothing
            call FlushChildHashtable(h,this)
        endmethod
        
        static method create takes nothing returns Array
            local thistype this=LoadInteger(h,0,0)
            if(0==this)then
                set this=size+1
                set size=this
            else
                call SaveInteger(h,0,0,LoadInteger(h,0,this))
            endif
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            call .flush()
            call SaveInteger(h,0,this,LoadInteger(h,0,0))
            call SaveInteger(h,0,0,this)
        endmethod
    endstruct
endlibrary
 
Last edited:

Cokemonkey11

Spell Reviewer
Level 29
Joined
May 9, 2006
Messages
3,534
I would vote needs fix.

You shouldn't initialize hashtables without using an abstraction.

This doesn't seem particularly useful if the dimensionality is constant.

What kind of Array object in computing is precisely 4 (or some other n | n != 1) dimensions?

I dislike the load/save API

Can I ask you this: do you use this library? Did you make it with the intention of simplifying your own code? I'd like to see an example - I'll be surprised if there isn't a better alternative.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
This doesn't really look like an Array class to me...

An Array should basically only provide indexers like operator[] and some methods to get its size/dimensionality. Why does this have operators like load?

I would be very confused by something like

JASS:
// Which dimensionality does arr have?
local Array arr = Array.create() 

// What does load mean here? Sounds more like a method than a property?
local Array arr2 = arr.load 

// Why does an array have a member "timerdialog"?
local timerdialog td = arr.timerdialog

What if someone wants to use a 2D and a 3D array at the same time? Thats not possible at the moment.

I'm not in principle against such a library, but there is a lot do do before this could be approved. I think it would be better to provide a set of fixed dimensions (Array1D, Array2D and maybe Array3D or just let the user define arrays of arrays), which should be sufficient for every real world purpose. This way you would also gain compile-time safety for your index operator.

It would also make sense to make the underlying container configurable, so that the user can decide which one he want to use:

JASS:
// 2D array of type integer with array as container
//! runtextmacro CREATE_2D_ARRAY("integer", "array") 

// 3D array of type string with hashtable as container
//! runtextmacro CREATE_3D_ARRAY("string", "hashtable")

// and so on
 
Last edited:
Level 9
Joined
Jun 21, 2012
Messages
432
@Almia: I vote for reject you

@Cokemonkey11: I use this in http://www.hiveworkshop.com/forums/submissions-414/snipet-soundfx-267091/

@looking_for_help: The method load is to prevent merge indexes when use the operator [] multiple times in one line: set arr[0][2].integer=arr[0][2].integer+1 this merge all index in the same call, should look like set arr[0][2].integer=arr.load[0][2].integer+1
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
@looking_for_help: The method load is to prevent merge indexes when use the operator [] multiple times in one line: set arr[0][2].integer=arr[0][2].integer+1 this merge all index in the same call, should look like set arr[0][2].integer=arr.load[0][2].integer+1

Yes, but thats because the implementation of your data access operators is problematic. Such problems should not affect the public API of a system or better, be avoided in the first place. Doing string concatenation just for indexing an array is unefficient, then one could just use a hashtable.

Its problematic anyway, because you can't check the dimensionality at compile time. So its perfectly valid to write something like:

JASS:
set arr[0][1][2][3][4][5][6][7].integer = 0

even though the dimension of the array is, lets say 4. The compiler can't notice this with your approach.

I also don't think an array should have fields like "integer" or "timerdialog". Thats just not what arrays are about. Also its not possible at the moment to have arrays of different dimensionality at the same time.

But most of those things were already mentioned in my first comment on this system.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Multi dimensional array should be a compiler-inherited feature imo (multi dimensional indexes are converted at compile time). Things like computing array offset (converting multi dimension to linear) every time you deal with the variable will just slow things down, hashtable is slow enough if you ask me maybe I'm wrong here. Unless you are able to allocate/deallocate memory dynamically (using linear array, not hashtable), then it could be better than hashtable.

Moreover, the max array size for every side is pretty much limited as the dimension increases. Let's say, we can only have ~100 max size for every side (if distributed equally) for 4 dimension array, which is considerably "small". You can improve this by occupying several parent keys for a variable tho (like what TableArray do). Anyway, you should tell users the max size they may use. Nestharus gave me this formula (if every side's size is distributed equally): MAX_INDEX = R2I(Pow(2^31-1, 1./dimension)) (converted for hashtable)

And this needs some security checks as well, like:
- what's the max index user may use?
- is the dimension assigned by user valid or not? (2 indices for 2D, 3 indices for 3D, etc.) keySize<=DIMENSIONAL_SIZE => keySize==DIMENSIONAL_SIZE

And as everybody said, 2D is pretty much enough for us. Some of those are the reasons why I gave up on my multi dimension thingy even tho it looks cool for me.

Wait, the dimension is static?
 
Last edited:
Level 14
Joined
Dec 12, 2012
Messages
1,007
I think it would be best to just provide a "normal" 1D array and let the user himself create arrays of arrays if he need multiple dimensions.

That way the dimension can be defined directy by the user for each array seperatly and we also can have compile time safety about dimensions and we don't need any string calculations for indexing.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
I think it would be best to just provide a "normal" 1D array and let the user himself create arrays of arrays if he need multiple dimensions.

That way the dimension can be defined directy by the user for each array seperatly and we also can have compile time safety about dimensions and we don't need any string calculations for indexing.

The problem with using array is very limited size. Using array with normal size of 8192 you can only have ~89 per side just for a 2D array. The only other way is to preserve several array variables, which is not exactly wins as well since it forces us to allocate a lot of memory spaces no matter we use it or not. This is why we need to be able to, like I said before, allocate/deallocate memory dynamically.

Btw, I have done this here before actually, and it supports dynamic dimension. But then I decided to GY it because it's too slow. It's completely safe but the safety checks really become burdens and slow things down, however they are required to avoid faulty results.

Moreover, it looks really bad in the way how it preserves the memory:
JASS:
            private $TYPE$ array Container__1[ALLOCATED_SPACE]
            private $TYPE$ array Container__2[ALLOCATED_SPACE]
            private $TYPE$ array Container__3[ALLOCATED_SPACE]
            private $TYPE$ array Container__4[ALLOCATED_SPACE]
            private $TYPE$ array Container__5[ALLOCATED_SPACE]
            private $TYPE$ array Container__6[ALLOCATED_SPACE]
            private $TYPE$ array Container__7[ALLOCATED_SPACE]
            private $TYPE$ array Container__8[ALLOCATED_SPACE]
            private $TYPE$ array Container__9[ALLOCATED_SPACE]
            private $TYPE$ array Container__10[ALLOCATED_SPACE]

Those memory are allocated no matter you use it or not, terrible isn't it? There are 409262x10=4092620 allocated spaces there, but it still can only reach 2023 max index for 2D.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
The problem with using array is very limited size. Using array with normal size of 8192 you can only have ~89 per side just for a 2D array. The only other way is to preserve several array variables, which is not exactly wins as well since it forces us to allocate a lot of memory spaces no matter we use it or not. This is why we need to be able to, like I said before, allocate/deallocate memory dynamically.

That shouldn't matter in most of the cases, bigger arrays than 8192 are hardly ever required.

Btw, I have done this here before actually, and it supports dynamic dimension. But then I decided to GY it because it's too slow. It's completely safe but the safety checks really become burdens and slow things down, however they are required to avoid faulty results.

Its not safe.

It has just the same problems like this resource, which is that you return thistype in your indexing operator. Therefore I can also write infinite chains like set arr[0][1][2][3][4]...[n] = 2 // oops, 1 bracket too much. The compiler can't notice such errors. Therefore an array-of-arrays approach should be better, for both performance as well as readability and safety.

Moreover, it looks really bad in the way how it preserves the memory:

Those memory are allocated no matter you use it or not, terrible isn't it? There are 409262x10=4092620 allocated spaces there, but it still can only reach 2023 max index for 2D.

2023 max indices for 2D is already an extremly huge number for vJass and the Wc3 environment. When would someone ever need such a huge matrix?


Suggestion: Before creating arrays of higher dimensions, maybe a nice wrapper for a standard 1D array would make sense. Maybe we could abuse fake defines to avoid the memory problem:

JASS:
//! textmacro CREATE_ARRAY takes TYPE, ARRAY_NUM
struct $TYPE$_Array_$ARRAY_NUM$
	private static constant boolean ARRAY_NUM_IS_$ARRAY_NUM$ = true
	
	static if thistype.ARRAY_NUM_IS_1 then
		private $TYPE$ array container1[8192]
	else if thistype.ARRAY_NUM_IS_2 then
		private $TYPE$ array container1[8192]
		private $TYPE$ array container2[8192]
	else if thistype.ARRAY_NUM_IS_3 then
		// etc
	endif
endstruct
//! endtextmacro
 
Level 9
Joined
Jun 21, 2012
Messages
432
New update guys

Could you write up a demo script?

Yes

And this needs some security checks as well, like:
- what's the max index user may use?

Check the demo script...

It has just the same problems like this resource, which is that you return thistype in your indexing operator. Therefore I can also write infinite chains like set arr[0][1][2][3][4]...[n] = 2 // oops, 1 bracket too much. The compiler can't notice such errors. Therefore an array-of-arrays approach should be better, for both performance as well as readability and safety.

This is the major constraint, but this is the fault of vjass ^^
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
@edo494, @Laiev, @looking_for_help: ok, ignore it, I said making an assumption: if the vjass have a new update with multidimensional syntax; It would be something like:

No it would not?
It would of course also rely on index calculation instead of strings. Also this is purely hypothetical and should not be used as an argument.

Also, it would make sense to respond on feedback. The new update has just exactly the same problems that were mentioned before.

And outputting an error message during runtime is a bad solution if the problem can already be caught at compile time.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
NewTable has TableArray and the HashTable struct. If you "need" a 3rd or 4th dimension, then build you resource off of either of those existing ones. The only time I've needed even a 3rd dimension was in Retro, but I did a faux 2D array to make it work within 2 indices. You had better have a kickass reason to go even beyond that. This resource should be named "Limited4DArray" due to it having many weaknesses and limitations VS existing standards.

Scheduling for graveyard next week.
 
Level 9
Joined
Jun 21, 2012
Messages
432
NewTable has TableArray and the HashTable struct. If you "need" a 3rd or 4th dimension, then build you resource off of either of those existing ones. The only time I've needed even a 3rd dimension was in Retro, but I did a faux 2D array to make it work within 2 indices. You had better have a kickass reason to go even beyond that. This resource should be named "Limited4DArray" due to it having many weaknesses and limitations VS existing standards.

My condolences, but I cannot access to it.

Now you can use this syntax without problems set myVar[0][0][0][0].integer = myVar[0][0].integer + 1

I'm finishing writing the new update, here a small preview:
JASS:
library DimensionalArray/*
****************************************************************************************
*
*   DimensionalArray
*   ________________
*   v2.0.0.0
*   by Thelordmarshall
*
*   
****************************************************************************************/
    
    //CONFIGURATION
    //====================================================================
    globals
        private constant integer MAX_INSTANCES = 8191
    endglobals
    //====================================================================
    //ENDCONFIGURATION

    globals
        private hashtable h=InitHashtable()
        private integer key=0
        private integer size=0
        private integer keySize=0
        private string array keyId
        private integer array list[MAX_INSTANCES]
        private boolean array active[MAX_INSTANCES]
    endglobals
    
    struct ArrayCore
        private method operator hash takes nothing returns hashtable
            if(active[this] and ""!=keyId[keySize])then
                set key=StringHash(keyId[keySize])
                set keyId[keySize]=""
                if(0<keySize)then
                    set keySize=keySize-1
                endif
                return h
            endif
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"[Dimensional-Array] error: null Array ("+I2S(this)+" )")
            return null
        endmethod
        
        method flush takes nothing returns nothing
            call FlushChildHashtable(.hash,this)
        endmethod
        
        //! textmacro ARRAY_OPERATOR takes OPERATOR,ARGUMENT,FUNC1,FUNC2
            method operator $OPERATOR$= takes $ARGUMENT$ value returns nothing
                call Save$FUNC1$(.hash,this,key,value)
            endmethod
            
            method has$FUNC2$ takes nothing returns boolean
                return HaveSaved$FUNC2$(.hash,this,key)
            endmethod
            
            method remove$FUNC2$ takes nothing returns nothing
                call RemoveSaved$FUNC2$(.hash,this,key)
            endmethod
        //! endtextmacro
        
        //! runtextmacro ARRAY_OPERATOR("boolean","boolean","Boolean","Boolean")
        //! runtextmacro ARRAY_OPERATOR("handle","agent","AgentHandle","Handle")
        //! runtextmacro ARRAY_OPERATOR("integer","integer","Integer","Integer")
        //! runtextmacro ARRAY_OPERATOR("real","real","Real","Real")
        //! runtextmacro ARRAY_OPERATOR("string","string","Str","String")
        
        //! textmacro ARRAY_TYPE takes TYPEA,TYPEB
            method operator $TYPEA$ takes nothing returns $TYPEA$
                return Load$TYPEB$(.hash,this,key)
            endmethod
        //! endtextmacro
        
        //       type list:
        //=========================|      Type            |       FuncType          |================
        //! runtextmacro ARRAY_TYPE(    "boolean",         "Boolean"                )
        //! runtextmacro ARRAY_TYPE(    "boolexpr",        "BooleanExprHandle"      )
        //! runtextmacro ARRAY_TYPE(    "button",          "ButtonHandle"           )
        //! runtextmacro ARRAY_TYPE(    "defeatcondition", "DefeatConditionHandle"  )
        //! runtextmacro ARRAY_TYPE(    "destructable",    "DestructableHandle"     )
        //! runtextmacro ARRAY_TYPE(    "dialog",          "DialogHandle"           )
        //! runtextmacro ARRAY_TYPE(    "effect",          "EffectHandle"           )
        //! runtextmacro ARRAY_TYPE(    "fogmodifier",     "FogModifierHandle"      )
        //! runtextmacro ARRAY_TYPE(    "fogstate",        "FogStateHandle"         )
        //! runtextmacro ARRAY_TYPE(    "force",           "ForceHandle"            )
        //! runtextmacro ARRAY_TYPE(    "group",           "GroupHandle"            )
        //! runtextmacro ARRAY_TYPE(    "image",           "ImageHandle"            )
        //! runtextmacro ARRAY_TYPE(    "integer",         "Integer"                )
        //! runtextmacro ARRAY_TYPE(    "item",            "ItemHandle"             )
        //! runtextmacro ARRAY_TYPE(    "itempool",        "ItemPoolHandle"         )
        //! runtextmacro ARRAY_TYPE(    "leaderboard",     "LeaderboardHandle"      )
        //! runtextmacro ARRAY_TYPE(    "lightning",       "LightningHandle"        )
        //! runtextmacro ARRAY_TYPE(    "location",        "LocationHandle"         )
        //! runtextmacro ARRAY_TYPE(    "multiboard",      "MultiboardHandle"       )
        //! runtextmacro ARRAY_TYPE(    "multiboarditem",  "MultiboardItemHandle"   )
        //! runtextmacro ARRAY_TYPE(    "player",          "PlayerHandle"           )
        //! runtextmacro ARRAY_TYPE(    "quest",           "QuestHandle"            )
        //! runtextmacro ARRAY_TYPE(    "questitem",       "QuestItemHandle"        )
        //! runtextmacro ARRAY_TYPE(    "real",            "Real"                   )
        //! runtextmacro ARRAY_TYPE(    "rect",            "RectHandle"             )
        //! runtextmacro ARRAY_TYPE(    "region",          "RegionHandle"           )
        //! runtextmacro ARRAY_TYPE(    "sound",           "SoundHandle"            )
        //! runtextmacro ARRAY_TYPE(    "string",          "Str"                    )
        //! runtextmacro ARRAY_TYPE(    "texttag",         "TextTagHandle"          )
        //! runtextmacro ARRAY_TYPE(    "timerdialog",     "TimerDialogHandle"      )
        //! runtextmacro ARRAY_TYPE(    "timer",           "TimerHandle"            )
        //! runtextmacro ARRAY_TYPE(    "trackable",       "TrackableHandle"        )
        //! runtextmacro ARRAY_TYPE(    "triggeraction",   "TriggerActionHandle"    )
        //! runtextmacro ARRAY_TYPE(    "triggercondition","TriggerConditionHandle" )
        //! runtextmacro ARRAY_TYPE(    "event",           "TriggerEventHandle"     )
        //! runtextmacro ARRAY_TYPE(    "trigger",         "TriggerHandle"          )
        //! runtextmacro ARRAY_TYPE(    "ubersplat",       "UbersplatHandle"        )
        //! runtextmacro ARRAY_TYPE(    "unit",            "UnitHandle"             )
        //! runtextmacro ARRAY_TYPE(    "unitpool",        "UnitPoolHandle"         )
        //! runtextmacro ARRAY_TYPE(    "widget",          "WidgetHandle"           )
        //! runtextmacro ARRAY_TYPE(    "hashtable",       "HashtableHandle"        )
    endstruct

    //! textmacro ARRAY_DIMENSIONAL takes NAME,RETURNS,EXTENDS
        struct $NAME$ extends $EXTENDS$
            method operator [] takes integer id returns $RETURNS$
                set keyId[keySize]=keyId[keySize]+","+I2S(id)
                return this
            endmethod
        endstruct
    //! endtextmacro
    
    //! runtextmacro ARRAY_DIMENSIONAL("Array4D","ArrayCore","array")
    //! runtextmacro ARRAY_DIMENSIONAL("Array3D","Array4D","ArrayCore")
    //! runtextmacro ARRAY_DIMENSIONAL("Array2D","Array3D","ArrayCore")
    
    struct Array extends ArrayCore
        method operator [] takes integer id returns Array2D
            set keySize=keySize+1
            set keyId[keySize]=I2S(id)
            return this
        endmethod
        
        static method create takes nothing returns Array
            local thistype this=list[0]
            if(0==this)then
                set this=size+1
                set size=this
            else
                set list[0]=list[this]
            endif
            set active[this]=true
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            call ArrayCore(this).flush()
            set active[this]=false
            set list[this]=list[0]
            set list[0]=this
        endmethod
    endstruct
endlibrary
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Its nice to see this getting an update again, but unfortunatly I think there are quite some problems even after the update.


I think the code is a bit confusing, is this the final update or what is meant with "small preview"? Some questions/suggestions:

  • The hash method is a bit strange... Why return a hashtable? From what I see it is more like a contains function that returns a boolean or something like that?
  • Why do you need inheritance here?
  • Why no operator[]= for something that should wrap around an array?
  • You use a hashtable, which is slower than a native array, but has size advantage. So far so good, but you use a standard array to manage your access keys, so you end up again with array size limitations? At the ends this combines the disadvantages of the both worlds.
  • In your access methods, you just concatenate the accessed indices to a string... but how do you ensure that given two different multidimensional arrays, you have no collisions if both are accessed at the same indices?
  • Something like set arr2d[0][0][0].integer = 2 works although it shouldn't (3D access on 2D array), while something like set arr3d[0][0][0].integer = 2 throws an error although it whould work (3D access on 3D array). Something like local Array4D arr4d = Array4D.create() doesn't even compile although it should?

My condolences, but I cannot access to it.

What do you mean?

Now you can use this syntax without problems set myVar[0][0][0][0].integer = myVar[0][0].integer + 1

Why is that desireable? Either myVar is 2D, then only the right hand side of this statement should be valid or myVar is 4D, then only the left hand side should be valid.

What is the above statement meant to express in your opinion?
 
Level 9
Joined
Jun 21, 2012
Messages
432
Its nice to see this getting an update again
thanks.
I think the code is a bit confusing, is this the final update or what is meant with "small preview"?
It is only a preview, I'm still working on this but I'm kind of busy with other things!
Yeah, is the final version, I guess I will have things to fix. :ogre_rage:
The hash method is a bit strange... Why return a hashtable? From what I see it is more like a contains function that returns a boolean or something like that?
It's for debug purposes, for example if i write set Array(0)[0].integer = 0 the method will return a null hashtable, to prevent save values in null Arrays.
Why no operator[]= for something that should wrap around an array?
Should I use? the problem is to use any type of variable for this method (integer, boolean, handle, etc ...)
You use a hashtable, which is slower than a native array, but has size advantage. So far so good, but you use a standard array to manage your access keys, so you end up again with array size limitations? At the ends this combines the disadvantages of the both worlds.
As I mentioned before, the hash method is designed to detect a null Array, and only know two ways to do this: using HaveSavedInteger(h, 0, this) or use the native array, I preferred the latter for its speed.
You think you should use the hashtable?
JASS:
private method operator hash takes nothing returns hashtable
    if(HaveSavedInteger(h,0,this) and ""!=keyId[keySize])then
    set key=StringHash(keyId[keySize])
    set keyId[keySize]=""
        if(0<keySize)then
            set keySize=keySize-1
        endif
        return h
    endif
    debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"[Dimensional-Array] error: null Array ("+I2S(this)+" )")
    return null
endmethod
In your access methods, you just concatenate the accessed indices to a string... but how do you ensure that given two different multidimensional arrays, you have no collisions if both are accessed at the same indices?
I'm trying to find a possible collision xD
Something like set arr2d[0][0][0].integer = 2 works although it shouldn't (3D access on 2D array), while something like set arr3d[0][0][0].integer = 2 throws an error although it whould work (3D access on 3D array). Something like local Array4D arr4d = Array4D.create() doesn't even compile although it should?
Unfortunately I do not get how to prevent the use of things such as set arr2d[0][0][0].integer = 2 in vJass.

But I come to mind to create a code in LUA to detect this, and prevent compile the map under these circumstances.
My condolences, but I cannot access to it.
What do you mean?
It was just an expression used to Bribe due to its previous comment :ogre_love:

Now you can use this syntax without problems set myVar[0][0][0][0].integer = myVar[0][0].integer + 1
Why is that desireable? Either myVar is 2D, then only the right hand side of this statement should be valid or myVar is 4D, then only the left hand side should be valid.

What is the above statement meant to express in your opinion?
It is an example anyone can have any number of bracket (obviously up to 4). In the previous version it was used in this way set myVar[0][0].integer = myVarload[0][0].integer + 1, because the method [] was an "infinite loop".

Well that's all for now ^^...
 
Last edited:
Level 9
Joined
Jun 21, 2012
Messages
432
Another update and no comments guys? :ogre_rage:

[*] Something like set arr2d[0][0][0].integer = 2 works although it shouldn't (3D access on 2D array), while something like set arr3d[0][0][0].integer = 2 throws an error although it whould work (3D access on 3D array). Something like local Array4D arr4d = Array4D.create() doesn't even compile although it should?

I solved this.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
I fail to see what's the point of people forcing other users to use/dl multidimensional array snippets. This seems to be the common trend lately.

Again, almost all problems related to MD arrays in War3 environment can be simplified/flattern into 1D/ 2D.
'Table' is the answer to all of these, and there is no need to rewrite it, reimplement it. Use Table's threat for suggestions and possible improvements.

Bribe has already answered plenty of times to all kinds of suggestions made by both, experienced and inexperienced users. Addition of INTEGER macro, HashTable struct, are examples of those.

That is to say, there are still spots that need improvement or holes to fill - none denies that - but that is mostly related to functionality (bonus API, extensions) not the array/hashtable handling itself.
 
You guys are right of course. Table absolutly covers everything already, and it's an awesome resource.
But also for running systems it may be interesting from time to time to see very new approaches which compete with the older ones. (just wideley said)

But to win against Table, at least to be an approved jass submission, it needs to have drastic improvements, which is not shown yet. :/
 
Level 9
Joined
Jun 21, 2012
Messages
432
@Bannar, @Almia:
I respect the opinion of each of you.

And my opinion is this: I believe that if someone does not like to use Table should have another similar or bether option (depending of the user experience level or whatever).

This seems to be the common trend lately.

Yeah you're right, people want multidimensional array snippets :ogre_icwydt:
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
I agree that the Table API is not the sexiest for multidimensional arrays beyond 2 slots, but I did make that cool add-on that makes it a lot nicer to read and write:

The best way to improve the syntax would be to add a struct for each dimension, and I can add this to Table if you want:

JASS:
//Not shown: the create/destroy/etc. methods, but the user can just use the normal HashTable ones with wrappers if needed.
struct HashTable3D extends array
    method operator [] takes integer index returns HashTable
        return HashTable(this)[index]
    endmethod
endstruct
struct HashTable4D extends array
    method operator [] takes integer index returns HashTable3D
        return HashTable(this)[index]
    endmethod
endstruct

Example:

JASS:
local HashTable3D h3d = HashTable.create()
local HashTable4D h4d = HashTable.create() //use normal create method of HashTable
set h3d[0][1][2] = 3
set h4d[0][1][2][3] = 4
 
Top