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

Help me improve this :P

Status
Not open for further replies.
Level 12
Joined
Jan 2, 2016
Messages
973
JASS:
library TableSpecial

    globals
        private hashtable T1 = InitHashtable()
        private hashtable T2 = InitHashtable()
        private constant string EMPTY = ""
    endglobals

    function CreateTableSpecial takes integer k1, integer k2 returns nothing
        local integer i = LoadInteger(T2, 0, 1)
        local integer c
        if k1 >= 0 and not HaveSavedInteger(T2, k1 + 1, k2) then
            if i == 0 then
                set i = LoadInteger(T2, 0, 0)
                call SaveInteger(T2, k1 + 1, k2, i)
                call SaveInteger(T2, 0, 0, i + 1)
            else
                set c = LoadInteger(T2, 0, i + 1)
                call RemoveSavedInteger(T2, 0, i + 1)
                call SaveInteger(T2, 0, 1, i - 1)
                call SaveInteger(T2, k1 + 1, k2, c)
            endif
        endif
    endfunction

    function DestroyTableSpecial takes integer k1, integer k2 returns nothing
        local integer i = LoadInteger(T2, 0, 1) + 1
        local integer c = LoadInteger(T2, k1 + 1, k2)
        if k1 >= 0 and HaveSavedInteger(T2, k1 + 1, k2) then
            call RemoveSavedInteger(T2, k1 + 1, k2)
            call FlushChildHashtable(T1, c)
            call SaveInteger(T2, 0, i + 1, c)
            set c = LoadInteger(T2, 0, 0)
            if c == i then
                call FlushChildHashtable(T2, 0)
            else
                call SaveInteger(T2, 0, 1, i)
            endif
        endif
    endfunction
   
    function FlushChildHashtableSpecial takes integer k1, integer k2 returns nothing
        local integer k4
        if HaveSavedInteger(T2, k1 + 1, k2) then
            set k4 = LoadInteger(T2, k1 + 1, k2)
            call FlushChildHashtable(T1, k4)
        endif
    endfunction

//! textmacro HasSavedNRemoveSaved takes NAME
    function HaveSaved$NAME$Special takes integer k1, integer k2, integer k3 returns boolean
        local integer k4
        if HaveSavedInteger(T2, k1 + 1, k2) then
            set k4 = LoadInteger(T2, k1 + 1, k2)
            return HaveSaved$NAME$(T1, k4, k3)
        endif
        return false
    endfunction

    function RemoveSaved$NAME$Special takes integer k1, integer k2, integer k3 returns nothing
        local integer k4
        if HaveSavedInteger(T2, k1 + 1, k2) then
            set k4 = LoadInteger(T2, k1 + 1, k2)
            call RemoveSaved$NAME$(T1, k4, k3)
        endif
    endfunction
//! endtextmacro

//! runtextmacro HasSavedNRemoveSaved("Integer")
//! runtextmacro HasSavedNRemoveSaved("Real")
//! runtextmacro HasSavedNRemoveSaved("Handle")
//! runtextmacro HasSavedNRemoveSaved("Boolean")
//! runtextmacro HasSavedNRemoveSaved("String")

//! textmacro SaveNLoad takes NAME, TYPE, HANDLE, VAL
    function Save$NAME$$HANDLE$Special takes integer k1, integer k2, integer k3, $TYPE$ val returns nothing
        local integer k4
        if HaveSavedInteger(T2, k1 + 1, k2) then
            set k4 = LoadInteger(T2, k1 + 1, k2)
            call Save$NAME$$HANDLE$(T1, k4, k3, val)
        endif
    endfunction
   
    function Load$NAME$$HANDLE$Special takes integer k1, integer k2, integer k3 returns $TYPE$
        local integer k4
        if HaveSavedInteger(T2, k1 + 1, k2) then
            set k4 = LoadInteger(T2, k1 + 1, k2)
            return Load$NAME$$HANDLE$(T1, k4, k3)
        endif
        return $VAL$
    endfunction
