• 🏆 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!

[vJASS] MultiDimension

Level 11
Joined
Dec 19, 2012
Messages
411
JASS:
library MultiDimension initializer Init /*

                      */requires Table, /* [url]http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/[/url]

                      */optional ErrorMessage/* [url]https://github.com/nestharus/JASS/tree/master/jass/Systems/ErrorMessage[/url]
                      

MultiDimension made by DD_LegionTN

A dimension library, made for simplify the complexity of an array
Supports minimum 2D, maximum 4D

Syntax inspired by New_Table

API :

struct Dimension

	readonly integer size
	
    static method create takes integer i returns nothing
        i : input dimension size, minimum 2, maximum 4
        
    method destroy takes nothing returns nothing
    
    method operator [] takes integer i returns thistype
        i : input value, as long as no less than 0 or greater than ARRAY_MAX_SIZE
        For 2D : [a][b] : a value will be stored first and then b value
        For 3D : [a][b][c] : a first, b second, c last
        For 4D : [a][b][c][d] : a first, b second, c third, d last
*/

globals
    //Debug purpose, an addition debug for retrieving stored/load key value.
    private constant boolean INTERNAL_DEBUG = true
    
//Below globals variables are non-configurable

    //constant array which able to determine the max size of a dimension
    private integer array ARRAY_MAX_SIZE
    
    //constant array used for formula
    private integer array ARRAY_MULTIPLY
    
    //Debug purpose, minimum dimension size
    debug integer MIN_SIZE = 2
    
    //Debug purpose, maximum dimension size
    debug integer MAX_SIZE = 4
endglobals

private function Init takes nothing returns nothing
    //multiplication of array must not exceed 2147483647 (2^31-1)
    
    //Formula for checking 2D maximum storage size:
    //ARRAY_MAX_SIZE[8]*ARRAY_MULTIPLY[8] + ARRAY_MAX_SIZE[9]
    //2D constant
    //[array8][array9]
    set ARRAY_MAX_SIZE[8] = 99
    set ARRAY_MAX_SIZE[9] = 99
    
    //Formula for checking 3D maximum storage size: 
    //ARRAY_MAX_SIZE[12]*ARRAY_MULTIPLY[12] + ARRAY_MAX_SIZE[13]*ARRAY_MULTIPLY[13] + ARRAY_MAX_SIZE[14]
    //3D constant
    //[array12][array13][array14]
    set ARRAY_MAX_SIZE[12] = 99
    set ARRAY_MAX_SIZE[13] = 99
    set ARRAY_MAX_SIZE[14] = 99
    
    //Formula for checking 4D maximum storage size:
    //ARRAY_MAX_SIZE[16]*ARRAY_MULTIPLY[16] + ARRAY_MAX_SIZE[17]*ARRAY_MULTIPLY[17] + ARRAY_MAX_SIZE[18]*ARRAY_MULTIPLY[18] + ARRAY_MAX_SIZE[19]
    //4D constant
    //[array16][array17][array18][array19]
    set ARRAY_MAX_SIZE[16] = 99
    set ARRAY_MAX_SIZE[17] = 99
    set ARRAY_MAX_SIZE[18] = 99
    set ARRAY_MAX_SIZE[19] = 99
    
    /*
    End of configuration
    */

    //Non-configurable
    set ARRAY_MULTIPLY[8] = (ARRAY_MAX_SIZE[8]+1)*(ARRAY_MAX_SIZE[9]+1)
    
    set ARRAY_MULTIPLY[13] = (ARRAY_MAX_SIZE[13]+1)*(ARRAY_MAX_SIZE[14]+1)
    set ARRAY_MULTIPLY[12] = (ARRAY_MAX_SIZE[12]+1)*ARRAY_MULTIPLY[13]
    
    set ARRAY_MULTIPLY[18] = (ARRAY_MAX_SIZE[18]+1)*(ARRAY_MAX_SIZE[19]+1)
    set ARRAY_MULTIPLY[17] = (ARRAY_MAX_SIZE[17]+1)*ARRAY_MULTIPLY[18]
    set ARRAY_MULTIPLY[16] = (ARRAY_MAX_SIZE[16]+1)*ARRAY_MULTIPLY[17]
endfunction

