AutoHotkey Community

It is currently May 24th, 2012, 2:07 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 20 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: January 19th, 2008, 8:20 pm 
Offline

Joined: November 7th, 2006, 9:47 pm
Posts: 1933
Location: Germany
EDIT: Source lost!

Note: Renamed from Skul to store.

Description

Wrapper function to create and manage static variables. The variables are only known in this function and created as statics. This helps us better to avoid globals and not to interfere with other scripts. For example to have variables known everywhere, but not as globals. Now with support for Namespaces. That way, multiple scopes can be used.

Look in source code for more info about the commands etc... There is a more specific description.

The LowLevel.ahk library is needed here and should be included if not found in stdlib folder.

Downloads


Usage Example

Code:
; Create some keys.
$("player1_name", "create", "Tuncay")
$("player1_hiscore", "create", "99999")

; Get the content of key "2" (name access is also possible).
value := $(2)
MsgBox %value%

; Assign and get new value.
value := $("player1_hiscore", "update", value + 10)
MsgBox %value%


Supported Commands:

create, update, setNamespace, get, getname, getindex, getaddress, getNamespace, keys, deref, exist

Last Changes, Version 0.7
  • small bug removed ("keys"-command returned an additional unneeded new line)
  • bug removed ("deref"-command related): If string contains "@", the string was also divided up into keyname and namespace components.
  • small performance improvements
  • removed creation of lists for performance reason, for simplefieying and because of some problems, it was not fast as thought because the string had to be parsed. Also the benefit is not much, so no need to slow down other commands.
  • Some checks in RegEx for Namespace validation is done. This slows a bit down back.


Last edited by Tuncay on March 7th, 2011, 10:24 pm, edited 16 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 19th, 2008, 9:20 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
I was waiting somebody do this. Thanks.

BTW, you can speed up the function in such long if else branches if you simply use

Code:
Goto % $_%_Methode%

$_Get:
    bla bla
return  ;or goto $_End

$_Update:

return


To copy the function later would require to search and replace $_ with the new name. Even a little speed increse matters on larger array iteration.

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 19th, 2008, 9:47 pm 
Offline

Joined: November 7th, 2006, 9:47 pm
Posts: 1933
Location: Germany
Using %A_ThisFunc% would be better to use. No replace is needed, on names.

I am not sure, if I would do this. The reason is, trieng to avoid all possible global names. And we know all, that subroutines in functions are taking global names, but are not callable from outside of it.

This type of function is not created to work with large number and data of arrays. In that case, it is recommended to work with another construct. I created this template only on some cases, where I want save settings known everywhere, but not as globals.

thx for the tipp, majkinetor. I think about it, may be making different versions?


Report this post
Top
 Profile  
Reply with quote  
 Post subject: Update to Version 0.2
PostPosted: January 20th, 2008, 4:57 pm 
Offline

Joined: November 7th, 2006, 9:47 pm
Posts: 1933
Location: Germany
I have updated to version 0.2. First post is reworked and the source contains more information.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 20th, 2008, 5:33 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
Quote:
. The reason is, trieng to avoid all possible global names. And we know all, that subroutines in functions are taking global names, but are not callable from outside of it.

This is theoretical. It makes no difference. Nobody will use such labels, and you can always extraprotect them using something like

Code:
%A_ThisFunc%_%GUID%_init

where Guid is some unique number.

Furthermore those globals are not visible anywhere.
The question is, why not making it as fast as posible for general usage ? We need such function. My suggestion is to make it as fast as posible (AFAP :) ), and to account into design large arrays.

OFCourse, another version without fancy things like RegExp may be more appropriate.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 20th, 2008, 5:48 pm 
Offline

Joined: November 7th, 2006, 9:47 pm
Posts: 1933
Location: Germany
Quote:
%A_ThisFunc%_%GUID%_init

I tried this and it does not work, because %A_ThisFunc% seems not to be supported on label names. More specifically, variable label names aren`t supported in general.
If Labels used instead of a long if...else statement, the user have to change all names manually.

The second point is about a GUID. This does not make much sense, because the function can be used multiple times with different names and the GUID would be still the same.

I like it, that only the function name is to be changed and no extra work is needed. Think of an update of the function. How to update it then?

Another point about labels is, it would not much be faster than you think. Every label have its own set of default variables and default settings assigned by AutoHotkey automatically.

And Ive reworked some on the if-structure to make less else`s.