//! endtextmacro

//! runtextmacro SaveNLoad("Boolean","boolean","","false")
//! runtextmacro SaveNLoad("Str","string","","EMPTY")
//! runtextmacro SaveNLoad("Real","real","","0.00")
//! runtextmacro SaveNLoad("Integer","integer","","0")
//! runtextmacro SaveNLoad("Player","player","Handle","null")
//! runtextmacro SaveNLoad("Widget","widget","Handle","null")
//! runtextmacro SaveNLoad("Destructable","destructable","Handle","null")
//! runtextmacro SaveNLoad("Item","item","Handle","null")
//! runtextmacro SaveNLoad("Unit","unit","Handle","null")
//! runtextmacro SaveNLoad("Ability","ability","Handle","null")
//! runtextmacro SaveNLoad("Timer","timer","Handle","null")
//! runtextmacro SaveNLoad("Trigger","trigger","Handle","null")
//! runtextmacro SaveNLoad("TriggerCondition","triggercondition","Handle","null")
//! runtextmacro SaveNLoad("TriggerAction","triggeraction","Handle","null")
//! runtextmacro SaveNLoad("TriggerEvent","event","Handle","null")
//! runtextmacro SaveNLoad("Force","force","Handle","null")
//! runtextmacro SaveNLoad("Group","group","Handle","null")
//! runtextmacro SaveNLoad("Location","location","Handle","null")
//! runtextmacro SaveNLoad("Rect","rect","Handle","null")
//! runtextmacro SaveNLoad("BooleanExpr","boolexpr","Handle","null")
//! runtextmacro SaveNLoad("Sound","sound","Handle","null")
//! runtextmacro SaveNLoad("Effect","effect","Handle","null")
//! runtextmacro SaveNLoad("UnitPool","unitpool","Handle","null")
//! runtextmacro SaveNLoad("ItemPool","itempool","Handle","null")
//! runtextmacro SaveNLoad("Quest","quest","Handle","null")
//! runtextmacro SaveNLoad("QuestItem","questitem","Handle","null")
//! runtextmacro SaveNLoad("DefeatCondition","defeatcondition","Handle","null")
//! runtextmacro SaveNLoad("TimerDialog","timerdialog","Handle","null")
//! runtextmacro SaveNLoad("Leaderboard","leaderboard","Handle","null")
//! runtextmacro SaveNLoad("Multiboard","multiboard","Handle","null")
//! runtextmacro SaveNLoad("MultiboardItem","multiboarditem","Handle","null")
//! runtextmacro SaveNLoad("Trackable","trackable","Handle","null")
//! runtextmacro SaveNLoad("Dialog","dialog","Handle","null")
//! runtextmacro SaveNLoad("Button","button","Handle","null")
//! runtextmacro SaveNLoad("TextTag","texttag","Handle","null")
//! runtextmacro SaveNLoad("Lightning","lightning","Handle","null")
//! runtextmacro SaveNLoad("Image","image","Handle","null")
//! runtextmacro SaveNLoad("Ubersplat","ubersplat","Handle","null")
//! runtextmacro SaveNLoad("Region","region","Handle","null")
//! runtextmacro SaveNLoad("FogState","fogstate","Handle","null")
//! runtextmacro SaveNLoad("FogModifier","fogmodifier","Handle","null")
//! runtextmacro SaveNLoad("Hashtable","hashtable","Handle","null")

endlibrary
This is basically a hashtable, with 3 keys.
I just made it today for 20 mins, so there must be things to improve.
Can anyone point out what could be improved, and how? :p
(Besides the textmacro, I kind a already know I should improve the 1-st one)

EDIT: Okay, fixed a bug, and improved the textmacro, improved the destructing method, what now?
EDIT 2: The way it was before wasn't really working, so I changed this and that :p
EDIT 3: Made it safe to use :D Now it wouldn't assign new key if a field already has one assigned. And also added the "HaveSaved..." function, which I haven't really used so far xP

