Jump to content

string replace


hectic1
 Share

You are about to reply to a thread that has been inactive for 636 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

Hello,

I was using my own string_replace() function which I wrote using strictly string functions: https://prnt.sc/qqc2pp

Today I run onto this one-liner which is using lists instead: http://wiki.secondlife.com/wiki/Combined_Library#Replace (I didn't bother "deciphering" the 2nd implementation with all those ~- SL specific hacks lol)

I was wondering if I have anything significant to gain if I start using that one-liner instead of my function. Seems like that the one-liner produces smaller bytecode by 512 bytes, tho I can't be sure cause I checked with llGetUsedMemory() and Mono is supposed to allocate needed memory in 512 chunks, but my query is more about any significant run-time benefits regarding memory and/or speed.

Thanks!

Edited by hectic1
Link to comment
Share on other sites

I notice that your function uses a loop, but Haravikk's function does not. That might give their code an edge over yours, since you have to spend additional resources looping through the string to break it up. Haravikk's code on the other hand lets llDumpList2String do the dirty work.

But to truly know which is better, you should do additional tests, with different sample inputs and look at the averages. You can find a speed tester on the wiki here: http://wiki.secondlife.com/wiki/LSL_Script_Efficiency#How_Fast_Does_That_Code_Run

  • Thanks 1
Link to comment
Share on other sites

lists are generally faster than strings. For example

string Int2Hex(integer n)
{
   string hex = "0123456789ABCDEF";
   return llGetSubString(hex, n, n);
}


string Int2Hex(integer n)
{
   list hex = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"];
   return llList2String(hex, n);
}

 

  • Thanks 1
Link to comment
Share on other sites

3 hours ago, hectic1 said:

Today I run onto this one-liner which is using lists instead: http://wiki.secondlife.com/wiki/Combined_Library#Replace (I didn't bother "deciphering" the 2nd implementation with all those ~- SL specific hacks lol)

They're not SL specific.

  • jump and @label are just C's goto
  • ~ is One's Complement (bitwise operator, also from C)
  • - (minus sign) just simply means "negative of" as in "-2" is "negative of 2"

Broken down one at a time:

integer len = (~-(llStringLength(from)));
integer len = (~-(llStringLength("hello")));
integer len = (~-(5));  //  5 = 00000000000000000000000000000101
integer len = (~(-5));  // -5 = 11111111111111111111111111111011
integer len = (4);      //  4 = 00000000000000000000000000000100

                        // And again...
if (~4)                 // -5 = 11111111111111111111111111111011
{                       // Any non-zero value will pass.
    // Do stuff with "from"
}

Or if you just want to see simple output:

Weird function: The "if" will pass when NOT 0.
llStringLength(from)             0
-(llStringLength(from))          0
len = ~-(llStringLength(from))  -1 (11111111111111111111111111111111)
if (~len)                        0 (00000000000000000000000000000000)

Weird function: The "if" will pass when NOT 0.
llStringLength(from)             1
-(llStringLength(from))         -1
len = ~-(llStringLength(from))   0 (00000000000000000000000000000000)
if (~len)                       -1 (11111111111111111111111111111111)

So when the actual length of the string is 1, the final if-check gets -1. If the length is 2, it gets -2, and so on. That's what it does.

This explanation is probably not very useful, but here it is anyway. I think bit-operations are interesting.