Report this post
Top
 Profile  
Reply with quote  
 Post subject: Update 0.3
PostPosted: January 21st, 2008, 9:47 pm 
Offline

Joined: November 7th, 2006, 9:47 pm
Posts: 1933
Location: Germany
Updated to version 0.3
  • 1 New Methode "exist" added.
  • "init" now acceptes a comma separated list of names to initialize.
  • Only variables with alpha numerical (a-zA-Z0-9) names are initialized.
  • Executing this script, can copy the main function automatically into clipboard.

Look in first post and in source.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 22nd, 2008, 1:52 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
majkinetor wrote:
BTW, you can speed up the function in such long if else branches if you simply use

Code:
Goto % $_%_Methode%

$_Get:
    bla bla
return  ;or goto $_End

$_Update:

return
To look up a label name, AutoHotkey compares it against each and every label name, starting at the first defined label and continuing until a match is found. Are you sure it is faster that way?
Quote:
I tried this and it does not work, because %A_ThisFunc% seems not to be supported on label names. More specifically, variable label names aren`t supported in general.
Almost any character is allowed in a label name. However, variable dereferencing is not supported. For instance,
Code:
goto `%foo`%
%foo%:
MsgBox %A_ThisLabel%

I would be interested to see how this script performs in comparison with Scripting.Dictionary via COM. :)

Edit: Skul out-performs Scripting.Dictionary with less than a few hundred items. :) It does seem to be exponentially slower the more items there are, most likely because you search the array of names in order.

The results I got with Skul were something like 80µs per item for 10 items, up to 5000µs per item for 1000 items. Scripting.Dictionary took approximately 800µs per item, regardless of the number of items. My own unreleased dict.ahk ranged from 300µs to 700µs per item. 8)

I do wonder why you don't use double-derefs...
Code:
$_%_VarName% := _Param1
AutoHotkey uses a binary search algorithm to search the function's list of local/static variables. To know if a particular item exists, you could either manually search the list of local variables or maintain a list of names. (I see $() has this list; my benchmarks were based on $2().)

Edit2: store() seems to be a constant 85-95µs per item, at least for 10 to 1000 items. :shock:
Code:
store(key, method="get", param="")
{
    if key is not alnum
    {
        ErrorLevel = 1
    }
    else if method = set
    {
        LowLevel_init() ; only has an effect the first time,
            ; but note that all script functions incur an amount of overhead
        __static( store_%key% := param )
        ErrorLevel = 0
    }
    else ; get
    {
        ; If the var doesn't exist, this may create it:
        if NumGet(__getVar(store_%key%)+13,0,"char") & 4 ; VAR_ATTRIB_STATIC
            return store_%key%
       
        ErrorLevel = -1
    }
}
It's slightly faster if you remove the "is static?" check, but then you can't tell the difference between an empty item and an item that hasn't been set. I suppose a minimal version would be:
Code:
store(key, method="get", param="")
{
    if method = set
        LowLevel_init(), __static( store_%key% := param )
    return store_%key%
}


Btw, my tests basically consisted of (init, set, get) * 10, then 100, then 1000.

Edit3: LowLevel_init() is actually two script function calls, so incurs a bit (maybe 30µs) of overhead. I've figured out a way to reduce the overhead to under 1µs:
Code:
__mcode("LowLevel_init","C3") ; RET

I think I went overboard. :lol:


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 22nd, 2008, 8:53 pm 
Offline

Joined: November 7th, 2006, 9:47 pm
Posts: 1933
Location: Germany
Thx lexikos, your information are very interesting. Badly, I am not everything understanding about what your writing. My abilities ... or more precisely experience with AutoHotkey are far under yours. I will reread your post.

Also the COM is a big treasure with a seal to me, that I have to crack and open it someday. :( Thank your for the comparison.

Skul was not designed to use with big data and large amount of variables. My thoughts was just to use it as a global settings container for all functions in a script, because I hate globals.

And also, if you or somebody else have a good name for Skul, please let me know. Or do you like the name SKUL?

lexikos wrote:
I do wonder why you don't use double-derefs...
Code:
$_%_VarName% := _Param1

The first version was that like with double derefs. I am not sure anymore, why I did changed this. I wanted that day the variable names allowing all characters and dublicate was also allowed. But now its changed and some checks are added.
Its a good point, I should change it back. Good that you mentioned it.

Your store() function seems to be fast. But I want some commands with high functionality. Speed is not that much important to me. I prefer functionality over it.

lexikos wrote:
Edit3: LowLevel_init() is actually two script function calls, so incurs a bit (maybe 30µs) of overhead. I've figured out a way to reduce the overhead to under 1µs:
Code:
__mcode("LowLevel_init","C3") ; RET

This may be correct, but with LowLevel_init() the file LowLevel.ahk will be searched and included automatically. May be this I would also change.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 23rd, 2008, 12:57 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
Tuncay wrote:
Speed is not that much important to me. I prefer functionality over it.
I thought as much. store() was meant more as a demonstration than an alternative. :) I think replacing the arrays of names/values with dynamically-named variables should improve the speed of your function considerably. It would probably also reduce code size.
Quote:
This may be correct, but with LowLevel_init() the file LowLevel.ahk will be searched and included automatically. May be this I would also change.
I think you misunderstood: the optimization I mentioned applies to LowLevel_init itself, and may be included in the next release of LowLevel. It allows LowLevel_init to be called at the beginning of any function that requires __static or __getVar without incurring the overhead of two script function-calls (LowLevel_init calls __init).
Quote:
Also the COM is a big treasure with a seal to me, that I have to crack and open it someday.
COM is very useful to know, but in this instance I think $() is much more convenient than Scripting.Dictionary.
Code:
COM_Init()
dic := COM_CreateObject("Scripting.Dictionary")
COM_Invoke(dic, "Item=", "key", value)
value := COM_Invoke(dic, "Item", "key")
; versus
$("key", "init", value)
value := $("key")
Though I would prefer "set" or "=" rather than "init" and "update". I don't really see the need for the two. Scripting.Dictionary, for instance, has both "Item=" and "Add", but "Item=" works regardless of whether the item exists, so I use it.
Quote:
Skul was not designed to use with big data and large amount of variables.
That is why I started with "Skul out-performs Scripting.Dictionary", rather than "Skul is hella slow with 1000 items." :lol:
Quote:
And also, if you or somebody else have a good name for Skul, please let me know. Or do you like the name SKUL?
I don't much like either name ($ or skul), since neither hints at the purpose of the script. Some programmers might associate $ with variables, but for some reason I have the idea stuck in my head that $() should be for dynamic expression evaluation. :?

Others have used VarStore, store and Module_FieldName.
Quote:
I wanted that day the variable names allowing all characters and dublicate was also allowed.
Laszlo's Poor man's associative array demonstrates how any arbitrary string can be used as a key (i.e. variable name.)


Report this post
Top
 Profile  
Reply with quote  
PostPosted: March 8th, 2008, 11:59 pm 
Offline

Joined: November 7th, 2006, 9:47 pm
Posts: 1933
Location: Germany
I have a updated version, that has nothing to to with prior versions. It should be very, very slow now. Some checks are done in RegEx and many more checks are done.

Most errors are catched also and ErrorLevel is always changed. 0 indicates always success and any other (greater or lower) contains errors.

I think, its the first useful version with namespace handling. Currently there isnt a full docu.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 9th, 2008, 2:54 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
It seems you've rewritten it into scratch. ;) (The store.ahk link seems to be wrong.)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 9th, 2008, 3:19 am 
lexiKos wrote:
It seems you've rewritten it into scratch. ;) (The store.ahk link seems to be wrong.)
...lol...I'm a very good guesser!...


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: March 9th, 2008, 6:14 pm 
Offline

Joined: November 7th, 2006, 9:47 pm
Posts: 1933
Location: Germany
lexikos wrote:
It seems you've rewritten it into scratch.

hihi, thx for the workaround Guest. 8) I´ve forgotten to change the file extension from .ahk to .zip. Its fixed now.

lexikos, if you have time to benchmark some simple cases, I would be happy. I´m not good at benchmarking and comparing. My results are not authentic. Would you please show me your test script? May be I can learn from it, may be not. Who knows? :)

lexikos wrote:
Though I would prefer "set" or "=" rather than "init" and "update". I don't really see the need for the two. Scripting.Dictionary, for instance, has both "Item=" and "Add", but "Item=" works regardless of whether the item exists, so I use it.

set
I like "update" over "set", because "update" explains more what it does; just updating an existing keys value. "set" can be understand as "creating".

init
Now it is renamed to "create". The "create" function is needed here, because the process of "creating" is huge time consuming with name validation (in RegEx) and creation of lists.

A note here: Because I changed the work from Loops to RegEx, it should not too slow on big number of keys now. But all this is theorethical. Currently I am not sure.

lexikos wrote:
I don't much like either name ($ or skul), since neither hints at the purpose of the script. Some programmers might associate $ with variables, but for some reason I have the idea stuck in my head that $() should be for dynamic expression evaluation.

Its all in your head. Free the variables content. :lol: :wink: I like $() ... what think others?


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 10th, 2008, 5:48 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
Tuncay wrote:
I´m not good at benchmarking and comparing. My results are not authentic.
Why do you say that? Mine are probably no more "authentic." Since I don't know what the typical usage patterns of $() etc. would be, I wouldn't know how to write an accurate benchmark. (They are "synthetic" benchmarks.)
Quote:
Would you please show me your test script?
I tend to delete benchmark scripts when I'm done with them. Here is the new one, requiring AutoHotkey v1.0.47.06 (dynamic function calls = less repitition, but probably less accurate benchmark :P):
Code:
#Include $.ahk

methods = simple_store,com_store,$
i = 10000 ; WARNING: 10000 takes a while ;)

Loop, Parse, methods, `,
{
    ; create
    T()
    Loop %i%
        %A_LoopField%("n" A_Index, "create", "." A_Index ".")
    TIME_CREATE_%A_LoopField% := T()/i
   
    ; update
    Loop %i%
        %A_LoopField%("n" A_Index, "update", "!" A_Index "!")
    TIME_UPDATE_%A_LoopField% := T()/i
   
    ; get
    Loop %i%
        %A_LoopField%("n" A_Index, "get")
    TIME_GET_%A_LoopField% := T()/i
}