//! textmacro ADD_TYPE takes TYPE, EMPTY, TYPE2
    private module $TYPE$a
        method operator $TYPE$ takes nothing returns $TYPE$
            local integer i = thistype.retrieveStoredInt()
            static if DEBUG_MODE then
                if inputSize != 0 then
                    static if LIBRARY_ErrorMessage then
                        call ThrowError(true, "Multidimension", "operator []", "size", this, "Input dimension size greater/lesser than " + I2S(size))
                    else
                        call BJDebugMsg("Multidimension - operator []: Input dimension size greater/lesser than " + I2S(size) + ", this : " + I2S(this))
                    endif
                elseif storedInt[1] == -1 then
                    static if LIBRARY_ErrorMessage then
                        call ThrowError(true, "Multidimension", "operator []", "size", this, "0 input dimension size!")
                    else
                        call BJDebugMsg("Multidimension - operator []: 0 input dimension size! this : " + I2S(this))
                    endif
                endif
            endif
            
            call thistype.clear()
            
            static if INTERNAL_DEBUG and DEBUG_MODE then
                call BJDebugMsg("this.tb.$TYPE$[" + I2S(i) + "] loaded")
            endif
            return this.tb.$TYPE$[i]
        endmethod
        
        method operator $TYPE$= takes $TYPE$ b returns nothing
            static if DEBUG_MODE then
                if inputSize != 0 then
                    static if LIBRARY_ErrorMessage then
                        call ThrowError(true, "Multidimension", "operator []", "size", this, "Input dimension size greater/lesser than " + I2S(size))
                    else
                        call BJDebugMsg("Multidimension - operator []: Input dimension size greater/lesser than " + I2S(size) + ", this : " + I2S(this))
                    endif
                elseif storedInt[1] == -1 then
                    static if LIBRARY_ErrorMessage then
                        call ThrowError(true, "Multidimension", "operator []", "size", this, "0 input dimension size!")
                    else
                        call BJDebugMsg("Multidimension - operator []: 0 input dimension size! this : " + I2S(this))
                    endif
                endif
            endif
            
            set storedIntLoaded = storedIntLoaded + 1
            set load = load + 1
            if b == $EMPTY$ then
                call this.tb.$TYPE2$.remove(storedInt[load])
				static if INTERNAL_DEBUG and DEBUG_MODE then
					call BJDebugMsg("this.tb.$TYPE$[" + I2S(storedInt[load]) + "] removed")
				endif
            else
				set this.tb.$TYPE$[storedInt[load]] = b
				static if INTERNAL_DEBUG and DEBUG_MODE then
					call BJDebugMsg("this.tb.$TYPE$[" + I2S(storedInt[load]) + "] stored")
				endif
			endif
            
            call thistype.clear()
        endmethod
    endmodule
//! endtextmacro

