Below you will find a test using DDB vs. COM vs. Laszlo vers. and vs. toralf version.
Edit:
Add and get are faster than com now
But DDB consumes still more memory, please help
Code:
#Include %A_ScriptDir%\Com.ahk
#Include %A_ScriptDir%\DDB.ahk
SetBatchLines,-1
;DDB create
DDB("DB","n",0)
;COM_Init() ; Initialized COM in DDB already
d := COM_CreateObject("Scripting.Dictionary") ; Create dictionary.
;Dic create by Toralf
Dic()
;Create Dictionary by Laszlo
dic:=CreateDictionary()
;how ofter to loop
LoopTimes:=10000
SplashTextOn,300,20,Creating %looptimes% items using DDB function
;Create 10000 Items
Start:=A_TickCount
Loop % LoopTimes
DDB("DB","+",A_Index,A_Index)
CreateDDB:=A_TickCount-Start
SplashTextOn,300,20,Creating %looptimes% items using COM function
Start:=A_TickCount
Loop % LoopTimes
COM_Invoke(d,"Item",A_Index,A_Index)
CreateCOM:=A_TickCount-Start
SplashTextOn,300,20,Creating %looptimes% items using Dic function
Start:=A_TickCount
Loop % LoopTimes
Dic_Add(A_Index,A_Index)
CreateDic:=A_TickCount-Start
SplashTextOn,300,20,Creating %looptimes% items using Add function
Start:=A_TickCount
Loop % LoopTimes
Add(dic,A_Index,A_Index)
CreateDict:=A_TickCount-Start
SplashTextOff
MsgBox % "Create " LoopTimes " items`nDDB: " CreateDDB "`nCOM: " CreateCOM "`nDic: " CreateDic "`nAdd: " CreateDict
SplashTextOn,300,20,Get %looptimes% items using DDB function
Start:=A_TickCount
Loop % LoopTimes
DDB("DB","<",A_Index,A_Index)
CreateDDB:=A_TickCount-Start
SplashTextOn,300,20,Get %looptimes% items using COM function
Start:=A_TickCount
Loop % LoopTimes
COM_Invoke(d,"Item",A_Index)
CreateCOM:=A_TickCount-Start
SplashTextOn,300,20,Get %looptimes% items using Dic function
Start:=A_TickCount
Loop % LoopTimes
Dic_Get(A_Index)
CreateDic:=A_TickCount-Start
SplashTextOn,300,20,Get %looptimes% items using Get function
Start:=A_TickCount
Loop % LoopTimes
Get(dic, A_Index)
CreateDict:=A_TickCount-Start
SplashTextOff
MsgBox % "Get " LoopTimes " items`nDDB: " CreateDDB "`nCOM: " CreateCOM "`nDic: " CreateDic "`nGet: " CreateDict
COM_Release(d) ; Done using dictionary d.
;COM_Term() ; Done using COM is done in DDB()
Dic(1)
Destroydictionary(dic)
DDB()
;###############################################################################
;### Scripting.Dictionary COM object Modul ###
;###############################################################################
Dic(Action=""){
static initialized, pdic
If (Action = "pdic") ;return pdic
Return pdic
Else If Action { ;exit - clean up
Dic_DestroyDictionary(pdic)
;DllCall("ole32\CoUninitialize")
}Else{ ;create a dictionary
;If !initialized {
; initialized := True
; DllCall("ole32\CoInitialize", UInt,0)
; }
pdic := Dic_CreateDictionary()
}
Return 1
}
Dic_Add(sKey, sItm) { ; If key exists: no effect (<--> Set)
pdic := Dic("pdic")
Dic_AllocBString(pKey, var1, sKey)
Dic_AllocBString(pItm, var2, sItm)
DllCall(Dic_VTable(pdic,10), UInt,pdic, UInt,&var1, UInt,&var2)
DllCall("oleaut32\SysFreeString", UInt,pKey)
DllCall("oleaut32\SysFreeString", UInt,pItm)
}
Dic_Set(sKey, sItm) { ; If key exists, update the item, Else create a new entry
pdic := Dic("pdic")
Dic_AllocBString(pKey, var1, sKey)
Dic_AllocBString(pItm, var2, sItm)
DllCall(Dic_VTable(pdic,8), UInt,pdic, UInt,&var1, UInt,&var2) ; 8 (Set0 -> 7)
DllCall("oleaut32\SysFreeString", UInt,pKey)
DllCall("oleaut32\SysFreeString", UInt,pItm)
}
Dic_Get(sKey) { ; empty if not exists
pdic := Dic("pdic")
Dic_AllocBString(pKey, var1, sKey)
DllCall(Dic_VTable(pdic,12), UInt,pdic, UInt,&var1, IntP,bExist)
If bExist { ; to avoid creating an unwanted new entry
VarSetCapacity(var2, 16, 0)
DllCall(Dic_VTable(pdic,9), UInt,pdic, UInt,&var1, UInt,&var2)
pItm := *(&var2+8) | *(&var2+9) << 8 | *(&var2+10) << 16 | *(&var2+11) << 24
Dic_Unicode2Ansi(pItm, sItm)
DllCall("oleaut32\SysFreeString", UInt,pItm)
}
DllCall("oleaut32\SysFreeString", UInt,pKey)
Return sItm
}
Dic_NextKey(ByRef penum) { ; penum = "": create new list
pdic := Dic("pdic")
If penum = ; not static: allow multiple independent lists
DllCall(Dic_VTable(pdic,20), UInt,pdic, UIntP,penum) ; create key-list in penum
VarSetCapacity(var, 16, 0)
If DllCall(Dic_VTable(penum,3), UInt,penum, UInt,1, UInt,&var, UInt,0) {
DllCall(Dic_VTable(penum,2), UInt,penum) ; END: destroy key-list
penum = ; signal end of list
Return ; empty
}
pKey := Dic_UInt@(&var + 8)
Dic_Unicode2Ansi(pKey, sKey)
DllCall("oleaut32\SysFreeString", UInt,pKey)
Return skey
}
Dic_Count() { ; #entries
pdic := Dic("pdic")
DllCall(Dic_VTable(pdic,11), UInt,pdic, IntP,nCount)
Return nCount
}
Dic_Exists(sKey) {
pdic := Dic("pdic")
Dic_AllocBString(pKey, var, sKey)
DllCall(Dic_VTable(pdic,12), UInt,pdic, UInt,&var, IntP,bExist)
DllCall("oleaut32\SysFreeString", UInt,pKey)
Return bExist
}
Dic_Rename(sKeyFr, sKeyTo) {
pdic := Dic("pdic")
Dic_AllocBString(pKeyFr, var1, sKeyFr)
Dic_AllocBString(pKeyTo, var2, sKeyTo)
DllCall(Dic_VTable(pdic,14), UInt,pdic, UInt,&var1, UInt,&var2)
DllCall("oleaut32\SysFreeString", UInt,pKeyFr)
DllCall("oleaut32\SysFreeString", UInt,pKeyTo)
}
Dic_Remove(sKey) {
pdic := Dic("pdic")
Dic_AllocBString(pKey, var, sKey)
DllCall(Dic_VTable(pdic,16), UInt,pdic, UInt,&var)
DllCall("oleaut32\SysFreeString", UInt,pKey)
}
Dic_RemoveAll() {
pdic := Dic("pdic")
Return DllCall(Dic_VTable(pdic,17), UInt,pdic)
}
Dic_SetCompareMode(nCompMode = 1) { ; 0: Binary, 1: Text, 2: Database, n: LCID
pdic := Dic("pdic")
Modes = btd
Loop, Parse, Modes
If RegExMatch(nCompMode, "i)^" A_LoopField)
nCompMode := A_Index - 1
DllCall(Dic_VTable(pdic,18), UInt,pdic, Int,nCompMode)
}
Dic_GetCompareMode() {
pdic := Dic("pdic")
DllCall(Dic_VTable(pdic,19), UInt,pdic, IntP,nCompMode)
Return nCompMode
}
Dic_HashVal(sKey) {
pdic := Dic("pdic")
Dic_AllocBString(pKey, var1, sKey)
DllCall(Dic_VTable(pdic,12), UInt,pdic, UInt,&var1, IntP,bExist)
VarSetCapacity(var2, 16, 0)
DllCall(Dic_VTable(pdic,21), UInt,pdic, UInt,&var1, UInt,&var2)
nHashVal := *(&var2+8) | *(&var2+9) << 8 | *(&var2+10) << 16 | *(&var2+11) << 24
DllCall("oleaut32\SysFreeString", UInt,pKey)
Return nHashVal
}
;######### PRIVATE FUNCTIONS ################################################
Dic_CreateDictionary() {
CLSID_Dictionary := "{EE09B103-97E0-11CF-978F-00A02463E06F}"
IID_IDictionary := "{42C642C1-97E1-11CF-978F-00A02463E06F}"
Return Dic_CreateObject(CLSID_Dictionary, IID_IDictionary)
}
Dic_DestroyDictionary(pdic) {
DllCall(Dic_UInt@(Dic_UInt@(pdic)+8), UInt,pdic)
}
Dic_AllocBString(ByRef Key, ByRef Var, sString) {
Dic_Ansi2Unicode(sString, wString)
Key := DllCall("oleaut32\SysAllocString", Str,wString)
VarSetCapacity(Var, 16, 0)
DllCall("ntdll\RtlFillMemoryUlong", UInt,&Var, UInt,4, UInt,8)
DllCall("ntdll\RtlFillMemoryUlong", UInt,&Var+8,UInt,4, UInt,Key)
}
Dic_UInt@(ptr) {
Return *ptr | *(ptr+1) << 8 | *(ptr+2) << 16 | *(ptr+3) << 24
}
Dic_CreateObject(ByRef CLSID, ByRef IID, CLSCTX = 5) {
If StrLen(CLSID) = 38
Dic_GUID4String(CLSID, CLSID)
If StrLen(IID) = 38
Dic_GUID4String(IID, IID)
DllCall("ole32\CoCreateInstance", Str,CLSID, UInt,0, UInt,CLSCTX, Str,IID, UIntP,ppv)
Return ppv
}
Dic_GUID4String(Byref CLSID, sString) {
VarSetCapacity(CLSID, 16)
Dic_Ansi2Unicode(sString, wString, 38)
DllCall("ole32\CLSIDFromString", Str,wString, Str,CLSID)
}
Dic_Ansi2Unicode(ByRef sString, ByRef wString, nLen = 0) {
If !nLen
nLen := DllCall("MultiByteToWideChar", UInt,0, UInt,0, UInt,&sString, Int,-1, UInt,0, Int,0)
VarSetCapacity(wString, nLen*2 + 1)
DllCall("MultiByteToWideChar", UInt,0, UInt,0, UInt,&sString, Int,-1, UInt,&wString, Int,nLen)
}
Dic_VTable(ppv, idx) {
Return Dic_UInt@(Dic_UInt@(ppv) + idx*4)
}
Dic_Unicode2Ansi(ByRef wString, ByRef sString, nLen = 0) {
pString := wString + 0 > 65535 ? wString : &wString
If !nLen
nLen := DllCall("WideCharToMultiByte", UInt,0, UInt,0, UInt,pString, Int,-1, UInt,0, Int,0, UInt,0, UInt,0)
VarSetCapacity(sString, nLen)
DllCall("WideCharToMultiByte", UInt,0, UInt,0, UInt,pString, Int,-1, Str,sString, Int,nLen, UInt,0, UInt,0)
}
;By Laszlo
CreateDictionary(nCompMode = 0) { ; Compare mode = 0: Binary, 1: Text, 2: Database, n: LCID
CLSID_Dictionary := "{EE09B103-97E0-11CF-978F-00A02463E06F}"
IID_IDictionary := "{42C642C1-97E1-11CF-978F-00A02463E06F}"
pdic := CreateObject(CLSID_Dictionary, IID_IDictionary)
DllCall(VTable(pdic,18), UInt,pdic, Int,nCompMode) ; Set compare mode
Return pdic
}
DestroyDictionary(pdic) {
DllCall(UInt@(UInt@(pdic)+8), UInt,pdic)
}
Add(pdic, sKey, sItm) { ; If key exists: no effect (<--> Set)
AllocBString(pKey, var1, sKey)
AllocBString(pItm, var2, sItm)
DllCall(VTable(pdic,10), UInt,pdic, UInt,&var1, UInt,&var2)
DllCall("oleaut32\SysFreeString", UInt,pKey)
DllCall("oleaut32\SysFreeString", UInt,pItm)
}
Set(pdic, sKey, sItm) { ; If key exists, update the item, Else create a new entry
AllocBString(pKey, var1, sKey)
AllocBString(pItm, var2, sItm)
DllCall(VTable(pdic,8), UInt,pdic, UInt,&var1, UInt,&var2) ; 8 (Set0 -> 7)
DllCall("oleaut32\SysFreeString", UInt,pKey)
DllCall("oleaut32\SysFreeString", UInt,pItm)
}
Get(pdic, sKey) { ; empty if not exists
AllocBString(pKey, var1, sKey)
DllCall(VTable(pdic,12), UInt,pdic, UInt,&var1, IntP,bExist)
If bExist { ; to avoid creating an unwanted new entry
VarSetCapacity(var2, 16, 0)
DllCall(VTable(pdic,9), UInt,pdic, UInt,&var1, UInt,&var2)
pItm := *(&var2+8) | *(&var2+9) << 8 | *(&var2+10) << 16 | *(&var2+11) << 24
Unicode2Ansi(pItm, sItm)
DllCall("oleaut32\SysFreeString", UInt,pItm)
}
DllCall("oleaut32\SysFreeString", UInt,pKey)
Return sItm
}
Count(pdic) { ; #entries
DllCall(VTable(pdic,11), UInt,pdic, IntP,nCount)
Return nCount
}
Exists(pdic, sKey) {
AllocBString(pKey, var, sKey)
DllCall(VTable(pdic,12), UInt,pdic, UInt,&var, IntP,bExist)
DllCall("oleaut32\SysFreeString", UInt,pKey)
Return bExist
}
Rename(pdic, sKeyFr, sKeyTo) {
AllocBString(pKeyFr, var1, sKeyFr)
AllocBString(pKeyTo, var2, sKeyTo)
DllCall(VTable(pdic,14), UInt,pdic, UInt,&var1, UInt,&var2)
DllCall("oleaut32\SysFreeString", UInt,pKeyFr)
DllCall("oleaut32\SysFreeString", UInt,pKeyTo)
}
Remove(pdic, sKey) {
AllocBString(pKey, var, sKey)
DllCall(VTable(pdic,16), UInt,pdic, UInt,&var)
DllCall("oleaut32\SysFreeString", UInt,pKey)
}
RemoveAll(pdic) {
Return DllCall(VTable(pdic,17), UInt,pdic)
}
GetCompareMode(pdic) {
DllCall(VTable(pdic,19), UInt,pdic, IntP,nCompMode)
Return nCompMode
}
HashVal(pdic,sKey) {
AllocBString(pKey, var1, sKey)
DllCall(VTable(pdic,12), UInt,pdic, UInt,&var1, IntP,bExist)
VarSetCapacity(var2, 16, 0)
DllCall(VTable(pdic,21), UInt,pdic, UInt,&var1, UInt,&var2)
nHashVal := *(&var2+8) | *(&var2+9) << 8 | *(&var2+10) << 16 | *(&var2+11) << 24
DllCall("oleaut32\SysFreeString", UInt,pKey)
Return nHashVal
}
NextKey(ByRef penum, pdic="") { ; penum = "": create new list. pdic=0,"Clear": destroy list
If penum = ; not static: allow multiple independent lists
DllCall(VTable(pdic,20), UInt,pdic, UIntP,penum) ; create key-list in penum
VarSetCapacity(var, 16, 0)
If (InStr("Clear0",pdic) || DllCall(VTable(penum,3), UInt,penum, UInt,1, UInt,&var, UInt,0)) {
DllCall(VTable(penum,2), UInt,penum) ; END: destroy key-list
penum = ; signal end of list
Return ; empty
}
pKey := UInt@(&var + 8)
Unicode2Ansi(pKey, sKey)
DllCall("oleaut32\SysFreeString", UInt,pKey)
Return skey
}
AllocBString(ByRef Key, ByRef Var, sString) {
Ansi2Unicode(sString, wString)
Key := DllCall("oleaut32\SysAllocString", Str,wString)
VarSetCapacity(Var, 16, 0)
DllCall("ntdll\RtlFillMemoryUlong", UInt,&Var, UInt,4, UInt,8)
DllCall("ntdll\RtlFillMemoryUlong", UInt,&Var+8,UInt,4, UInt,Key)
}
UInt@(ptr) {
Return *ptr | *(ptr+1) << 8 | *(ptr+2) << 16 | *(ptr+3) << 24
}
;;; COM Helper functions
CreateObject(ByRef CLSID, ByRef IID, CLSCTX = 5) {
If StrLen(CLSID) = 38
GUID4String(CLSID, CLSID)
If StrLen(IID) = 38
GUID4String(IID, IID)
DllCall("ole32\CoCreateInstance", Str,CLSID, UInt,0, UInt,CLSCTX, Str,IID, UIntP,ppv)
Return ppv
}
GUID4String(Byref CLSID, sString) {
VarSetCapacity(CLSID, 16)
Ansi2Unicode(sString, wString, 38)
DllCall("ole32\CLSIDFromString", Str,wString, Str,CLSID)
}
Ansi2Unicode(ByRef sString, ByRef wString, nLen = 0) {
If !nLen
nLen := DllCall("MultiByteToWideChar", UInt,0, UInt,0, UInt,&sString, Int,-1, UInt,0, Int,0)
VarSetCapacity(wString, nLen*2 + 1)
DllCall("MultiByteToWideChar", UInt,0, UInt,0, UInt,&sString, Int,-1, UInt,&wString, Int,nLen)
}
VTable(ppv, idx) {
Return UInt@(UInt@(ppv) + idx*4)
}
Unicode2Ansi(ByRef wString, ByRef sString, nLen = 0) {
pString := wString + 0 > 65535 ? wString : &wString
If !nLen
nLen := DllCall("WideCharToMultiByte", UInt,0, UInt,0, UInt,pString, Int,-1, UInt,0, Int,0, UInt,0, UInt,0)
VarSetCapacity(sString, nLen)
DllCall("WideCharToMultiByte", UInt,0, UInt,0, UInt,pString, Int,-1, Str,sString, Int,nLen, UInt,0, UInt,0)
}