Good point, I just changed VariantCopy and VariantCopyInt without thinking much.
Not sure why it used those APIs in the first place instead of just VB's copying.
Printable View
Good point, I just changed VariantCopy and VariantCopyInt without thinking much.
Not sure why it used those APIs in the first place instead of just VB's copying.
I now see that the MS's dictionary object have the parameters "inverted" too.
You have to provide the second parameter "Item" anyway, it is not optional, so I don't see why MS "broke" collection's order.
PS: I get the point @Arnould that in dictionaries becomes more important the key, but still think that it would have been better to keep compatibility with Collections.
That can cause trouble in code when moving from collections to dictionaries since both parameters are Variant and the developer could not realize about the change.
I updated the class, thanks Olaf and vbwins.
I found a bug in cHashDStr, and since it will be left here in the forum for anybody to download I want to fix it.
In the Remove method, the line:
causes an overflow error, since it is now Long.Code:mValues(Idx) = NoEntry
What do you suggest to use now with Long instead of NoEntry?
OK, updated the upload, there is no perfect solution. Now -&H7FFFFFFF is a reserved value (not allowed).
HOW TO USE RC6.cHashD?
DIM A AS NEW cHashD? CAN't use this
'Set Rc6cHashD_OldProc = New cHashD
Set Rc6cHashD_OldProc = New_c.HashD
The normal way is to call it like this: New cHashD
dim web1 as new rc6.cwebview
Most components can use the NEW ** method, but this one is not.
Although this rc6.chashd is not CHASHD.CLS, it is not off topic.
I call the same function to process the subclassed messages of multiple controls, so I need to obtain the original message processing address according to the handle value each time. Is there any way to make it faster?
If you can write a dedicated key-value object, it will be better if it is only for numbers. The faster the speed, the better, and you don't need to deal with duplicate data and other issues.
[The speed of the test is not necessarily accurate and is for reference only. This is just using ranges based on dictionaries with only 2 elements. If it is 1000, 100,000 data, the speed ranking may be completely different. The slower one here may be the fastest in big data.]
'0.0412 milliseconds, 24,300 times per second --GetProp(Hwnd, StrPtr_m_OldProc)
'0.0068 milliseconds, 147,100 times, AllUsedTime=17.0919 'ClsHashList
'0.0036 milliseconds, 277,800 times, AllUsedTime=21.0183 cHashD2 (vb6 class)
'0.0029 milliseconds, 344,800 times per second, AllUsedTime=5.589 --Collection(Hwnd & "")
'0.0027 milliseconds, 370,400 times per second, AllUsedTime=9.9265 'clsTrickHashTable
'0.0022 milliseconds, 454,500 times per second, AllUsedTime=10.0871 RC6.cCollection
'0.0008 milliseconds, 1.25 million times, AllUsedTime=1.3141 = Dictionary(Hwnd)-Dc_OldProc
Code:m_OldProc = SetWindowLong(Hwnd, GWL_WNDPROC, AddressOf ControlCallBack)
Private Function ControlCallBack(ByVal Hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim m_OldProc As Long
MsgCount = MsgCount + 1
Dim C1 As Currency, C2 As Currency, U1 As Currency
QueryPerformanceCounter C1
m_OldProc = Dc_OldProc(Hwnd)
QueryPerformanceCounter C2
'm_OldProc = clsTrickHashTable_OldProc(Hwnd)
'm_OldProc = ClsHashList_OldProc.Item(Hwnd & "")
'm_OldProc = Rc6cHashD_OldProc(Hwnd)
'm_OldProc = Rc6C_OldProc("" & Hwnd)
'm_OldProc = ListOldProc(Hwnd & "")
'GetProp(Hwnd, StrPtr_m_OldProc)
'GetProp(Hwnd, StrPtr("m_OldProc"))
Remember that all RC6 classes should be initialized with New_c, e.g.Code:Dim oHash As cHashD
Set oHash = New_c.HashD
New_c.Collection
New_c.StringBuilder
New_c.ArrayList(...)
You can view RC6.cConstructor in VB6-ObjectBrowser to get the initialization definition parameters for the classes.
Very good improvement.
Although Olaf provides the source code of cHashD, I would like RC6 to provide two cHashD forks:
(1) cStrVarHashD (String-Variant)
(2) cStrLngHashD (String-Long)
This not only allows RC6 users to more concisely emulate C# generics, but also allows me to avoid the biggest trouble/annoyance, which is that vbTextCompare is not valid for me in VB6-IDE environment.
Also, my parsers needs high-performance HashD, and optimized cStrLngHashD and cStrVarHashD are very important to me.
if i change to only for long type Dictionary object ,
Will it be faster to add BYVAL to the parameter?
Code:Public Sub Add(Key As Long, Item As Long)
Public Sub Add(byval Key As Long, byval Item As Long)
Public Function Exists( Key As Long) As Boolean
Exists = FindIndex(Key) >= 0
End Function
Public Function Exists(ByVal Key As Long) As Boolean
Exists = FindIndex(Key) >= 0
End Function
You misunderstand. It's all for practical use.Relatively speaking, many methods do not have a great impact on speed.
With GetPropA(hwnd,"key") can only be read 20,000 times per second.
Other general dictionary objects can reach 300000 to 2 million times.
My simple use is, for example, in a timer callback or a subclassing callback.There are multiple objects calling back to this address. There is a parameter hwnd, or the address of the timer.I just want to make a distinction, so either get it from the specified object or read it from the array.
Just now I thought of a way to make it possible to use XOR faster, so that no objects are needed.
These two different comparison methods may also have different CPU speeds, although the impact is hardly 1%.Code:If FindIndex(Key) <> -1 Then
If FindIndex(Key) >=0 Then
If I know how to write faster, 10-30 ways for VB6 to improve the running speed, there will always be better results.
Although some people say that if you pursue the speed of operation so much, it is better to write it in vc++ or GO language.
But that's another topic, isn't it?
The Fourth World War did not happen here, everyone is just exchanging technology, I hope there will be no quarrel.
TimerEx for vb6,vba, Timer in vb6 Class-VBForums
https://www.vbforums.com/showthread....12#post5608612
Multiple different objects call back to the same function in the module, how to distinguish who is the caller, and then use:Code:lngTimerID = SetTimer(0, 0, m_Interval, AddressOf TimerExProc)
TimerExClass.Add Me, lngTimerID & ""
Public TimerExClass As New Collection
Public Sub TimerExProc(ByVal Hwnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, ByVal dwTime As Long)
Dim Ex As TimerEx
Set Ex = TimerExClass(idEvent & "")
Ex.TimerProc()
End Sub
Object.Method X(***) simulates an event execution to the calling form.
For example form1.Timer_Tick(), form2.Timer_Tick()
Set Ex = TimerExClass(idEvent & "")
Set Ex = TimerExClass(hwnd & "")
Most of the callbacks have a handle as a parameter, and then what method is used to get the form or VB class1 object from the handle
Generally, I like to use Collection objects, and later I found a SetPropA method, which hardly requires writing any redundant code.
The price is that it can only read 20,000 times per second in the VB6 IDE, which is relatively slow.
VB6.Collection, 300,000 times per second
RC6.cCollection, about 600,000 times per second.
Using the "Dictionary" object can reach 2 million times per second,
Because VB6, Collection, does not support using integers as key values, so it can only be Collection1.add(m_OldProc,hwnd & "")
In this case where only integers are needed as keys, coercion to strings will definitely cause some performance loss.
It was only after discovering this huge difference that we tested different dictionary objects.
This is mainly used for queries with a very small amount of data. Generally, there are no more than 10 timers or subclassed callbacks, which are usually 2-3 objects.
Compared with the query of tens of thousands of data, it is better to use Dictionary and other methods.
The data volume is small and the data volume is large, and different object components are used, and the speed is also very different.
Code:m_OldProc = SetWindowLong(Hwnd, GWL_WNDPROC, AddressOf ControlCallBack)
SetPropA Hwnd, "m_OldProc", m_OldProc
Function ControlCallBack(ByVal Hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
dim m_OldProc as long
m_OldProc=GetPropA(Hwnd,"m_OldProc")
'm_OldProc=Dictionary(Hwnd)
ControlCallBack = CallWindowProc(m_OldProc, Hwnd, Msg, wParam, lParam)
end function
I wrote a key-value object module for a small amount of data
(Only for the primary key is a number, and the data is also an integer type) If you need other types, please modify it yourself
The code is short enough that it should be easy to change.
Code:Private DataArr() As Long, KeyArr() As Long, UB As Long
Private ArrSize As Long, AddSize As Long
Sub IntData(Optional AddSizeA As Long = 100)
UB = -1
AddSize = AddSizeA
ReDim KeyArr(AddSize)
ReDim DataArr(AddSize)
End Sub
Public Property Get Item(ByVal Key As Long) As Long
Dim ID As Long: ID = FindIndex(Key)
If ID = -1 Then Exit Property
Item = DataArr(ID)
End Property
Sub Add(Key As Long, Val As Long)
If FindIndex(Key) <> -1 Then Exit Sub
UB = UB + 1
KeyArr(UB) = Key
DataArr(UB) = Val
End Sub
Function FindIndex(ByVal Key As Long) As Long
Dim i As Long
For i = 0 To UB
If KeyArr(i) = Key Then
FindIndex = i
Exit Function
End If
Next
FindIndex = -1
End Function
In some special cases, sometimes only the string type is required for Key primary key information.
Sometimes the primary key is of integer type, but each value item is all of object type.
Sometimes for the sake of efficiency, it is a good way to simplify the modification from a dictionary object with source code.
Please post "your technology" in your own threads -
instead of spamming this one (which is about cHashD) -
with unrelated information, nobody want's to read.
I asked you a concrete question in #75 - and you did not answer it (instead you posted your usual nonsense about "all your current activities and plans").
A reasonable and on-topic dialog with you is impossible as it seems...
Olaf
Originally, I just asked a simple question.
In the previous example, the primary key is a string, and the data is: integer
My usage is: primary key: value, the data is also a value, how to optimize it better, or how to change the source code of this dictionary object, because many people will not change it.
Then adding or querying the primary key is:
add(key as long, value as long)
add(byval key as long, value as long)
Which is faster, I just asked 2 sentences, and you guys responded with hundreds of words, but did not solve the actual problem.
I hope there will be no war in the world, no atomic bombs, no missiles.
Of course, everyone can discuss technical issues on the forum, but it should not be so intense.
at #75,you say , can you write a new class for this?
so i finished in #78.
I would have expected someone more professional to implement this class module with a simple modification
Since I'm not familiar with dictionary objects, modification takes hours.
My hints for you in #75 were comparably short (21 words).
It's you who's producing spam-postings with hundreds of words (which don't belong into this discussion-topic here).
Please inform yourself, about the purpose of "discussion-topics in the CodeBank" first
(before you start typing, placing your unrelated nonsense, in threads where it does not belong)
Your obsession with "war and atomic-bombs" aside,
please allow me to be "intense", whilst pointing out your "rude, spamming behaviour" here.
#78 did neither answer your own question -
nor has it anything to do with cHashD (which is the topic of this discussion-thread).
Olaf
Because this topic itself is about discussing lightweight dictionary objects. The code is small enough, but not everyone has the ability to change what they need. In the end, it took me a few hours to complete it.
I just had a question at the beginning, why getpropA can only execute 20,000 times a second, but the Dictionary object can read the key value 2 million times a second, and the speed difference is 100 times. I have doubts about the problem, so I studied it for a while.
If I don't make it clear about the specific usage scenarios, it is definitely not appropriate.
The actual situation is that I only use it to read 2 data, and the maximum number does not exceed 50.
For the case of using 1000, 100,000 key values, some objects may be faster.
So my question is actually, which dictionary object is faster to use when only a small amount of data is required to be queried?
Finally, I changed the dictionary object that supports dozens of different data types to only support integer types. This code still has 324 lines.
In the end, I changed a dictionary object with only about 30 lines.
Again, this is not the right place for you to "think out loud" (beginner-style, in bad english).
It goes without saying, that "finding the index among Long-Values, with max 50 entries", performs best, when done:
- via brute force, against a normal VB-LongArray with 50 slots
- using a FindIndexForValue-function, placed in a *.bas-Module
But nothing of that has anything to do, with the universally usable Class-encapsulation of cHashD (which this thread is dedicated to).
Please move your "musings, and findings" whilst "learning to program" into the Main-Forum please.
Olaf
I just need a faster object for reading few properties. Perhaps properties such as HASHTABLE"CalcHash(key) as long" are not used at all.
I only need to read an array of 10 data in a loop to find out which row is eligible, but its usage is the same as that of a dictionary, and it also needs ADD, GETITEM, Remove
I just don't understand why Microsoft's Dictionary, which supports dozens of data types, can still maintain 2 million calls per second when there are only 10 data types.
But VBA.Collection only has 300,000 times.
cHashD2 IS 350,000 times.
No, you don't -
and I will consider you a beginner, as long as you do not understand the meaning of "No, you don't" (in that context).
Also, the results of your performance-comparisons are misleading (probably because you did not compile to native code, all options checked).
Just played that through with the cHashD-implementation as posted in #30 here -
and with Long-Values as Keys, cHashD (in a small set of 50 entries) is only about factor 2 slower than the MS-Dictionary (not factor 5-6 as you claimed).
So again, please stop posting so much non-sensical or misleading information here.
Olaf
Ok,sorry,I TEST IN VB6 IDE,
Compile it into EXE to run faster (and set various optimizations), and the power mode of the computer must be turned on to high performance, so that the comparison speed can be objective.
At the same time, my test does not represent the actual performance of the components. Everyone should test on their own computer. The running speed of WIN7 and WIN10 may be quite different.
GetArrHwnd in ide :2 million times per second
GetArrHwnd in Exe :5 million times per second
my test not like this:
Code:for i 1 to 1000
m_OldProc = GetArrHwnd(Hwnd)
next
Code:Private Function ControlCallBack(ByVal Hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'---------------------------------
QueryPerformanceCounter C1
Dim m_OldProc As Long
m_OldProc = GetArrHwnd(Hwnd)
QueryPerformanceCounter C2
'---------------------------------
AllUsedTime = C2 - C1 + AllUsedTime
MsgCount = MsgCount + 1
ControlCallBack = CallWindowProc(m_OldProc, Hwnd, Msg, wParam, lParam)
end function
I added 20 subclasses of controls and ended up with about the same speed. That's all for this topic.Code:Private Function GetArrHwnd(ByVal Hwnd As Long) As Long
Dim i As Long
For i = 0 To HookCount
If ArrHwnd(i) = Hwnd Then
GetArrHwnd = ArrOldProc(i)
Exit For
End If
Next
End Function
I'm sorry for misleading you.