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

Shared Memory

Level 26
Joined
Aug 18, 2009
Messages
4,097
Note: Ignore the hidden codes in case you are not familiar with my other system Structfollowers. My main purpose to start this thread was to tell of concepts, not how the result realization should look like.

Exposition
You can only have a certain amount of hashtables[1]. One hashtable suffices for most things, that's why I'd like to divide it neatly, instead of using multiples. vJass provides the key-function, that delivers another integer each time, so you can use them as keys in a hashtable. Even so, said function only gives you a one-dimensional series of numbers, you won't get another series that includes all of them again. That's why, in my opinion, the function should be used for the main table, specific tables will have their own way to obtain keys anyway[2]. Additionally, the key function starts at 0 or 1 to give out keys, not at the integer minimum[3], that method already blasts away half of the 4 billion slots. This does not please me - I try to change it. Furthermore, you often need a third dimension in the table to dedicate an undetermined amount of abilities to a unit for example and this unit already requires one of the two keys[4]. So I chop up the available keys in portions, to carve out a third dimension, so each unit receives a whole array of keys for use. In order to still being effective, I fragment the data, I don't dynamically reset the tables' positions where they fit but have a static max size. Thus it's crucial that when I want to assign arrays of values to an object, I only pass the first key and all other ones get calculated by the position index in the array, hence are reserved for this one array.

