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

[Snippet] String

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Jass implementation of string library from c++ accommodated for jass environment.

JASS:
/*****************************************************************************
*
*    String v2.3.0.6
*       by Bannar aka Spinnaker
*
*    Jass version of string library.
*
******************************************************************************
*
*    struct String:
*
*       readonly static constant integer npos
*          special value, the exact meaning depends on the context 
*
*
*       String ctors & dctors:
*
*        | static method create takes string s returns thistype
*        |    default ctor
*        |
*        | method destroy takes nothing returns nothing
*        |    default dctor
*        |
*        | static method operator [] takes thistype js returns thistype
*        |    copy ctor
*
*
*       Capacity:
*
*        | method empty takes nothing returns boolean
*        |    checks whether the string is empty
*        |
*        | method size takes nothing returns integer
*        |    returns the number of characters
*        |
*        | static constant method maxSize takes nothing returns integer
*        |    returns the maximum number of characters
*
*
*       Element access:
*
*        | method operator [] takes integer pos returns string
*        |    access specified character
*        |
*        | method operator []= takes integer pos, string s returns nothing
*        |    sets specified character
*        |
*        | method operator front takes nothing returns string
*        |    accesses the first character
*        |
*        | method operator back takes nothing returns string
*        |    accesses the last character
*        |
*        | method operator str takes nothing returns string
*        |    returns value of this string
*
*
*       Operations:
*
*        | method clear takes nothing returns nothing
*        |    clears the contents
*        |
*        | method assign takes string str returns thistype
*        |    replaces this string with a copy of str
*        |
*        | method assignSubstring takes string str, integer pos, integer count returns thistype
*        |    replaces this string with substring of str
*        |
*        | method insert takes integer pos, string str returns thistype
*        |    inserts str before character pointed by pos
*        |
*        | method insertSubstring takes integer pos, string str, integer subpos, integer count returns thistype
*        |    inserts substring of str before character pointed by pos
*        |
*        | method erase takes integer pos, integer count returns thistype
*        |    erases count characters starting at pos
*        |
*        | method pop takes nothing returns thistype
*        |    removes the last character 
*        |
*        | method shift takes nothing returns thistype
*        |    removes the first character 
*        |
*        | method append takes string str returns thistype
*        |    appends str to the end of this string
*        |
*        | method appendSubstring takes string str, integer pos, integer count returns thistype
*        |    appends substring of str to the end of this string
*        |
*        | method compare takes string str returns integer
*        |    compares value of this string with str
*        |
*        | method compareSubstrings takes integer pos, integer len, string str, integer subpos, integer sublen returns integer
*        |    compares substring of this string with substring of str
*        |
*        | method replace takes integer pos, integer count, string str returns thistype
*        |    replaces count characters starting at pos with str
*        |
*        | method replaceSubstrings takes integer pos, integer len, string str, integer subpos, integer sublen returns thistype
*        |    replaces len characters starting at pos with substring of str
*        |
*        | method substr takes integer pos, integer count returns string
*        |    returns substring of count characters starting at pos
*        |
*        | method resize takes integer count returns nothing
*        |    changes the number of characters stored
*
*
*       Search:
*
*        | method find takes string str returns integer
*        |    searches for the first occurrence of string str
*        |
*        | method findBuffer takes string str, integer pos, integer count returns integer
*        |    finds the first substring equal to the first count characters of str starting from pos
*        |
*        | method rfind takes string str returns integer
*        |    searches for the last occurrence of string s
*        |
*        | method rfindBuffer takes string str, integer pos, integer count returns integer
*        |    finds the last substring equal to the first count characters of str starting from pos
*
*
*       Case conversion:
*
*        | method capital takes nothing returns string
*        |    returns the value of string with first character in upper and all subsequent in lower case
*        |
*        | method upper takes nothing returns string
*        |    returns the value of this string in upper case
*        |
*        | method lower takes nothing returns string
*        |    returns the value of this string in lower case
*
*
*****************************************************************************/
library String

    struct String extends array
        readonly static constant integer npos = -1
        private static integer count = 0
        private thistype recycle

        private string value
        private integer length

        static method create takes string s returns thistype
            local thistype this = thistype(0).recycle

            if this == 0 then
                set count = count + 1
                set this = count
            else
                set thistype(0).recycle = this.recycle
            endif

            set value = s
            set length = StringLength(s)

            return this
        endmethod

        method clear takes nothing returns nothing
            set value = null
            set length = 0
        endmethod

        method destroy takes nothing returns nothing
            call clear()

            set this.recycle = thistype(0).recycle
            set thistype(0).recycle = this
        endmethod

        static method operator [] takes thistype js returns thistype
            return create(js.value)
        endmethod

        method empty takes nothing returns boolean
            return length == 0
        endmethod

        method size takes nothing returns integer
            return length
        endmethod

        static constant method maxSize takes nothing returns integer
            return 1023
        endmethod

        // private asserts for String objects
        private method assert_pos takes integer pos, string f returns boolean
            debug if ( pos < 0 or pos >= length ) then
                debug call DisplayTimedTextFromPlayer(GetLocalPlayer(),0,0,60,"String::assert_pos failed at "+f+" for instance "+I2S(this)+". Invalid index at position "+I2S(pos)+".")
            debug endif

            return ( pos >= 0 and pos < length )
        endmethod

        private method assert_size takes integer count, string f returns boolean
            debug if ( count > maxSize() ) then
                debug call DisplayTimedTextFromPlayer(GetLocalPlayer(),0,0,60,"String::assert_size failed at "+f+" for instance "+I2S(this)+". Maximum size reached.")
            debug endif

            return ( count <= maxSize() )
        endmethod

        private method assert_range takes integer index, string f returns boolean
            debug if ( index < 0 and index > length ) then
                debug call DisplayTimedTextFromPlayer(GetLocalPlayer(),0,0,60,"String::assert_range failed at "+f+" for instance "+I2S(this)+". Invalid iterator at position "+I2S(index)+".")
            debug endif

            return ( index >= 0 and index <= length )
        endmethod

        private method assert_resize takes integer count, string f returns boolean
            return assert_size(length + count, f)
        endmethod

        method operator [] takes integer pos returns string
            debug if not assert_pos(pos, "operator []") then
                debug return null
            debug endif

            return SubString(value, pos, pos+1)
        endmethod

        method operator []= takes integer pos, string s returns nothing
            debug if not assert_pos(pos, "operator []=") then
                debug return
            debug endif

            set value = SubString(value, 0, pos) + SubString(s, 0, 1) + SubString(value, pos+1, length)
        endmethod

        method operator front takes nothing returns string
            return SubString(value, 0, 1)
        endmethod

        method operator back takes nothing returns string
            return SubString(value, length-1, length)
        endmethod

        method operator str takes nothing returns string
            return value
        endmethod

        method assign takes string str returns thistype
            local integer len = StringLength(str)

            if ( assert_size(len, "assign") ) then
                set value = str
                set length = len
            endif

            return this
        endmethod

        method assignSubstring takes string str, integer pos, integer count returns thistype
            if ( count == npos ) then
                set count = StringLength(str)
            endif

            return assign(SubString(str, pos, pos+count))
        endmethod

        method insert takes integer pos, string str returns thistype
            local integer len

            if ( assert_range(pos, "insert") ) then
                set len = StringLength(str)

                if ( len > 0 and assert_resize(len, "insert") ) then
                    set value = SubString(value, 0, pos) + str + SubString(value, pos, length)
                    set length = length + len
                endif
            endif

            return this
        endmethod

        method insertSubstring takes integer pos, string str, integer subpos, integer count returns thistype
            if ( count == npos ) then
                set count = StringLength(str)
            endif

            return insert(pos, SubString(str, subpos, subpos+count))
        endmethod

        method erase takes integer pos, integer count returns thistype
            if assert_pos(pos, "erase") then
                if ( count == npos ) or ( pos+count > length ) then
                    set count = length - pos
                endif

                if ( count > 0 ) then
                    set value = SubString(value, 0, pos) + SubString(value, pos+count, length)
                    set length = length - count
                endif
            endif

            return this
        endmethod

        method pop takes nothing returns thistype
            if ( length > 0 ) then
                set value = SubString(value, 0, length-1)
                set length = length - 1
            endif

            return this
        endmethod

        method shift takes nothing returns thistype
            if ( length > 0 ) then
                set value = SubString(value, 1, length)
                set length = length - 1
            endif

            return this
        endmethod

        method append takes string str returns thistype
            local integer len = StringLength(str)

            if ( len > 0 and assert_resize(len, "append") ) then
                set value = value + str
                set length = length + len
            endif

            return this
        endmethod

        method appendSubstring takes string str, integer pos, integer count returns thistype
            if ( count == npos ) then
                set count = StringLength(str)
            endif

            return append(SubString(str, pos, pos+count))
        endmethod

        method compare takes string str returns integer
            if ( value == str ) then
                return 0
            elseif length > StringLength(str) then
                return 1
            endif

            return -1
        endmethod

        method compareSubstrings takes integer pos, integer len, string str, integer subpos, integer sublen returns integer
            local integer result = -1
            local string sub
            local string sub2

            if ( len == npos ) then
                set len = length
            endif
            if ( sublen == npos ) then
                set sublen = StringLength(str)
            endif

            set sub = SubString(value, pos, pos+len)
            set sub2 = SubString(str, subpos, subpos+sublen)

            if sub == sub2 then
                set result = 0
            elseif StringLength(sub) > StringLength(sub2) then
                set result = 1
            endif

            set sub = null
            set sub2 = null
            return result
        endmethod

        method replace takes integer pos, integer count, string str returns thistype
            local integer len

            if ( assert_pos(pos, "replace") ) then
                if ( count == npos ) or ( pos+count > length ) then
                    set count = length - pos
                endif

                set len = StringLength(str) - count
                if ( assert_resize(len, "replace") ) then 
                    set value = SubString(value, 0, pos) + str + SubString(value, pos+count, length)
                    set length = length + len
                endif
            endif

            return this
        endmethod

        method replaceSubstrings takes integer pos, integer len, string str, integer subpos, integer sublen returns thistype
            if ( sublen == npos ) then
                set sublen = StringLength(str)
            endif

            return replace(pos, len, SubString(str, subpos, subpos+sublen))
        endmethod

        method substr takes integer pos, integer count returns string
            if ( assert_pos(pos, "substr") ) then
                if ( count == npos ) then
                    set count = length
                endif

                return SubString(value, pos, pos+count)
            endif

            return null
        endmethod

        method resize takes integer count returns nothing
            if ( count > length ) then
                if ( assert_size(count, "resize") ) then
                    loop
                        exitwhen length >= count
                        set value = value + " "
                        set length = length + 1
                    endloop
                endif
            elseif ( count >= 0 and count < length ) then
                set value = SubString(value, 0, count)
                set length = count
            endif
        endmethod

        method find takes string str, integer pos returns integer
            local integer count

            if ( assert_pos(pos, "find") ) then
                set count = StringLength(str)

                if ( count > 0 ) then
                    loop
                        exitwhen ( pos+count > length )
                        if ( SubString(value, pos, pos+count) == str ) then
                            return pos
                        endif
                        set pos = pos+1
                    endloop
                endif
            endif

            return npos
        endmethod

        method findBuffer takes string str, integer pos, integer count returns integer
            return find(SubString(str, 0, count), pos)
        endmethod

        method rfind takes string str, integer pos returns integer
            local integer count

            if ( pos == npos or pos >= length ) then
                set pos = length - 1
            endif

            if ( assert_pos(pos, "rfind") ) then
                set count = StringLength(str)

                if ( count > 0 ) then
                    set pos = pos - count + 1

                    loop
                        exitwhen ( pos+1 < count )
                        if ( SubString(value, pos, pos+count) == str ) then
                            return pos
                        endif
                        set pos = pos-1
                    endloop
                endif
            endif

            return npos
        endmethod

        method rfindBuffer takes string str, integer pos, integer count returns integer
            return rfind(SubString(str, 0, count), pos)
        endmethod

        method capital takes nothing returns string
            return StringCase(SubString(value, 0, 1), true) + SubString(value, 1, length)
        endmethod

        method upper takes nothing returns string
            return StringCase(value, true)
        endmethod

        method lower takes nothing returns string
            return StringCase(value, false)
        endmethod
    endstruct