ListVars
Pause

T() {
    Static freq, last_count
    if !freq
        DllCall("QueryPerformanceFrequency","int64*",freq)
    DllCall("QueryPerformanceCounter","int64*",count)
    return (count-last_count)/freq, last_count:=count
}

simple_store(key, method="get", param="")
{
    if method != get
    {
        LowLevel_init(), __static( store_%key% := param )
        return param ; avoid a second unnecessary lookup.
    }
    return store_%key%
}

com_store(key, method="get", param="")
{
    static dict
    if !dict {
        COM_Init()
        dict := COM_CreateObject("Scripting.Dictionary")
    }
    if method != get
    {
        COM_Invoke(dict, "Item=", key, param)
        return param ; avoid a second unnecessary lookup.
    }
    return COM_Invoke(dict, "Item", key)
}
I normally keep T() in my function library. The results I got with i=10000 were:
Quote:
TIME_CREATE_$ = 0.001017
TIME_CREATE_com_store = 0.000914
TIME_CREATE_dict_store = 0.000979

TIME_CREATE_simple_store = 0.000137
TIME_GET_$ = 0.000417
TIME_GET_com_store = 0.000776
TIME_GET_dict_store = 0.000815

TIME_GET_simple_store = 0.000261
TIME_UPDATE_$ = 0.000425
TIME_UPDATE_com_store = 0.000882
TIME_UPDATE_dict_store = 0.000920

