 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
animeaime
Joined: 04 Nov 2008 Posts: 1045
|
Posted: Mon Mar 09, 2009 5:46 am Post subject: |
|
|
| bmcclure wrote: | | For instance, the DOMNode class I'm working with has a childObjects vector containing all children, but it also has a firstChild and lastChild field containing the first and last objects in the vector. |
I just thought of this. Why are you storing a reference to the first and last child, anyway? I mean, why not in your getFirstChild and getLastChild function return a reference to the first and last object in the vector? I mean, it sounds like a waste of space. I presume you are using "ptr" types for them. If so, then when you compare two objects, the first and last child get compared twice - one from first/list child and a second time in the Vector. Also, this adds 8 bytes of memory. I mean, that's not much, but if your object is 24 bytes total (as an example), then these two redundant values take up 33% of your built-in values - that sounds expensive. Also, if/when you add items, you have to update lastChild. Now, if they are needed, ignore this post. I mean, I'm not aware of the design or structure, so I say this out of intuition, not out of some insight or knowledge. _________________ As always, if you have any further questions, don't hesitate to ask.
Add OOP to your scripts via the Class Library. Check out my scripts. |
|
| Back to top |
|
 |
animeaime
Joined: 04 Nov 2008 Posts: 1045
|
Posted: Tue Mar 10, 2009 11:58 pm Post subject: |
|
|
Ok, there is a TON of new stuff - there is a high probability I'm leaving something out. If that happens, I'll post the other updates when I find a feature I forgot to share. You can download the updated zip.
I want to state that I still haven't fixed the shallow clone - still wrapping my mind around it - been focusing on other areas. Also, the Dictionary classes that are added are in a "beta" state. They work, have no memory leaks, etc; however, I may change the internals. This won't affect your code, so don't worry about it, but this is why the features for the Dictionary classes aren't up to par with Vector and Array - I need to decide what to do. I'm thinking about adding hashing, because lookups take WAY too long. On my computer it takes around 1 second to add 2500 "dictionary entries" (I can add 5000 Vector entries in the same time). The internals of the Dictionary classes are set-up to allow changing it to a HashMap. Don't worry, all additions or changes will be backward-compatable. I wanted to get it out, so that it can be incorporated into code. When I figure out the small details, I'll upload the updated version.
Functionality that affects Array is updated in Vector as well (and visa-versa)
Updates:
1) Added "Type options". Specify NoEquals / NoClone to skip a Class' value during an equals / clone operation. For example, instead "uint" specify "NoEquals& uint" to skip the value during the equals operation, specify "NoClone& uint" to skip the value during clone, and specify "NoClone& NoEquals& uint" to skip the value during both. The space between is optional (used for clarity).
2) Added Dictionary & SDictionary Container classes. These are a mapping / dictionary class that associates a key to a value. See the included Dictionary_test.ahk and SDictionary_test.ahk for usage. For both classes, only Strings are accepted as keys (value is an class object). The key can only be used once. Use Dictionary_put (mimics Vector_set) or Dictionary_replace to set a new value to the key. If the key doesn't exist, it will be created. There is no "add" method, use put or replace instead. The difference between the classes is that Dictionary uses case-insensitive keys while SDictionary (case-Sensitive Dictionary) uses case-sensitive keys. Otherwise, they function identically. Both are based on Vector, so their capacity grows as needed.
3) Overloaded Vector_indexOf type functions to allow both these formats:
| Code: | Vector_indexOf(VectorObject, searchValue, startIndex, useFunction) - current
Vector_indexOf(VectorObject, searchValue, useFunction, startIndex)
|
The format remains like the first (the original), but the second is used if startIndex is not a integer type (decimal or hex). So, provided you don't have any class functions named, as examples, YourClass_1234 or YourClass_0x1234, then you can use the second format seemlessly. This allows this shortened format for finding the index of the first occurance: Vector_indexOf(VectorObject, searchValue, useFunction) (if omitted, the startIndex will be 1 when finding the first occurance, and 0 (the last item) when finding the last occurance).
4) Added Array_size function and refitted Array, Vector, and the newly added container classes to use V2 design.
5) Fixed a syntax error in the SString wrapper. It now correctly compares the strings using a case-sensitive compare (it was case-insensitive by mistake)
6) added #NoEnv to Class.ahk This significantly speeds up the program, and does not need to be specified directly in the code - automatically included when using any Class, or Class.ahk function
7) added several search features to vector and array
a) RegEx searches - index and object
b) Find object (updated)
c) Find unset
| Code: | Vector_indexOf(VectorObject, searchValue, startIndex = 1, useFunction = "getValue")
Vector_regexIndexOf(VectorObject, compareRegEx, startIndex = 1, useFunction = "getValue")
Vector_findObject(VectorObject, searchObject, startIndex = 1)
Vector_firstUnset(VectorObject, startIndex = 1)
Vector_findMatch(VectorObject, searchValue, startIndex = 1, useFunction = "getValue")
Vector_findRegExMatch(VectorObject, compareRegEx, startIndex = 1, useFunction = "getValue")
Vector_lastIndexOf(VectorObject, searchValue, startIndex = 0, useFunction = "getValue")
Vector_regexLastIndexOf(VectorObject, compareRegEx, startIndex = 0, useFunction = "getValue")
Vector_findLastObject(VectorObject, searchObject, startIndex = 0)
Vector_lastUnset(VectorObject, startIndex = 0)
Vector_findLastMatch(VectorObject, searchValue, startIndex = 0, useFunction = "getValue")
Vector_findLastRegExMatch(VectorObject, compareRegEx, startIndex = 0, useFunction = "getValue")
|
I'm not sure if I mentioned this add already, but you can specify the empty string for the useFunction to compare the object (the address) instead of calling a function.
9) Overloaded Vector_get:
| Code: | Vector_get(VectorObject, index, useFunction = "")
Vector_getAddress(VectorObject, index, useFunction = "") |
If useFunction is the empty string (default), the behavior is the same as before. If useFunction != "", then in both Get and GetAddress, for wrappers and non-wrappers alike, the specified function is called on the would-be return object, and it's return is returned instead. This is a shortcut for the following.
| Code: | node := Vector_get(VectorObject, index)
className := Class_getName(node)
value := %className%_%useFunction%(node) |
<value> is returned instead of <node>. Wrapper objects won't unwrap if useFunction != ""; instead, this behavior will be used. This allows using the get function to return a class value, or running a class function on the returned object.
For example, if myVector contains Rectangle objects, then Vector_get(myVector, 1, "area") would return the area for the first Rectangle object.
Like I said, I think that's it for updates, but if I forgot something, I'll be back. Still working on the other stuff, and I'll post the update when I figure it out. _________________ As always, if you have any further questions, don't hesitate to ask.
Add OOP to your scripts via the Class Library. Check out my scripts. |
|
| Back to top |
|
 |
