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

HashTable for struct values

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

Can hashtables have instances of structs as values?

From my understanding structs are internally just integers, so this should work ok as outlined below?

JASS:
library HashTable initializer initTable

globals
  hashtable ht = InitHashtable()
endglobals

struct MyStruct
integer a = 0
endstruct

function load takes integer id returns MyStruct //or integer?
    return LoadInteger(ht, id, 0)
endfunction

private function initTable takes nothing returns nothing
    local MyStruct m = MyStruct.create()
    set m.a = 5
    call SaveInteger(ht, 'hfoo', 0, m) //need to cast m to int?
    set m = MyStruct.create() //this will create a new struct instance?
    set m.a = 6
    call SaveInteger(ht, 'n00b', 0, m)
endfunction
...
load('hfoo') //this will return what?  
               //a pointer to the struct?  its integer index?
load('hfoo').a == 5 //true? is this valid?
load('n00b').a == 6 //true?  
endlibrary
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
You should use the this and thistype keywords. (when using methods) It is a lot nicer.
I prefer methods as the thistype comes in handy whenever you change the name of the struct.

Example:

JASS:
method load takes integer id returns thistype //or integer? thistype / struct is an integer. 
    return LoadInteger(ht, id, 0)
endmethod

private static method initTable takes nothing returns nothing
    local thistype this = thistype.create()
    set this.a = 5  //  Could also be   .a = 5
    call SaveInteger(ht, 'hfoo', 0, this) //need to cast m to int?    m / this as i have changed it is already an integer.
    set this = thistype.create() //this will create a new struct instance?   yes
    set this.a = 6
    call SaveInteger(ht, 'n00b', 0, this)
endmethod

this also needs to be changed.

JASS:
load('hfoo') //this will return what?  
               //a pointer to the struct?  its integer index?
load('hfoo').a == 5 //true? is this valid?
load('n00b').a == 6 //true?

to this

JASS:
local thistype this = load('hfoo', 0)
The above will load the struct instance

You can also save struct instances to an integer array and load it like that.
I did that on a few of my systems. I believe my item drop system and my item recipe system use this method.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
bleh

JASS:
//this is a struct

globals
    integer instanceCount = 0
    integer array recycler
endglobals


function CreateInstance takes nothing returns integer
    local integer this = recycler[0]

    if (this == 0) then
        set this = instanceCount + 1
        set instanceCount = this
    else
        set recycler[0] = recycler[this]
    endif

    return this
endfunction

function DestroyInstance takes integer this returns nothing
    set recycler[this] = recycler[0]
    set recycler[0] = this
endfunction

That is literally all it is. What about the fields?

JASS:
globals
    integer array field1
    integer array field2
    integer array field3
    integer array field4
endglobals

what is myStruct.field1?

field1[myStruct]

And finally

JASS:
local integer instance = CreateInstance()

set field1[instance] = 5
set field2[instance] = 6

call DestroyInstance(instance)



And that is literally what a struct is. There are a few extra things depending on what you do, but that's the bare bones.

So yes, a struct is an integer. Look at the code : p, it's literally an integer. The recycler array is a stack. The instanceCount is just a counter. This ensures that you get a unique integer. If the stack is empty, increase the counter. If it's not empty, pop the stack. When you destroy, push the thing on to the stack. That's all there is to it.

The fields are just arrays, as I showed.

What are the methods? Just functions.

function MyMethod takes integer this returns nothing

I've said all of this before, but you are asking questions that show that you don't get this at all : p


What's up with all of the weirdness then? The OO stuffs? it's just syntactic sugar. All it does is directly translate to the code I showed above. It is literally a "pretty wrapper"


Now please tell me that this is all clear to you now.

edit
Here is default struct code from vJASS (the output). It's not very good actually, if you read it ; p. It generates 3 variables instead of 2 for one.

JASS:
constant integer si__MyStruct=1
integer s__MyStruct_instanceCount= 0
integer s__MyStruct_recycle= 0
integer array s__MyStruct_recycleNext

function s__MyStruct_create takes nothing returns integer
    local integer this
    if ( s__MyStruct_recycle == 0 ) then
        set s__MyStruct_instanceCount=s__MyStruct_instanceCount + 1
        set this=s__MyStruct_instanceCount
    else
        set this=s__MyStruct_recycle
        set s__MyStruct_recycle=s__MyStruct_recycleNext[s__MyStruct_recycle]
    endif
    return this
endfunction

function s__MyStruct_destroy takes integer this returns nothing
    set s__MyStruct_recycleNext[this]=s__MyStruct_recycle
    set s__MyStruct_recycle=this
endfunction

The super modern ones only generate 1 variable, the stack ;). They have no counter.

JASS:
        private static integer array recycler
        
        static method allocate takes nothing returns thistype
            local thistype this = recycler[0]
            
            set recycler[0] = recycler[this]
            
            return this
        endmethod
        
        method deallocate takes nothing returns nothing
            set recycler[this] = recycler[0]
            set recycler[0] = this
        endmethod
 