//! runtextmacro ADD_TYPE("integer", "0", "integer")
//! runtextmacro ADD_TYPE("real", "0.", "real")
//! runtextmacro ADD_TYPE("boolean", "false", "boolean")
//! runtextmacro ADD_TYPE("string", "\"\"", "string")
//! runtextmacro ADD_TYPE("player", "null", "handle")
//! runtextmacro ADD_TYPE("destructable", "null", "handle")
//! runtextmacro ADD_TYPE("item", "null", "handle")
//! runtextmacro ADD_TYPE("unit", "null", "handle")
//! runtextmacro ADD_TYPE("ability", "null", "handle")
//! runtextmacro ADD_TYPE("timer", "null", "handle")
//! runtextmacro ADD_TYPE("trigger", "null", "handle")
//! runtextmacro ADD_TYPE("triggercondition", "null", "handle")
//! runtextmacro ADD_TYPE("rect", "null", "handle")
//! runtextmacro ADD_TYPE("effect", "null", "handle")
//! runtextmacro ADD_TYPE("widget", "null", "handle")
//! runtextmacro ADD_TYPE("triggeraction", "null", "handle")
//! runtextmacro ADD_TYPE("event", "null", "handle")
//! runtextmacro ADD_TYPE("force", "null", "handle")
//! runtextmacro ADD_TYPE("group", "null", "handle")
//! runtextmacro ADD_TYPE("location", "null", "handle")
//! runtextmacro ADD_TYPE("boolexpr", "null", "handle")
//! runtextmacro ADD_TYPE("sound", "null", "handle")
//! runtextmacro ADD_TYPE("unitpool", "null", "handle")
//! runtextmacro ADD_TYPE("itempool", "null", "handle")
//! runtextmacro ADD_TYPE("quest", "null", "handle")
//! runtextmacro ADD_TYPE("questitem", "null", "handle")
//! runtextmacro ADD_TYPE("defeatcondition", "null", "handle")
//! runtextmacro ADD_TYPE("timerdialog", "null", "handle")
//! runtextmacro ADD_TYPE("leaderboard", "null", "handle")
//! runtextmacro ADD_TYPE("multiboard", "null", "handle")
//! runtextmacro ADD_TYPE("multiboarditem", "null", "handle")
//! runtextmacro ADD_TYPE("trackable", "null", "handle")
//! runtextmacro ADD_TYPE("dialog", "null", "handle")
//! runtextmacro ADD_TYPE("button", "null", "handle")
//! runtextmacro ADD_TYPE("texttag", "null", "handle")
//! runtextmacro ADD_TYPE("lightning", "null", "handle")
//! runtextmacro ADD_TYPE("image", "null", "handle")
//! runtextmacro ADD_TYPE("ubersplat", "null", "handle")
//! runtextmacro ADD_TYPE("region", "null", "handle")
//! runtextmacro ADD_TYPE("fogstate", "null", "handle")
//! runtextmacro ADD_TYPE("fogmodifier", "null", "handle")
//! runtextmacro ADD_TYPE("hashtable", "null", "handle")

    struct Dimension extends array
        implement integera
        implement reala
        implement booleana
        implement stringa
        implement playera
        implement destructablea
        implement itema
        implement unita
        implement abilitya
        implement timera
        implement triggera
        implement triggerconditiona
        implement eventa
        implement effecta
        implement widgeta
        implement triggeractiona
        implement forcea
        implement groupa
        implement locationa
        implement boolexpra
        implement sounda
        implement unitpoola
        implement itempoola
        implement questa
        implement questitema
        implement defeatconditiona
        implement timerdialoga
        implement leaderboarda
        implement multiboarda
        implement multiboarditema
        implement trackablea
        implement dialoga
        implement buttona
        implement texttaga
        implement lightninga
        implement imagea
        implement ubersplata
        implement regiona
        implement fogstatea
        implement fogmodifiera
        implement hashtablea
        
        private static integer instanceCount = 0
        private static thistype recycle = 0
        private thistype recycleNext
        
        readonly integer size
        
        private static integer storedIntCount = 0
        private static integer storedIntLoaded = 0
        private static integer load = 0
        private static integer inputSize = 0
        private static integer array storedInt
        
        private Table tb
        
        static method create takes integer i returns thistype
            local thistype this

            if (recycle == 0) then
                set instanceCount = instanceCount + 1
                set this = instanceCount
            else
                set this = recycle
                set recycle = recycle.recycleNext
            endif

            static if DEBUG_MODE then
                if i < MIN_SIZE or i > MAX_SIZE then
                    static if LIBRARY_ErrorMessage then
                        call ThrowError(true, "Multidimension", "create", "i", 0, "assigned dimension size lesser/greater than " + I2S(i))
                    else
                        call BJDebugMsg("Multidimension - create() : assigned dimension size lesser/greater than " + I2S(i))
                        return 1/0
                    endif
                endif
            endif
            
            set size = i
            set tb = Table.create()
            
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            set recycleNext = recycle
            set recycle = this
            call tb.destroy()
        endmethod
        
		private static method clear takes nothing returns nothing
            if storedIntLoaded == storedIntCount then
                set storedIntLoaded = 0
                set storedIntCount = 0
                set load = 0
                debug set storedInt[1] = -1
            endif
		endmethod
		
		private static method retrieveStoredInt takes nothing returns integer
            set storedIntLoaded = storedIntLoaded + 1
            return storedInt[storedIntCount]
		endmethod
		
        method operator [] takes integer i returns thistype
            set inputSize = inputSize + 1
            
            static if DEBUG_MODE then
                if i > ARRAY_MAX_SIZE[size*4+(inputSize-1)] then
                    static if LIBRARY_ErrorMessage then
                        call ThrowError(true, "Multidimension", "operator []", "none", this, "input value : " + I2S(i) + " greater than ARRAY_MAX_SIZE[" + I2S(size*4+(inputSize-1)) + "]!")
                    else
                        call BJDebugMsg("Multidimension - operator [] : input value " + I2S(i)+ " greater than ARRAY_MAX_SIZE[" + I2S(size*4+(inputSize-1)) + "]! this : " + I2S(this))
                        return 1/0
                    endif
                elseif i < 0 then
                    static if LIBRARY_ErrorMessage then
                        call ThrowError(true, "Multidimension", "operator []", "none", this, "input value : " + I2S(i) + " cannot be lesser than 0!")
                    else
                        call BJDebugMsg("Multidimension - operator [] : input value " + I2S(i)+ " cannot be lesser than 0! this : " + I2S(this))
                        return 1/0
                    endif
                endif
            endif
            
            if inputSize == size then
                set storedInt[storedIntCount] = storedInt[storedIntCount] + i
                set inputSize = 0
            else
                if inputSize == 1 then
                    set storedIntCount = storedIntCount + 1
                    set storedInt[storedIntCount] = 0
                endif
                set storedInt[storedIntCount] = storedInt[storedIntCount] + i*ARRAY_MULTIPLY[size*4+(inputSize-1)]
            endif
            
            return this
        endmethod
        
        static if DEBUG_MODE then
            private static method onInit takes nothing returns nothing
                //Setting -1 to indicate no value assigned
                set storedInt[1] = -1
            endmethod
        endif
        
    endstruct
endlibrary

Demo Code :
JASS:
function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing
	local Dimension d = Dimension.create(2)
	local Dimension d2 = Dimension.create(3)
	local Dimension d3 = Dimension.create(4)
	
	set d[0][0].integer = 5 //store integer
	set d[0][1].real = 6.4 //store real
	set d[7][2].player = Player(0) //store player
									//load player handle
	set d2[1][2][88].unit = CreateUnit(d[7][2].player, 'hfoo', 0, 0, 0) // store unit
	
	set d3[0][3][1][42].multiboard = CreateMultiboard() //create a multiboard
	
	call d.destroy() //destroy it
endfunction