Regarding the speed factor of the one-liner vs other implementations; The one-liner method should in theory be much faster compared to any other. LSL code is subject to the time-slices doled out by the sim. But every time you call a function, the sim has to take a step back to process that function, just like we have to define our own functions. The speed at which the sim will perform llParseStringKeepNulls and llDumpList2String is several magnitudes faster than anything you can do in "pure" LSL. For example, your loop may be forced by the sim to pause before it finishes and to continue later, while the two individual functions are guaranteed to finish in one go. (I'm 99% sure there's no space for a "yield point" ((that's a whole other technical topic)) anywhere in the function, so the whole user-defined function should be guaranteed to run.)

Edited by Wulfie Reanimator
  • Thanks 1
Link to comment
Share on other sites

Regarding the 512 byte memory difference, I understand that mono LSL aligns user functions on 512 byte boundaries, so inline code tends to use less memory than a function, at least up to the point where the inline code is repeated often enough to overtake the function's memory usage. Which way to go depends on which you value more: your sanity or your script's memory usage.

  • Thanks 1
Link to comment
Share on other sites

Thank you all for your input! I'll prolly switch to the one-liner from now on ♥

 

14 hours ago, Wulfie Reanimator said:

They're not SL specific.

  • jump and @label are just C's goto
  • ~ is One's Complement (bitwise operator, also from C)
  • - (minus sign) just simply means "negative of" as in "-2" is "negative of 2"

...

Thank you for the detailed answer! Actually I'm pretty familiar with C. Sorry if i made it sound otherwise, but by "SL ~- specific hacks" I meant I am not sure I should restrict the code of this function on machine architecture specifics, cause I am also using it in OpenSim (and frankly I'll have to test the one-liner there too before I adopt it). In SL I often use bit operators too, but mostly for compacting booleans to integer bits (besides the mem gain, it's quite handy for permanent storage/retrieval of "settings", say on a child prim's description, name, or whatever).

You are right about the one-liner's big speed gain, I should have probably thought of that *giggles*. The thing is I have no idea about the internal implementation overhead of lists versus strings, and their corresponding functions, so it's usually not obvious to me which one is better to use in different use-cases. Btw, do we have access to the internal implementation code of LSL? Lists and strings for starters would be nice. I was always wondering for example, does llStringLength() actually parses the whole string or is the length saved say in an overhead byte/word in the front for rapid access? Same for llGetListLength(), etc, etc.

 

12 hours ago, KT Kingsley said:

Regarding the 512 byte memory difference, I understand that mono LSL aligns user functions on 512 byte boundaries, so inline code tends to use less memory than a function, at least up to the point where the inline code is repeated often enough to overtake the function's memory usage. Which way to go depends on which you value more: your sanity or your script's memory usage.

So true, and Firestorm's pre-processor macros support is a God sent for keeping most of your sanity when inlining lol. However, finding the sweet-spot after which a heavily used macro should be converted to a function is pretty much a "trial-and-error" thing, at least in my experience so far (very recently I saved more than 5K of script memory by converting a couple of macros to regular functions, but it took me time to figure out that "sweet spot" lol).

 

17 hours ago, Fenix Eldritch said:

I notice that your function uses a loop, but Haravikk's function does not. That might give their code an edge over yours, since you have to spend additional resources looping through the string to break it up. Haravikk's code on the other hand lets llDumpList2String do the dirty work.

But to truly know which is better, you should do additional tests, with different sample inputs and look at the averages. You can find a speed tester on the wiki here: http://wiki.secondlife.com/wiki/LSL_Script_Efficiency#How_Fast_Does_That_Code_Run

Very nice links, thank you very much!

 

Edited by hectic1
typos
Link to comment
Share on other sites

4 hours ago, hectic1 said:

Btw, do we have access to the internal implementation code of LSL? Lists and strings for starters would be nice. I was always wondering for example, does llStringLength() actually parses the whole string or is the length saved say in an overhead byte/word in the front for rapid access? Same for llGetListLength(), etc, etc.

We do have some kind of LSL compiler somebody has pulled from some viewer source, but mainly no. We don't have the exact source implementation for any functions or data, especially since even compilation is server-side these days.

All we have is some studies of memory usage and speed, by users, by using inworld means.

http://wiki.secondlife.com/wiki/LSL_Script_Memory

There are also some really old tech talks by Lindens themselves, and while interesting, they're like over 10 years old so the exact details are probably not the same even if the concepts are still there. 

  • Thanks 1
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 636 days.

Please take a moment to consider if this thread is worth bumping.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...