AutoHotkey Community

It is currently May 27th, 2012, 11:22 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 29 posts ]  Go to page 1, 2  Next
Author Message
 Post subject:
PostPosted: July 6th, 2009, 3:06 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
SKAN wrote:
Shorter:
Code:
MsgBox, % DllCall( "msvcrt.dll\_strrev", Str,"autohotkey", UInt,0, Str )

Firstly and most importantly, _strrev modifies the string you pass it. If you run the same line of code again, you will get the opposite result even though you are passing a literal string:
Code:
Loop 2
    MsgBox, % DllCall( "msvcrt.dll\_strrev", Str,"autohotkey", UInt,0, Str )
Typically passing a literal string would be of no use anyway, so assume you always pass a variable:
Code:
var = AutoHotkey
MsgBox, % DllCall( "msvcrt.dll\_strrev", Str,var, UInt,0, Str )
While this works, there are still problems. Note that _strrev defines only a single parameter. Passing the additional unused parameter is harmless, but ultimately takes time. Now consider this performance note:
Quote:
Finally, when passing a string-variable to a function that will not change the length of the string, performance is improved by passing the variable by address (e.g. &MyVar) rather than as a "str" (especially when the string is very long).
Source: DllCall
So,
Code:
var = AutoHotkey
MsgBox, % DllCall( "msvcrt.dll\_strrev", UInt,&var, Str )
There is (at least) one remaining inefficiency: _strrev actually returns the same pointer we gave it, so we are unnecessarily measuring and copying from var when we could be using it directly. I suppose the fastest we can make it while keeping it simple would be:
Code:
Flip(Str) {
    DllCall("msvcrt\_strrev", "UInt",&Str, "CDecl")
    return Str
}
Note that since the parameter is always copied into the local Str variable and not passed directly to _sttrev, it is safe to do Flip("literal string").

We could cache a pointer to msvcrt\_strrev to improve performance by a set amount per call. For strings up to 10000 characters, the difference seems to be about 10%. The longer the string, the less significant the gain is, relatively speaking. Also note that as with most functions in msvcrt.dll (the Microsoft Visual C run-time), _strrev uses the C calling convention (CDecl).
SKAN wrote:
Faster:
As already demonstrated, it isn't faster. For every character in the string, it must move every character preceding it. This means that as the string gets longer, the function takes exponentially longer. There are a number of different ways to do it, but I think this is the simplest:
Code:
Flip(in) {
    VarSetCapacity(out, n:=StrLen(in))
    Loop %n%
        out .= SubStr(in, n--, 1)
    return out
}
This should take an amount of time directly proportional to the length of the string. I tried several variations and other methods (such as NumGet with concat or NumPut/NumGet), but couldn't trust my benchmark results as I've noticed the order the functions are defined in seems to have an effect.

Generally if a script needs to loop to achieve its result, DllCall to an equivalent compiled function will outperform it.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 6th, 2009, 4:12 pm 
Offline
User avatar

Joined: March 19th, 2008, 12:43 am
Posts: 5482
Location: the tunnel(?=light)
So when "flipping" a string using these functions is there a call that would also flip any parenthesis/brackets/braces? Obviously you could run a RegEx loop to correct them but I was just curious.

_________________
Image
Try Quick Search for Autohotkey or see the tutorial for newbies.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 7th, 2009, 5:46 am 
Offline
User avatar

Joined: December 26th, 2005, 4:40 pm
Posts: 8776
Lexikos wrote:
Firstly and most importantly, _strrev modifies the string you pass it. If you run the same line of code again, you will get the opposite result even though you are passing a literal string:
Code:
Loop 2
    MsgBox, % DllCall( "msvcrt.dll\_strrev", Str,"autohotkey", UInt,0, Str )


:shock:

I could never guess this. I tried it just the way I would have done with CharUpperA()

Quote:
note that as with most functions in msvcrt.dll (the Microsoft Visual C run-time), _strrev uses the C calling convention (CDecl).