//===========================================================================
function InitTrig_Untitled_Trigger_001 takes nothing returns nothing
    set gg_trg_Untitled_Trigger_001 = CreateTrigger(  )
    call TriggerRegisterTimerEventSingle( gg_trg_Untitled_Trigger_001, 0.00 )
    call TriggerAddAction( gg_trg_Untitled_Trigger_001, function Trig_Untitled_Trigger_001_Actions )
endfunction

Since there is no simple library that could create dimension array, therefore i made 1.

Someone would think 2D array is sufficient and there is no point for creating more dimension. But whatever, more resource is still good, let the others choose what they want :)


EDIT : Found a small mistake made by myself, changed :

JASS:
            if b != $EMPTY$ then
                call this.tb.$TYPE2$.remove(storedInt[load])
            endif
            
            static if INTERNAL_DEBUG and DEBUG_MODE then
                call BJDebugMsg("this.tb.$TYPE$[" + I2S(storedInt[load]) + "] stored")
            endif
            set this.tb.$TYPE$[storedInt[load]] = b
to
JASS:
            if b == $EMPTY$ then
                call this.tb.$TYPE2$.remove(storedInt[load])
				static if INTERNAL_DEBUG and DEBUG_MODE then
					call BJDebugMsg("this.tb.$TYPE$[" + I2S(storedInt[load]) + "] removed")
				endif
            else
				set this.tb.$TYPE$[storedInt[load]] = b
				static if INTERNAL_DEBUG and DEBUG_MODE then
					call BJDebugMsg("this.tb.$TYPE$[" + I2S(storedInt[load]) + "] stored")
				endif
			endif
 
Last edited:
Level 13
Joined
Nov 7, 2014
Messages
571
A dimension library, made for simplify the complexity of an array

~300 lines of code (expanded into who knows how many) so that you can write:

JASS:
    local Dimension d = Dimension.create(2)
    local Dimension d2 = Dimension.create(3)
    local Dimension d3 = Dimension.create(4)

    set d[0][0].integer = 5 //store integer
    set d[0][1].real = 6.4 //store real
    set d[7][2].player = Player(0) //store player
                                    //load player handle
    set d2[1][2][88].unit = CreateUnit(d[7][2].player, 'hfoo', 0, 0, 0) // store unit

    set d3[0][3][1][42].multiboard = CreateMultiboard() //create a multiboard

o_O?

instead of using multiplication and addition:

JASS:
globals
    hashtable mdas = InitHashtable() // multidimensional arrays storage
endglobals

local integer ma1 = 1 // [3]
local integer ma2 = 2 // [3][2]
local integer ma3 = 3 // [4][2][3]
local integer ma4 = 4 // [4][5][3][2]
local integer ma5 = 5 // [5][6][7][8][9]

local integer d1
local integer d2
local integer d3
local integer d4
local integer d5
local integer i
local integer j
local integer k
local integer l
local integer m


// ma1[3], ma1[i]
set i = 0 // 0 .. 2
call SaveInteger(mdas, ma1, i, 0xCAFE)


// ma2[3][2], ma2[i][j]
set i = 0 // 0 .. 2
set j = 0 // 0 .. 1
set d2 = 2
call SaveInteger(mdas, ma2, i * d2 + j, 0xBABE)


// ma3[4][2][3], ma3[i][j][k]
set i = 0 // 0 .. 3
set j = 0 // 0 .. 1
set k = 0 // 0.. 2
set d2 = 2
set d3 = 3
call SaveInteger(mdas, ma3, (i * d2 * d3) + j * d3 + k, 0xDEAD)


// ma4[4][5][3][2], ma4[i][j][k][l]
set i = 0 // 0 .. 3
set j = 0 // 0 .. 4
set k = 0 // 0 .. 2
set l = 0 // 0 .. 1
set d2 = 5
set d3 = 3
set d4 = 2
call SaveInteger(mdas, ma4, (i * d2 * d3 * d4) + (j * d3 * d4) + k * d4 + l, 0xBEEF)


// ma5[5][6][7][8][9], ma5[i][j][k][l][m]
set i = 0 // 0 .. 4
set j = 0 // 0 .. 5
set k = 0 // 0 .. 6
set l = 0 // 0 .. 7
set m = 0 // 0 .. 8
set d2 = 6
set d3 = 7
set d4 = 8
set d5 = 9
call SaveInteger(mdas, ma5, (i * d2 * d3 * d4 * d5) + (j * d3 * d4 * d5) + (k * d4 * d5) + l * d5 + m, 0xBADA55)


// I hope you can see the pattern...


// iterate and initialize ma3[4][2][3], ma3[i][j][k]
//
set d1 = 4
set d2 = 2
set d3 = 3

set i = 0
loop
    exitwhen i >= d1

    set j = 0
    loop
        exitwhen j >= d2

        set k = 0
        loop
            exitwhen k >= d3

            call SaveInteger(mdas, ma3, (i * d2 * d3) + j * d3 + k, 0x4B1D + i + j + k)

            set k = k + 1
        endloop

        set j = j + 1
    endloop

    set i = i + 1
endloop