EDIT 4: I could make it simpler - have only 2 hashtables, and a integer.
When a table is created - it gives it the value of the integer, and increases the integer's value by 1. After that - I never remove that value from the field.
Which way is better? Having 3 tables, or 2 tables + integer, but be unable to clear the tables completely :p
And meanwhilie - I prevented saving/loading any values into undeclared tables :D
 
Last edited:
Level 12
Joined
Jan 2, 2016
Messages
973
k1 = key 1
k2 = key 2
k3 = key 3

example trigger:
JASS:
function Trig_Test_Actions takes nothing returns nothing
    call CreateTableSpecial(0,0)
    call CreateTableSpecial(0,1)
    call CreateTableSpecial(0,2)
    call CreateTableSpecial(1,0)
    call SaveIntegerSpecial(0,0,0,10)
    call SaveIntegerSpecial(0,0,1,12)
    call SaveIntegerSpecial(0,0,2,14)
    call SaveIntegerSpecial(0,1,0,20)
    call SaveRealSpecial(0,1,1,25.5)
    call SaveIntegerSpecial(0,1,2,30)
    call SaveIntegerSpecial(0,2,0,50)
    call SaveIntegerSpecial(0,2,1,60)
    call SaveStrSpecial(0,2,2,"WOAH!")
    call SaveIntegerSpecial(1,0,0,100)
    call SaveIntegerSpecial(1,0,1,125)
    call BJDebugMsg(I2S(LoadIntegerSpecial(0,0,0)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(0,0,1)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(0,0,2)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(0,1,0)))
    call BJDebugMsg(R2S(LoadRealSpecial(0,1,1)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(0,1,2)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(0,2,0)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(0,2,1)))
    call BJDebugMsg(LoadStrSpecial(0,2,2))
    call BJDebugMsg(I2S(LoadIntegerSpecial(1,0,0)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(1,0,1)))
    call DestroyTableSpecial(0,1)
    call DestroyTableSpecial(0,2)
    call DestroyTableSpecial(0,0)
    //call DestroyTableSpecial(1,0)
    call CreateTableSpecial(0,0)
    //call CreateTableSpecial(0,1)
    call CreateTableSpecial(0,2)
    call CreateTableSpecial(1,0)  // doesn't do anything, cuz it hasn't been destroyed.
    call SaveIntegerSpecial(0,0,0,10)
    call SaveIntegerSpecial(0,0,1,12)
    call SaveIntegerSpecial(0,0,2,14)
    call SaveIntegerSpecial(0,1,0,20)
    call SaveIntegerSpecial(0,1,1,25)
    call SaveIntegerSpecial(0,1,2,30)
    call SaveIntegerSpecial(0,2,0,50)
    call SaveIntegerSpecial(0,2,1,60)
    call SaveIntegerSpecial(0,2,2,70)
    call SaveIntegerSpecial(1,0,0,100)
    call SaveIntegerSpecial(1,0,1,125)
    call BJDebugMsg(I2S(LoadIntegerSpecial(0,0,0)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(0,0,1)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(0,0,2)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(0,1,0)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(0,1,1)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(0,1,2)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(0,2,0)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(0,2,1)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(0,2,2)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(1,0,0)))
    call BJDebugMsg(I2S(LoadIntegerSpecial(1,0,1)))
    call DestroyTableSpecial(0,0)
    call DestroyTableSpecial(0,1)
    call DestroyTableSpecial(0,2)
    call DestroyTableSpecial(1,0)
endfunction

//===========================================================================
function InitTrig_Test takes nothing returns nothing
    set gg_trg_Test = CreateTrigger(  )
    call TriggerRegisterPlayerEventEndCinematic( gg_trg_Test, Player(0) )
    call TriggerAddAction( gg_trg_Test, function Trig_Test_Actions )