Level 15
Joined
Aug 7, 2013
Messages
1,337
JASS:
local thistype this = load('hfoo', 0)
The above will load the struct instance

You can also save struct instances to an integer array and load it like that.
I did that on a few of my systems. I believe my item drop system and my item recipe system use this method.

If I wanted to cut to the chase, could I not just have the load function return the struct, e.g.

JASS:
function load takes integer id returns thistype //or do I need to specify the struct, e.g. MyStruct?
    local thistype this = LoadInteger(ht, id, 0)
    return this
endfunction

@Nestharus: Part of my ignorance is from reading the vJass manual, which basically called structs a way of bringing OOP into the language. If structs are objects, then as a coder of Jass I should not need to care about the internal implementation. This is from my understanding of how objects behave in languages like Java and Python.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
thistype(LoadInteger(ht, 'hfoo', 0)).a
thistype[LoadInteger(ht, 'hfoo', 0)].a

The [] can be overloaded tho


Other interesting things you can do

JASS:
struct Hashtable extends array
    private static hashtable table = InitHashtable()

    static method operator [] takes integer i returns thistype
        return i
    endmethod
    method operator [] takes integer i returns thistype
        return LoadInteger(table, this, i)
    endmethod
    method operator []= takes integer i, integer b returns nothing
        call SaveInteger(table, this, i, b)
    endmethod
endstruct

integer i = Hashtable[5][6]
set Hashtable[5][6] = 4

You can actually change them together too through multiple structs, like

table[5][6][7] //3 dimensional and instanced

edit
@Nestharus: Part of my ignorance is from reading the vJass manual, which basically called structs a way of bringing OOP into the language. If structs are objects, then as a coder of Jass I should not need to care about the internal implementation. This is from my understanding of how objects behave in languages like Java and Python.

However, you are asking a lot of lame questions because you won't learn how they operate. If you look at the very top of my post, it's very, very simple. If you read those few lines of code, you will be able to answer your own questions because you will understand what they are. Practically every vJASS programmer knows the internal workings of a struct ;P. You'd have to be pretty noob not to know them.

You can't treat JASS or vJASS like you do Java. You have to be very creative a lot of the time and take advantage of the inner workings of the language :p. For example, modules are meant to work one way, but if you know how they actually work, then you can use them in a variety of ways that were unintended by the original author ;). Structs were meant to work one way, but once again, if you know how they work, you can do a lot of crazy stuff.

You'll also improve your code. If you compare the vJASS struct allocator to the one in the Alloc module, you should notice some pretty big differences. Put simply, the vexorian vjass allocator/deallocator kinda suck ^)^.

Also, avoid using hashtables. We have this

http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/

And that's not possible to write unless you know the inner workings of structs ; P

Until you learn this stuff, you are going to be very limited and very confused ;)

we also have insanity resources like this

http://www.hiveworkshop.com/forums/jass-resources-412/snippet-trigger-240414/

Once again, not possible without a deep understanding of every behavior of vJASS. That one actually also requires a deep understanding of JASS too (not the syntax, the inner workings), and most of the inner workings of JASS can only be guessed at : p.

This one requires that you know how texttags are indexed, including the limits and behaviors of what happens when you go over those limits.

http://www.hiveworkshop.com/forums/jass-resources-412/snippet-texttag-213488/

attack indexing, which isn't possible, requires that you know the damage handling and combat system of warcraft 3 very intimately


Point is, if you wanna be good, learn this stuff. If you wanna be another noob, then just stay in the dark ^_^.
 
Last edited:
Level 15
Joined
Aug 7, 2013
Messages
1,337
I have been reading through it, just takes me a while to internalize.

Also, it is a lot easier to learn this stuff by asking these kind of questions and discussing them, than via trial and error. It's sort of like a bootstrapping learning mechanism. The manuals on vJASS did not even mention the existence of hash tables (I suppose that's sound since this would be in the manual for JASS) nor did they discuss the underlying implementations of things like struct in sufficient detail that I would not have questions (for example efficiency/performance).
 
Last edited:
JASS:
function load takes integer id returns thistype //or do I need to specify the struct, e.g. MyStruct?
    local thistype this = LoadInteger(ht, id, 0)
    return this
endfunction

==>

JASS:
function load takes integer id returns thistype //or do I need to specify the struct, e.g. MyStruct?
    return LoadInteger(ht, id, 0)
endfunction

thistype only works inside a struct, remember that...

so that should be

JASS:
struct A
static method load takes integer id returns thistype
    return LoadInteger(ht, id, 0)
endmethod
end

or if you need it outside of the struct
JASS:
function load takes integer id returns STRUCT_NAME //you need the name of the struct
    return LoadInteger(ht, id, 0)
endfunction
 
Status
Not open for further replies.
Top