Using multiplication and addition works for "any" number of dimensions (not just, 2, 3 and 4), also if the user
wants to iterate the multidimensional arrays, your syntax sugar "eats" a lot of ops, i.e it's easier to reach to op-limit.
It also introduces an overhead of calling those "getindex/[]" functions and bookkeeping.
 
Level 26
Joined
Mar 19, 2008
Messages
3,140
Almost every resource/ script in jass that would require working with 3-4 dimensions could be simplified to work with one or two.

Function "Init" is a nono when working with Table which is using module initializer already.

Since there is no simple library that could create dimension array, therefore i made 1.
No, there is one already, and it's called Vector<T>.

Instead of reimplementing whole Table's API, Vector takes advantage of Table and even uses its ctor/dctor (simulate actual extending).
Vector supports multi dimentions just as easily as single one - just create a vector of a vector.
Provides actual modifiers API, not just the accessors.

Right now, this is a wrapper of Table that provides no additional functionality yet still generates code bloat similar to one from Table.
 
Level 13
Joined
Jan 2, 2016
Messages
973
Well, that's not a bad resource, I have needed a hashtable with 3 keys before (and yesterday I made one). But the problem I see here is, that the indexes go up to 99, and that's not really enough for linking data to a unit (for example) xP
 
Level 11
Joined
Dec 19, 2012
Messages
411
@Aniki
Compare to
JASS:
call SaveInteger(mdas, ma3, (i * d2 * d3) + j * d3 + k, 0xDEAD)
and
JASS:
set [0][0][0].integer = 0xDEAD

which one looks nicer and easier to understand?

Using multiplication and addition works for "any" number of dimensions (not just, 2, 3 and 4)
Of course you can have more than 4, but I don't really see to have a dimension more than 5.

your syntax sugar "eats" a lot of ops, i.e it's easier to reach to op-limit.
Probably, depends on the code. But the system mainly calculate integers, so I suppose it shouldn't be a heavy work for war3.
As a reference :
JASS:
function test takes nothing returns nothing
	local Dimension d = Dimension.create(4)
	local integer i = 0
	local integer i2 = 0
	
	loop
		set d[i][i2][i2][i].unit = CreateUnit(Player(0), 'hfoo', 0, 0, 0)
		exitwhen i2 == 20
		if i == 10 then
			set i = 0
			set i2 = i2 + 1
		endif
		set i = i + 1
	endloop
	
	call BJDebugMsg("finished")
endfunction
"finished" is printed, so i suppose it should be fine.


@Banner
I would probably need time to understand how it works before I can answer...

Function "Init" is a nono when working with Table which is using module initializer already.
It actually working, or I should change it to module?

@WereElf
The index is configurable, as long as the maximum storage integer not exceed (2^31)-1.


Yep, it basically copy the whole Table *syntax* (I should specific it is just copy of syntax), most likely is the extension dimension of Table.

EDIT :
@Bannar
Correct me if I'm wrong since i only take a rough reading.

In my opinion, it more like 2 different kind of resources although multi-dimension do support by them.

Mine resource is more easier to use - due to the similar syntax which Table used, as well as less API
Mine resource focus on multi-dimension creation - this is the main reason as well as main point of this resource to exist


But that doesn't mean my resource is more powerful than yours, your Vector<T> have more API, in which it should be an advantage compare to my resource. As I said, I think it more like 2 different kind of resources, so it pretty hard for me to compare between 2 different (imo) resources.
 
Last edited:
Level 11
Joined
Dec 19, 2012
Messages
411
Really? That I honestly don't know...

So do you mean something like this?
JASS:
	local HashTable ht = HashTable.create()
	
	set ht[0][1] = 1
	set ht[0][2] = 1
	
	set HashTable(ht[0][1])[1][1] = 5
	set HashTable(ht[0][2])[1][1] = 10
	
	call BJDebugMsg(I2S(HashTable(ht[0][1])[1][1]))
	call BJDebugMsg(I2S(HashTable(ht[0][2])[1][1]))
 
Really? That I honestly don't know...

So do you mean something like this?
JASS:
	local HashTable ht = HashTable.create()
	
	set ht[0][1] = 1
	set ht[0][2] = 1
	
	set HashTable(ht[0][1])[1][1] = 5
	set HashTable(ht[0][2])[1][1] = 10
	
	call BJDebugMsg(I2S(HashTable(ht[0][1])[1][1]))
	call BJDebugMsg(I2S(HashTable(ht[0][2])[1][1]))

i think so, but upon my second look I think there needs to be one more HashTable wrapper.
 
Level 11
Joined
Dec 19, 2012
Messages
411
Oh, thanks for clarification. So it would look like :
JASS:
	local HashTable ht = HashTable.create()
	
	set ht[0][1] = 1
	set ht[0][2] = 1
	
	set HashTable(HashTable(ht[0][1])[1])[1] = 5 //Syntax error
	set HashTable(HashTable(ht[0][2])[1])[1] = 10
	
	call BJDebugMsg(I2S(HashTable(HashTable(ht[0][1])[1])[1]))
	call BJDebugMsg(I2S(HashTable(HashTable(ht[0][2])[1])[1]))
