Raised This Month: $138 Target: $400
 34% 

[ TUT ]Dynamic Array


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
HamletEagle
AMX Mod X Plugin Approver
Join Date: Sep 2013
Location: Romania
Old 10-08-2014 , 14:33   [ TUT ]Dynamic Array
Reply With Quote #1


Dynamic Array

What you have to know before we begin ?
  • This tutorial is for medium to advanced users only, beginners my be confused.
  • This subject is huge, there are a lot of things to say, and this can't be done in one tutorial.

First, I will call dynamic arrays dyn arrays, and the normal arrays as normal arrays( note that normal mean regular in this context, not perpendicular or sth else. I also don't like the word default, some people may think that dyn arrays are not default and they should not be used)

But, before we start what is a regular array ? This quote from wiki is self explanatory:
Quote:
Pawn features basic "arrays". An array is a simple type of aggregate data. This means you can store multiple values in one variable! An array follows the same rules as a regular variable, and it has the same types. It simply can contain multiple values. You define an array with brackets, and how many values it can hold.
However, you are limited to only 3 dimensions.
Code:
//This is completly valid new test[34][34][45] //This will throw an error new test[34][34][45][87]

But, let's go back to the topic. A dynamic array basically do the same, but you can have unlimited storage space, with an dyn array you assign data to a cell. If you want a comparasion between tries and dyn arrays read this: https://forums.alliedmods.net/showthread.php?t=88396

Limitations:
  • Dynamic arrays are limited only on two dimensions. The first one is the entry number, which is dynamic, this mean that it doesn't have a limit, the second one is the cellsize, which is fixed, you specify it when using ArrayCreate.
  • Arrays are homogenous containers, this mean that you can have only 1 data type in the same dyn array( cell/string/array ). To make them heterogeneous you can use ArrayPushArray, and store in that array what you want, so you will be able to store both cell and multicell in the same dyn array. For more details, see https://forums.alliedmods.net/showthread.php?t=88304.
Now, another smart quote from cellarray.inc
Quote:
/**
* These arrays are intended to be used for a form of global storage without
* requiring a #define that needs to be increased each time a person needs more
* storage.
* These are not designed to be used as a replacement for normal arrays, as
* normal arrays are faster and should be used whenever possible.
*/
What this tells us ?
  • You have unlimited storage space.
  • Normal arrays are faster. Generally, tries and dyn arrays are very slow on data insertion but they are very fast when retrieving.

For example, if you get some content from a file, just when map change/ server start, you can use a dynamic array without problems. You instert data just one time, then you retrieve it when you need, this is generally better than a normal array, in most cases you won't know the dimension of what you read from file.

If you will look in cellarray.inc you will notice that dyn arrays have a lot of native, a nightmare, really.

I can't explain all of them so I will choose the most used ones, I may edit later and add more.
  • ArrayCreate
  • ArrayClear
  • ArraySize
  • ArrayGetArray
  • ArrayGetCell
  • ArrayGetString
  • ArrayPushArray
  • ArrayPushCell
  • ArrayPushString
  • ArrayDeleteItem
  • ArrayDestroy

As you can see, even with just the most usefull ones, we have a list of 11 natives. Now, let's create a simple plugin:
Code:
#include < amxmodx > //Create a new variable, it's tagged as Array, so it's for a dyn array new Array: g_aArray public plugin_init( ) {     register_plugin( "CellArray Example", "0.1", "HamletEagle" )             //Create our array     g_aArray = ArrayCreate( 1 ) } public plugin_end( ) {         //Destroy our array     ArrayDestroy( g_aArray ) }

So, what this plugin do ? Well, nothing, it just create a dynamic array with 1 as cellsize and then destroy it. What you can see ?
  • A dynamic array is created with ArrayCreate( cellsize=1, reserved=32 ). I would advise you to don't use the reserved param, it's bugged, this mean that it's not doing what the documentation says. Arkshine tryed to fix it, but it breaked a lot of plugins, so the fix was removed. cellsize is basically the size of an entry in the array, not the number of entryes as in a normal array. The reserved param should create some blank entries that are not usable, until you use ArraySet on them.
  • A dynamic array must be destroyed in plugin_end with ArrayDestroy( &Array:which ) native, to free up memory.

Now, let's advance a bit.

Code:
#include < amxmodx > //Create a new variable, it's tagged as Array, so it's for a dyn array new Array: g_aArray public plugin_init( ) {     register_plugin( "CellArray Example", "0.1", "HamletEagle" )             //Create our array     g_aArray = ArrayCreate( 1 )         register_srvcmd( "cellarray_writetest", "ServerCommand_WriteToArray" )     register_srvcmd( "cellarray_readtest", "ServerCommand_ReadFromArray" ) } public plugin_end( ) {         //Destroy our array     ArrayDestroy( g_aArray ) } public ServerCommand_WriteToArray( ) {     //A constant to store some numbers     new szConst[ ] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }         //Create a for loop     for( new i; i < sizeof szConst; i++ )     {         //Add everything to the array         ArrayPushCell( g_aArray, szConst[ i ] )     } } public ServerCommand_ReadFromArray( ) {     //A for loop from 0 to arraysize     for( new i; i < ArraySize( g_aArray ); i++ )     {         //Print what's stored into dyn array         server_print( "Number: %i", ArrayGetCell( g_aArray, i ) )     } }

What this plugin will do ? Well, when you execute cellarray_writetest from server console, it will push all the numbers from the cost to the array, then when you type cellarray_readtest it will print everything.

Output:
Code:
] cellarray_writetest
] cellarray_readtest
Number: 0
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5
Number: 6
Number: 7
Number: 8
Number: 9
What we see new in this ?