endfunction

This displays:
10
12
14
20
25.500
30
50
60
WOAH!
100
125
10
12
14
0 // didn't re-create the table
0 // same here
0 // and here
50
60
70
100
125

The way it works is:
When I 'create' a table - "1, 0" - it saves a UNIQUE key into one hashtable's "1 , 0", and uses this key as a parent later on.
So when I create a table "930526 , 82405" - it gives me a key, that isn't used. Let's say "42".
And when I want to save something into "930526, 82405, 56912" - it will save it into a hashtable's "42, 56912"

I'm using 3 tables to make it work:
T1 - hashtable to save stuff into
T2 - hashtable, that keeps the parent keys for T1
T3 - hashtable, keeping track which keys have been assigned, and which havent. It gives key (0) 1-st, then key (1), key (2), and so on.
Let's say it has assgned 10 keys, and then the 6-th table is destroyed (6 stops being used)
it is saved into T3, and is assigned next time a table is created.
If more than 1 tables have been destroyed - it saves all their keys (and keeps track how many "destroyed" keys are saved), and re-assinges then in reverse order - last one destroyed gets re-assigned 1-st.

When the amount of destroyed keys becomes equal to the amount of assigned keys - it flushes the hashtable, and starts the count from 0.

T3 also keeps track of which fields of T2 have a key assigned to them :p
(tho this may be unnecessary)
EDIT: Okay, stopped saving booleans in T3, I'm using it simply to keep the keys. Now I'm just checking if anything is saved in T2.
But now that I think about it - I could stop using T3 at all :p

EDIT 2: Okay, got rid of the 3-rd hashtable, now I'm using only T1, and T2. Now it works more like:
T1 - keeps the data
T2 - keeps the keys, which are being used, and the unique keys for T1.
When a table ( 1, 1 ) is created - T2 creates a unique key, and saves it in its ( 2 , 1 ), because the 1-st row (0) is used to store the free keys :p
 
Last edited:
Level 11
Joined
Dec 19, 2012
Messages
411
Hm, the only thing I feel like is, it would be messy when using it. like (just examples) :
JASS:
	local integer i = 0
	local integer i2 = 0
	local integer i3 = 0
	
	loop
		call CreateTable4D(i, i2)
		
		loop
			loop
				call SaveInteger4D(i, i2, i3, value)
				exitwhen i3 == 10
				set i3 = i + 1
			endloop
		
			exitwhen i2 == 5
			set i2 = i2 + 1
		endloop
		
		exitwhen i == 5
		set i = i + 1
	endloop

and

JASS:
	call CreateTable4D(0, 0)
	call SaveInteger4D(0, 0, 0, 1)
	call SaveMultiboard4D(0, 0, 1, CreateMultiboard())
	call SaveUnit4D(0, 0, 2, CreateUnit(...))
	call SaveBoolean4D(0, 0, 3, true)

And so you will need some time to understand the "array" position, and the code.
 
Level 12
Joined
Jan 2, 2016
Messages
973
yeah, I admit that I'm felt little confused at 1-st.
I'm not used to using 3 keys for saving data.
However, I made it with a purpose.
I want to save different things into ability's id handle, and I want differnt units to be able to have different abilities saved into their hashtable, and each unit's abilities to have unique things saved int them.