bmcclure
Joined: 24 Nov 2007 Posts: 774
|
Posted: Wed Mar 11, 2009 12:30 am Post subject: |
|
|
This sounds awesome! I'm in portland for a couple days looking at houses, so I apologize for my lack of response to this so far.
Dictionaries will be extremely handy to me in the classes I'm working on right now. Currently it will store the parameters used when an installer was called for my Installer class (mapping parameters to values), but I can already see other uses for it.
Although it would be nice if it were faster, I don't think half as fast as Vector is too bad, seeing as Vector is so fast anyhow, and a dictionary needs to map two objects for each definition.
I might have missed this in your explanation, but for which cases would you use replace instead of put? Does replace only work if the key already exists? _________________ Ben
My Trac projects
My Wiki
[Broken] - My music |
|
| Back to top |
|
 |
animeaime
Joined: 04 Nov 2008 Posts: 1045
|
Posted: Wed Mar 11, 2009 1:01 am Post subject: |
|
|
No problem, enjoy yourself.
| bmcclure wrote: | | For which cases would you use replace instead of put? Does replace only work if the key already exists? |
Dictionary_put mimics Vector_set. Dictionary_replace mimics Vector_replace. Both put and replace can replace the old value, or add the value if it's not created.
Now if you are asking what the difference bteewn the two are - it's the set type. put / set destroys the old object, whereas replace doesn't (the lock count is still decreased by one to reflect the removal).
Does that clear things up? _________________ As always, if you have any further questions, don't hesitate to ask.
Add OOP to your scripts via the Class Library. Check out my scripts. |
|
| Back to top |
|
 |