endlibrary
Demo:
JASS:
struct StringTest extends array

    static method print takes string s returns nothing
        call DisplayTimedTextFromPlayer(GetLocalPlayer(), 0, 0, 60, s)
    endmethod

    static method onInit takes nothing returns nothing
        local String s = String.create("this is a test string.")

        call print(s.str)                                                // this is a test string.
        call s.replace(9,5,"n example")
        call print("\nAfter replacing pos 5 span 9: "+s.str)             // this is an example string.
        call s.destroy()

        call PolledWait(4.0)

        set s = String.create("question string?")
        call print("New string: "+s.str)                                 // question string?
        call s.insert(0, "hmm, ")
        call print("\nAfter inserting at possition 0 'hmm, ': "+s.str)   // hmm, question string?
        call print("Character at pos 8: "+s[8])                          // 's'

        set s[4] = "Xxxx"                                                // this also makes sure that only single char will be set
        call print("\nInserted 'Xxxx' value at pos 4: "+s.str)           // hmm,Xquestion string?

        call s.assign("some things are just worth fighting for")
        call print(s.str)                                                // some things are just worth fighting for

        call print("\nSearching for 'igh'")
        call print("found at pos: "+I2S(s.rfind("igh",String.npos)))     // found at pos: 28

        call s.assign("This is an example sentence.")
        call s.erase(10,8)
        call print("\nAfter erasing 8 characters starting from pos 10: "+s.str) // This is an sentence.

        call print("\nCharacter at pos 6: "+s[6])                        // s
        call print(s.upper())                                            // THIS IS AN SENTENCE.
        call print(s.lower())                                            // this is an sentence.
    endmethod