But a syntax error pop out : s__HashTable__getindex((s__Table__getindex(s__HashTable__getindex(ht, 0), 1)), 1)) is not an array.
 
Level 26
Joined
Mar 19, 2008
Messages
3,140
Though, that's not really necessary. Seems like overhead ;/
Think about usage.

"Powerful" is not the right word here. It's better to take as much from Table as possible when wrapping around it. That's why core Vector is so small. It allows for multiple dimensions, though its syntax wouldn't be as nice as one presented by Bribe.
 
Level 11
Joined
Dec 19, 2012
Messages
411
Small update, slightly optimized the code for generates lesser code. Changes made :

JASS:
//! textmacro ADD_TYPE takes TYPE, EMPTY, TYPE2
    private module $TYPE$a
        method operator $TYPE$ takes nothing returns $TYPE$
            local integer i = thistype.retrieveStoredInt()
            static if DEBUG_MODE then
                if inputSize != 0 then
                    static if LIBRARY_ErrorMessage then
                        call ThrowError(true, "Multidimension", "operator []", "size", this, "Input dimension size greater/lesser than " + I2S(size))
                    else
                        call BJDebugMsg("Multidimension - operator []: Input dimension size greater/lesser than " + I2S(size) + ", this : " + I2S(this))
                    endif
                elseif storedInt[1] == -1 then
                    static if LIBRARY_ErrorMessage then
                        call ThrowError(true, "Multidimension", "operator []", "size", this, "0 input dimension size!")
                    else
                        call BJDebugMsg("Multidimension - operator []: 0 input dimension size! this : " + I2S(this))
                    endif
                endif
            endif
            
            call thistype.clear()
            
            static if INTERNAL_DEBUG and DEBUG_MODE then
                call BJDebugMsg("this.tb.$TYPE$[" + I2S(i) + "] loaded")
            endif
            return this.tb.$TYPE$[i]
        endmethod
        
        method operator $TYPE$= takes $TYPE$ b returns nothing
            static if DEBUG_MODE then
                if inputSize != 0 then
                    static if LIBRARY_ErrorMessage then
                        call ThrowError(true, "Multidimension", "operator []", "size", this, "Input dimension size greater/lesser than " + I2S(size))
                    else
                        call BJDebugMsg("Multidimension - operator []: Input dimension size greater/lesser than " + I2S(size) + ", this : " + I2S(this))
                    endif
                elseif storedInt[1] == -1 then
                    static if LIBRARY_ErrorMessage then
                        call ThrowError(true, "Multidimension", "operator []", "size", this, "0 input dimension size!")
                    else
                        call BJDebugMsg("Multidimension - operator []: 0 input dimension size! this : " + I2S(this))
                    endif
                endif
            endif
            
            set storedIntLoaded = storedIntLoaded + 1
            set load = load + 1
            if b == $EMPTY$ then
                call this.tb.$TYPE2$.remove(storedInt[load])
				static if INTERNAL_DEBUG and DEBUG_MODE then
					call BJDebugMsg("this.tb.$TYPE$[" + I2S(storedInt[load]) + "] removed")
				endif
            else
				set this.tb.$TYPE$[storedInt[load]] = b
				static if INTERNAL_DEBUG and DEBUG_MODE then
					call BJDebugMsg("this.tb.$TYPE$[" + I2S(storedInt[load]) + "] stored")
				endif
			endif
            
            call thistype.clear()
        endmethod
    endmodule
//! endtextmacro

Separated the actions into 2 functions :

JASS:
		private static method clear takes nothing returns nothing
            if storedIntLoaded == storedIntCount then
                set storedIntLoaded = 0
                set storedIntCount = 0
                set load = 0
                debug set storedInt[1] = -1
            endif
		endmethod
		
		private static method retrieveStoredInt takes nothing returns integer
            set storedIntLoaded = storedIntLoaded + 1
            return storedInt[storedIntCount]
		endmethod
 
Level 13
Joined
Jan 2, 2016
Messages
973
And what is the difference with this?

Sincerely my Dimensional-Array uses fewer resources (no recourse)...

From what I saw, I'd say that this resource is more noob-friendly.
I'm still relatively new to structs, and for me it's hard to read your library xP

Let me not mention that in the example(s) you've given - you are still using structs and methods. Even if I didn't care about how the resource works - I'd still get confused how to use it.

While this resource is using normal functions when used, which is way more comfortable for not-so-experianced-with-structs people.
 
Level 11
Joined
Dec 19, 2012
Messages
411
And what is the difference with this?

Sincerely my Dimensional-Array uses fewer resources (no recourse)...

Opps, I never notice your did create such a similar library before (I never check graveyarded resources...)

A quick look though it :

1. I didn't look too deep into the code, my first sight tells me that mine and yours resource algorithm is completely different, so hopefully I didn't copy anything from your resource.

2. I prefer the consistency of the array-dimension.