animeaime
Joined: 04 Nov 2008 Posts: 1045
|
Posted: Wed Mar 11, 2009 3:50 pm Post subject: |
|
|
I'm modifing the Dictionary class to use a HashMap instead of the inefficient LinearMap it uses now (it will not require changes on your end). This will allow each put / get to work in constant time, O(1), instead of linear, O(n). This will drastically spead up the class.
I've been debating whether to force "equal" number keys to be treated as the same key (this is the current behavior). I've decided that this is best for simplicity of use. For example, these keys are all identical (as seen by the dictionary class): "2", "02", "0x2", "0x02", " 2 " (leading or trailing space / tabs are allowed), "2.0" (even though is a float, it equals the integer 2). This means that regardless which format the number is in, the key is the same. Note, this only effects numberic keys. For example, "0xz" and "z" are not the same, since "0xz" is not a hex value. Now, "0xa" and "10" ARE the same, because both equal 10. _________________ As always, if you have any further questions, don't hesitate to ask.
Add OOP to your scripts via the Class Library. Check out my scripts. |
|
| Back to top |
|
 |
animeaime
Joined: 04 Nov 2008 Posts: 1045
|
Posted: Fri Mar 13, 2009 7:22 am Post subject: |
|
|
Evidently no one has been using Vectors or the Dictionary class. I found syntax error in the ReAlloc method - I typed something I shouldn't. I fixed it and updated the zip.
There are no updates in this release, just that "bug" / typo fix. I just finished implementing Dictionary as a hash map and was testing the old version and found that bug. It's sad, and I was worried this might be the case, the old linear search method is quicker than hashing - this shouldn't be the case (logically speaking that is). My quess is the fact that, like CDLL, because a hashTable / hashMap creates a new object for each added node, this is sadly always going to be the case. I'm going to check, tomorrow, and see if I can't find a way around this. If not, then we'll still have a Dictionary class, but it will use a linear search (much like Vector would) to search for it's value. In theory at least, a hashMap which provides contstant time lookup and add should perform better than the current Dictionary class. Currently, it has linear lookup, O(n), and constant add, O(1). However, theory goes out the door because for some reason object creation isn't cheap.
I'm trying to optimize the library, but I haven't yet isolated why object creation is so expensive. I mean, it's a memory allocation and a bunch of puts (maybe that's the problem...). I might find out that's the limit. Maybe AHK DllCalls can't go faster, maybe NumPut - not sure. I'm not one to give up and say "hey, it's the language, not me". I mean, maybe this is the case, but it's too early to throw in the towel.
I'm going to work on it a little tomorrow, but more than likely, the Dictionary class will remain how it is, and I'll focus my attention more on optimizing the library - which is time well spent - if I can optimize it some.
Well, that's the progress. I'm not going to spend more than a day on this though. My quess is that I've hit the glass ceiling of semi-interpreted scripts. However, it's a pretty high ceiling in my opinion. Just want to say thanks to Chris for adding tools that allowed this library to spawn. I mean, being able to programically create OOP in a non-OOP language - for this, I owe the credit to Chris for all the wonderful toys he gave me to play with. Without them, this project wouldn't have been possible.
Edit:
I just realized. The numbers I posted before for the Dictionary's speed had the typo in them - I was wondering why they were so fast. I'm now getting values like I remember (when first testing).
Dictionary speed tests:
On my computer, it's taking 1 second for 500 insertions and 4 seconds for 1000. As stated above, insertions are linear. So, inserting 1 item takes n loops (to see if the item already exists); thus, inserting n items takes n^2 loops. So, as you double the number of items, you quadruple the time required to add them all.
On this note, the new dictionary is better. Yeah! I was very concerned. I was trying to figure out how something with linear insertions was beating something with constant. Good old math, never fails. My code, on the other hand, yeah, it fails time-to-time.
I'll post the new Dictionary Class after I clean it up some.
In the new class, I'm getting about 1 second for 500 insertions and only 2 seconds for 1000. Because insertions are now constant, O(1), it takes about 1 (excluding some collisions) search to find where to insert. So, it takes n to insert n items. This means, double the number of items, and double the time to insert them all. Note, constant time means the time to add a single item is independent of how many there already are. In otherwords, if you have 5000 items, it takes the same time to add a new item than if you had only 100.
Likewise, searches are constant time operations (and very quick). Since a search doesn't need to create an object, they get much better times. It takes about 1/4 of a second to search for each of the 500 items, and 1/2 second to search 1000. So, it might take some time to add items, but to search, it won't. Likewise, because they are both constant time operations, the speed isn't based on the number of items.
Hopefully I can figure out someway to optimize the class library. However, I think those are pretty good times - especially searching. _________________ As always, if you have any further questions, don't hesitate to ask.
Add OOP to your scripts via the Class Library. Check out my scripts. |
|
| Back to top |
|
 |
