Meh, I'm glad it's there but it was really more work to write it than what I was prepared for. It's annoying that you can't do static if's outside of functions, which is why Table is currently a requirement instead of optional. The main reasons I chose Zinc were because
1. I wanted to practice my C-syntax
2. (and most importantly) I felt too lazy to write using ugly JASS loop structure.
This thing was very annoying to convert from Luck, the language I had it in first... you have to enclose (parenthesis) for all if-statements in Zinc, you have those artsy curly brackets that are just in the most difficult possible spot to reach on the keyboard, etc.
Luck Ascii
Hex is going to be a seperate resource, I originally combined them in the development process.
Code:
library Ascii:
/*
Useful API that can be used to help parse strings dynamically (in-game).
For completeness, provides the constant string ASCII.
API
---------------------
| integer.hex(256) -> string
| returns '0x100'
|
| integer.chr(48) -> string
| returns '0'
|
| integer.rawcode(1093677104) -> string
| returns 'A000'
|
| '100'.hex() -> integer
| returns 256
|
| '0'.ord() -> integer
| returns 48
|
| 'A000'.rawcode() -> integer
| returns 1093677104
*/
public static constant string ASCII = " \b\t\n \f\r !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
static:
# For converting integer to string:
string array CHR, HEX
# For converting string to integer:
Dict:
ORD = #! Dict()
VAL = #! Dict()
struct integer:
public:
string hex(): # Developed by Azlier
local string s = "", p = ""
if this < 0:
p = '-'
this = -this
while this != 0:
s = HEX[this.mod(16)] .. s
this /= 16
return p .. s
string chr(): # Developed by TheDamien
debug:
if CHR[this] == ""
print("TypeError: Tried to get the char of invalid int: " .. this)
return ""
return CHR[this]
string rawcode(): # Developed by Blizzard with changes by the community
local string s = ""
if this < '!!!!' or this > '~~~~':
debug print("TypeError: Tried to get rawcode of invalid int: " .. this)
return ""
while this != 0:
s = this.mod(256).chr .. s
this /= 256
return s
struct string:
public:
integer hex(): # Developed by Bribe
local:
integer i, p = 0, end = this.len()
boolean neg = false
debug boolean safe = true
if this[0] == "-":
neg = true
p = 1
if this[p:p+2] == "0x":
p += 2
foreach(p, p, end):
i = i * 16 + VAL[this[p]]
debug:
if not VAL.contains(this[p]) and safe:
safe = false
print("TypeError: Returning the hex value of non-hex string: " .. this)
return integer.tertiaryOp(neg, -i, i)
integer ord(): # Developed by TheDamien with changes by Bribe
local integer i = ORD[this]
if this == "\\":
return '\\' # Switch slashes
elseif this != i.chr():
if i == 0:
debug print("TypeError: Tried to get the ord value of invalid char: " .. this)
return 0
return i + 32 # Switch to lowercase
return i
integer rawcode(): # Developed by Nestharus
local integer pos, val = 0
if this.len() != 4:
debug print("TypeError: Tried to get rawcode of invalid string: " .. this)
return 0
foreach(pos, 3): val = val * 256 + this[pos].ord()
return val
oninit:
local integer i
foreach(i, 8, 13):
if i != 11:
CHR[i] = ASCII[i]
ORD[CHR[i]] = i
# ASCII formatting characters
foreach(i, 32, 126):
CHR[i] = ASCII[i]
if i != 92 and i < 97 or i > 122: ORD[CHR[i]] = i
# ASCII text characters
foreach(i, 15):
if i < 10: HEX[i] = i # 0-9
else: HEX[i] = CHR[i + 55] # A-F
VAL[HEX[i]] = i
# Hex characters
__________________
How to post your triggers on the Hive Workshop. JPAG - Bettering the cause of readable source code.
Here is an optimized Ascii. Extra space is removed and the comparisons are more optimal.
Jass:
library Ascii /////////////////////////////////////////////////////////////////// // function Char2Ascii takes string s returns integer // integer ascii = Char2Ascii("F") // // function Ascii2Char takes integer a returns string // string char = Ascii2Char('F') // // function A2S takes integer a returns string // string rawcode = A2S('CODE') // // function S2A takes string s returns integer // integer rawcode = S2A("CODE") // /////////////////////////////////////////////////////////////////// globals privateintegerarray i // Integers privatestringarray c // Characters endglobals function Char2Ascii takesstring s returnsinteger localinteger a if("\\"==s)then return92// "/" and "\\" have same hash endif set a=i[StringHash(s)/0x1F0748+0x3EA] if(64<a and91>a)then return a+32//shift to lowercase, upper/lower have same hash endif debugif((7<a and14>a)or(31<a and127>a))then return a debugendif debugcallDisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ASCII CONVERSION ERROR: INVALID CHAR "+s) debugreturn0 endfunction function Ascii2Char takesinteger a returnsstring debugif((7<a and14>a)or(31<a and127>a))then return c[a] debugendif debugcallDisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ASCII CONVERSION ERROR: INVALID INT "+I2S(a)) debugreturnnull endfunction function A2S takesinteger a returnsstring localstring s="" debugif(7<a)then loop set s=c[a-a/256*256]+s set a=a/256 exitwhen0==a endloop return s debugendif debugcallDisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ASCII CONVERSION ERROR: INVALID INT "+I2S(a)) debugreturnnull endfunction function S2A takesstring s returnsinteger localinteger a=0 localinteger l=StringLength(s) localinteger i=0 debugif(0<l)then loop set a=a*256+Char2Ascii(SubString(s,i,i+1)) set i=i+1 exitwhen(i==l) endloop return a debugendif debugcallDisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ASCII CONVERSION ERROR: INVALID STR "+s) debugreturn0 endfunction privatemodule Init privatestaticmethod onInit takesnothingreturnsnothing set i[931]=8 set i[1075]=9 set i[1586]=10 set i[1340]=12 set i[412]=13 set i[198]=32 set i[1979]=33 set i[1313]=34 set i[1003]=35 set i[1264]=36 set i[983]=37 set i[1277]=38 set i[306]=39 set i[904]=40 set i[934]=41 set i[917]=42 set i[1972]=43 set i[1380]=44 set i[1985]=45 set i[869]=46 set i[1906]=47 set i[883]=48 set i[1558]=49 set i[684]=50 set i[582]=51 set i[668]=52 set i[538]=53 set i[672]=54 set i[1173]=55 set i[71]=56 set i[277]=57 set i[89]=58 set i[1141]=59 set i[39]=60 set i[1171]=61 set i[51]=62 set i[305]=63 set i[0]=64 set i[222]=65 set i[178]=66 set i[236]=67 set i[184]=68 set i[1295]=69 set i[1390]=70 set i[1276]=71 set i[203]=72 set i[1314]=73 set i[209]=74 set i[1315]=75 set i[170]=76 set i[1357]=77 set i[1343]=78 set i[1397]=79 set i[1420]=80 set i[1419]=81 set i[1396]=82 set i[1374]=83 set i[1407]=84 set i[499]=85 set i[1465]=86 set i[736]=87 set i[289]=88 set i[986]=89 set i[38]=90 set i[1230]=91 set i[1636]=93 set i[1416]=94 set i[1917]=95 set i[217]=96 set i[833]=123 set i[1219]=124 set i[553]=125 set i[58]=126 set c[8]="\b" set c[9]="\t" set c[10]="\n" set c[12]="\f" set c[13]="\r" set c[32]=" " set c[33]="!" set c[34]="\"" set c[35]="#" set c[36]="$" set c[37]="%" set c[38]="&" set c[39]="'" set c[40]="(" set c[41]=")" set c[42]="*" set c[43]="+" set c[44]="," set c[45]="-" set c[46]="." set c[47]="/" set c[48]="0" set c[49]="1" set c[50]="2" set c[51]="3" set c[52]="4" set c[53]="5" set c[54]="6" set c[55]="7" set c[56]="8" set c[57]="9" set c[58]=":" set c[59]=";" set c[60]="<" set c[61]="=" set c[62]=">" set c[63]="?" set c[64]="@" set c[65]="A" set c[66]="B" set c[67]="C" set c[68]="D" set c[69]="E" set c[70]="F" set c[71]="G" set c[72]="H" set c[73]="I" set c[74]="J" set c[75]="K" set c[76]="L" set c[77]="M" set c[78]="N" set c[79]="O" set c[80]="P" set c[81]="Q" set c[82]="R" set c[83]="S" set c[84]="T" set c[85]="U" set c[86]="V" set c[87]="W" set c[88]="X" set c[89]="Y" set c[90]="Z" set c[92]="\\" set c[97]="a" set c[98]="b" set c[99]="c" set c[100]="d" set c[101]="e" set c[102]="f" set c[103]="g" set c[104]="h" set c[105]="i" set c[106]="j" set c[107]="k" set c[108]="l" set c[109]="m" set c[110]="n" set c[111]="o" set c[112]="p" set c[113]="q" set c[114]="r" set c[115]="s" set c[116]="t" set c[117]="u" set c[118]="v" set c[119]="w" set c[120]="x" set c[121]="y" set c[122]="z" set c[91]="[" set c[93]="]" set c[94]="^" set c[95]="_" set c[96]="`" set c[123]="{" set c[124]="|" set c[125]="}" set c[126]="~" endmethod endmodule privatestruct Inits extendsarray implement Init endstruct endlibrary
And keep in mind that in your Zinc version, Ascii doesn't necessarily only deal with raw codes.
I should also mention that your new onInit is significantly slower =).
1. Array is faster than a simple +1 operation
2. Hashtable takes twice as long to compute as an array
With these, hashtable would clearly be faster than an array + three math operations.
Factors of doing it with hashtable:
Much shorter code length
Faster execution in-game
Insignificantly slower init time (seriously not worth talking about)
You are also still doing the useless integer checks that TheDamien added.
Jass:
function Char2Ascii takesstring s returnsinteger localinteger a if("\\"==s)then return92// "/" and "\\" have same hash endif set a=i[StringHash(s)/0x1F0748+0x3EA] if(64<a and91>a and s!=c[a])then return a+32//shift to lowercase, upper/lower have same hash endif debugif((7<a and14>a)or(31<a and127>a))then return a debugendif debugcallDisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ASCII CONVERSION ERROR: INVALID CHAR "+s) debugreturn0 endfunction
Compared to mine:
Jass:
function Char2Ascii(string c)->integer{//OrdFromChar integer a = data.ord[StringHash(c)]; if(c =="\\") return92; //'\\' does not compile with JassHelper but works fine in vanilla JASS elseif(c != data.char[a]){ if(a ==0){ debugBJDebugMsg("TypeError: Tried to get the ord value of invalid char: "+I2S(c)); return0; } return a +32; //Switch to lowercase } return a; }
__________________
How to post your triggers on the Hive Workshop. JPAG - Bettering the cause of readable source code.
Actually, if c not the character, then add 32. If c still not the character, then invalid (if not doing a hash read).
I'd like to see the math stuff benched against the hashtable stuff is possible ^)^. Keep in mind that as a hashtable gets more data, it does get slower =P.
edit
Your method fails..
Jass:
//set a=i globals constantboolean F=true integerarray i hashtable t=InitHashtable() integer h=0 string s="c" integer m endglobals function r takesnothingreturnsnothing localinteger x=5000 loop //20 frames per second staticif F then set m=LoadInteger(t,h,StringHash(s)) //36 frames per second else set m=i[StringHash(s)/0x1F0748+0x3EA] endif
I've seen tests that show if the hashtable has more data, it operates at the same speed. Maybe the tests were not thorough as this was done on wc3c.net when hashtables first came out. They filled the entries of the hashtable (needed a lot of entries to do so) then compared the speed.
Since you did this test with hashtables I recommend you use it as argument against anyone who says hashtable is only 2x slower than an array.
I don't know what you mean by this:
>> Actually, if c not the character, then add 32.
>> If c still not the character, then invalid (if not doing a hash read).
A bad char would just load 0 from that hashtable, so you only need to check if the char's ord is not equal to 0 (invalid) and not equal to its output (uppercase).
I also don't like the array method because:
1. All the unhashing work is stolen from TheDamien. Open source, lack of credit or whatever you use to try to justify pretty much copying an entire project, it's something that doesn't sit with me.
2. A lot more lines of code to achieve a total speed difference of an entire 5-10% when compared to the size of the Ord function. Having a smaller map size is much more important than such a pathetic speed increase.
__________________
How to post your triggers on the Hive Workshop. JPAG - Bettering the cause of readable source code.
All the unhashing work is stolen from TheDamien. Open source, lack of credit or whatever you use to try to justify pretty much copying an entire project, it's something that doesn't sit with me.
He was credited..
Quote:
A lot more lines of code to achieve a total speed difference of an entire 5-10% when compared to the size of the Ord function. Having a smaller map size is much more important than such a pathetic speed increase.
Different pros/cons, and virtually nobody cares about the map size resulting from code anyways.
If two resources have very different worthwhile pros, then there should be 2 versions of that resource up.
The next thing I'll check today is comparing strings vs comparing integers (single characters in strings). I want to see if many integer comparisons is slower than 1 string comparison : P. If the string comparison wins, then it could easily be this-
Jass:
if("\\"==s)then return92 endif set i=h[StringHash(s)/0x1F0748+0x3EA] if(s!=c[i])then if(s==c[i+32])then return i+32 endif return0//invalid endif return i
edit
Results are in
Jass:
globals constantboolean F=true stringarray i endglobals function r takesnothingreturnsnothing localinteger x=5000 localstring s="c" localinteger c=95 loop //36 frames per second w/o debug mode //16 frames per second w/ debug mode staticif F then if(64<c and91>c)then //uppercase elseif("\\"==s)then // \\ character debugelseif(7>c or14<c)and(31>c or127<c)then //invalid endif //valid
//20 frames per second else if(s!=i[c])then if(s!=i[c+32])then if("\\"==s)then // \\ character endif //invalid endif //uppercase endif //valid, non uppercase, non \\ endif
If you shift the hash bias by 1 and subsequently shift the arrays by one (turning 0x3EA into 0x3EB and array index 0 to array index 1) You could simplify this:
if s != c[i]then if0== i then return0//invalid endif return i +32 endif
Although, the way he hashes things there may a potential to cause some conflicts in bad strings (longer than 1 char). So using a hashtable in this way would be safer.
I also challenge you to pull from the top of the array (closer to TheDamien's max value of 1979) and see the benchmarks then. You'll of course want to initialize the array from an onInit in order for the benchmarks to be fair. And possibly fill that array up with all the indices TheDamien uses.
__________________
How to post your triggers on the Hive Workshop. JPAG - Bettering the cause of readable source code.
As you wish. The ! is that 1979 value you were eying.
First one is my final solution
Jass:
globals constantboolean F=false stringarray i integerarray h hashtable t=InitHashtable() integer l=0 endglobals function r takesnothingreturnsnothing localinteger x=5000 localstring s="!" localinteger c loop if("\\"==s)then //return 92 endif
//17 fps staticif F then //hash set c=h[StringHash(s)/0x1F0748+0x3EA]
if(64<c and91>c)then //return c+32 endif //return c (will be null if invalid)
//0, can't keep up with timer else set c=LoadInteger(t,l,StringHash(s)) if(64<c and91>c)then //return c+32 endif //return c (will be null if invalid) endif
Tx to you and TheDamien, I've once again come up with the perfect algorithm to a problem >.>.
edit
Updated script (couldn't use integer comparison, I was being stupid ; P). This one ofc outperforms yours =).
Jass:
library Ascii /////////////////////////////////////////////////////////////////// // function Char2Ascii takes string s returns integer // integer ascii = Char2Ascii("F") // // function Ascii2Char takes integer a returns string // string char = Ascii2Char('F') // // function A2S takes integer a returns string // string rawcode = A2S('CODE') // // function S2A takes string s returns integer // integer rawcode = S2A("CODE") // /////////////////////////////////////////////////////////////////// globals privateintegerarray i //hash privatestringarray c //char endglobals function Char2Ascii takesstring s returnsinteger localinteger a if("\\"==s)then return92 endif set a=i[StringHash(s)/0x1F0748+0x3EA] if(s!=c[a])then debugif(0==a)then debugcallDisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ASCII ERROR: INVALID CHARACTER") debugreturn0 debugendif return a+32 endif return a endfunction function Ascii2Char takesinteger a returnsstring return c[a] endfunction function A2S takesinteger a returnsstring localstring s="" loop set s=c[a-a/256*256]+s set a=a/256 exitwhen0==a endloop return s endfunction function S2A takesstring s returnsinteger localinteger a=0 localinteger l=StringLength(s) localinteger j=0 localstring m localinteger h loop exitwhen j==l set m=SubString(s,j,j+1) if("\\"==m)then set a=a*256+92 else set h=i[StringHash(m)/0x1F0748+0x3EA] if(m!=c[h])then debugif(0==a)then debugcallDisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ASCII ERROR: INVALID CHARACTER") debugreturn0 debugendif set a=a*256+h+32 else set a=a*256+h endif endif set j=j+1 endloop return a endfunction privatemodule Init privatestaticmethod onInit takesnothingreturnsnothing set i[931]=8 set i[1075]=9 set i[1586]=10 set i[1340]=12 set i[412]=13 set i[198]=32 set i[1979]=33 set i[1313]=34 set i[1003]=35 set i[1264]=36 set i[983]=37 set i[1277]=38 set i[306]=39 set i[904]=40 set i[934]=41 set i[917]=42 set i[1972]=43 set i[1380]=44 set i[1985]=45 set i[869]=46 set i[1906]=47 set i[883]=48 set i[1558]=49 set i[684]=50 set i[582]=51 set i[668]=52 set i[538]=53 set i[672]=54 set i[1173]=55 set i[71]=56 set i[277]=57 set i[89]=58 set i[1141]=59 set i[39]=60 set i[1171]=61 set i[51]=62 set i[305]=63 set i[0]=64 set i[222]=65 set i[178]=66 set i[236]=67 set i[184]=68 set i[1295]=69 set i[1390]=70 set i[1276]=71 set i[203]=72 set i[1314]=73 set i[209]=74 set i[1315]=75 set i[170]=76 set i[1357]=77 set i[1343]=78 set i[1397]=79 set i[1420]=80 set i[1419]=81 set i[1396]=82 set i[1374]=83 set i[1407]=84 set i[499]=85 set i[1465]=86 set i[736]=87 set i[289]=88 set i[986]=89 set i[38]=90 set i[1230]=91 set i[1636]=93 set i[1416]=94 set i[1917]=95 set i[217]=96 set i[833]=123 set i[1219]=124 set i[553]=125 set i[58]=126 set c[8]="\b" set c[9]="\t" set c[10]="\n" set c[12]="\f" set c[13]="\r" set c[32]=" " set c[33]="!" set c[34]="\"" set c[35]="#" set c[36]="$" set c[37]="%" set c[38]="&" set c[39]="'" set c[40]="(" set c[41]=")" set c[42]="*" set c[43]="+" set c[44]="," set c[45]="-" set c[46]="." set c[47]="/" set c[48]="0" set c[49]="1" set c[50]="2" set c[51]="3" set c[52]="4" set c[53]="5" set c[54]="6" set c[55]="7" set c[56]="8" set c[57]="9" set c[58]=":" set c[59]=";" set c[60]="<" set c[61]="=" set c[62]=">" set c[63]="?" set c[64]="@" set c[65]="A" set c[66]="B" set c[67]="C" set c[68]="D" set c[69]="E" set c[70]="F" set c[71]="G" set c[72]="H" set c[73]="I" set c[74]="J" set c[75]="K" set c[76]="L" set c[77]="M" set c[78]="N" set c[79]="O" set c[80]="P" set c[81]="Q" set c[82]="R" set c[83]="S" set c[84]="T" set c[85]="U" set c[86]="V" set c[87]="W" set c[88]="X" set c[89]="Y" set c[90]="Z" set c[92]="\\" set c[97]="a" set c[98]="b" set c[99]="c" set c[100]="d" set c[101]="e" set c[102]="f" set c[103]="g" set c[104]="h" set c[105]="i" set c[106]="j" set c[107]="k" set c[108]="l" set c[109]="m" set c[110]="n" set c[111]="o" set c[112]="p" set c[113]="q" set c[114]="r" set c[115]="s" set c[116]="t" set c[117]="u" set c[118]="v" set c[119]="w" set c[120]="x" set c[121]="y" set c[122]="z" set c[91]="[" set c[93]="]" set c[94]="^" set c[95]="_" set c[96]="`" set c[123]="{" set c[124]="|" set c[125]="}" set c[126]="~" endmethod endmodule privatestruct Inits extendsarray implement Init endstruct endlibrary