• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Jass' hidden, first-class, immutable integer arrays

Status
Not open for further replies.
Level 13
Joined
Nov 7, 2014
Messages
571
Jass' hidden, first-class, immutable integer arrays

Arrays in Jass are not first-class, but here's a simple/goofy way to emulate them:

JASS:
library acmeiardemo initializer demo uses acmeiar

private function iar_sort takes string ar returns string
    local integer len
    local integer a
    local integer b
    local integer x
    set len = iar_len(ar)
    set a = 1
    loop
        exitwhen a == len
        set x = iar_get(ar, a)
        set b = a - 1
        loop
            exitwhen b < 0 or iar_get(ar, b) <= x
            set ar = iar_set(ar, b + 1, iar_get(ar, b))
            set b = b - 1
        endloop
        set ar = iar_set(ar, b + 1, x)
        set a = a + 1
    endloop
    return ar
endfunction

private function iar_remove_negative takes string ar returns string
    local string r = ""
    local integer a
    local integer len
    local integer x

    set a = 0
    set len = iar_len(ar)
    loop
        exitwhen a == len

        set x = iar_get(ar, a)
        if x >= 0 then
            set r = iar_push(r, x)
        endif

        set a = a + 1
    endloop

    return r
endfunction

private function demo_delayed takes nothing returns nothing
    local string ar = "" // empty "integer array" (iar)
    local integer a

    set a = 0
    loop
        exitwhen a == 5
        set ar = iar_push(ar, GetRandomInt(-9, 9))
        set a = a + 1
    endloop

    call BJDebugMsg("got " + I2S(iar_len(ar)) + " elements")

    call BJDebugMsg("before sort")
    call BJDebugMsg(ar) // "builtin" to string function =)

    set ar = iar_sort(ar)
    call BJDebugMsg("after sort")
    call BJDebugMsg(ar)

    call BJDebugMsg("removing negative numbers")
    call BJDebugMsg(iar_remove_negative(ar))

    // look ma no 'call iar_destroy(ar)'
endfunction

private function demo takes nothing returns nothing
    call TimerStart(CreateTimer(), 0.0, false, function demo_delayed)
endfunction

endlibrary // acmeiardemo

acmeiar.j
JASS:
library acmeiar initializer init

static if DEBUG_MODE then
private function error takes string s returns nothing
    call BJDebugMsg("|cffFF0000[iar] error: |r" + s)
    call I2S(1/0)
endfunction
endif

// we keep the length of the array in chars [0 .. 10]

globals
    private string array g_pads
endglobals

private function pads_init takes nothing returns nothing
    set g_pads[11] = ""
    set g_pads[10] = " "
    set g_pads[9] = "  "
    set g_pads[8] = "   "
    set g_pads[7] = "    "
    set g_pads[6] = "     "
    set g_pads[5] = "      "
    set g_pads[4] = "       "
    set g_pads[3] = "        "
    set g_pads[2] = "         "
    set g_pads[1] = "          "
endfunction

private function i2s takes integer a returns string
    local string s = I2S(a)
    return g_pads[StringLength(s)] + s
endfunction

function iar_len takes string ar returns integer
    return S2I(SubString(ar, 0, 11))
endfunction

function iar_get takes string ar, integer index returns integer
    return S2I(SubString(ar, 11*(1+index), 11*(1+index) + 11))
endfunction

function iar_set takes string ar, integer index, integer val returns string
    local integer len
    local integer x

static if DEBUG_MODE then
    set len = iar_len(ar)
    if index >= len then
        call error("iar index(" + I2S(index) + ") out of bounds, iar_len(" + I2S(len) + ")")
    endif
endif

    set x = 11*(1+index)
    return SubString(ar, 0, x) + i2s(val) + SubString(ar, x + 11, StringLength(ar))
endfunction

function iar_push takes string ar, integer val returns string
    return i2s(iar_len(ar) + 1) + SubString(ar, 11, StringLength(ar)) + i2s(val)
endfunction

globals
    integer iar_pop_result = 0
endglobals

function iar_pop takes string ar returns string
    local integer len = iar_len(ar)

static if DEBUG_MODE then
    if len == 0 then
        call error("iar_pop: empty iar")
    endif
endif

    set iar_pop_result = iar_get(ar, len - 1)
    return i2s(len - 1) + SubString(ar, 11, StringLength(ar) - 11)
endfunction

private function init takes nothing returns nothing
    call pads_init()
endfunction

endlibrary // acmeiar

PS: documentation
 
Level 9
Joined
Jul 20, 2018
Messages
177
A little suggestion: do not use BJDebugMsg. It's bad function with local variable and loop.
Use these. They are net safe.
JASS:
// LocalPlayer must be set to GetLocalPlayer() during initialization.
// DebugMsgDuration is a real constant, I prefer 5 seconds.

function DebugMsg takes string s returns nothing
    debug call DisplayTimedTextToPlayer(LocalPlayer, 0., 0., DebugMsgDuration, s)
endfunction

function DebugMsgIf takes boolean bool, string s returns nothing
    static if DEBUG_MODE then
        if bool then
            call DebugMsg(s)
        endif
    endif
endfunction

function DebugMsgIfElse takes boolean bool, string s1, string s2 returns nothing
    static if DEBUG_MODE then
        if bool then
            call DebugMsg(s1)
        else
            call DebugMsg(s2)
        endif
    endif
endfunction
Actually, I took the idea of DebugMsg from sending error messages in creating an object of a vJass struct if debug mode enabled.
 
Level 18
Joined
Jun 13, 2016
Messages
580
Probably worth mentioning that active modification of a string (such as would be the case here), causes memory leaks that can actually spiral out of control very quickly.

JASS globally caches the results of every intermediate string operation and every string stored, and never clears them. Over time this can accumulate and cause very significant slowdowns as the size of this cache bloats.
 
Level 14
Joined
Oct 18, 2013
Messages
709
JASS globally caches the results of every intermediate string operation and every string stored, and never clears them. Over time this can accumulate and cause very significant slowdowns as the size of this cache bloats.

Yesterday I was pondering the usefulness of this, and with the current state of the JASS engine, it seems pretty nil (atleast for multiplayer maps). The VM could always be altered so that this isn't the case though, so it's still nice to have these code snippets floating around.
 
Status
Not open for further replies.
Top