bmcclure
Joined: 24 Nov 2007 Posts: 774
|
Posted: Fri Mar 13, 2009 3:27 pm Post subject: |
|
|
That sounds very promising!
And I've been using Vector in most of my classes already FYI, not sure why I haven't noticed the bug--was it introduced in the last several days when I may not have updated?
I'll start using Dictionaries today  _________________ Ben
My Trac projects
My Wiki
[Broken] - My music |
|
| Back to top |
|
 |
animeaime
Joined: 04 Nov 2008 Posts: 1045
|
Posted: Fri Mar 13, 2009 11:49 pm Post subject: |
|
|
Yeah, the bug was a typo in the Class_ReAlloc function. It prevented Vector (and Dictionary) from resizing. So, if you tried to add more than the initial capacity (default 10) to a Vector, it wouldn't resize, and thus, the new items wouldn't be added.
| bmcclure wrote: | | I'll start using Dictionaries today |
You aren't even using them...
Well, I was exausted today (just woke up), so I'm going to start cleaning up the Dictionary Class, adding some functionality, and upload it. _________________ As always, if you have any further questions, don't hesitate to ask.
Add OOP to your scripts via the Class Library. Check out my scripts. |
|
| Back to top |
|
 |
animeaime
Joined: 04 Nov 2008 Posts: 1045
|
Posted: Thu Mar 19, 2009 5:49 am Post subject: |
|
|
Ok, I recently found out about the COM library and got an inspiration from it - allowing "dot syntax" for the Class library.
However, this requires some standardization, and some changes. This will be added in using the class option "3" for (V3 design). This will allow backward compatability as well as ease into this new design (for "legacy" classes). Also, this functionality will be added in slowly, as my attention is on my bookmark manager now, and hastefully adding this feature could lead to problems later on. Right now, the idea is just that, an idea. I'm not sure how (or to what extent) my idea is, but it will be a nice addition.
The goal:
1a) New will remain as is. This allows the class file to be included via use of the library folders.
1b) Destroy will be redone. Hopefully I can use RegisterCallback to remove the need for dynamic function calls (for both destroy methods and others); this is presuming that this method is quicker than a dynamic call. I'm going to try different methods and use the most efficient one.
2) getters and setters:
Getter:
| Code: | ;Old version
Rectangle_getValue1(RectangleObject)
;New version
Class_call(RectangleObject, ".value1")
|
Setter:
| Code: | ;Old version
Rectangle_setValue1(RectangleObject, newValue)
;New version
Class_call(RectangleObject, ".value1=", newValue)
|
3) Function calls:
| Code: | ;Old Version
Rectangle_getArea(RectangleObject)
;New Version
Class_call(RectangleObject, ".getArea()") |
4a) Elements in an array
| Code: | ;Old Version
Vector_getAddress(VectorObject, index, "getArea")
;New Version
Class_call(VectorObject, "[" index "].getArea()"
;also
Class_call(VectorObject "[" index "].value1") |
Not that <index> is not inside quotes; this allows expressions to be entered and computed by AHK and then used as the index.
4b) "Unwrap" elements in an array
| Code: | ;Old Version
Vector_get(VectorObject, index)
;New Version
;if not a wrapper, the address will be returned instead
;leave off the ".value" to return the object
Class_call(VectorObject, "[" index "].value" |
5) Using the "equals" function
| Code: | ;Old Version
Vector_equals(VectorObject, ClassObject)
;New Version
Class_call(VectorObject, "==", ClassObject) |
When compareTo gets added, "<", ">", "<=", ">=", "!=", "<>" will be added as well.
The standard will be as follows:
1) The first parameter is the Class object
2) The second parameter is the "function train"
3) The third parameter is the store / compare value
Note: I'm going to redo the format for the Class objects. I'm going to modify BuiltInValues to allow getting and setting values directly - versus the use of function calls. You can still create the functions, but they won't be used by Class_call - Rather, it will use the new format.
This new design will be faster because it will remove the need for dynamic calls (except for "true" functions - like Rectangle_getArea and getValue for unwrapping)
2) For Vectors/Arrays, the "[]" will be used for indexes in the array. The indexes will support "index wrapping" and if no index is specified (the empty string), the index is assumed to be zero (i.e. the last element; end of the list). If possible, I'm going to add the ability to specify the use of 0-based indexes (versus the current one-based). Also, if one-based is used, there will still be the option to have negative indexes be wrapped using zero-based form. Ex. -1 would be the last element in this notation - wheras currently 0 refers to the last element. This would allow ease from languages like C++ where the notation is zero-based. I think I can develop it in a way that would allow one-based and zero-based notation to mingle. However, such a feat might not be possible, so no promises on that end. Of coures, if added, it would be opt-in. One-based would be default.
As a note, because I'm going to change to this design, the website will be much neater (sadly, though, all the work I put into the many pages sitting on my computer was for naught). This change will mean a cleaner library, a quicker library (because the standard will allow some optimizations that I couldn't do before), and most importantly a more OOP-like library. _________________ As always, if you have any further questions, don't hesitate to ask.
Add OOP to your scripts via the Class Library. Check out my scripts. |
|
| Back to top |
|
 |