1. ArrayPushCell( Array:which, any:input )
  • This will create a new entry on the array, and asign to it the value in the input param.
  • Notice, this native is only for numbers, so the cellsize MUST be 1 !

2.ArraySize( Array:which )
  • Return the size of a dynamic array.
  • This array should be valid, obviousely.

3.ArrayGetCell( Array:which, item )
  • Get the value that is stored in an array entry.
  • item is the entry that we want to return value from.
  • It's only for numbers, for string you will use another native.

Now, another example for strings:

Code:
#include < amxmodx > //Create a new variable, it's tagged as Array, so it's for a dyn array new Array: g_aArray public plugin_init( ) {     register_plugin( "CellArray Example", "0.1", "HamletEagle" )             //Create our array     g_aArray = ArrayCreate( 15 )         register_srvcmd( "cellarray_writetest", "ServerCommand_WriteToArray" )     register_srvcmd( "cellarray_readtest", "ServerCommand_ReadFromArray" ) } public plugin_end( ) {         //Destroy our array     ArrayDestroy( g_aArray ) } public ServerCommand_WriteToArray( ) {     //A constant to store some numbers     new szConst[ ][ ] = { "TEST", "TEST1", "TEST2", "TEST3", "TEST4" }         //Create a for loop     for( new i; i < sizeof szConst; i++ )     {         //Add everything to the array         ArrayPushString( g_aArray, szConst[ i ] )     } } public ServerCommand_ReadFromArray( ) {     new szTemp[ 15 ]     //A for loop from 0 to arraysize     for( new i; i < ArraySize( g_aArray ); i++ )     {         ArrayGetString( g_aArray, i, szTemp, charsmax( szTemp ) )         server_print( "String: %s", szTemp )     } }

Output:
Code:
] cellarray_writetest
] cellarray_readtest
String: TEST
String: TEST1
String: TEST2
String: TEST3
String: TEST4
What is different now ?

1. I changed the ArrayCreate line, we are going to store string, so we should provide a maxim size for that string. I choosed 15, even if it's too high for so little string, just for an example.

2. ArrayPushString( Array:which, const input[] )
  • This will create a new entry on the array, and asign to it the value from the buffer( input ).
  • If you provide a longer string than the cellsize( a string that has the size x+1 and the cellsize is x for example ) will be truncated.

3. ArrayGetString( Array:which, item, output[], size )
  • Get the string value from an array.
  • item is the entry that we want to get string from.
  • We need to store the output string in a buffer, this mean we need to create a normal array( string ) to keep the output.
  • size is the normal array( string ) size, you can get it with charsmax( )