3. My library requires Table (optional ErrorMessage which doesn't force user to implement it into the map), I don't think that it is a specific usage resource, it is a general resource, a vjass user mostly would have Table inside their map.
 
Level 9
Joined
Jun 21, 2012
Messages
432
While this resource is using normal functions when used, which is way more comfortable for not-so-experianced-with-structs people.

mm? its the same.... with some differences:
JASS:
function Dimension_Test takes nothing returns nothing
	local Dimension d = Dimension.create(2)
	local Dimension d2 = Dimension.create(3)
	local Dimension d3 = Dimension.create(4)
	
	set d[0][0].integer = 5 //store integer
	set d[0][1].real = 6.4 //store real
	set d[7][2].player = Player(0) //store player
									//load player handle
	set d2[1][2][88].unit = CreateUnit(d[7][2].player, 'hfoo', 0, 0, 0) // store unit
	
	set d3[0][3][1][42].multiboard = CreateMultiboard() //create a multiboard
	
	call d.destroy() //destroy it
endfunction

JASS:
function Array_Test takes nothing returns nothing
	local Array d = Array.create()
	local Array d2 = Array.create()
	local Array d3 = Array.create()
	
	set d[0][0].integer = 5 //store integer
	set d[0][1].real = 6.4 //store real
	set d[7][2].player = Player(0) //store player
									//load player handle
	set d2[1][2][88].unit = CreateUnit(d[7][2].player, 'hfoo', 0, 0, 0) // store unit
	
	set d3[0][3][1][42].multiboard = CreateMultiboard() //create a multiboard
	
	call d.destroy() //destroy it
endfunction
 
Actually, with one HashTable you can create unlimited array slots, but it adds hashtable lookups for each referenced index. There is scarce need to do anything beyond 2 indices, and if you need more and don't understand how to do HashTable wrappers to achieve unlimited indices you can manually store nested Tables and get syntax like table[value1][value2][value3][value4][value5]

Keep in mind that you'll need to have a legit reason to have a resource. A resource should not be approved if not even the OP has found a use for it other than "because it can exist".
 
Level 26
Joined
Mar 19, 2008
Messages
3,140
If the only useful thing it brings is multidimensional syntax, than I'd just stick with Vector<T> - even that md functionality isn't as easy to implement for user as in your case, it has 2 main advantages over this:
- c++ vector functionality
- wrapps itself around Table, instead of rewriting whole api again
 
Level 11
Joined
Dec 19, 2012
Messages
411
Bribe said:
Actually, with one HashTable you can create unlimited array slots, but it adds hashtable lookups for each referenced index. There is scarce need to do anything beyond 2 indices, and if you need more and don't understand how to do HashTable wrappers to achieve unlimited indices you can manually store nested Tables and get syntax like table[value1][value2][value3][value4][value5]
Hopefully you could provide an example here, because I failed to work it out.
JASS:
    local HashTable ht = HashTable.create()
    
    set ht[0][1] = 1
    set ht[0][2] = 1
    
    set HashTable(ht[0][1])[1][1] = 5
    set HashTable(ht[0][2])[1][1] = 10 // will overwrite the value of 5
    
    call BJDebugMsg(I2S(HashTable(ht[0][1])[1][1])) //prints 10
    call BJDebugMsg(I2S(HashTable(ht[0][2])[1][1])) //prints 10


Bannar said:
If the only useful thing it brings is multidimensional syntax, than I'd just stick with Vector<T> - even that md functionality isn't as easy to implement for user as in your case, it has 2 main advantages over this:
- c++ vector functionality
- wrapps itself around Table, instead of rewriting whole api again
As a user, user always want a simplest resource that fit their need best. It depend on what user need.

-A user who only wants to store data inside a hashtable with array dimension supports -> MultiDimension
-A user who wants to have linked list between stored data as well as array dimension supports -> Vector<T>

I never learn c++, so I cant tell if it is an advantage over here.

For your vector, if I want to save over 10 variables types, then I would need to define 10 variables type, it just that this resource just define whole instead of letting user define the types manually.

Perhaps you could provide something that is useful and could be added into this resource? :)
 
Hopefully you could provide an example here, because I failed to work it out.
JASS:
    local HashTable ht = HashTable.create()
    
    set ht[0][1] = 1
    set ht[0][2] = 1
    
    set HashTable(ht[0][1])[1][1] = 5
    set HashTable(ht[0][2])[1][1] = 10 // will overwrite the value of 5
    
    call BJDebugMsg(I2S(HashTable(ht[0][1])[1][1])) //prints 10
    call BJDebugMsg(I2S(HashTable(ht[0][2])[1][1])) //prints 10

The syntax is:

JASS:
    local HashTable ht = HashTable.create()
    
    set ht[0][1] = 1
    set ht[0][2] = 1
    
    set HashTable(HashTable(ht[0][1])[1])[1] = 5
    set HashTable(HashTable(ht[0][2])[1])[1] = 10 // does not overwrite the value of 5
    
    call BJDebugMsg(I2S(HashTable(HashTable(ht[0][1])[1])[1])) //prints 5
    call BJDebugMsg(I2S(HashTable(HashTable(ht[0][2])[1])[1])) //prints 10
 
