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

Mutable strings

Status
Not open for further replies.
Level 13
Joined
Nov 7, 2014
Messages
571
Strings in Jass are immutable and there really isn't much support for working with them. This is an example implementation of mutable strings that are somewhat easier to work with.

JASS:
library mutstrdemo initializer mutstr_demo uses libmutstr, libH

function im_ascii_to_lower takes H_u8 s returns nothing
    call ascii_to_lower(s)
    call s.destroy() // s is an immediate
endfunction

function im_ascii_to_upper takes H_u8 s returns nothing
    call ascii_to_upper(s)
    call s.destroy()
endfunction

globals
    mutstr g_s
    boolean dir_is_up
    integer color_offset
    integer letters_offset
endglobals

function prev_hex_digit takes integer d returns integer
    local integer p
    if d == '0' then
        set p = 'F'
    elseif d == '1' then
        set p = '0'
    elseif d == '2' then
        set p = '1'
    elseif d == '3' then
        set p = '2'
    elseif d == '4' then
        set p = '3'
    elseif d == '5' then
        set p = '4'
    elseif d == '6' then
        set p = '5'
    elseif d == '7' then
        set p = '6'
    elseif d == '8' then
        set p = '7'
    elseif d == '9' then
        set p = '8'
    elseif d == 'A' then
        set p = '9'
    elseif d == 'B' then
        set p = 'A'
    elseif d == 'C' then
        set p = 'B'
    elseif d == 'D' then
        set p = 'C'
    elseif d == 'E' then
        set p = 'D'
    elseif d == 'F' then
        set p = 'E'
    else
        call assert("[prev_hex_digit]: d = " + I2S(d) + " is not a hex digit", false)
    endif
    return p
endfunction

function next_hex_digit takes integer d returns integer
    local integer p
    if d == '0' then
        set p = '1'
    elseif d == '1' then
        set p = '2'
    elseif d == '2' then
        set p = '3'
    elseif d == '3' then
        set p = '4'
    elseif d == '4' then
        set p = '5'
    elseif d == '5' then
        set p = '6'
    elseif d == '6' then
        set p = '7'
    elseif d == '7' then
        set p = '8'
    elseif d == '8' then
        set p = '9'
    elseif d == '9' then
        set p = 'A'
    elseif d == 'A' then
        set p = 'B'
    elseif d == 'B' then
        set p = 'C'
    elseif d == 'C' then
        set p = 'D'
    elseif d == 'D' then
        set p = 'E'
    elseif d == 'E' then
        set p = 'F'
    elseif d == 'F' then
        set p = '0'
    else
        call assert("[next_hex_digit]: d = " + I2S(d) + " is not a hex digit", false)
    endif
    return p
endfunction

function im_next_hex_digit_H_u8 takes H_u8 s returns nothing
    local integer i = 0
    local integer ii = s.len
    loop
        exitwhen i >= ii
        set s[i] =  next_hex_digit(s[i])
        set i = i + 1
    endloop

    call s.destroy() // s is an immediate
endfunction

function im_prev_hex_digit_H_u8 takes H_u8 s returns nothing
    local integer i = 0
    local integer ii = s.len
    loop
        exitwhen i >= ii
        set s[i] =  prev_hex_digit(s[i])
        set i = i + 1
    endloop

    call s.destroy()
endfunction

function print_mutstr takes nothing returns nothing
    call ClearTextMessages()
    call BJDebugMsg(g_s.str())

    if g_s[color_offset] == 'F' then
        set dir_is_up = false
    elseif g_s[color_offset] == '0' then
        set dir_is_up = true
    endif

    if dir_is_up then
        call im_next_hex_digit_H_u8(g_s.buf.H(color_offset, color_offset + 6))
        set g_s.dirty = true

        call im_ascii_to_upper(g_s.buf.H(letters_offset, letters_offset + 26))
    else
        call im_prev_hex_digit_H_u8(g_s.buf.H(color_offset, color_offset + 6))
        set g_s.dirty = true

        call im_ascii_to_lower(g_s.buf.H(letters_offset, letters_offset + 26))
    endif
endfunction

function mutstr_demo takes nothing returns nothing
    local integer i
    set g_s = mutstr.create()

    call g_s.push2(0xCE, 0xB1)
    call g_s.push_string(">count leaves\n")
    call g_s.push_string("|cff")
    set color_offset = g_s.len
    call g_s.push_string("000000There are 69105 leaves here.|r\n")

    set i = 0x91
    loop
        exitwhen i > 0xA9
        call g_s.push2(0xCE, i)
        set i = i + 1
    endloop

    set i = 0xB1
    loop
        exitwhen i > 0xBF
        call g_s.push2(0xCE, i)
        set i = i + 1
    endloop

    set i = 0x80
    loop
        exitwhen i > 0x89
        call g_s.push2(0xCF, i)
        set i = i + 1
    endloop

    call g_s.push(10)

    set letters_offset = g_s.len
    call g_s.push_string("ABCDEFGHIJKLMNOPQRSTUVWXYZ\n")

    set dir_is_up = true
    call TimerStart(CreateTimer(), 0.1, true, function print_mutstr)
endfunction

endlibrary
 

Attachments

  • bytes-string-ability.w3a.txt
    342 bytes · Views: 47
  • libmutstr.j
    9.5 KB · Views: 45
  • libH.j
    59.7 KB · Views: 47
