added support for VarSetCapacity "Buffer"
the trick is that COPY of Buffer is different from Byref Buffer, while copy of String is identical
Code: Select all
if (v "") { ;concatenation works too, you can MsgBox % Buffer, but a Buffer won't concat
return "String" ;non empty String, we cover empty String down below
} else {
return "Buffer"
}
and added support for Array
isArray() by jeeswg, then I edited it..
Type.ahk
Code: Select all
; /*
; TESTS
emptyString:=""
assert(type(emptyString), "String") ;String
VarSetCapacity(structZero, 0)
; MsgBox % VarSetCapacity(structZero) ;0
assert(type(structZero), "String") ;String..
; THEY'RE THE SAME ADDRESS &emptyString==&structZero==5369930888, seeing "" can mean that the Buffer has been freed, and no one uses an empty Buffer
; MsgBox % &emptyString "`n" &structZero
VarSetCapacity(struct1, 16)
; Msgbox % VarSetCapacity(struct1) ;16
assert(type(struct1), "Buffer") ;Buffer
VarSetCapacity(struct2, 1)
; Msgbox % VarSetCapacity(struct2) ;6 even if 1
assert(type(struct2), "Buffer") ;Buffer
randomBuff(len, Byref RandomBuffer) {
static hModule_Advapi32 := DllCall("LoadLibrary", "Str", "Advapi32.dll", "Ptr")
static Proc_RtlGenRandom := DllCall("GetProcAddress", "Ptr", hModule_Advapi32, "AStr", "SystemFunction036", "Ptr")
RandomBufferLength:=Ceil(0.75*len)
VarSetCapacity(RandomBuffer, RandomBufferLength)
ok:=DllCall(Proc_RtlGenRandom, "Ptr", &RandomBuffer, "UInt", RandomBufferLength)
}
randomBuff(100, RandomBuffer)
assert(type(RandomBuffer), "Buffer")
assert(type("abc"), "String")
assert(type("1"), "String")
assert(type(1.1), "String")
assert(type(1), "Integer")
assert(type(1/1), "Float")
assert(type([]), "Array")
assert(type([1,2,3]), "Array")
assert(type({1:1, 3:3, 4:4}), "Object")
assert(type({1:"a", 3:"c", x:"x"}), "Object")
assert(type({1:"a", "2":"b", 3:"c"}), "Object")
assert(type(1), "fwiefowief") ;test if my assert function works :)
assert(actual, expected) {
if !(actual==expected)
MsgBox % "Line " Exception("", -1).Line " Failed`nactual: " actual "`nexpected: " expected
;https://www.autohotkey.com/board/topic/71487-can-a-function-grab-the-calling-lines-line-number/#post_id_453358
}
; */
; "0 size String" v=="" && [v].GetCapacity(1)==0 && VarSetCapacity()==0
; "0 size Buffer" v=="" && [v].GetCapacity(1)==0 && VarSetCapacity()==0
; "16 size Buffer with no string representation" v=="" && [v].GetCapacity(1)==0 && VarSetCapacity()>0
; "String" v!="" && [v].GetCapacity(1)>0 && VarSetCapacity()>0
; Byref "Buffer" v!="" && [v].GetCapacity(1)>0 && VarSetCapacity()>0
; I think Byref Buffer could be v=="" (by chance)
; the trick is that COPY of Buffer is different from Byref Buffer, while copy of String is identical
; COPY OF BUFFER v=="" && [v].GetCapacity(1)==0 && VarSetCapacity()>0
; Number v!="" && [v].GetCapacity(1)=="" && VarSetCapacity()==0
type(Byref v) { ; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=2306
if IsObject(v) {
; if isArray() https://www.autohotkey.com/boards/viewtopic.php?f=76&t=64332&p=434396#p434396
if (!ObjCount(v) || ObjMinIndex(v) == 1 && ObjMaxIndex(v) == ObjCount(v) && v.Clone().Delete(1, v.MaxIndex()) == ObjCount(v)) {
return "Array"
} else {
return "Object"
}
} else {
objCapacity:=[v].GetCapacity(1)
if (objCapacity>0) {
;strings will get perfectly copied, but Buffer won't
; if ([copy:=v].GetCapacity(1)>0) {
if (v "") { ;concatenation works too, you can MsgBox % Buffer, but a Buffer won't concat
return "String" ;non empty String, we cover empty String down below
} else {
return "Buffer" ;Buffer with string representation, but can't concat
}
} else if (objCapacity==0) {
if (VarSetCapacity(v)) {
return "Buffer" ; 16 size Buffer with no String representation
} else {
return "String" ; 0 size String And 0 size Buffer, they're the same thing
}
} else {
if (InStr(v,".")) {
return "Float"
} else {
return "Integer"
}
}
}
}
ternary version:
Code: Select all
type(Byref v) { ; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=2306
return IsObject(v) ? ((!ObjCount(v) || ObjMinIndex(v) == 1 && ObjMaxIndex(v) == ObjCount(v) && v.Clone().Delete(1, v.MaxIndex()) == ObjCount(v)) ? "Array" : "Object") : ((objCapacity:=[v].GetCapacity(1))>0 ? (v "" ? "String" : "Buffer") : objCapacity==0 ? (VarSetCapacity(v) ? "Buffer" : "String") : (InStr(v,".") ? "Float" : "Integer"))
}
version with "uninitialized variable" added:
Code: Select all
; Double-deref "" is a fatal error in general, try (MsgBox % %v%)
; so I can 'not support it', I also cannot support it...
; check before Double-deref:
; (v=="" ? "fatal error" : type(%v%))
MsgBox % type(a) ;"uninitialized variable"
MsgBox % type(a:="") ;"String"
MsgBox % (v=="" ? "fatal error" : type(%v%)) ;"fatal error"
v:="abc"
MsgBox % (v=="" ? "fatal error" : type(%v%)) ;"uninitialized variable"
type(Byref v) { ; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=2306
; Array, Object, String, Buffer, Float, Integer, uninitialized variable
static Func_mParam := 3*A_PtrSize, Var_mAttrib := 8 + 3*A_PtrSize + 1
, Var_mAliasFor := 8 + A_PtrSize
, VAR_ATTRIB_UNINITIALIZED := 0x04
, funcAddress := &Func("type")
if IsObject(v) {
; if isArray() https://www.autohotkey.com/boards/viewtopic.php?f=76&t=64332&p=434396#p434396
if (!ObjCount(v) || ObjMinIndex(v) == 1 && ObjMaxIndex(v) == ObjCount(v) && v.Clone().Delete(1, v.MaxIndex()) == ObjCount(v)) {
return "Array"
} else {
return "Object"
}
} else {
objCapacity:=[v].GetCapacity(1)
if (objCapacity>0) {
;strings will get perfectly copied, but Buffer won't
; if ([copy:=v].GetCapacity(1)>0) {
if (v "") { ;concatenation works too, you can MsgBox % Buffer, but a Buffer won't concat
return "String" ;non empty String, we cover empty String down below
} else {
return "Buffer" ;Buffer with string representation, but can't concat
}
} else if (objCapacity==0) {
if (VarSetCapacity(v)) {
return "Buffer" ; 16 size Buffer with no String representation
} else {
; click the spoiler at the bottom in https://www.autohotkey.com/boards/viewtopic.php?f=76&t=89664&start=20#p395439
if (return NumGet(NumGet(NumGet(NumGet(funcAddress + Func_mParam)) + Var_mAliasFor) + Var_mAttrib, "uchar") & VAR_ATTRIB_UNINITIALIZED) {
return "uninitialized variable"
} else {
return "String" ; 0 size String And 0 size Buffer, they're the same thing
}
}
} else {
if (InStr(v,".")) {
return "Float"
} else {
return "Integer"
}
}
}
}
___
I'm using this in Array_p()
to print a Buffer like this : < 255 0 1 3 >
I'm using recursion in a Byref function to print deep arrays
I have a question :
; using [Value24][1] because Value24 breaks Byref, why does it break Byref ?
(Ctrl+F to find this in code)
Code: Select all
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#SingleInstance, force
ListLines Off
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
SetBatchLines, -1
#KeyHistory 0
doPrint:=true
; doPrint:=false
emptyString:=""
printIfTrue(Array_p(emptyString))
VarSetCapacity(structZero, 0)
; MsgBox % VarSetCapacity(structZero) ;0
printIfTrue(Array_p(structZero))
; THEY'RE THE SAME ADDRESS &emptyString==&structZero==5369930888, seeing "" can mean that the Buffer has been freed, and no one uses an empty Buffer
; MsgBox % &emptyString "`n" &structZero
VarSetCapacity(struct1, 16)
; Msgbox % VarSetCapacity(struct1) ;16
printIfTrue(Array_p(struct1))
VarSetCapacity(struct2, 1)
; Msgbox % VarSetCapacity(struct2) ;6 even if 1
printIfTrue(Array_p(struct2))
randomBuff(len, Byref RandomBuffer) {
static hModule_Advapi32 := DllCall("LoadLibrary", "Str", "Advapi32.dll", "Ptr")
static Proc_RtlGenRandom := DllCall("GetProcAddress", "Ptr", hModule_Advapi32, "AStr", "SystemFunction036", "Ptr")
RandomBufferLength:=Ceil(0.75*len)
VarSetCapacity(RandomBuffer, RandomBufferLength)
ok:=DllCall(Proc_RtlGenRandom, "Ptr", &RandomBuffer, "UInt", RandomBufferLength)
}
randomBuff(100, RandomBuffer)
printIfTrue(Array_p(RandomBuffer))
printIfTrue(Array_p("abc"))
printIfTrue(Array_p("1"))
printIfTrue(Array_p(1.1))
printIfTrue(Array_p(1))
printIfTrue(Array_p(1/1))
printIfTrue(Array_p([]))
printIfTrue(Array_p([1,2,3]))
printIfTrue(Array_p({1:1, 3:3, 4:4}))
printIfTrue(Array_p({1:"a", 3:"c", x:"x"}))
printIfTrue(Array_p({1:"a", "2":"b", 3:"c"}))
ExitApp
printIfTrue(toPrint) {
global doPrint
if (doPrint) {
MsgBox % toPrint
}
}
type(Byref v) { ; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=2306
return IsObject(v) ? ((!ObjCount(v) || ObjMinIndex(v) == 1 && ObjMaxIndex(v) == ObjCount(v) && v.Clone().Delete(1, v.MaxIndex()) == ObjCount(v)) ? "Array" : "Object") : ((objCapacity:=[v].GetCapacity(1))>0 ? (v "" ? "String" : "Buffer") : objCapacity==0 ? (VarSetCapacity(v) ? "Buffer" : "String") : (InStr(v,".") ? "Float" : "Integer"))
}
;Byref for Buffer() < 255 0 1 3 >
Array_p(Byref Arr21, delim:=", ") {
OutPut:=""
theType:=type(Arr21)
switch (theType) {
case "Array":
; For Key23, Value24 in Arr21 { ;we cannot use this because it breaks Byref, why does it break Byref ?
For Key23 in Arr21 {
Output .= delim Array_p(Arr21[Key23], delim)
}
OutPut := "[" SubStr(OutPut, StrLen(delim)+1) "]" ;remove the first ", "
case "Object":
; using [Value24][1] because Value24 breaks Byref, why does it break Byref ?
For Key23, Value24 in Arr21 {
Output .= delim (type(Key23) == "String" ? """" Key23 """" : Key23) ":" Array_p([Value24][1], delim)
}
OutPut := "{" SubStr(OutPut, StrLen(delim)+1) "}" ;remove the first ", "
case "Integer", "Float":
Output .= Arr21
case "String":
Output .= """" Arr21 """"
case "Buffer":
Size:=VarSetCapacity(Arr21)
offset:=0
OutPut.="< "
while (offset < Size) {
OutPut.=NumGet(Arr21, offset, "UChar") " "
offset++
}
OutPut.=">"
}
Return OutPut
}
f3::Exitapp