This version runs as fast as 1-line looper. Absolutely the same timing. Just a side-note: so there is no point in stuffing things in super-long lines for performance increase.
![Very Happy :D](./images/smilies/icon_e_biggrin.gif)
This version runs as fast as 1-line looper. Absolutely the same timing. Just a side-note: so there is no point in stuffing things in super-long lines for performance increase.
This patch I liked. =) 828 vs 844. +1.9% (with compact json. I think we should focus on compact json optimizations) and readability increase. before it was:oif2003 wrote: ↑13 Dec 2018, 12:01and this in json.get(): combined conditionals on (a) and removed StrLen(v)Code: Select all
: ((c==q) ? (_n:=InStr(_s,q,, n+1),v:=SubStr(_s, n+1, _n-n-1) , n:=_n, (kf) && (k:=v, z:=":", u:=1)) ;string literals : (_n:=SubStr(_s, n) ~= "[\]\},\s]|$",v:=SubStr(_s, n, _n-1) , n+=_n-2, (v is "Number") ? v+=0:E(c, n)) ;number , (u) || (a ? (k:=b.Push(v), z:=",]"):(b[k]:=v, z:=",}")))
Code: Select all
: ((c==q) ? (d:=InStr(_s,q,, n+1),v:=SubStr(_s, n+1, d-n-1)
, n:=d, (kf) && (k:=v, z:=":", u:=1)) ;string literals
: (d:=SubStr(_s, n) ~= "[\]\},\s]|$",v:=SubStr(_s, n, d-1)
, n+=d-2, (v is "Number") ? v+=0:E(c, n)) ;number
, (u) || (a ? (k:=b.Push(v), z:=",]"):(b[k]:=v, z:=",}")))
Nice! it's one step closer to perfection!
No doubt. whopping +30% performance increase since 1170 score.
Code: Select all
;a=flag: simple arr [], n=cur. parsing pos in the json str, c=cur chr, z=next chr(s) expected,
; v=cur val, k=cur key name, kf=flag: literal key name is allowed as next token
; d=len of the right val (literal string/number), u=flag: we've got key (not val) at this step
; s:{} =stack, b:{} =sub-objects/keys for cur level of nesting, p=prototype obj for simple arr []
Code: Select all
;parse json string. obj:=json.get(str)
;JSON keys are always "strings", expected values r: number|"string"|{object}|[array]
Get(ByRef _s){
static q:=Chr(34), x:=q "{[0123456789-" ;json: allowed chars outside strings
n:=0, k:="", kf:=0, s:=[b:=root:={}], z:="{", y:=0
;a=flag: simple arr [], n=cur. parsing pos in the json str, c=cur chr, z=next chr(s) expected,
; v=cur val, k=cur key name, kf=flag: literal key name is allowed as next token
; d=len of the val/literal right string, u=flag: we've got key (not val) at this step
; s:{} =stack, b:{} =sub-objects/keys for cur level of nesting, p=prototype obj for simple arr []
while(c:=SubStr(_s, ++n, 1))!==""
InStr(" `t`n`r", c) || (
InStr(z, c) || E(c, n), u:=0
, InStr("}]", c) ? ((s.1=root) && E(c, n)
, s.RemoveAt(1), b:=s.1, y>>=1, z:=(a:=y&1) ? ",]" : ",}")
: InStr(",:", c) ? (z:=(kf:=!a && c==",") ? q:x)
: InStr("{[", c) ? ((c=="{") ? (kf:=1, y:=y<<1&~1, z:=q "}") : (y:=y<<1|1, z:=x "]")
, s.InsertAt(1,v:={}), a ? k:=b.Push(v):b[k]:=v
, b:=s.1, a:=y&1)
: ((c==q) ? (d:=InStr(_s,q,, n+1),v:=SubStr(_s, n+1, d-n-1)
, n:=d, (kf) && (k:=v, z:=":", u:=1)) ;string literals
: (d:=SubStr(_s, n) ~= "[\]\},\s]|$",v:=SubStr(_s, n, d-1)
, n+=d-2, (v is "Number") ? v+=0:E(c, n)) ;number
, (u) || (a ? (k:=b.Push(v), z:=",]"):(b[k]:=v, z:=",}")))
)
return(s.1=root || E(c, n), s[1,""]) ;s.Count()!=1 ;unpaired {}, []
E(_c,_n)=>this._T("Unexpected char <" _c "> in pos " _n)
}
Code: Select all
j:='{"k":[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]}'
I think 3-4 levels max is regular use. Try to recall when u used 4-dimentional a[x,y,z,w] arrays last time
well, yeah. But I think something like 10-15 levels is a sane limit. And cap is 63 (cuz first level bit is wasted with opening bracket - and its always {} type of Array).oif2003 wrote: ↑14 Dec 2018, 00:50One time I used json to store files inside ahk script's block comment section preserving file directory structure. In that situation, being able to go 4 deep is kind of nice. Also I might use json to autoload objects into memory on script load and autosave on exit to give the script a persistent feel without using ini files. Not being limited to a shallow depth like 4 levels would be a nice feature. I think we should stick with the current implementation for now unless we find something that is at least twice as fast. But that is not to say we can't keep trying!
This one just hangs. btw new version throws an exception normally.
The recursive calls will crash AHK (stack overflow) for strings longer than 373 (U64), 587 (U32), and 758 (A32) characters (at least on my system).
Code: Select all
#SingleInstance force
class json{ ;json.get by coco and heavily modified by vvhitevvizard and oif2003
;json.set by vvhitevvizard and heavily modified by oif2003
;ver 1.2.3
;1) 0=enable indentation and line feed, 1=the most compact representation:
;2) spaces per level, similar to JavaScript's JSON.stringify() 'space' parameter
; JSON array elements and object members will be pretty-printed with the indent level
;3) Sanity check of input json data for level of nesting. capped at 63
;4) 0=suppress error on built-in object types, just output a class name, e.g.: "File Object"
;5) 0=supress error if the root is not an object:
static Compact:=0, Space:=4, Nesting:=10, ErrObjType:=0, ErrObj:=0
;"stringify": format [associative] array (object) as JSON string
;str:=json.set(obj). returns empty-line if non-object passed
Set(_o, _d:="") { ;_d:cur indent
static q:=Chr(34), t, p
if !IsObject(_o) ;"string" | number
return this.ErrObj && this._T("Not an object.")
(p=this.Space) || t:=indent(p:=this.Space)
, (this.Compact) ? n:=d:="" : (n:="`n", d:=_d t), VarSetCapacity(s,1024*8)
try a:=_o._ ;trying to get a unique key
catch ;"Unknown property" exception means its a built-in inenumerable obj
return(s:=Type(_o) " Object"
, (this.ErrObjType) && this._T(s " type is not supported."), "{" q s q "}")
if(a:=_o.HasKey(_o.Count())){ ;=0: not a linear array
for i in _o ;loop check for tricky arr, e.g. {"key":0,"2":0}
if !(a:=i=A_Index)
break
} ;flag a=0:associative or sparse (e.g. [1,,3]) array -> to be treated as obj {}
for k,v in _o ;recursive
s.=d (a ? "" : q k q ":") (isObject(v) ? this.Set(v, d)
: (Type(v)=="String") ? q v q : (Type(v)=="Float") ? Format("{:g}", v) : v) "," n
return(a ? "[" : "{") (s ? (n RTrim(s, "," n) n _d) : "") (a ? "]" : "}") ;wrap in brackets
indent(n)=>--n ? indent(n) " ":""
}
;parse json string. obj:=json.get(str)
;JSON keys are always "strings", expected values r: number|"string"|{object}|[array]
Get(ByRef _s){
static q:=Chr(34), x:=q "{[0123456789-" ;json: allowed chars outside strings
n:=0, k:="", kf:=0, s:=[b:=root:={}], z:="{", y:=0
;a=flag: 1:array [], 0:object {}, y=bits for 63 nested levels for a flag
; n=cur. parsing pos in the json str, c=cur chr, z=next chr(s) expected
; v=cur val, k=cur key name, kf=flag: literal key name is allowed as next token
; d=len of the val/literal right string, u=flag: we've got key (not val) at this step
; s:{} =stack, b:{} =sub-objects/keys for cur level of nesting
while(c:=SubStr(_s, ++n, 1))!==""
InStr(" `t`n`r", c,1) || ( ;1=CaseSensitive
InStr(z,c,1) || E(c, n), u:=0
, InStr("}]", c) ? ((s.1=root) && E(c, n)
, s.RemoveAt(1), y>>=1, b:=s.1, z:=(a:=y&1) ? ",]" : ",}")
: InStr(",:",c,1) ? (z:=(kf:=!a && c==",") ? q:x)
: InStr("{[",c,1) ? (s.Count()>this.Nesting && E(c, n)
, (c=="{") ? (kf:=1, y:=y<<1&~1, z:=q "}") : (y:=y<<1|1, z:=x "]")
, s.InsertAt(1,v:={}), a ? k:=b.Push(v):b[k]:=v, b:=s.1, a:=y&1)
: ((c==q) ? (d:=InStr(_s,q,1, n+1),v:=SubStr(_s, n+1, d-n-1)
, n:=d, (kf) && (k:=v, z:=":", u:=1)) ;string literals
: (d:=SubStr(_s, n) ~= "[\]\},\s]|$",v:=SubStr(_s, n, d-1)
, n+=d-2, (v is "Number") ? v+=0:E(c, n)) ;number
, (u) || (a ? (k:=b.Push(v), z:=",]"):(b[k]:=v, z:=",}")))
)
return(s.1=root || E(c, n), s[1,""]) ;s.Count()!=1 ;unpaired {}, []
E(_c,_n)=>this._T("Unexpected char <" _c "> in pos " _n)
}
_T(_s){
throw(_s)
}
}
; Test runs
j:="
(
{
"a":[
111,
"aa"
],
"amount":101,
"price":104.2,
"r1":{
"misc":12,
"r2":{
"type1":11,
"type2":11
}
},
"type":"ask"
}
)"
j:='{"r1":{"r2":{"type1":11,"type2":11},"misc":12}, "type":"ask","price":104.2,"amount":101, "a":[111,"aa"]}'
n:=20000
t:=A_TickCount
loop(n)
b:=json.Get(j)
a1:=A_TickCount-t
t:=A_TickCount
loop(n)
s:=json.Set(b)
a2:=A_TickCount-t
msgbox(clipboard:=a1 "|" a2 "`n`n" s)
Code: Select all
Anchor(_c, _a, d:=0){
;controls are moved/resized by a fraction of the amount the gui changes size
;e.g. New pX := orig. pX + factor * ( current guiW - orig. guiW )
static pos
sig=`n%A_Gui%:%_c%= ;unique prefix to store pos/size
if(d=1)
draw:="Draw", d:=1,1,1,1
else if (!d)
d:=1,1,1,1
StringSplit q, d, `,
;on first call for this control, remember original position, size and factor:
if !InStr(pos, sig){
;get pos/size of control
GuiControlGet p, Pos, %_c%
;store (orig. control pos/size - orig. gui width/height * factor) and factor in one var
pos:=pos . sig . px-A_GuiWidth*q1 . "/" . pw-A_GuiWidth*q2 . "/"
. py-A_GuiHeight*q3 . "/" . ph-A_GuiHeight*q4 . "/"
}
;get pos/size string and split into array
StringTrimLeft p, pos, InStr(pos, sig)-1+StrLen(sig)
StringSplit p, p, /
c:="xwyh"
;calculate new position and size
loop parse, c
if InStr(_a, A_LoopField){
if(A_Index<3) ;for x/w use current gui width
e:=p%A_Index%+A_GuiWidth*q%A_Index%
else
e:=p%A_Index%+A_GuiHeight*q%A_Index% ;otherwise use current gui height
;combine "x/w/y/h"
;with (orig. control pos/size - orig. gui width/height*factor + current gui width/height*factor)
m = %m%%A_LoopField%%e%
}
;move/resize control to new pos/size
GuiControl %A_Gui%:Move%draw%, %_c%, %m%
}
Code: Select all
#SingleInstance force
global oo:={}
;#Include %A_ScriptDir%\anchor v3.2.ahk
o:=oo
g:=o[1]:=GuiCreate(" +Resize","test")
g.marginX:=g.marginY:=3
o[4]:=g.Add("button", "section vBtnAddGroup" , "+")
o[5]:=g.Add("edit", "x+1 ys+1 w200 vEdtGroupName")
o[6]:=g.Add("button", "x+1 ys vBtnRemoveGroup" , "-")
o[7]:=g.Add("button", "x+40 ys vBtnAddScriptlet" , "+")
o[8]:=g.Add("edit", "x+1 ys+1 w150 vEdtScriptletName")
o[9]:=g.Add("button", "x+1 ys vBtnRemoveScriptlet", "-")
o[10]:=g.Add("ddl", "x+40 ys w150 vDdbScriptletInGroup Sort")
o[11]:=g.Add("button", "ys vBtnCopyToClipboard", "Copy to &Clipboard")
o[12]:=g.Add("treeview", "xs section w250 h500 vTrvScriptlets")
o[13]:=g.Add("edit", "ys w500 h500 vEdtScriptletData")
g.OnEvent("Close", ()=>ExitApp())
g.OnEvent("Escape", ()=>ExitApp())
g.OnEvent("Size", "Size")
g.Show("AutoSize")
exit
Size(_g, _e, _w, _h){
; if(_e<0)
; msgbox(_g.title ":Minimized")
}
Code: Select all
a:=[1,2,3,4]
msgbox(a.HasKey(a.Count())) ;=1
a:=[1,2,,4]
msgbox(a.HasKey(a.Count())) ;=0 (not a linear array)
Code: Select all
if(a:=_o.HasKey(_o.Count())){ ;=0: not a linear array
for i in _o
if !(a:=i=A_Index)
break
} ;flag a=0:associative or sparse (e.g. [1,,3]) array -> to be treated as obj {}
Code: Select all
a:={"key":0,"2":0}
msgbox(a.HasKey(a.Count())) ;=1, but it CANT be exported as [] array, it has a named key!
Code: Select all
/*_C func
int main(int a) {
return a+1;
}
*/
Code: Select all
/*
Needs TCC: https://download.savannah.gnu.org/releases/tinycc/tcc-0.9.27-win64-bin.zip
place script in the same folder as libtcc.dll
*/
#singleinstance force
load_cObject(make_cObject("otest.o"), code)
myfunc(x) => DllCall(&code, "Int", x)
/*_C func
int main(int a) {
return a+1;
}
*/
t := A_TickCount
x := 0
loop 1000000
x := myfunc(x)
msgbox(A_TickCount - t " : " x)
load_cObject(oName, ByRef code) {
o := FileRead(A_ScriptDir "\" oName, "RAW")
,tableAdd := NumGet(o, 0x28, "Ptr")
,toffset := 0x40
,padd := NumGet(o, tableAdd + toffset +0x18, "UInt")
,plen := NumGet(o, tableAdd + toffset +0x20, "UInt")
,VarSetCapacity(code, plen)
Loop plen//4
NumPut(NumGet(o, padd + (A_Index - 1)*4, "UInt"), code, (A_Index-1)*4, "UInt")
return DllCall("VirtualProtect", "Ptr", &code, "UInt", plen, "UInt", 0x40, "Ptr*" , 0)
}
make_cObject(cObjectName) {
directory := A_ScriptDir
;read c code
,startLabel := "/*_C" " func"
,endLabel := "*/"
,script := fileRead(A_ScriptFullPath)
,cStart := InStr(script, startLabel) + StrLen(startLabel) + 2
,cEnd := InStr(script, endLabel, , cStart + 1)
,cStr := SubStr(script, cStart, cEnd - cStart)
;LIBTCC calls
htcclib := DllCall("LoadLibrary", "Str", directory "\libtcc.dll", "Ptr")
,Context := DllCall("libtcc\tcc_new", "Ptr")
;set path to our include/lib folders
;~ StrPutVar(directory "\lib", libraryPath)
;~ StrPutVar(directory "\include", includePath)
;~ StrPutVar(directory "\include", sysincludePath)
;~ StrPutVar(directory, tcclibPath)
;~ DllCall("libtcc\tcc_add_library_path", "Ptr", Context, "Str", libraryPath, "Int")
;~ DllCall("libtcc\tcc_add_include_path", "Ptr", Context, "Str", includePath, "Int")
;~ DllCall("libtcc\tcc_add_sysinclude_path", "Ptr", Context, "Str", sysincludePath, "Int")
;~ DllCall("libtcc\tcc_set_lib_path", "Ptr", Context, "Str", tcclibPath)
;StrPutVar("", options)
;DllCall("libtcc\tcc_set_options", "Ptr", Context, "Str", options)
;TCC_OUTPUT_MEMORY := 1 ; output will be run in memory (default)
;TCC_OUTPUT_EXE := 2 ; executable file
;TCC_OUTPUT_DLL := 3 ; dynamic library
,TCC_OUTPUT_OBJ := 4 ; object file
;TCC_OUTPUT_PREPROCESS := 5 ; only preprocess (used internally)
,DllCall("libtcc\tcc_set_output_type", "Ptr", Context, "UInt", TCC_OUTPUT_OBJ, "Int")
,StrPutVar(cStr, _cStr)
,DllCall("libtcc\tcc_compile_string", "Ptr", Context, "Str", _cStr, "Int")
,StrPutVar(directory "\" cObjectName, filename)
,DllCall("libtcc\tcc_output_file", "Ptr", Context, "Str", filename, "Int")
;clean up
,DllCall("libtcc\tcc_delete", "Ptr", Context)
,DllCall("FreeLibrary", "Ptr", htcclib)
return cObjectName
StrPutVar(s, ByRef v) => (VarSetCapacity(v, StrPut(s, "cp0")), StrPut(s, &v, "cp0"))
}
welcome back
Very pertinent find u come up with! the reason I havent touched C builders for years is gigabytes of bloatware. AHK is a mere godsend here with a sole 500Kb (after UPX compression) file (and w/o any dependancies) required to run scripts for everyday tasks.Tiny C Compiler
Code: Select all
SmartT(_a){ ;for float numbers, get rid of leading/trailing 0 and .
a:="" _a
if(InStr(a,".")){ ;if decimals
while(SubStr(a,-1,1)="0")
a:=SubStr(a,1,-1)
if(SubStr(a,-1,1)=".")
a:=SubStr(a,1,-1)
}
return a
}
;g: Leading/trailing zeros are truncated, and the decimal point appears only
; if one or more digits follow it
SmartT_(_a)=>Format("{:g}", _a)
a:="-0000001.55" ; -> -1.55
n:=200*1000
t:=A_TickCount
loop(n)
s:=SmartT(a)
a1:=A_TickCount-t
t:=A_TickCount
loop(n)
b:=SmartT_(a)
a2:=A_TickCount-t
msgbox(clipboard:=a1 "|" a2 "`n`n" s)
Users browsing this forum: sofista, teadrinker and 47 guests