Now, the last part, pushing an array to an dyn array. I will choose an enum for this, but you don't need it everytime. If you don't know how to use an enum, you are invited to read here https://forums.alliedmods.net/showthread.php?t=140103 and here https://forums.alliedmods.net/showthread.php?t=26634

Another quick plugin example:

Code:
#include < amxmodx > enum _: eData {     szString[ 50 ],     iValue } //Create a new variable, it's tagged as Array, so it's for a dyn array new Array: g_aArray public plugin_init( ) {     register_plugin( "CellArray Example", "0.1", "HamletEagle" )             //Create our array     g_aArray = ArrayCreate( eData )         register_srvcmd( "cellarray_writetest", "ServerCommand_WriteToArray" )     register_srvcmd( "cellarray_readtest", "ServerCommand_ReadFromArray" ) } public plugin_end( ) {         //Destroy our array     ArrayDestroy( g_aArray ) } public ServerCommand_WriteToArray( ) {     new Data[ eData ]     new const szConst[] = "test"     copy( Data[ szString ], charsmax( Data ), szConst )     Data[ iValue ] = 15     //Push the array into our array     ArrayPushArray( g_aArray, Data ) } public ServerCommand_ReadFromArray( ) {     new Data[ eData ]     //Get the needed data     ArrayGetArray( g_aArray, 0, Data )     server_print( "String: %s", Data[ szString ] )     server_print( "Number: %i", Data[ iValue ] ) }

This one is completly different.

1. ArrayCreate( eData ): we create the array with the cellsize = eData size
2. I'm not doing for loops, since I'm using only the entry 0 to push the array, sure that you should create a loop when using more entryes.
3. new Data[ eData ] this will create a normal array with the data. Copy in Data[ szString ] a simple text, this is done with copy native. Assign to Data[ iValue ] a random number, let's say 15. Push everyting into the array with ArrayPushArray.
4. When we read from the file, we create a normal array again, sure that it can be global, but I think in this way it's more clear. Get in the Data arrray what the dyn array contains, and print the info.

Output:
Code:
String: test
Number: 15
5. ArrayPushArray( Array:which, const any:input[] )
  • Push an array into a dynamic array.
  • The cellsize must be equal to normal array size.

6. ArrayGetArray( Array:which, item, any: output[] )
  • Get the array that is stored in an array entry.
  • item is the entry that we want to return value from.
  • output: the buffer what will be writed( it will contain the data from dyn arrat )

Huh, I'm done with all of this stuffs. Some end notes:
  • You can store a trie into an array or an array into a trie, it's fine if you do it when it should and correctly.
  • ArrayClear will simply clear all the entries from an array, it's usefull when you want an empty array, and you will use it later.
  • With a trie you assign data to a group of cells, with an array you assign data to a cell. So, in a trie you know if you have a specific entry in it, you don't need a loop. In an array, you need to loop through all items and check if it contains what you need, like a gag plugin, you store the gagged info into an array, an you need to know if a specific id is into it, but an array is not the best solution for this kind of problem, a trie is much much better for this.
  • A trie is better for storing string than a dyn array.
  • You are not forced to create an array in plugin_init and destroy in plugin_end, you can create it when you need, and destroy it when you are done with it.
  • Don't try to get values from an invalid entry, it will throw invalid cellvector provided error.
  • ArrayDeleteItem( Array:which, item ) will detele the specified entry from an dyn array, it must be valid. Also, all entries get shifted with 1 space( x become x-1 and so on ).
  • For a trie tutorial read here: https://forums.alliedmods.net/showthread.php?t=201872
  • If you want a combinations between an array and a trie, you can use celltravtrie, it will allow you to traverse a trie, like you do for an array: https://forums.alliedmods.net/showth...=74753?t=74753

If you have questions fell free to ask. This is my first tutorial, I'm sorry for my english, also I'm not used to give explanations, if you can't understand something please ask, I will try to say in other words. Also, for more informations about this natives and for more natives see cellarray.inc, everything is well documented.

__________________