Last edited:
Level 13
Joined
Nov 7, 2014
Messages
571
Could you explain the purpose of the library?

When one doesn't have to decode the bytes of a string every time they want to poke at them, things become simpler (and more efficient?).

e.g sorting strings:

JASS:
function mutstrs_cmp takes mutstr a, mutstr b returns integer
    local integer a_len = a.len
    local integer b_len = b.len
    local integer i

    if a_len != b_len then
        set i = 0
        loop
            if i == a_len then
                return -1
            endif
            if i == b_len then
                return 1
            endif
            if a[i] < b[i] then
                return -1
            endif
            if a[i] > b[i] then
                return 1
            endif

            set i = i + 1
        endloop
    else
        set i = 0
        loop
            if i == a_len then
                return 0
            endif
            if a[i] < b[i] then
                return -1
            endif
            if a[i] > b[i] then
                return 1
            endif

            set i = i + 1
        endloop
    endif

    // unreachable
    return 0
endfunction

function mutstrs_sort_asc takes nothing returns nothing
    set cmp_result = mutstrs_cmp(mutstr_a, mutstr_b)
endfunction

function mutstrs_sort_desc takes nothing returns nothing
    set cmp_result = mutstrs_cmp(mutstr_b, mutstr_a)
endfunction

function sort_H_mutstr_insertion takes H_int /*H_mutstr*/ s, code cmp_func returns nothing
    local integer i = 1
    local integer ii = s.len
    local integer j

    loop
        exitwhen i >= ii
        set mutstr_a = mutstr(s[i])

        set j = i - 1
        loop
            if j < 0 then
                exitwhen true
            endif

            set mutstr_b = mutstr(s[j])

            call call_func(cmp_func)
            if cmp_result >= 0 then
                exitwhen true
            endif

            set s[j+1] = mutstr_b
            set j = j - 1
        endloop

        set s[j+1] = mutstr_a
        set i = i + 1
    endloop
endfunction

private function H_mutstr_to_str takes H_int /*H_mutstr*/ s returns string
    local string r
    local integer i

    set r = "["
    if s.len > 0 then
        set r = r + "\"" + mutstr(s[0]).str() + "\""
        set i = 1
        loop
            exitwhen i >= s.len
            set r = r + " " + "\"" + mutstr(s[i]).str() + "\""
            set i = i + 1
        endloop
        set r = r + "]"
    endif

    return r
endfunction

public function sort_H_mutstr_test takes nothing returns nothing
    local H_int /*H_mutstr*/ s = H_int(0)
    local string t

    set s = s.push(integer(mutstr.from_string("")))
    set s = s.push(integer(mutstr.from_string("Q")))
    set s = s.push(integer(mutstr.from_string("A")))
    set s = s.push(integer(mutstr.from_string("a")))
    set s = s.push(integer(mutstr.from_string("B")))
    set s = s.push(integer(mutstr.from_string("∑")))
    set s = s.push(integer(mutstr.from_string("aa")))
    set s = s.push(integer(mutstr.from_string("™")))
    set s = s.push(integer(mutstr.from_string("π")))
    set s = s.push(integer(mutstr.from_string("Z")))
    set s = s.push(integer(mutstr.from_string("Ω")))
    set s = s.push(integer(mutstr.from_string("Q")))

    if false then
        call writeln(H_mutstr_to_str(s))
        call sort_H_mutstr_insertion(s, function mutstrs_sort_asc)
        call writeln(H_mutstr_to_str(s))
        call sort_H_mutstr_insertion(s, function mutstrs_sort_desc)
        call writeln(H_mutstr_to_str(s))
    endif

    call sort_H_mutstr_insertion(s, function mutstrs_sort_asc)
    set t = H_mutstr_to_str(s)
    call assert("[sort_H_mutstr_test] 1", "[\"\" \"A\" \"B\" \"Q\" \"Q\" \"Z\" \"a\" \"aa\" \"Ω\" \"π\" \"™\" \"∑\"]" == t)

    call sort_H_mutstr_insertion(s, function mutstrs_sort_desc)
    set t = H_mutstr_to_str(s)
    call assert("[sort_H_mutstr_test] 2", "[\"∑\" \"™\" \"π\" \"Ω\" \"aa\" \"a\" \"Z\" \"Q\" \"Q\" \"B\" \"A\" \"\"]" == t)
endfunction
 

Deleted member 219079

D

Deleted member 219079

Can you put the code in [code=jass][/code] tags?
 
Level 6
Joined
Jul 30, 2013
Messages
282
warcraft 3 strings are UTF8, as long as you are dealing with text you dont really want to poke at the underlying bytes..

you could want to construct a new string peacewise but then sth that looks like a java StringBuilder would be a lot more usable.. or just a loop and repeated concatenation.. its not that bad. jass strings cant get too long anyway ...

or you could want to parse the string in which case methods to split a string into substrings at certain delimiters could be useful..
or a way to iterate over the codepoints possibly if you are parsing eg json?



i dont really see many uses why it would be necessary to have this system.
you either want to construct a new string in which case you want a builder of some sort, and its just fine if it emits a standard string at the end.
or you want some sort of iterator or parser interfaces to easier extract data from a string, but you dont necessarily need or want to change the underlying string to do that


in closing i'd say i see a lot of issues with jass2 strings, but immutability is not one of them.
 
Status
Not open for further replies.
Top