I am aware ( from Laszlo's Bit Wizardry ) that ignoring CDecl would result in An errorlevel. Is it important here?

Quote:
Generally if a script needs to loop to achieve its result, DllCall to an equivalent compiled function will outperform it.


It would do good here to mention Laszlo's Machine code version of Flip().
I do not know if it is fast, but is the only solution that will work past nulls.

Thanks.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 7th, 2009, 9:49 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
SKAN wrote:
I could never guess this. I tried it just the way I would have done with CharUpperA()
Incidentally, CharUpperA() also modifies its input.
Quote:
I am aware ( from Laszlo's Bit Wizardry ) that ignoring CDecl would result in An errorlevel. Is it important here?
DllCall has an undocumented "safety feature" which allows you to get away with it. OTOH, the documentation seems to imply "Cdecl" should always be used if the function uses the C calling convention. (It's only logical...)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 7th, 2009, 10:06 am 
Offline
User avatar

Joined: December 26th, 2005, 4:40 pm
Posts: 8776
Lexikos wrote:
DllCall has an undocumented "safety feature" which allows you to get away with it.


Wow! I love AutoHotkey :D


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 7th, 2009, 10:17 am 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
Code:
Loop 2
    MsgBox, % DllCall("msvcrt.dll\_strrev", "str", "autohotkey", "cdecl str")
IMO, this should be considered as a bug, comparing with
Code:
MsgBox, % DllCall("msvcrt.dll\_strrev", "str", "autohotkey", "cdecl str")
MsgBox, % DllCall("msvcrt.dll\_strrev", "str", "autohotkey", "cdecl str")


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 7th, 2009, 10:56 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
Why? You are modifying two separate literal strings.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 7th, 2009, 11:08 am 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
Are you serious? Do we need a poll on how users are expecting it to behave?
Code:
Loop 2
    MsgBox, % DllCall("msvcrt.dll\_strrev", "str", _:="autohotkey", "cdecl str") . "|" . _


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 7th, 2009, 11:51 am 
Offline

Joined: June 18th, 2008, 8:36 am
Posts: 4923
Location: AHK Forum
This is really strange behavior. Is the literal string being buffered inside the loop and not buffered if there is no loop :?

_________________
AHK_H (2alpha) AHF TT _Struct WatchDir Yaml _Input ObjTree RapidHotkey DynaRun :wink:


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 7th, 2009, 12:23 pm 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
No, it's not a matter of buffering. What it does is very similar to the example of my last post. The only difference is that it just skips the assignment/update (of my last example) in the second iteration.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 7th, 2009, 1:04 pm 
Offline

Joined: June 18th, 2008, 8:36 am
Posts: 4923
Location: AHK Forum
Sean wrote:
No, it's not a matter of buffering. What it does is very similar to the example of my last post. The only difference is that it just skips the assignment/update (of my last example) in the second iteration.


So as far as i understand here assignment is not skept and all works right:
Code:
Loop 2
    MsgBox, % DllCall("msvcrt.dll\_strrev", "str", _:="autohotkey", "cdecl str")


But here it is skept all the time?
Code:
Loop 5
    MsgBox, % DllCall("msvcrt.dll\_strrev", "str", "autohotkey", "cdecl str")


And as far as I understand it does affect other DllCalls when working with a literal string in a loop as well, right?

Then it might be wise not to use a literal string in DllCall at all, just to be sure or even better to fix it?

_________________
AHK_H (2alpha) AHF TT _Struct WatchDir Yaml _Input ObjTree RapidHotkey DynaRun :wink:


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 7th, 2009, 1:12 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
Sean,
What I meant to ask was why you would use the comparison of those two code samples as a basis for your statement that there is a bug. Either way the literal string is modified, you just don't see it if you don't execute the same line twice.

Seriously, the function is asking for a string to modify and you are passing it a literal string. As I see it (metaphorically speaking), you are asking a stupid question and should therefore expect a stupid answer.

Perhaps a more appropriate "answer" would be to recognize the string should not be modified and raise an (access violation) exception - as would be done in C, for example. The more I think about it, the more reasonable it seems. (For instance, DllCall would catch the exception and report the problem via ErrorLevel.) However, I think it would be much more trouble to implement than the added error-detection is worth. The only other solution I can think of is unconditionally copying the literal string on every call (rather than directly using the literal string), and freeing the copy after the function returns - it would allow the string to be modified without side-effects, but would negatively impact the performance of every other script which uses literal strings with DllCall.


HotKeyIt,
With the loop, there is one line of code, with one literal string. Each time the line executes, it refers to the same literal string (i.e. at the same address). After the first iteration, you've essentially modified the code itself:
Code:
    MsgBox, % DllCall("msvcrt.dll\_strrev", "str", "autohotkey", "cdecl str")
    MsgBox, % DllCall("msvcrt.dll\_strrev", "str", "yektohotua", "cdecl str")
You may consider it equivalent to this:
Code:
a = autohotkey
MsgBox, % DllCall("msvcrt.dll\_strrev", "str", a, "cdecl str")
MsgBox, % DllCall("msvcrt.dll\_strrev", "str", a, "cdecl str")

With two separate lines, each line refers to its own literal string (i.e. at two different addresses), like this:
Code:
a = autohotkey
b = autohotkey
MsgBox, % DllCall("msvcrt.dll\_strrev", "str", a, "cdecl str")
MsgBox, % DllCall("msvcrt.dll\_strrev", "str", b, "cdecl str")

In other words, for each (copy of a) literal string in your source code there will be exactly one (copy of the) string in memory after the script loads.
Quote:
Then it might be wise not to use a literal string in DllCall at all, just to be sure?
It is perfectly safe if you know the function will not modify the string, but unwise otherwise.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 7th, 2009, 2:31 pm 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
HotkeyIt wrote:
So as far as i understand here assignment is not skept and all works right:
...
But here it is skept all the time?
Yes, that's what I meant by the only difference.

Lexikos wrote:
What I meant to ask was why you would use the comparison of those two code samples as a basis for your statement that there is a bug.
Well, just to be precise, I didn't say it's a bug but should be considered as a bug. I could guess it was a design decision, likely for performance. What I really wanted to say was that the behaviors/end-results appeared inconsistent.

I understood AHK treated a literal string as sort of a constant string (however without protecting it). But there is no concept of the constant string in AHK, so the behavior/end-result will be confusing many users IMO.


Last edited by Sean on July 8th, 2009, 7:36 am, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 7th, 2009, 6:43 pm 
Offline

Joined: June 18th, 2008, 8:36 am
Posts: 4923
Location: AHK Forum
Awesome, thanks for explanation Lexikos.

So as I understand now, this literal string is saved in an address on load of script and not on each DllCall.So, a literal string can be modified as well.
I assume when a variable is used in DllCall, it uses its address instead.

How would I know whether the DllCall modifies that literal string, is this documented somewhere at MSDN, i could not find it.

I think that behaviour should be documented in AutoHotkey Help.

While experimenting, i come to more confusion but I think I understand it now :)
As I understand here each DllCall uses separate buffer/address for its string.
When code is run first time, inner string is reversed and outer DllCall reverses it back but in a different buffer/address.
When it runs second time inner DllCall reverses string back so that is why output is different.
Code:
test:
MsgBox,262148,Run Again
            ,% DllCall("msvcrt.dll\_strrev", "str"
               , DllCall("msvcrt.dll\_strrev", "str", "autohotkey", "cdecl str")
            , "cdecl str")
            ,2
   IfMsgBox No
      ExitApp
   else   Goto, Test


And finally, as I understand, here outer DllCall will alter the string by address as well, so no separate buffer will be used, right?
Code:
test:
MsgBox,262148,Run Again
            ,% DllCall("msvcrt.dll\_strrev", "Uint"
               , DllCall("msvcrt.dll\_strrev", "str", "autohotkey")
            , "cdecl str")
            ,2
   IfMsgBox No
      ExitApp
   else   Goto, Test

_________________
AHK_H (2alpha) AHF TT _Struct WatchDir Yaml _Input ObjTree RapidHotkey DynaRun :wink:


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 8th, 2009, 9:01 am 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
HotKeyIt wrote:
While experimenting, i come to more confusion but I think I understand it now :)
Really? Then, can you guess the outcome of the following?
Code:
Loop 2
   MsgBox, % DllCall("msvcrt.dll\_strrev", "str", "auto" . "hotkey", "cdecl str")

I suggest to not waste any more time to understand this. It's not in the realm of understanding, but implementation detail.


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

All times are UTC [ DST ]


Who is online

Users browsing this forum: No registered users and 21 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