bmcclure
Joined: 24 Nov 2007 Posts: 774
|
Posted: Thu Mar 19, 2009 6:28 am Post subject: |
|
|
It may take some getting used to, but I'm definitely open to the idea.
I never much cared for the COM library's method of setting values using a parameter of "key=" and another parameter containing the value, but I think I can see why it's done that way, and why it could potentially be beneficial for the Class library.
The issue I can see is that it makes "call" calls ambiguous, since you can use it for so many different things, it isn't clear what it really does until you understand the parameter syntax.
My preference would be on creating separate functions, such as a generic "get" function to get a value, "set" function to set a value (eliminating the need for the '=' in the parameters and other things that may not be obvious to users), and a "call" function for actually calling class methods. Though maybe there is an advantage I'm not seeing to keeping the entire functionality within a single function?
I guess I'm more trying to understand the reasoning behind it than trying to suggest an alternate method, since it's likely there are pieces of the puzzle I'm missing currently.
Will built-in and user-defined values still be based off of a byte/word index as before, or is there a different way to access them now (since it appears you've got values stored by name (".value1")? _________________ Ben
My Trac projects
My Wiki
[Broken] - My music |
|
| Back to top |
|
 |
animeaime
Joined: 04 Nov 2008 Posts: 1045
|
Posted: Thu Mar 19, 2009 6:40 am Post subject: |
|
|
Well, you bring up a good point - is it worth it?
1) the code changes in the Class library - and the overhead in adding the feature (i.e. time on my part)
2) The overhead in you (and any "shadow people" using the library - i.e. people in the shadows) changing your classes to make use of the new form
3) The user using the form. Will it be more intuitive for them, or more of a headache?
If there are reservations on the idea, I'll put it away. I was acting more as a programmer (and out of a rare moment of spontaneity), and maybe I should be thinking more of practical use. Maybe it's not practical... good point. So, should I throw it out; it could always be added later if the need arises - less work for me . _________________ As always, if you have any further questions, don't hesitate to ask.
Add OOP to your scripts via the Class Library. Check out my scripts. |
|
| Back to top |
|
 |