Before I was dynamically saving a hashtable into the unit's table, and there I was saving the data for different abilities.
However, this way of doing things is limited to 250 units having data saved at once.
While with this table I can just do:
JASS:
set id = GetHandleId(u)
set abil = 'A000'
call CreateTableSpecial(id, abil)
call SaveRealSpecial(id, abil, 'time', 10.0)
call SaveRealSpecial(id, abil, 'line', 0.76)
call SaveRealSpecial(id, abil, 'hype', 1.00)
set abil = 'A001'
call CreateTableSpecial(id, abil)
call SaveRealSpecial(id, abil, 'time', 5.0)
call SaveRealSpecial(id, abil, 'line', 0.90)
call SaveRealSpecial(id, abil, 'hype', 0.6)
set id = GetHandleId(c)
call CreateTableSpecial(id, abil)
call SaveRealSpecial(id, abil, 'time', 12.0)
call SaveRealSpecial(id, abil, 'line', 1.24)
call SaveRealSpecial(id, abil, 'hype', 1.01)
set abil = 'A002'
call CreateTableSpecial(id, abil)
call SaveRealSpecial(id, abil, 'time', 2.0)
call SaveRealSpecial(id, abil, 'line', 0.4)
call SaveRealSpecial(id, abil, 'hype', 0.8)
It's not so confusing like this :D

And yes, I know I can just save a struct into a table like call SaveInteger( Table, id, abil, struct )
I already am doing that. Kind a had to, since I made this table just yesterday.
However, now I need to save multiple structs for each ability :D
So this table will come in handy :)
 
Level 11
Joined
Dec 19, 2012
Messages
411
As long as you feel handy, go ahead and use your own table version (or you can use mine, but I cant guarantee that it contains no bug). I don't think there is much more to improve unless you change the algorithm of how the table works :)
 
Level 12
Joined
Jan 2, 2016
Messages
973
By the way, what do you think of this function
JASS:
function FlushParentHashtableSpecial takes nothing returns nothing
    local integer i = LoadInteger(T2, 0, 0)
    local integer j = 0
    loop
        exitwhen j >= i
        call FlushChildHashtable( T1, j )
        set j = j + 1
    endloop
endfunction
It only flushes tho, doesn't destroy xP
 
Level 12
Joined
Jan 2, 2016
Messages
973
And hmm, now I'm kind a wondering shouldn't I just do this:
JASS:
    function GetKey takes integer k1, integer k2 returns integer
        local integer i
        local integer c
        if k1 >= 0 and not HaveSavedInteger(T2, k1 + 1, k2) then
            set i = LoadInteger(T2, 0, 1)
            if i == 0 then
                set i = LoadInteger(T2, 0, 0)
                call SaveInteger(T2, k1 + 1, k2, i)
                call SaveInteger(T2, 0, 0, i + 1)
                return i
            else
                set c = LoadInteger(T2, 0, i + 1)
                call RemoveSavedInteger(T2, 0, i + 1)
                call SaveInteger(T2, 0, 1, i - 1)
                call SaveInteger(T2, k1 + 1, k2, c)
                return c
            endif
        elseif k1 >= 0 then
            return LoadInteger(T2, k1 + 1, k2)
        endif
    endfunction

    function StopUsingKey takes integer k1, integer k2 returns nothing
        local integer i = LoadInteger(T2, 0, 1) + 1
        local integer c = LoadInteger(T2, k1 + 1, k2)
        if k1 >= 0 and HaveSavedInteger(T2, k1 + 1, k2) then
            call RemoveSavedInteger(T2, k1 + 1, k2)
            call FlushChildHashtable(T1, c)
            call SaveInteger(T2, 0, i + 1, c)
            set c = LoadInteger(T2, 0, 0)
            if c == i then
                call FlushChildHashtable(T2, 0)
            else
                call SaveInteger(T2, 0, 1, i)
            endif
        endif
    endfunction

And then just use it like:

JASS:
function Somefunc takes nothing returns nothing
    local integer k = GetKey(1, 1)
    call SaveInteger( TableSpecial_T1, k, 0, 100 )
    call SaveInteger( TableSpecial_T1, k, 1, 120 )
    call StopUsingKey(1, 1)
endfunction

This way the system will be lighter, and it can use indexing to save the keys, if they are linked to units :p
Even if they aren't - I can just call "GetKey" to get them again, even if it's a microsecond slower :D
 
Status
Not open for further replies.
Top