Last edited by HamletEagle; 01-05-2018 at 12:00.
HamletEagle is offline
Adventx
Member
Join Date: Feb 2014
Location: Romania
Old 10-08-2014 , 14:37   Re: Dynamic Array
Reply With Quote #2

It's very nice, thanks you Hamlet
Adventx is offline
Send a message via Yahoo to Adventx
fysiks
Veteran Member
Join Date: Sep 2007
Location: Flatland, USA
Old 10-08-2014 , 16:44   Re: [ TUT ]Dynamic Array
Reply With Quote #3

Quote:
Originally Posted by HamletEagle View Post
But, before we start what is a regular array ? This quote from wiki is self explanatory:


However, you are limited to only 3 dimensions.
Code:
//This is completly valid new test[34][34][45] //This will throw an error new test[34][34][45][87]

But, let's go back to the topic. A dynamic array basically do the same, but you can have unlimited storage space, with an dyn array you assign data to a cell. If you want a comparasion between tries and dyn arrays read this: https://forums.alliedmods.net/showthread.php?t=88396
Dynamic arrays are limited to two dimensions, FYI. The first dimension if dynamic and the second is static.
__________________

Last edited by fysiks; 10-08-2014 at 16:45.
fysiks is offline
HamletEagle
AMX Mod X Plugin Approver
Join Date: Sep 2013
Location: Romania
Old 10-09-2014 , 05:09   Re: [ TUT ]Dynamic Array
Reply With Quote #4

I was speacking about normal arrays and not the dynamic ones. If someone think a bit, it's obvious that dynamic arrays are only 2nd dimension, the first one is the entry number, which is dynamic, the second one is the cellsize, with is fixed, so it's static. I guess I didn't explained well what I mean with unlimited storage, I can't say exactly what I want in english, my vocabular is pretty limited.

Edit: added more info about dynamic arrays, limitations and another native.
__________________

Last edited by HamletEagle; 10-09-2014 at 10:23.
HamletEagle is offline
fysiks
Veteran Member
Join Date: Sep 2007
Location: Flatland, USA
Old 10-09-2014 , 14:32   Re: [ TUT ]Dynamic Array
Reply With Quote #5

I pointed it out because you mention that 3 dimensional arrays are possible but 4+ dimensions are not possible which implies that your tutorial will explain how to use dynamic arrays to overcome that limitation.
__________________
fysiks is offline
HamletEagle
AMX Mod X Plugin Approver
Join Date: Sep 2013
Location: Romania
Old 10-09-2014 , 14:37   Re: [ TUT ]Dynamic Array
Reply With Quote #6

Quote:
Originally Posted by fysiks View Post
I pointed it out because you mention that 3 dimensional arrays are possible but 4+ dimensions are not possible which implies that your tutorial will explain how to use dynamic arrays to overcome that limitation.
This is due to my english, it's creating a wrong meaning. Thx for pointing this out.
__________________

Last edited by HamletEagle; 10-09-2014 at 15:05.
HamletEagle is offline
Arkshine
AMX Mod X Plugin Approver
Join Date: Oct 2005
Old 10-09-2014 , 16:29   Re: [ TUT ]Dynamic Array
Reply With Quote #7

Some thoughts:

Quote:
Arrays are homogenous containers
If I don't say bullshits, in dev build, it's now heterogeneous. Same as Trie. Both internal libraries have been completely replaced by the libraries from SourceMod.

Quote:
tries and dyn arrays are very slow on data insertion
This should be relativized. No that slow. It could have been true with Trie, but in dev build, since it uses hashmap now, speed has been drastically improved. About Array, insertion is just about something like array[count++] = cell ; that's not something which should be considerated as slow. The only thing left is the memory allocation but not really and in dev build, it happens even less often. Also you can always pre-allocate memory ; so at the end I don't think we can still say such statement. Of course this will be always slower than native arrays.

Quote:
I can't explain all
Why? All are properly documented.

Quote:
I would advise you to don't use the reserved param
Quote:
The reserved param should create some blank entries that are not usable, until you use ArraySet on them.
Well, it's still can be used, nothing wrong with it, but yes, doesn't follow completely documentation.
Current pre-allocates memory but don't update count. This means you still have to use Push (and not Set).
To have like documentation says, you need to use ArrayResize(), this will update the count (so real blank entry) and you will be able to use Set directly.