endstruct
 
Last edited:

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Nes, again - please tell more then throwing statements kinda "fix it" or "fix that". I'm happy that ppl like you review stuff and point where improvements needs to be made but.. you actually need to tell me whats missing.

Additional portion will come tomorrow as said. Watching RiotStream.
 
I think this library would be more effective if it had only the struct in it :p

There's this famous quote I read once:

A perfect library is not something you can't add anything to, it's a library that you can't remove anything from.

I think you have the substr function wrong though :eek:
In C++, std::string::substr takes a position and a length. (Assuming you're aiming to make a duplicate of the standard C++ string library for JASS :D)
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
If I recall correctly it's Vex quote. His quotes were always neat. And yes:
Code:
string substr (size_t pos = 0, size_t len = npos) const;
I will add some stuff from wxWidget's wxString.

Edit: you missed something else. For example copy method, traditional:
Code:
size_t copy (char* s, size_t n, size_t pos = 0) const;
Original method copies substring starting from pos with length n to array pointed by s. There are no references, no pointers, no functors, no overloading (it's cut to minimum) so many features can't be implemented.

I will probably leave it as:
- substr -> returns substring starting from position pos ending with position end (intuitive for wc3 standard)
- copy -> returns number of character copied by setting xstring data to substring starting from pos with span length
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
hey! What improvements are needed - regarding API: what would u like to see?
Honestly, I've taken a lot from wxString lib inside wxWidget standard libs. Anyways, I guess additional overloaded functions are needed just bcs standard c str lib got plenty of it.

Guess leaving unfinished package wasn't best idea.
Sorry.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Here is more C-ish interface (without some misc funcs taken from other libs).
We can't overload function here (jass), so function name coresponds to: basic_name + application. There are no iterators and implementing api for "const" members basically doesnt exists or has no meaning in jass.

JASS:
// Append:
        method AppendString takes string str returns xstring
            set this.value = this.value + str
            return this
        endmethod

        method AppendSubstring takes string str, integer subpos, integer sublen returns xstring
            set this.value = this.value + SubString(str, subpos, subpos+sublen)
            return this
        endmethod

        method AppendBuffer takes string str, integer size returns xstring
            set this.value = this.value + SubString(str, 0, size)
            return this
        endmethod

        method AppendChar takes string char, integer count returns xstring
            local string str = ""

            // Let us not get fooled..
            if (StringLength(char) > 1) then
                set char = SubString(char, 0, 1)
            endif

            loop
                exitwhen count <= 0
                set str = str + char
                set count = count - 1
            endloop

            set this.value = this.value + str
            return this
        endmethod

        method AppendRange takes string str, integer start, integer end returns xstring
            set this.value = this.value + SubString(str, start, end)
            return this
        endmethod

// Assign:
        method AssignString takes string str returns xstring
            set this.value = str
            return this
        endmethod

        method AssignSubstring takes string str, integer subpos, integer sublen returns xstring
            set this.value = SubString(str, subpos, subpos+sublen)
            return this
        endmethod

        method AssignBuffer takes string str, integer size returns xstring
            set this.value = SubString(str, 0, size)
            return this
        endmethod

        method AssignChar takes string char, integer count returns xstring
            local string str = ""

            // Let us not get fooled..
            if (StringLength(char) > 1) then
                set char = SubString(char, 0, 1)
            endif

            loop
                exitwhen count <= 0
                set str = str + char
                set count = count - 1
            endloop

            set this.value = this.value + str
            return this
        endmethod

        method AssignRange takes string str, integer start, integer end returns xstring
            set this.value = SubString(str, start, end)
            return this
        endmethod

// Character access:
        method at takes integer i returns string
            return SubString(this.value, i, 0)
        endmethod

        method back takes nothing returns string
            return SubString(this.value, this.len-1, this.len)
        endmethod

        method front takes nothing returns string
            return SubString(this.value, 0, 1)
        endmethod

        method operator [] takes integer pos returns string
            return SubString(this.value, pos-1, pos)
        endmethod

        method getchar takes integer pos returns string
            return SubString(this.value, pos-1, pos)
        endmethod

        method operator []= takes integer pos, string s returns nothing
            if StringLength(s)>1 then
                set s = SubString(s, 0, 1)
            endif
            set this.value = SubString(this.value, 0, pos-1) + s + SubString(this.value, pos, this.len)
        endmethod

        method setchar takes integer pos, string s returns nothing
            if StringLength(s)>1 then
                set s = SubString(s, 0, 1)
            endif
            set this.value = SubString(this.value, 0, pos-1) + s + SubString(this.value, pos, this.len)
        endmethod

// Compare:
        method CompareString takes string str returns integer
            if this.value == str then
                return 0
            elseif this.len > StringLength(str) then
                return 1
            endif
            return -1
        endmethod

        method CompareSubstring takes integer pos, integer len, string str returns integer
            local string thissub = SubString(this.value, pos, pos+len)
            if thissub == str then
                return 0
            elseif StringLength(thissub) > StringLength(str) then
                return 1
            endif
            return -1
        endmethod

        method CompareSubstring2 takes integer pos, integer len, string str, integer subpos, integer sublen returns integer
            local string thissub = SubString(this.value, pos, pos+len)
            local string substr = SubString(str, subpos, subpos+sublen)
            if thissub == substr then
                return 0
            elseif StringLength(thissub) > StringLength(substr) then
                return 1
            endif
            return -1
        endmethod

        method CompareBuffer takes integer pos, integer len, string str, integer count returns integer
            return CompareSubstring2(pos, len, str, 0, count)
        endmethod

// Find:
        method Find takes string str, integer pos returns integer
            local string thissub = SubString(this.value, pos, this.len)
            local string cmpstr
            local integer strlen = StringLength(str)

            if StringLength(thissub) < strlen then
                return npos
            endif

            loop
                exitwhen (pos >= this.len) or (this.len-pos < strlen)
                set cmpstr = SubString(thissub, pos, pos+strlen)
                if (cmpstr == str) then
                    return pos
                endif
                set pos = pos+1
            endloop

            return npos
        endmethod

        method FindBuffer takes string char, integer pos, integer count returns integer
            return Find(SubString(char, 0, count), pos)
        endmethod

        method RFind takes string str, integer pos returns integer
            local string thissub = SubString(this.value, pos, this.len)
            local string cmpstr
            local integer strlen = StringLength(str)
            local integer end = this.len

            if StringLength(thissub) < strlen then
                return npos
            endif

            set pos = end
            loop
                exitwhen (pos <= 0) or (pos-strlen < strlen)
                set cmpstr = SubString(thissub, pos-strlen, end)
                if (cmpstr == str) then
                    return pos
                endif
                set pos = pos-1
            endloop

            return npos
        endmethod

        method RFindBuffer takes string char, integer pos, integer count returns integer
            return Find(SubString(char, 0, count), pos)
        endmethod

// Insert:
        method InsertString takes integer pos, string str returns xstring
            set this.value = SubString(this.value, 0, pos) + str + SubString(this.value, pos, this.len)
            return this
        endmethod

        method InsertSubstring takes integer pos, string str, integer subpos, integer sublen returns xstring
            set this.value = SubString(this.value, 0, pos) + SubString(str, subpos, subpos+sublen) + SubString(this.value, pos, this.len)
            return this
        endmethod

        method InsertBuffer takes integer pos, string str, integer count returns xstring
            set this.value = SubString(this.value, 0, pos) + SubString(str, 0, count) + SubString(this.value, pos, this.len)
            return this
        endmethod

        method InsertChar takes integer pos, string char, integer count returns xstring
            local string str = ""
            if StringLength(char) > 1 then
                set char = SubString(char, 0, 1)
            endif

            loop
                exitwhen count <= 0
                set str = str + char
                set count = count - 1
            endloop

            set this.value = SubString(this.value, 0, pos) + str + SubString(this.value, pos, this.len)
            return this
        endmethod

// Replace:
        method ReplaceString takes integer pos, integer len, string s returns xstring
            set this.value = SubString(this.value, 0, pos) + s + SubString(this.value, pos+len, this.len)
            return this
        endmethod

        method ReplaceSubstring takes integer pos, integer len, string str, integer subpos, integer sublen returns xstring
            set this.value = SubString(this.value, 0, pos) + SubString(str, subpos, subpos+sublen) + SubString(this.value, pos+len, this.len)
            return this
        endmethod

        method ReplaceBuffer takes integer pos, integer len, string str, integer count returns xstring
            set this.value = SubString(this.value, 0, pos) + SubString(str, 0, count) + SubString(this.value, pos+len, this.len)
            return this
        endmethod

        method ReplaceChar takes integer pos, integer len, string char, integer count returns xstring
            local string str = ""
            if StringLength(char) > 1 then
                set char = SubString(char, 0, 1)
            endif

            loop
                exitwhen count <= 0
                set str = str + char
                set count = count - 1
            endloop

            set this.value = SubString(this.value, 0, pos) + str + SubString(this.value, pos+len, this.len)
            return this
        endmethod

// Miscellaneous:
        method Copy takes string s, integer length, integer pos returns integer
            set this.value = SubString(s, pos, pos+length)
            return this.len
        endmethod

        method Data takes nothing returns string
            return this.value
        endmethod

        method Substr takes integer pos, integer len returns string
            return SubString(this.value, pos, pos+len)
        endmethod

        method Empty takes nothing returns boolean
            return this.len == 0
        endmethod

        method Clear takes nothing returns nothing
            set this.value = ""
        endmethod

        method Erase takes integer pos, integer len returns xstring
            set this.value = SubString(this.value, 0, pos) + SubString(this.value, pos+len, this.len)
            return this
        endmethod

        method PopBack takes nothing returns nothing
            local integer len = this.len
            if (len > 0) then
                set this.value = SubString(this.value, 0, len-1)
            endif
        endmethod

        method PushBack takes string s returns nothing
            call AppendChar(s, 1)
        endmethod

        method Resize takes integer size returns nothing
            local integer len = this.len
            local string s
            if (size > len) then
                loop
                    exitwhen size >= len
                    set s = s + " "
                    set size = size + 1
                endloop
                set this.value = this.value + s
            elseif (size < len) then
                set this.value = SubString(this.value, 0, size)
            endif
        endmethod
camel case seems to be the best idea, can fix that later. Thanks for replay TriggerHappy.
"npos" is standard declaration for invalid position or to indicate that no matches were found. Declared as public const static string.

Again, I'm aware that such API may be too specific for limitations brough by jass. I'm open for suggestions, post which functions should or should not be included. Anyways, adding wrapped for "string" in wc3 seems to be a good idea. Last thing: don't you guys think that libs name should be kinda jstring or smthng rather than xstring? Thanks for your time!
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
There are few options already:
JASS:
*       miscellaneous:
*        | method trim takes nothing returns string
*        |    removes white characters from xstring data
*        | method trunc takes integer pos returns string
*        |    cuts xstring data starting from chatacter at position 0 with span pos
*        | method strip takes nothing returns string
*        |    same as trim, although doesn't change xstring data value
*        | method print takes nothing returns nothing
*        |    prints current xstring data
*        | method strip_f takes nothing returns string
*        |    similar to strip, although strips white characters only from string's front
*        | method strip_b takes nothing returns string
*        |    strips white characters from string's back
although names are poor. Strip differs from Trim in just one way: it doesn't change object value after procedure is done, returned value is a copy of given string of characters. Anyway, since strip and trim don't really require list of parameters I could instead add a boolean: "trailing" or "fromLeft" - if true, go from L, if not head R. Truncate will be replaced with Resize - those do basically the same thing yet resize (func name) is more userfriendly (easier to understand) - especially for non-Eng-folks.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Updated to 2.0.0.0.
After more testing I'll couple this with Ascii or such, adding trunc, trim, strip methods - similar to those from 1.x.x.x versions.

There are no comments, yet I just want you to take a look, provide feeback if you wish to. API is entirely based on c++' std::basic_string and maybe, just maybe it needs improvements.
Will tryhard test it today/following days to ensure it's reliability, as I did yesterday with ConstructEvent.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Finally a replay!

Honestly, you might be right. Implementing custom char type within wc3 seems pointless and without such, those api funcs miss point of thier imprementation. Thanks for feedback, thats what we need to improve jass resources afterall.
I might consider changing costructor from initializing to default, meaning create won't be taking any parameters. Main classes throughout whole jass resources have their create method member implemented in such style. On the other hand copy ctr is something that might be usefull, as kind of stardard for implementation. Not all classes need those, but its usefull method for sure. If such standard do happen, libraries like containers can take advantege of this feature.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
I might consider changing costructor from initializing to default, meaning create won't be taking any parameters. Main classes throughout whole jass resources have their create method member implemented in such style. On the other hand copy ctr is something that might be usefull, as kind of stardard for implementation. Not all classes need those, but its usefull method for sure. If such standard do happen, libraries like containers can take advantege of this feature.

Method overloading would be the perfect solution here but unfortunatly its not supported by vJass... I would keep the initializing constructor as you basically never want to create an empty string. And if so you could just add a static thistype emptyString on which users could rely.

Btw, why readonly static constant integer npos = -1? Readonly and constant is kinda... pointless :D
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Updated to 2.2.0.0. Renamed to String.

- reduced snippet code size tremendously (compared to previous version) Yey Bribe!
Logic behind: instead of providing Range/Buffer/Substring and other versions of given member function, there are just two per operation.
First: simple, straight forward and second: substring based. There are no actuall iterators in jass, thus user typing Range (first, last) probably knows how to count the length of such range. Buffer: its the same situation as with substring but with 0 as substring start parameter.

- fixed bugs which hasnt been solved previously
- added extra space and made code generaly cleaner
- fixed documentation
- reduced safety checking: strongly imitates c++ string behaviour

Request: change threads name to [Strings] String. Sorry @TH for this :"DDDD

Demo will be added tomorrow.
 
Last edited:
Why aren't these private?

JASS:
globals
    constant string NullString = null
    constant string EmptyString = ""
endglobals
andmethod maxSizeshould be static. or a constant.

You can also optimize your assert methods like this

JASS:
private method assert_pos takes integer pos returns boolean
    return not ( pos < 0 or pos >= length ) // will inline
endmethod
We also need some example usage somewhere.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
NullString and EmptyString are not private for a reason: generic global string comparison ;>
Such idea is implemented in multiple environments, like gui applications. I could move them to String if needed.

True, maxSize might be static, it is not as of now because its normal method in c++ ;S

I want assert to display message, instead of spamming displays throughout the code, whereever assert is used. I know that it could inline, however, just think this way its smoother.
Just count how many times asserts are used vs number of asserts.
 
Bannar said:
NullString and EmptyString are not private for a reason: generic global string comparison ;>

What's wrong with comparing them directly (why are the globals even needed).

Bannar said:
I want assert to display message, instead of spamming displays throughout the code, whereever assert is used. I know that it could inline, however, just think this way its smoother.

You can have debugging functionality while still making the functions inline.
 
For the error messages, just do this:
JASS:
private function DisplayError takes boolean b, string s returns nothing 
    if b then
        call DisplayTimedTextFromPlayer(GetLocalPlayer(), 0, 0, 60, s)
    endif
endfunction

//.... later in the code
private method assert_pos takes integer pos returns boolean
    debug call DisplayError(not (pos < 0 or pos >= length), "String::assert_pos Invalid index at position pos.")
    return pos < 0 or pos >= length
endmethod

You can also wrap the DisplayError function in static if DEBUG_MODE if you'd like. That way, you can reduce most of your functions down to a single return. You can also make it like "assert" in python by checking "if not b" i.e. assert whether a condition is true. if it fails, then throw an error.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Updated. Removed following methods:

* at
* str= operator
* swap
* copy

'at' & []= operator has been merged. []= operator performs bound check in DEBUG mode and inlines when in RELEASE mode.
str= operator was redundand - assign method is already there.
swap was unnecessary, not really usefull in jass environment.
copy method was redundand - assignSubstring is already there. If you want to retrieve the size of buffer copied into your String object instance, simply do: call buffer.assignSubstring(source.str, pos, count).size().

assignSubstring is now wrapped around assign method to prevent unnecessary code generation.
replace method now correctly checks for out of range error.
assert_pos now correctly prevents further actions from occuring.

left & right find methods now correctly return position of the first character from searched string. Both search algorithms have been improved and no longer generate additional local variables - 'pos' argument is enough, methods operate directly on it.
compareSubstring & right-find methods recieved 'npos' support similar to one seen in other methods. For right-find methods, if 'npos' or any value not smaller than size() is passed as 'pos', whole string will be searched.

Reduced the number of StringLength() calls wherever possible, e.g in assign & append methods.
pop and shift methods now return 'thistype' allowing for cascade operations.

Documentation and test script reflect the changes made.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Sure, but this is related to tokenizers and I've prepared separate resource for that. There is also additional extension that provides strip-related methods that had been part of original library, but were removed later on. I wanted to keep main lib as short as possible without sacrificing important functionality from string library.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Some ppl complained about the API so here is my suggestions:

size => length
str => text
upper => toUpper
lower => toLower

This provides tons of string operation which is very nice. :thumbs_up:
On hive meet people from many different IOT and programming domains, and more often than not, from none at all - hobbyists. Each group has their own preferences, and one cannot possibly satisfy them all. Provided naming is biased towards c-syntax rather than the java one. Thanks for your input.
 
Level 11
Joined
Jul 4, 2016
Messages
626
the substring method could make use of a integer end to specify between which characters we want to grab the substring since the original native also allowed for this specification.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
the substring method could make use of a integer end to specify between which characters we want to grab the substring since the original native also allowed for this specification.
The 'substr' method works the same way as C I suppose (have not used C enough to know). I'm only guessing because much of the previous discussion here concerned C syntax.

What some were looking for is actually a complete rewrite of this, but with Java naming/API convention.

It's also possible to implement a RegEx library into JASS as well, but it would perform extremely slowly and suffer from string leaks.

Honestly, people who are looking to use sophisticated programming constructs like this are far better off coding WarCraft 3 in Lua - or - using one of the many different X2Lua transcompilers that exist and then programming in X instead of directly in Lua.
 
Level 11
Joined
Jul 4, 2016
Messages
626
The 'substr' method works the same way as C I suppose (have not used C enough to know). I'm only guessing because much of the previous discussion here concerned C syntax.

What some were looking for is actually a complete rewrite of this, but with Java naming/API convention.

It's also possible to implement a RegEx library into JASS as well, but it would perform extremely slowly and suffer from string leaks.

Honestly, people who are looking to use sophisticated programming constructs like this are far better off coding WarCraft 3 in Lua - or - using one of the many different X2Lua transcompilers that exist and then programming in X instead of directly in Lua.
I would like to switch to Lua but for my existing map, it would be a massive pain to either remove systems that are no longer needed in the Lua environment or to rewrite stuff to utilize the Lua systems that are avaliable here on the hive.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I would like to switch to Lua but for my existing map, it would be a massive pain to either remove systems that are no longer needed in the Lua environment or to rewrite stuff to utilize the Lua systems that are avaliable here on the hive.
You would not have to rewrite very much (if at all) manually if you used vJass2Lua.
 
Top