1. (you won't break this limit easily though unless you have a system that dynamically allocates them or you have an arithmetic array)
2. (e.g. by multiplication or powers)
3. -(2^8)^4/2 = -2^31 = -2147483648
4. (or at least is included in one of the keys)

The basic idea is

JASS:
//! textmacro GetKey takes name
    static key $name$_BASE

    static constant integer $name$ = Math.Integer.MIN + $name$_BASE
//! endtextmacro

//! textmacro GetKeyArray takes name
    static key $name$_BASE

    static constant integer $name$ = Math.Integer.MIN + Memory.IntegerKeys.Array.OFFSET + $name$_BASE * Memory.IntegerKeys.Array.SIZE
//! endtextmacro

You get unique ids in constant distances, so the ids between can be treated as part of a coherent array. The first index, which you gain by GetKeyArray, is the root key you pass to the header and stores up to which index the array holds data.

The code below is an example for a shared memory that can be implemented by other structs that want to use it.
Requires:
  • Structfollowers
  • some basic globals

    JASS:
    //! runtextmacro Folder("BasicConstants")
              globals
                  constant integer STRUCT_MAX = 8190
                  constant integer STRUCT_MIN = 1
    
                  constant integer STRUCT_BASE = STRUCT_MAX + 1
                  constant integer STRUCT_EMPTY = STRUCT_MIN - 1
    
                  constant integer NULL = STRUCT_EMPTY
              endglobals
          endscope
  • some maths

    JASS:
    //! runtextmacro Folder("Math")
              //! runtextmacro Struct("Integer")
                  static integer MIN = -2147483645
              endstruct
          endscope
    
          //! runtextmacro StaticStruct("Math")
              //! runtextmacro LinkToStaticStruct("Math", "Integer")
    
              static method RandomI takes integer lowBound, integer highBound returns integer
                  return GetRandomInt(lowBound, highBound)
              endmethod
          endstruct
  • CreateSimpleAddState (that's my standard textmacro for creating simple abstract numeric values as struct members)

    JASS:
    //! textmacro CreateSimpleAddState takes type, defaultValue
              $type$ value
    
              method Get takes nothing returns $type$
                  return this.value
              endmethod
    
              method Set takes $type$ value returns nothing
                  set this.value = value
              endmethod
    
              method Add takes $type$ value returns nothing
                  call this.Set(this.Get() + value)
              endmethod
    
              method Start takes nothing returns nothing
                  call this.Set($defaultValue$)
              endmethod
    
              method Subtract takes $type$ value returns nothing
                  call this.Set(this.Get() - value)
              endmethod
          //! endtextmacro
  • Wrappers for GameCache and HashTable (not shown here because not important)

Head:

JASS:
//! runtextmacro Folder("Memory")
    //! runtextmacro Folder("IntegerKeys")
        //! runtextmacro Struct("Array")
            static constant integer EMPTY = -1
            static constant integer OFFSET = 8192
            static constant integer SIZE = 8192  //you can have up to SIZE - 1 values in an array, that would fit with the normal max amount of instances of a struct
            static constant integer STARTED = 0  //the first index holds the amount of elements

            //! textmacro Memory_IntegerKeys_Array_CreateType takes name, type, bugConverter
                static method Count$name$s takes integer parentKey, integer key returns integer
                    return (thistype.EMPTY + Memory.IntegerKeys.GetInteger(parentKey, key))
                endmethod

                static method Count$name$sByHandle takes handle handleSource, integer key returns integer
                    return thistype.Count$name$s(GetHandleId(handleSource), key)
                endmethod

                static method Get$name$ takes integer parentKey, integer key, integer index returns $type$
                    return Memory.IntegerKeys.Get$name$(parentKey, key + thistype.EMPTY + index + 2)
                endmethod

                static method Get$name$ByHandle takes handle handleSource, integer key, integer index returns $type$
                    return thistype.Get$name$(GetHandleId(handleSource), key, index)
                endmethod

                static method Contains$name$ takes integer parentKey, integer key, $type$ value returns boolean
                    local integer iteration = Count$name$s(parentKey, key)

                    loop
                        exitwhen (iteration < thistype.STARTED)

                        exitwhen (Get$name$(parentKey, key, iteration) == value)

                        set iteration = iteration - 1
                    endloop

                    if (iteration < thistype.STARTED) then
                        return false
                    endif

                    return true
                endmethod

                static method Add$name$ takes integer parentKey, integer key, $type$ value returns boolean
                    local integer count = Count$name$s(parentKey, key) + 1

                    call Memory.IntegerKeys.SetInteger(parentKey, key, count - thistype.EMPTY)

                    call Memory.IntegerKeys.Set$name$(parentKey, key + thistype.EMPTY + count + 2, value)

                    return (count == thistype.STARTED)
                endmethod

                static method Add$name$ByHandle takes handle handleSource, integer key, $type$ value returns boolean
                    return thistype.Add$name$(GetHandleId(handleSource), key, value)
                endmethod

                static method Remove$name$ takes integer parentKey, integer key, $type$ value returns boolean
                    local integer count = Count$name$s(parentKey, key)

                    local integer iteration = count

                    loop
debug                        exitwhen (iteration < thistype.STARTED)

                        exitwhen (Get$name$(parentKey, key, iteration) == value)

                        set iteration = iteration - 1
                    endloop

debug                    if (iteration < thistype.STARTED) then

debug                        call BJDebugMsg("Failed to remove "+$BugConverter$(value)+" from array "+I2S(key)+" of parentKey "+I2S(parentKey)+" ("+I2S(count)+")")

debug                    else
                    call Memory.IntegerKeys.Set$name$(parentKey, key + thistype.EMPTY + iteration + 2, Get$name$(parentKey, key, count))

                    set count = count - 1

                    call Memory.IntegerKeys.SetInteger(parentKey, key, count - thistype.EMPTY)
debug                    endif

                    return (count == thistype.EMPTY)
                endmethod

                static method Remove$name$ByHandle takes handle handleSource, integer key, $type$ value returns boolean
                    return thistype.Remove$name$(GetHandleId(handleSource), key, value)
                endmethod

                static method Random$name$ takes integer parentKey, integer key, integer lowerBound, integer higherBound returns $type$
                    return thistype.Get$name$(parentKey, key, Math.RandomI(lowerBound, higherBound))
                endmethod

                static method Random$name$ByHandle takes handle handleSource, integer key, integer lowerBound, integer higherBound returns $type$
                    return thistype.Random$name$(GetHandleId(handleSource), key, lowerBound, higherBound)
                endmethod

                static method Random$name$All takes integer parentKey, integer key returns $type$
                    return thistype.Random$name$(parentKey, key, thistype.STARTED, Count$name$s(parentKey, key))
                endmethod
            //! endtextmacro

            //! runtextmacro Memory_IntegerKeys_Array_CreateType("Boolean", "boolean", "B2S")
            //! runtextmacro Memory_IntegerKeys_Array_CreateType("Integer", "integer", "I2S")
            //! runtextmacro Memory_IntegerKeys_Array_CreateType("Real", "real", "R2S")
            //! runtextmacro Memory_IntegerKeys_Array_CreateType("String", "string", "")
        endstruct
    endscope

    //! runtextmacro Struct("IntegerKeys")
        static HashTable CACHE

        //! runtextmacro LinkToStruct("IntegerKeys", "Array")

        static method RemoveChild takes integer parentKey returns nothing
            call CACHE.RemoveMission(parentKey)
        endmethod

        //! textmacro Memory_IntegerKeys_CreateType takes name, type
            static method Set$name$ takes integer parentKey, integer key, $type$ value returns nothing
                call CACHE.$name$.Set(parentKey, key, value)
            endmethod

            static method Set$name$ByHandle takes handle handleSource, integer key, $type$ value returns nothing
                call thistype.Set$name$(GetHandleId(handleSource), key, value)
            endmethod

            static method Remove$name$ takes integer parentKey, integer key returns nothing
                call CACHE.$name$.Remove(parentKey, key)
            endmethod

            static method Remove$name$ByHandle takes handle handleSource, integer key returns nothing
                call thistype.Remove$name$(GetHandleId(handleSource), key)
            endmethod

            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            static method Get$name$ takes integer handleSource, integer key returns $type$
                return CACHE.$name$.Get(handleSource, key)
            endmethod

            static method Get$name$ByHandle takes handle handleSource, integer key returns $type$
                return thistype.Get$name$(GetHandleId(handleSource), key)
            endmethod
        //! endtextmacro

        //! runtextmacro Memory_IntegerKeys_CreateType("Boolean", "boolean")
        //! runtextmacro Memory_IntegerKeys_CreateType("Integer", "integer")
        //! runtextmacro Memory_IntegerKeys_CreateType("Real", "real")
        //! runtextmacro Memory_IntegerKeys_CreateType("String", "string")

        static method Init takes nothing returns nothing
            set CACHE = HashTable.Create()
        endmethod
    endstruct

    //! runtextmacro Folder("StringKeys")
        //! runtextmacro Struct("Array")
            static constant integer EMPTY = -1
            static constant integer STARTED = 0

            //! textmacro Memory_StringKeys_Array_CreateType takes name, type, bugConverter
                static method Count$name$s takes string parentKey, string key returns integer
                    return (thistype.EMPTY + Memory.StringKeys.GetInteger(parentKey, key))
                endmethod

                static method Get$name$ takes string parentKey, string key, integer index returns $type$
                    return Memory.StringKeys.Get$name$(parentKey, key + I2S(thistype.EMPTY + index + 2))
                endmethod

                static method Contains$name$ takes string parentKey, string key, $type$ value returns boolean
                    local integer iteration = Count$name$s(parentKey, key)

                    loop
                        exitwhen (iteration < thistype.STARTED)

                        exitwhen (Get$name$(parentKey, key, iteration) == value)

                        set iteration = iteration - 1
                    endloop

                    if (iteration < thistype.STARTED) then
                        return false
                    endif

                    return true
                endmethod

                static method Add$name$ takes string parentKey, string key, $type$ value returns boolean
                    local integer count = Count$name$s(parentKey, key) + 1

                    call Memory.StringKeys.SetInteger(parentKey, key, count - thistype.EMPTY)

                    call Memory.StringKeys.Set$name$(parentKey, key + I2S(thistype.EMPTY + count + 2), value)

                    return (count == thistype.STARTED)
                endmethod

                static method Remove$name$ takes string parentKey, string key, $type$ value returns boolean
                    local integer count = Count$name$s(parentKey, key)

                    local integer iteration = count

                    loop
debug                        exitwhen (iteration < thistype.STARTED)

                        exitwhen (Get$name$(parentKey, key, iteration) == value)

                        set iteration = iteration - 1
                    endloop

debug                    if (iteration < thistype.STARTED) then

debug                        call BJDebugMsg("Failed to remove "+$BugConverter$(value)+" from array "+key+" of parentKey "+parentKey+" ("+I2S(count)+")")

debug                    else
                    call Memory.StringKeys.Set$name$(parentKey, key + I2S(thistype.EMPTY + iteration + 2), Get$name$(parentKey, key, count))

                    set count = count - 1

                    call Memory.StringKeys.SetInteger(parentKey, key, count)
debug                    endif

                    return (count == thistype.EMPTY)
                endmethod

                static method Random$name$ takes string parentKey, string key returns $type$
                    return thistype.Get$name$(parentKey, key, Math.RandomI(thistype.STARTED, Count$name$s(parentKey, key)))
                endmethod
            //! endtextmacro

            //! runtextmacro Memory_StringKeys_Array_CreateType("Boolean", "boolean", "B2S")
            //! runtextmacro Memory_StringKeys_Array_CreateType("Integer", "integer", "I2S")
            //! runtextmacro Memory_StringKeys_Array_CreateType("Real", "real", "R2S")
            //! runtextmacro Memory_StringKeys_Array_CreateType("String", "string", "")
        endstruct
    endscope

    //! runtextmacro Struct("StringKeys")
        static GameCache CACHE

        //! runtextmacro LinkToStruct("StringKeys", "Array")

        static method RemoveChild takes string parentKey returns nothing
            call CACHE.RemoveMission(parentKey)
        endmethod

        //! textmacro Memory_StringKeys_CreateType takes name, type
            static method Set$name$ takes string parentKey, string key, $type$ value returns nothing
                call CACHE.$name$.Set(parentKey, key, value)
            endmethod

            static method Remove$name$ takes string parentKey, string key returns nothing
                call CACHE.$name$.Remove(parentKey, key)
            endmethod

            static method Get$name$ takes string parentKey, string key returns $type$
                return CACHE.$name$.Get(parentKey, key)
            endmethod
        //! endtextmacro

        //! runtextmacro Memory_StringKeys_CreateType("Boolean", "boolean")
        //! runtextmacro Memory_StringKeys_CreateType("Integer", "integer")
        //! runtextmacro Memory_StringKeys_CreateType("Real", "real")
        //! runtextmacro Memory_StringKeys_CreateType("String", "string")

        static method Init takes nothing returns nothing
            set CACHE = GameCache.Create("blub")
        endmethod
    endstruct
endscope

//! runtextmacro StaticStruct("Memory")
    //! runtextmacro LinkToStaticStruct("Memory", "IntegerKeys")
    //! runtextmacro LinkToStaticStruct("Memory", "StringKeys")

    static method Init takes nothing returns nothing
        call IntegerKeys.Init()
        call StringKeys.Init()
    endmethod
endstruct

For implementation:

JASS:
//! textmacro Data_Implement takes baseType
    method Destroy takes nothing returns nothing
        call Memory.IntegerKeys.RemoveChild($baseType$(this).Id.Get())
    endmethod
//! endtextmacro

//! textmacro Data_Type_Implement takes baseType, whichTypeName, whichType
    method Get takes integer key returns $whichType$
        return Memory.IntegerKeys.Get$whichTypeName$($baseType$(this).Id.Get(), key)
    endmethod

    method Is takes integer key returns boolean
        return (this.Get(key) != HASH_TABLE.$whichTypeName$.DEFAULT_VALUE)
    endmethod

    method Remove takes integer key returns nothing
        call Memory.IntegerKeys.Remove$whichTypeName$($baseType$(this).Id.Get(), key)
    endmethod

    method Set takes integer key, $whichType$ value returns nothing
        call Memory.IntegerKeys.Set$whichTypeName$($baseType$(this).Id.Get(), key, value)
    endmethod
//! endtextmacro

//! textmacro Data_Type_Array_Implement takes baseType, whichTypeName, whichType
    method Contains takes integer key, $whichType$ value returns boolean
        return Memory.IntegerKeys.Array.Contains$whichTypeName$($baseType$(this).Id.Get(), key, value)
    endmethod

    method Count takes integer key returns integer
        return Memory.IntegerKeys.Array.Count$whichTypeName$s($baseType$(this).Id.Get(), key)
    endmethod

    method Get takes integer key, integer index returns $whichType$
        return Memory.IntegerKeys.Array.Get$whichTypeName$($baseType$(this).Id.Get(), key, index)
    endmethod

    method Clear takes integer key returns nothing
        call Memory.IntegerKeys.Array.Clear($baseType$(this).Id.Get(), key)
    endmethod

    method Remove takes integer key, $whichType$ value returns boolean
        return Memory.IntegerKeys.Array.Remove$whichTypeName$($baseType$(this).Id.Get(), key, value)
    endmethod

    method RemoveSorted takes integer key, $whichType$ value returns boolean
        return Memory.IntegerKeys.Array.RemoveSorted$whichTypeName$($baseType$(this).Id.Get(), key, value)
    endmethod

    method Add takes integer key, $whichType$ value returns boolean
        return Memory.IntegerKeys.Array.Add$whichTypeName$($baseType$(this).Id.Get(), key, value)
    endmethod

    method AddSorted takes integer key, $whichType$ value returns boolean
        return Memory.IntegerKeys.Array.AddSorted$whichTypeName$($baseType$(this).Id.Get(), key, value)
    endmethod

    method Random takes integer key, integer lowerBound, integer higherBound returns $whichType$
        return Memory.IntegerKeys.Array.Random$whichTypeName$($baseType$(this).Id.Get(), key, lowerBound, higherBound)
    endmethod

    method RandomAll takes integer key returns $whichType$
        return this.Random(key, Memory.IntegerKeys.Array.STARTED, this.Count(key))
    endmethod
//! endtextmacro

//additional

//! textmacro Data_Boolean_Implement takes baseType
    method Add takes integer key returns boolean
        local boolean oldValue = this.Get(key)

        call this.Set(key, HASH_TABLE.Boolean.DEFAULT_VALUE == false)

        return (oldValue == HASH_TABLE.Boolean.DEFAULT_VALUE)
    endmethod

    method Subtract takes integer key returns boolean
        local boolean oldValue = this.Get(key)

        call this.Set(key, HASH_TABLE.Boolean.DEFAULT_VALUE)

        return (oldValue != HASH_TABLE.Boolean.DEFAULT_VALUE)
    endmethod
//! endtextmacro

//! textmacro Data_Integer_Implement takes baseType
    method Contains takes integer key returns boolean
        return (this.Get(key) > HASH_TABLE.Integer.DEFAULT_VALUE)
    endmethod

    method Add takes integer key, integer value returns boolean
        local integer oldValue = this.Get(key)

        call this.Set(key, oldValue + value)

        if (oldValue != HASH_TABLE.Integer.DEFAULT_VALUE) then
            return false
        endif

        return (value != HASH_TABLE.Integer.DEFAULT_VALUE)
    endmethod

    method Subtract takes integer key, integer value returns boolean
        local integer oldValue = this.Get(key)

        set value = (oldValue - value)

        call this.Set(key, value)

        if (oldValue == HASH_TABLE.Integer.DEFAULT_VALUE) then
            return false
        endif

        return (value == HASH_TABLE.Integer.DEFAULT_VALUE)
    endmethod
//! endtextmacro

//! textmacro Data_Real_Implement takes baseType
    method Add takes integer key, real value returns boolean
        local real oldValue = this.Get(key)

        call this.Set(key, oldValue + value)

        if (oldValue != HASH_TABLE.Real.DEFAULT_VALUE) then
            return false
        endif

        return (value != HASH_TABLE.Real.DEFAULT_VALUE)
    endmethod

    method Subtract takes integer key, real value returns boolean
        local real oldValue = this.Get(key)

        set value = (oldValue - value)

        call this.Set(key, value)

        if (oldValue == HASH_TABLE.Real.DEFAULT_VALUE) then
            return false
        endif

        return (value == HASH_TABLE.Real.DEFAULT_VALUE)
    endmethod
//! endtextmacro

//! textmacro Data_String_Implement takes baseType
    method Add takes integer key, string value returns boolean
        local string oldValue = this.Get(key)

        call this.Set(key, oldValue + value)

        if (oldValue != HASH_TABLE.String.DEFAULT_VALUE) then
            return false
        endif

        return (value != HASH_TABLE.String.DEFAULT_VALUE)
    endmethod

    method Subtract takes integer key, real value returns boolean
        local string oldValue = this.Get(key)

        set value = (oldValue - value)

        call this.Set(key, value)

        if (oldValue == HASH_TABLE.String.DEFAULT_VALUE) then
            return false
        endif

        return (value == HASH_TABLE.String.DEFAULT_VALUE)
    endmethod
//! endtextmacro

//for string keys

//! textmacro Data_StringKey_Implement
    static method Destroy takes string whichString returns nothing
        call Memory.StringKeys.RemoveChild(whichString)
    endmethod
//! endtextmacro

//! textmacro Data_StringKey_Type_Implement takes whichTypeName, whichType
    static method Get takes string whichString, integer key returns $whichType$
        return Memory.StringKeys.Get$whichTypeName$(whichString, Integer.ToString(key))
    endmethod

    static method Remove takes string whichString, integer key returns nothing
        call Memory.StringKeys.Remove$whichTypeName$(whichString, Integer.ToString(key))
    endmethod

    static method Set takes string whichString, integer key, $whichType$ value returns nothing
        call Memory.StringKeys.Set$whichTypeName$(whichString, Integer.ToString(key), value)
    endmethod
//! endtextmacro

//! textmacro Data_StringKey_Type_Array_Implement takes whichTypeName, whichType
    static method Count takes string whichString, integer key returns integer
        return Memory.StringKeys.Array.Count$whichTypeName$s(whichString, Integer.ToString(key))
    endmethod

    static method Get takes string whichString, integer key, integer index returns $whichType$
        return Memory.StringKeys.Array.Get$whichTypeName$(whichString, Integer.ToString(key), index)
    endmethod

    static method Remove takes string whichString, integer key, $whichType$ value returns boolean
        return Memory.StringKeys.Array.Remove$whichTypeName$(whichString, Integer.ToString(key), value)
    endmethod

    static method Add takes string whichString, integer key, $whichType$ value returns boolean
        return Memory.StringKeys.Array.Add$whichTypeName$(whichString, Integer.ToString(key), value)
    endmethod

    static method Random takes string whichString, integer key, integer lowerBound, integer higherBound returns $whichType$
        return Memory.StringKeys.Array.Random$whichTypeName$(whichString, Integer.ToString(key), lowerBound, higherBound)
    endmethod

    static method RandomAll takes string whichString, integer key returns $whichType$
        return thistype.Random(whichString, key, Memory.IntegerKeys.Array.STARTED, thistype.Count(whichString, key))
    endmethod
//! endtextmacro

Here you get unique keys for the memory:

JASS:
//! textmacro GetKey takes name
    static key $name$_BASE

    static constant integer $name$ = Math.Integer.MIN + $name$_BASE
//! endtextmacro

//! textmacro GetKeyArray takes name
    static key $name$_BASE

    static constant integer $name$ = Math.Integer.MIN + Memory.IntegerKeys.Array.OFFSET + $name$_BASE * Memory.IntegerKeys.Array.SIZE
//! endtextmacro

Actually, you could forget GetKey and instead always take GetKeyArray since the base key vJass provides gets blown either way but I think that's semantically tidier.


Implementation:

The following shows how it is implemented in a struct, so this struct automatically gets a parentkey and you can easily store data belonging to it.

Macros:

Example on Unit:

JASS:
//! runtextmacro Folder("Unit")
    //! runtextmacro Folder("Data")
        //! runtextmacro Struct("Boolean")
            //! runtextmacro Data_Type_Implement("Unit", "Boolean", "boolean")
        endstruct

        //! runtextmacro Folder("Integer")
            //! runtextmacro Struct("Array")
                //! runtextmacro Data_Type_Array_Implement("Unit", "Integer", "integer")
            endstruct
        endscope

        //! runtextmacro Struct("Integer")
            //! runtextmacro LinkToStruct("Integer", "Array")

            //! runtextmacro Data_Type_Implement("Unit", "Integer", "integer")
        endstruct
    endscope

    //! runtextmacro Struct("Data")
        //! runtextmacro LinkToStruct("Data", "Boolean")
        //! runtextmacro LinkToStruct("Data", "Integer")

        //! runtextmacro Data_Implement("Unit")
    endstruct

    //! runtextmacro Struct("Id")
        //! runtextmacro GetKeyArray("KEY_ARRAY")

        //! runtextmacro CreateSimpleAddState("integer", "KEY_ARRAY + this")
    endstruct
endscope

//! runtextmacro BaseStruct("Unit", "UNIT")
    //! runtextmacro LinkToStruct("Unit", "Data")
    //! runtextmacro LinkToStruct("Unit", "Id")

    static method Create takes <params> returns thistype
        local unit self = <unit>
        local thistype this = thistype.allocate()

        set this.self = self

        call this.Id.Start()  //must be called to equip the unit with its parentkey for the memory

        return this
    endmethod
endstruct

Call:

When you now want to use it:

JASS:
struct IceCream
    //! runtextmacro GetKey("KEY")
    //! runtextmacro GetKeyArray("SCOOP_KEY_ARRAY")

    Waffle base

    method AddToUnit takes Unit whichUnit returns nothing
        call whichUnit.Data.Integer.Set(KEY, this)
    endmethod

    method AddScoop takes IceCreamType whichType returns nothing
        call this.Data.Integer.Array.Add(SCOOP_KEY_ARRAY, whichType)
    endmethod

    static method Create takes nothing returns thistype
        local thistype this = thistype.allocate()

        set this.base = Waffle.Create()

        return this
    endmethod
endstruct
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
What the hell.

Do matrix math and you can get n dimensions based on each dimension size limited by 2^32/2 (unless you want to check for negatives like ARGB, which would yield 2^32 at the cost of more than double overhead of 2^32/2).

dimension*size+dimension2

where dimension2 < size

where dimension*size+dimension2 < 2^32/2

This can be used to craft a lot of dimensions

((dimension*size+dimension2)*size2+dimension3)*size3+dimension4

etc

You can split the dimensions into two keys (take advantage of hashtable having two dimensions), although this shouldn't be done as then the instances can't be passed around.

I don't get why you have all of this extra complexity... furthermore, the dimension sizes really vary depending on what a person is trying to accomplish... I've used 91, 16, 8192, etc. One I've used was [8192][8192][16].

Matrix math in the programming world is used to create multi dimensional arrays. Arrays storing pointers to other arrays = jagged arrays.

jagged
Code:
int[][] numArray = new int[][] { new int[] {1,3,5}, new int[] {2,4,6,8,10} };

multidimensional
Code:
int[,] numbers = { {1, 2}, {3, 4}, {5, 6} };
 
Top