bmcclure
Joined: 24 Nov 2007 Posts: 774
|
Posted: Thu Mar 19, 2009 6:52 am Post subject: |
|
|
I kind of like the idea, but am somewhat hazy on its exact usage and how it differs from what is currently possible.
I can see that it makes the function call itself more object oriented, so it looks more like Object.method(parameters) than Class_method(Object, parameters).
Speaking hypothetically if you decide on these features: Is it only the calling of the function that is different, but the methods themselves are the same? Is the object still provided as the first parameter of a method, even though when calling it with Class_call it's provided directly?
For example, when using Class_call(Object, ".GetArea()"), does getArea correspond to a standard Class_getArea(Object, ...) function like it would in the current Class V2?
I'm not sure if I'm understanding the full scope of this, but I do understand how its used in the COM library (since I used that for my initial XML classes using your library ), so I'm thinking it's quite similar in concept at least.
--
A couple related questions. If you use () to indicate you're calling a method (as seen in your getArea() line), is the = sign really needed when setting a value? The only thing I can see it being useful for is setting a blank value, to differentiate it from getting the current value; is that the reason? Apart from that, it seems the presence of a third parameter would indicate a set operation, negating the need for the = sign.
Likewise, is the first . (period) before the key name or method required? It seems it's always there, and if that is the case, does it need to be there at all? I know it's generally used to separate the object from the method you're calling, but since they're already separated in different parameters, it seems like it might be extra. _________________ Ben
My Trac projects
My Wiki
[Broken] - My music |
|
| Back to top |
|
 |
animeaime
Joined: 04 Nov 2008 Posts: 1045
|
Posted: Thu Mar 19, 2009 7:06 am Post subject: |
|
|
Ok. Scratch my idea - bad idea. After putting some thought into it (probably should of done that earlier ), I realize that this really won't do much of anything. It probably won't offer a more optimized call (might even be worse, depending). It's not intuitive, and worse it's completely different than the current method.
Sorry for the waste of time...
Next "good idea" I have, I'll think it over first and make sure it's actually a good idea. Sorry to get your hopes up. _________________ As always, if you have any further questions, don't hesitate to ask.
Add OOP to your scripts via the Class Library. Check out my scripts. |
|
| Back to top |
|
 |
bmcclure
Joined: 24 Nov 2007 Posts: 774
|
Posted: Thu Mar 19, 2009 7:13 am Post subject: |
|
|
No problem, I think it's an interesting idea none-the-less, but I'll support either way you decide to go. If it adds unneeded additional overhead, then I'm also leaning toward preferring to keep things the way they are.
And I have no problems with you bouncing potential new ideas around first, even if they turn out to not be keepers. It helps get the creative juices flowing and could very well spark additional ideas for features from my end too
--
UPDATE
--
I do like the == and comparison features you've proposed still. Do you plan on implementing something similar in the current Class design, or did that go out the window as well?  _________________ Ben
My Trac projects
My Wiki
[Broken] - My music
Last edited by bmcclure on Thu Mar 19, 2009 7:15 am; edited 2 times in total |
|
| Back to top |
|
 |
animeaime
Joined: 04 Nov 2008 Posts: 1045
|
Posted: Thu Mar 19, 2009 7:14 am Post subject: |
|
|
Thanks for that. _________________ As always, if you have any further questions, don't hesitate to ask.
Add OOP to your scripts via the Class Library. Check out my scripts. |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|