Quote:
A dynamic array must be destroyed in plugin_end with ArrayDestroy( &Array:which ) native, to free up memory.
I think this should be rephrased, like you should always destroy an Array/Trie right after you don't need it. Of course if you an Array/Trie globally, one of place could be plugin_end().

Quote:
for( new i; i < ArraySize( g_aArray ); i++ )
Even if just an example, it would be welcomed to cache ArraySize() value. Let's keep good practice.

Quote:
You can store a trie into an array or an array into a trie, it's fine if you do it when it should and correctly
Just to comment that this is kind of silly to say that because well what you can store anything and an Array/Trie handle is just an integer number. There is nothing special.

Quote:
you need to loop through all items and check if it contains what you need
This is no totally true with dev build, you have now ArrayFindString and ArrayFindValue.

Quote:
A trie is better for storing string than a dyn array
You should not say such shortcut. It's depending what you want to do.

Quote:
If you want a combinations between an array and a trie, you can use celltravtrie, it will allow you to traverse a trie
With dev build, you have something called Snapshot which allows you to traverse a trie, but this might be removed at some point to a different API ; but just saying there should be anyway something to traverse a trie.

About the presentation itself, it would be cool you make anchors on your natives menu so we can jump directly to the native we want.
__________________

Last edited by Arkshine; 10-09-2014 at 16:33.
Arkshine is offline
HamletEagle
AMX Mod X Plugin Approver
Join Date: Sep 2013
Location: Romania
Old 10-10-2014 , 09:54   Re: [ TUT ]Dynamic Array
Reply With Quote #8

Most of your points are taking into accout the dev builds and I'm not used with them, also this tutorial is for the latest stable version, 1.8.2

I said I can't explain all, because I don't have the time to write them, not that I don't know or whatever.

Quote:
To have like documentation says, you need to use ArrayResize(), this will update the count (so real blank entry) and you will be able to use Set directly.
After I test this, it will be added to the tutorial.

Quote:
think this should be rephrased, like you should always destroy an Array/Trie right after you don't need it. Of course if you an Array/Trie globally, one of place could be plugin_end().
I mentioned this:
Quote:
You are not forced to create an array in plugin_init and destroy in plugin_end, you can create it when you need, and destroy it when you are done with it.
Quote:
Just to comment that this is kind of silly to say that because well what you can store anything and an Array/Trie handle is just an integer number. There is nothing special.
It may be, but a lot of peoples are confused by it.

Quote:
Even if just an example, it would be welcomed to cache ArraySize() value. Let's keep good practice.
Hehe, you are right, didn't pay atention on it.

I will also add anchors tag.
__________________
HamletEagle is offline
Arkshine
AMX Mod X Plugin Approver
Join Date: Oct 2005
Old 10-10-2014 , 12:32   Re: [ TUT ]Dynamic Array
Reply With Quote #9

Quote:
Most of your points are taking into accout the dev builds and I'm not used with them, also this tutorial is for the latest stable version, 1.8.2
What I've figured out, still it won't hurt to get some thoughts on the matter.
I think you should either clearly stated is about only <= 1.8.2 or adding support for 1.8.3 at the same time. IMO, you should do the latter.
__________________
Arkshine is offline
edon1337
Penguin Enthusiast
Join Date: Jun 2016
Location: Macedonia
Old 01-19-2017 , 12:28   Re: [ TUT ]Dynamic Array
Reply With Quote #10

Sorry for bumping.
1. Is it possible to skip the "Array" part when creating an Array ? Like
instead of
PHP Code:
 new Array: g_newArray 
to make
PHP Code:
 new g_newArray[] 
If not, what's the difference between these two ?
2. why is this called a 2 Dimensional array if it has got 3 parameters
PHP Code:
new test[34][34][45
3. Can you give a proper explanation about Dynamic Arrays ? Thanks for the tut ^_^
__________________
edon1337 is offline
Send a message via Skype™ to edon1337
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 02:59.


Powered by vBulletin®
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Theme made by Freecode