AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Code Snippets/Tutorials (https://forums.alliedmods.net/forumdisplay.php?f=83)
-   -   String Slicing (https://forums.alliedmods.net/showthread.php?t=61367)

Twilight Suzuka 09-28-2007 08:14

String Slicing
 
1 Attachment(s)
An important optimization that is a little counter intuitive is PAWN string slicing, best shown in the following example:

SUMMARY: By passing an indexed array (my_array[5] instead of my_array) into a function or native which accepts an array, the index you pass in becomes the base of the array the function you called accepts.

So, if you pass in my_array[5] to my_func, then when my_func does your_array[0], it is the value of my_array[5].

LONGER EXPLANATION:
Code:

public test()
{
        new str2[100] = "y halo thar"
        test2(str2[2]);
}

// This shows that its not a fluke or a compiler optimization
public test2(str[])
{
        test3(str)
}

public test3(str[])
{
        // Writes "halo thar" to file
        write_file("addons/amxmodx/test.ini",str);
}

To most, this would be assumed to be a compiler error. After all, it looks as if you are simply handing test2 a cell indexed FROM the string, not a string itself!

This is a primitive form of "array slicing", which can be done with any kind of array. It lets you cut out a subset of the array by telling where you want the array to start at when you pass it. True array slicing can do a lot more, but this is the same amount that C affords us natively using pointers, so we can't be picky.

USES:

Why is this useful? Well, for one thing, it can allow us to do a lot of operations without calls to natives. For example, usually when you want a subset of the string, you have to use copyc or format to get it out, therefore using a native call AND allocating a buffer onto the stack (costly due to zeroing).

However, what if you don't REALLY want a new copy; it'd be perfectly fine if the old copy was messed with and mangled, you just don't want the front part? Or, what if you aren't even going to edit the string; you just need to cut a part out? In that case, string slicing is the only real way to do it, unless you want to go to costly natives like format. Here is a peice of code which makes this easy to understand:

Code:

new str_to_cut[] = "Cut us here| Woah important info"

stock testfunc(str[])
{
        new i = containi(str,"|")
        parse_me(str[i])
}

stock parse_me(str[])
{
        // Do stuff on string AFTER pipe
}

We still use a str function: containi. However, to do stuff in "parse" normally, we'd have to pass in i, and do all offsets based on i. This is extremely cost ineffecient, ugly to look at, and hard to understand (and thus error prone). The string slicing method is a lot cleaner.

Obviously, there are better examples; for instance, the one I am quite fond of is for using in set_task. Instead of using explode (costly) or strtok (costly), if we assume we don't really need nor care about keeping the integrity of the string (which is almost always the case; you use parts of the string, then you don't use them again, therefore you can ruinate them all you want) then the string slicing alternative becomes a lot more cost efficient.

Another example is when you wish to stuff non-string data at the beginning of a string, for space or efficiency reasons. In some of my newer code, it is often the case that stuffing a few integer values at the beginning of a string is more portable than enum based structs, and a lot simpler to understand in code; what was perhaps 4 integers and a string being passed into another plugin, saved somewhere, only to be passed back without ever being parsed, is now one array. Quite a lot easier on the eyes.

A full explanation of how string slicing works is attached to this post, if you care to read it; I do not guarantee its validity, as it is quite early in the morning.


Good night.

purple_pixie 09-28-2007 08:48

Re: String Slicing
 
Well if that didn't just make my life a little easier ...

You, my friend, are a legend.

String manipulation ftw.

EDIT: And your text file is very readable an explains it rather well.

Twilight Suzuka 09-28-2007 09:19

Re: String Slicing
 
I figured it was well known, but worth posting.

purple_pixie 09-28-2007 09:22

Re: String Slicing
 
I didn't know it, but then I am quite new.

I've never really dealt with pointers before, though.
Though I do understand them.

I've never really seen them because I'm used to Caché which allows for indirection, so it doesn't need pointers.
(that is, referencing a variable (or function) by name, where the name is stored in another variable)

e.g.
PHP Code:

set x="y"
set y="hello"
write @

would write "hello" to the screen.

Much less confusing than pointers.

Twilight Suzuka 09-28-2007 09:28

Re: String Slicing
 
but also fundamentally less powerful.

purple_pixie 09-28-2007 11:37

Re: String Slicing
 
I assume pointers are pointers directly to memory, then?

So you can pass them between programs and still access the same data?

If that's the case, then pointers pwn indirection.

But I still love indirection ... it also allows for a lot that pointers don't (in the same way)
e.g.
PHP Code:

set x="y+10"
set y=7
write 
@

would, of course, write 17 :-D

Still, someone get us back on-topic ...

sawce 09-29-2007 11:49

Re: String Slicing
 
The topic is now about bees.

Twilight Suzuka 09-30-2007 02:29

Re: String Slicing
 
Oh come on, I posted something useful for once!

Though bees are pretty awesome....

_Master_ 09-30-2007 14:26

Re: String Slicing
 
It's been a while since I looked into amxx source code so I could be wrong about this: doesn't amxx declare the buffer for string manipulations as static?!? If that's true then the main cost would be the actual native call.

Anyways this is usefull if the target position is known, but if you want a subset starting after a certain character then you would still have to use natives ( or not ).

sawce 10-01-2007 03:19

Re: String Slicing
 
Quote:

Originally Posted by _Master_ (Post 537220)
It's been a while since I looked into amxx source code so I could be wrong about this: doesn't amxx declare the buffer for string manipulations as static?!?

wut

If you're talking about how the core and modules read a string from a Pawn script, then yes and no, although declaring a heavily used variable static doesn't have as huge of a performance benefit in C as it does with Pawn - the string buffer is declared static internally for convenience.

However, Pawn stores 1 character from each string in one cell. One character in a C-style string is 1 byte long, there are (normally) 4 bytes in one cell - the extra 3 bytes are wasted. The routine to read a Pawn string inside of core or a module has to basically make its own copy of the string, and manipulate it from there.

However, that is assuming the string needs to be passed to a routine expecting a C-style string, a lot of the natives are written to read and change the string as a Pawn style string, so it doesn't have to do the fairly expensive copy back - the inclusion of formatex() was an example of this optimization.


All times are GMT -4. The time now is 13:33.

Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.