TIME_UPDATE_simple_store = 0.000283
I omitted dict_store from the code above since it relies on functions I haven't released.
Quote:
The "create" function is needed here, because the process of "creating" is huge time consuming with name validation (in RegEx) and creation of lists.
Why validate the name only on creation? Have you noticed that you'll get a run-time error if you attempt to get using an invalid key name?
Quote:
A note here: Because I changed the work from Loops to RegEx, it should not too slow on big number of keys now. But all this is theorethical.
Looking back at my results with the previous version...
I wrote:
The results I got with Skul were something like 80µs per item for 10 items, up to 5000µs per item for 1000 items.
...the new version is much improved: 120µs per item for 1000 items. (The benchmark results above are based on 10000 items.)


Optimization: Code like the following performs multiple binary searches of the variable list:
Code:
__static($_%Match1%@%Match3%)   
$_%Match1%@%Match3% := _Param1
Since := assignment yields the variable on the left-hand side of the operator, it is possible to do the above with only one search of the variable list:
Code:
__static($_%Match1%@%Match3% := _Param1)
Think of it as making a static assignment, rather than declaring a static variable and setting it. The variable does not need to be empty when you make it static.


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 20 posts ]  Go to page 1, 2  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: Bing [Bot], Exabot [Bot], RaptorX, tomoe_uehara and 17 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group