Level 11
Joined
Dec 19, 2012
Messages
411
@Bribe
Test it on JNGP first, because i got syntax error...

Bannar said:
Except for simple fact: this resource isn't modular. No matter if you just need md-array for unit/ interger type - you always end up rewriting whole Table. This is what I wanted to avoid ;/
I personally would rewrite (or probably extends) it if what I want doesn't exist in the resource (or perhaps I don't know it exist...)
 
Apologies for the syntax error. I was putting the HashTable wrappers too far to the right.
JASS:
    local HashTable ht = HashTable.create()
    
    set ht[0][1] = 1
    set ht[0][2] = 1
    
    set HashTable(HashTable(ht[0])[1])[1][1] = 5
    set HashTable(HashTable(ht[0])[2])[1][1] = 10 // does not overwrite the value of 5
    
    call BJDebugMsg(I2S(HashTable(HashTable(ht[0])[1])[1][1])) //prints 5
    call BJDebugMsg(I2S(HashTable(HashTable(ht[0])[2])[1][1])) //prints 10
 
Level 11
Joined
Dec 19, 2012
Messages
411
Err, I tested, the result :
JASS:
    local HashTable ht = HashTable.create()
    
    set ht[0][1] = 1
    set ht[0][2] = 1
    
    set HashTable(HashTable(ht[0])[1])[1][1] = 5
    set HashTable(HashTable(ht[0])[2])[1][1] = 10 //still overwrite 5
    
    call BJDebugMsg(I2S(HashTable(HashTable(ht[0])[1])[1][1])) //prints 10
    call BJDebugMsg(I2S(HashTable(HashTable(ht[0])[2])[1][1])) //prints 10
 
You are most likely not using the latest version of Table, then. This prints 1 and 2:

JASS:
function InitTrig_HashTable_tests takes nothing returns nothing
    local HashTable ht = HashTable.create()
    set HashTable(HashTable(ht[0])[1])[1][1] = 1
    set HashTable(HashTable(ht[0])[2])[1][1] = 2
    call BJDebugMsg(I2S(HashTable(HashTable(ht[0])[1])[1][1]))
    call BJDebugMsg(I2S(HashTable(HashTable(ht[0])[2])[1][1]))
endfunction

Attached is the test map.
 

Attachments

  • IPool Test.w3x
    28.8 KB · Views: 54
Level 11
Joined
Dec 19, 2012
Messages
411
Oh, found out the problem, it because these 2 making it not working :
JASS:
    set ht[0][1] = 1
    set ht[0][2] = 1

I'm glad to know that your Table did supports array-dimension (although the syntax won't be so nice), I guess this resource could move to graveyard :)

Hopefully in your Table forums you could add a trigger that shows the support of array-dimension of your Table so that people like me wouldn't need to seek for/make an array-dimension resource.
 
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
 
Level 11
Joined
Dec 19, 2012
Messages
411
Thanks you, but probably that would be too specific just for my case, still adding some addition syntax support would be nice.

How about if I want to save the other types?
JASS:
local HashTable3D h3d = HashTable.create()
set h3d[0][1][2].real = 3. //will throw you syntax error

Pretty off topic, since we're discussing Table instead of MultiDimension, probably we should continue at your Table resource page :)
 
Sadly, there is no way to achieve "method operator type=" syntax since it requires the extra parameter to run. Believe me, I would prefer table[0].real = syntax, but JassHelper has no way of interpreting that. It would need to support "method operator []type= which is too much for it.

I won't gy this yet as I want to leave the discussion open.
 
Level 13
Joined
Nov 7, 2014
Messages
571
Believe me, I would prefer table[0].real = syntax, but JassHelper has no way of interpreting that.

JASS:
globals
    hashtable ht = InitHashtable()
    integer child_key
endglobals

struct Bar extends array

    method operator real= takes real value returns nothing
        call SaveReal(ht, this, child_key, value)
    endmethod

    method operator real takes nothing returns real
        return LoadReal(ht, this, child_key)
    endmethod

endstruct

struct Foo
    method operator[] takes integer i returns Bar
        set child_key = i
        return Bar(this)
    endmethod
endstruct

function main takes nothing returns nothing
    local Foo foo = Foo.create()
    local real r
    local Bar bar

    set foo[4].real = 6.2831
    set r = foo[4].real

    set bar = foo[4]
endfunction

Seems to work, doesn't fully inline, but when you are using hashtables you are not exactly aiming for speed.
 
It is a good approach if it weren't for the fact it would break some 99% of resources using Table for the vanilla [] syntax. The overhead is not the worst thing in the world, but the fact you can't even do simple ops on the table without spamming function calls doesn't sit well with me on in terms of goals. Either JassHelper could be upgraded to support multiple operator overloads in one method, or the whole thing needs to be moved into ugly functions so as to take multiple parameters.

I could add a new type called Hash which carries the same overhead as you just identified, and otherwise extending Table. Should I make that a thing?
 
Top