Difference between revisions of "Array Module (AMX Mod X)"
(→Empty Index Searching) |
m |
||
(20 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
− | Array module, created and maintained by Twilight Suzuka and Anpheus, brings fast, easy, and | + | Array module, created and maintained by Twilight Suzuka and Anpheus, brings fast, easy, and efficient dynamic storage into PAWN coding. |
It is essential for many tasks, such as copying entities and is useful in a great many applications, mainly because of how it overcomes PAWN's static nature. | It is essential for many tasks, such as copying entities and is useful in a great many applications, mainly because of how it overcomes PAWN's static nature. | ||
Line 6: | Line 6: | ||
== History == | == History == | ||
− | The original Array module, first written by BAILOPAN for AMXx 1.0, used a vector (or dynamic array) system to create "lists" and "tables". Its | + | The original Array module, first written by BAILOPAN for AMXx 1.0, used a vector (or dynamic array) system to create "lists" and "tables". Its implementation, a hard to understand and convoluted system which daunted many coders, would have nevertheless been very successful if not for a few key factors: It crashed on unload and reload. |
− | While using this module, for the purposes of creating a customized vault system, Twilight Suzuka discovered these flaws, and investigated. She, along with her good friend Anpheus, pointed out said errors, and fixed a great deal of them. Unsatisfied, Twilight Suzuka created the ArrayX module, using a dual linked list system of | + | While using this module, for the purposes of creating a customized vault system, Twilight Suzuka discovered these flaws, and investigated. She, along with her good friend Anpheus, pointed out said errors, and fixed a great deal of them. Unsatisfied, Twilight Suzuka created the ArrayX module, using a dual linked list system of implementation. |
− | While the ArrayX module did work, and did work well, providing a simple (if "not professional" as Anpheus would say) interface to a simple dynamic array. | + | While the ArrayX module did work, and did work well, providing a simple (if "not professional" as Anpheus would say) interface to a simple dynamic array. Sparse, relatively quick, and offering a tri-unit storage (three different types: float, string, integer: per index), ArrayX worked relatively well. However, as BAILOPAN was quick to point out, it utilized an inefficient linked list design. |
− | While searching for an appropriately | + | While searching for an appropriately sparse vector design for the new ArrayX, Anpheus chanced upon the Judy library. It offered unparalleled speed, efficiency, and sparse capabilities compared to any other system we could find. Implementing Judy's trie design, they created ArrayX 2.0, which was basically the same then as it is now. It was eventually implemented into the CVS. |
== Description == | == Description == | ||
− | Array module, originally ArrayX, provides dynamic storage units in the form of three generic ''types'': Array, Keytable, Hashtable. | + | Array module, originally ArrayX, provides dynamic storage units in the form of three generic ''types'': Array, Keytable, and Hashtable. |
− | While each of these types are carefully disguised to make them easier to use, the back bone of Array module is the Judy library, which uses a trie | + | While each of these types are carefully disguised to make them easier to use, the back bone of Array module is the Judy library, which uses a trie implementation to allow for sparse and efficient data structures. |
− | In effect, all three units allow for | + | In effect, all three units allow for sparse settings, as well as providing huge speed and memory increases over other implementations. |
=== Arrays === | === Arrays === | ||
Line 32: | Line 32: | ||
# Advantages: | # Advantages: | ||
## They do not have upper bounds; you can write to any index. | ## They do not have upper bounds; you can write to any index. | ||
− | ## They can be | + | ## They can be sparse; you may write to any index, anywhere, and not waste the space between the two. |
## Easy to use natives for several important features, such as searching and saving/loading. | ## Easy to use natives for several important features, such as searching and saving/loading. | ||
# Disadvantages: | # Disadvantages: | ||
## Slightly more difficult to use. | ## Slightly more difficult to use. | ||
− | ## Slightly slower, slightly less memory | + | ## Slightly slower, slightly less memory efficient than generic arrays. |
=== Keytables === | === Keytables === | ||
Line 55: | Line 55: | ||
# Disadvantages: | # Disadvantages: | ||
− | ## Less | + | ## Less efficient than hashtables. |
=== Hashtables === | === Hashtables === | ||
Hashtables work as generic vaults; you cannot search through them. | Hashtables work as generic vaults; you cannot search through them. | ||
− | However, they are much faster than any other data structure available through AMXx that allows for | + | However, they are much faster than any other data structure available through AMXx that allows for associative array properties. |
<tt>Basics:</tt> | <tt>Basics:</tt> | ||
; Method : bind a value to a string key, decompiled through a hash. | ; Method : bind a value to a string key, decompiled through a hash. | ||
− | ; Allows: Fastest possible | + | ; Allows: Fastest possible retrieval. |
− | ; Useful for vault-like programming and fast | + | ; Useful for vault-like programming and fast retrieval |
# Advantages: | # Advantages: | ||
Line 82: | Line 82: | ||
'''Dynamic vs Generic''': | '''Dynamic vs Generic''': | ||
− | ; Array | + | ; Array - Array |
− | ; Keytable | + | ; Keytable - Vault |
− | ; Hashtable | + | ; Hashtable - Fastest Vault |
− | === | + | === Persistence === |
Dynamic units must be deallocated or deleted when you are done using them if the scope is local; they will not be deleted at the end of the function they were created in, and thus will be a memory leak if you no longer have a reference to them. | Dynamic units must be deallocated or deleted when you are done using them if the scope is local; they will not be deleted at the end of the function they were created in, and thus will be a memory leak if you no longer have a reference to them. | ||
Line 96: | Line 96: | ||
"disable_check = 0" is present as a parameter in a great deal of Array functions. | "disable_check = 0" is present as a parameter in a great deal of Array functions. | ||
− | |||
Checking is done internally, and by changing this to 1, you turn off the internal checking. | Checking is done internally, and by changing this to 1, you turn off the internal checking. | ||
− | Typically, this is looked upon as bad form; however, it is | + | Typically, this is looked upon as bad form; however, it is necessary in a few situations, such as: |
* Checking an index that does not yet exist for a value. | * Checking an index that does not yet exist for a value. | ||
Line 105: | Line 104: | ||
As the default value is '0', it is highly recommended that it remain 0; however, it is true that setting the value to 1 will render a slightly higher speed of checking. | As the default value is '0', it is highly recommended that it remain 0; however, it is true that setting the value to 1 will render a slightly higher speed of checking. | ||
− | As disabling checking may result in a crash, it is | + | As disabling checking may result in a crash, it is unadvised that it be set to 1 unless ones code is flawless. |
==== &success ==== | ==== &success ==== | ||
Line 111: | Line 110: | ||
If checking is enabled, this parameter may turn to 0 due to internal checking errors. If a value was returned, it will typically be NULL (0). | If checking is enabled, this parameter may turn to 0 due to internal checking errors. If a value was returned, it will typically be NULL (0). | ||
− | + | Success does not necessarily have to be passed; leaving it as default is perfectly fine, though inadvisable. | |
− | Success does not | ||
− | |||
It is highly recommended that all of your code include success checks, just in case. | It is highly recommended that all of your code include success checks, just in case. | ||
Line 128: | Line 125: | ||
To reduce the size of this page, these specifications have been created: | To reduce the size of this page, these specifications have been created: | ||
− | |||
*The symbol '*' is used to represent 'array', 'keytable', and 'hashtable'. | *The symbol '*' is used to represent 'array', 'keytable', and 'hashtable'. | ||
Line 137: | Line 133: | ||
Recognize these shortcuts will not work in actual code; they are used to reduce the size of this document. | Recognize these shortcuts will not work in actual code; they are used to reduce the size of this document. | ||
− | |||
Always be sure to clean them up. | Always be sure to clean them up. | ||
Line 149: | Line 144: | ||
<tt>*_create( arrayid = 0, reserve_id = 0)</tt> | <tt>*_create( arrayid = 0, reserve_id = 0)</tt> | ||
− | The parameters are for backwards compatibility only; they have no true purpose now. They were once used as a form of hard coded communication; you may create a unit with a specified id number, or reserve a specific id number for generic usage. Neither | + | The parameters are for backwards compatibility only; they have no true purpose now. They were once used as a form of hard coded communication; you may create a unit with a specified id number, or reserve a specific id number for generic usage. Neither is needed anymore. |
The id number that this returned must be stored in some fashion; if it is not, the unit will persist and become a memory leak. | The id number that this returned must be stored in some fashion; if it is not, the unit will persist and become a memory leak. | ||
Line 167: | Line 162: | ||
<tt>*_clear( arrayid )</tt> | <tt>*_clear( arrayid )</tt> | ||
− | This will remove all | + | This will remove all indexes from the unit, but leave it intact, allowing you to reuse it. |
==== Memory ==== | ==== Memory ==== | ||
− | The basic native for | + | The basic native for retrieving the amount of memory used by a unit is: |
<tt>*_memory (arrayid, disable_check = 0); </tt> | <tt>*_memory (arrayid, disable_check = 0); </tt> | ||
− | This will tell you exactly how much memory has been allocated within the unit, including its own overhead. | + | This will tell you exactly how much memory has been allocated within the unit, including its own overhead. It is useful for debugging. |
==== Count ==== | ==== Count ==== | ||
− | The basic native for | + | The basic native for retrieving the amount of units in existence is: |
<tt>*_count( start = 0, stop = -1);</tt> | <tt>*_count( start = 0, stop = -1);</tt> | ||
− | This will state the amount of units of the specified type in | + | This will state the amount of units of the specified type in existence; as they are created in sequence, this can also be used to find out the ids of the available units. |
=== Index manipulation === | === Index manipulation === | ||
Line 217: | Line 212: | ||
==== Remove ==== | ==== Remove ==== | ||
− | The basic native for removing | + | The basic native for removing indexes completely is: |
<tt>*_remove (arrayid, index) | <tt>*_remove (arrayid, index) | ||
Line 228: | Line 223: | ||
==== Filled ==== | ==== Filled ==== | ||
− | The basic native for getting conformation of | + | The basic native for getting conformation of indexes in dynamic units is: |
<tt>*_isfilled(arrayid, index) | <tt>*_isfilled(arrayid, index) | ||
Line 239: | Line 234: | ||
==== Empty ==== | ==== Empty ==== | ||
− | The basic native for getting conformation of | + | The basic native for getting conformation of indexes in dynamic units is: |
<tt>*_isempty(arrayid, index) | <tt>*_isempty(arrayid, index) | ||
Line 274: | Line 269: | ||
===== Filled Index Searching ===== | ===== Filled Index Searching ===== | ||
− | These functions allow the coder to search through filled | + | These functions allow the coder to search through filled indexes in arrays and keytables. |
− | These functions do not | + | These functions do not guarantee success, so it is recommended that the success parameter be checked. |
<tt>*_first (arrayid, index, &success = 0); | <tt>*_first (arrayid, index, &success = 0); | ||
Line 283: | Line 278: | ||
Index parameter: Starting index | Index parameter: Starting index | ||
</tt> | </tt> | ||
+ | |||
Note: in keytables and hashtables, index will be a string. | Note: in keytables and hashtables, index will be a string. | ||
===== Empty Index Searching ===== | ===== Empty Index Searching ===== | ||
− | These functions allow the coder to search through empty | + | These functions allow the coder to search through empty indexes in arrays. |
− | These functions do not | + | These functions do not guarantee success, so it is recommended that the success parameter be checked. |
<tt>*_firstempty (arrayid, index, &success = 0); | <tt>*_firstempty (arrayid, index, &success = 0); | ||
Line 293: | Line 289: | ||
*_prevempty (arrayid, index, &success = 0); | *_prevempty (arrayid, index, &success = 0); | ||
*_lastempty (arrayid, index, &success = 0); | *_lastempty (arrayid, index, &success = 0); | ||
− | Index parameter: | + | Index parameter: Starting index. |
</tt> | </tt> | ||
==== Array Information ==== | ==== Array Information ==== | ||
− | Arrays have two additional natives, which allow for | + | Arrays have two additional natives, which allow for retrieval of additional information: |
<tt> Get the size of the array from one index to another </tt> | <tt> Get the size of the array from one index to another </tt> | ||
Line 309: | Line 305: | ||
* Units of Units: | * Units of Units: | ||
− | ** Storing the references to units into an array, allowing for two dimension dynamic unit storage and | + | ** Storing the references to units into an array, allowing for two dimension dynamic unit storage and retrieval |
− | ** Use of a keytable and hashtable in | + | ** Use of a keytable and hashtable in conjunction to enhance the properties of both - faster gets + searching and saving - |
** Dynamic storage of: functions, units, and much more | ** Dynamic storage of: functions, units, and much more | ||
Line 316: | Line 312: | ||
− | [[Category: | + | [[Category:3rd Party Modules (AMX Mod X)]] |
Latest revision as of 02:58, 24 May 2018
Array module, created and maintained by Twilight Suzuka and Anpheus, brings fast, easy, and efficient dynamic storage into PAWN coding.
It is essential for many tasks, such as copying entities and is useful in a great many applications, mainly because of how it overcomes PAWN's static nature.
Contents
History
The original Array module, first written by BAILOPAN for AMXx 1.0, used a vector (or dynamic array) system to create "lists" and "tables". Its implementation, a hard to understand and convoluted system which daunted many coders, would have nevertheless been very successful if not for a few key factors: It crashed on unload and reload.
While using this module, for the purposes of creating a customized vault system, Twilight Suzuka discovered these flaws, and investigated. She, along with her good friend Anpheus, pointed out said errors, and fixed a great deal of them. Unsatisfied, Twilight Suzuka created the ArrayX module, using a dual linked list system of implementation.
While the ArrayX module did work, and did work well, providing a simple (if "not professional" as Anpheus would say) interface to a simple dynamic array. Sparse, relatively quick, and offering a tri-unit storage (three different types: float, string, integer: per index), ArrayX worked relatively well. However, as BAILOPAN was quick to point out, it utilized an inefficient linked list design.
While searching for an appropriately sparse vector design for the new ArrayX, Anpheus chanced upon the Judy library. It offered unparalleled speed, efficiency, and sparse capabilities compared to any other system we could find. Implementing Judy's trie design, they created ArrayX 2.0, which was basically the same then as it is now. It was eventually implemented into the CVS.
Description
Array module, originally ArrayX, provides dynamic storage units in the form of three generic types: Array, Keytable, and Hashtable.
While each of these types are carefully disguised to make them easier to use, the back bone of Array module is the Judy library, which uses a trie implementation to allow for sparse and efficient data structures.
In effect, all three units allow for sparse settings, as well as providing huge speed and memory increases over other implementations.
Arrays
Arrays are the simplest unit provided by Array module. They function almost exactly like their static counterpart, the traditional array, but are dynamic.
Basics:
- Method : bind a value to an integer key.
- Allows: Advanced Searching, Saving/Loading
- Useful for array-like programming.
- Advantages:
- They do not have upper bounds; you can write to any index.
- They can be sparse; you may write to any index, anywhere, and not waste the space between the two.
- Easy to use natives for several important features, such as searching and saving/loading.
- Disadvantages:
- Slightly more difficult to use.
- Slightly slower, slightly less memory efficient than generic arrays.
Keytables
Keytables are Array modules counter-part to an advanced vault that allows searching. While they are not nearly as fast as hashtables, they allow for searching, and are significantly faster than any other vault like structure available through AMXx, over amortized time.
Basics:
- Method : bind a value to a string key.
- Allows: Searching, Saving/Loading
- Useful for vault-like programming.
- Advantages:
- Allows for simplified storage of vault-like values.
- Are extremely fast, and can be searched.
- Has searching and saving/loading natives.
- Disadvantages:
- Less efficient than hashtables.
Hashtables
Hashtables work as generic vaults; you cannot search through them. However, they are much faster than any other data structure available through AMXx that allows for associative array properties.
Basics:
- Method
- bind a value to a string key, decompiled through a hash.
- Allows
- Fastest possible retrieval.
- Useful for vault-like programming and fast retrieval
- Advantages:
- Allows for simplified storage of vault-like values.
- Are extremely fast, faster than typical vectors with amortized cost
- Did we mention they are fast?
- Disadvantages:
- No searching.
- Potential for memory leaks.
- No saving/loading
Usage
It is very simple to use Array Module, as the natives were created for ease of use. Think of them in terms of the generic units you already know, and you will be set:
Dynamic vs Generic:
- Array - Array
- Keytable - Vault
- Hashtable - Fastest Vault
Persistence
Dynamic units must be deallocated or deleted when you are done using them if the scope is local; they will not be deleted at the end of the function they were created in, and thus will be a memory leak if you no longer have a reference to them.
Generic Conventions
Array Module uses a few conventions which may be difficult to understand at first, but which are quite easy to understand once the reasons behind them are understood.
Disable Check
"disable_check" will disable internal checking, and is not recommended.
"disable_check = 0" is present as a parameter in a great deal of Array functions. Checking is done internally, and by changing this to 1, you turn off the internal checking. Typically, this is looked upon as bad form; however, it is necessary in a few situations, such as:
- Checking an index that does not yet exist for a value.
Most of these instances are bad form; a more air tight method is possible and recommended. As the default value is '0', it is highly recommended that it remain 0; however, it is true that setting the value to 1 will render a slightly higher speed of checking.
As disabling checking may result in a crash, it is unadvised that it be set to 1 unless ones code is flawless.
&success
The success parameter is set to 1 on success of internal functions. Do not set it to a constant.
If checking is enabled, this parameter may turn to 0 due to internal checking errors. If a value was returned, it will typically be NULL (0). Success does not necessarily have to be passed; leaving it as default is perfectly fine, though inadvisable. It is highly recommended that all of your code include success checks, just in case.
Generic functions
All Array Module functions use the same basic format for similar natives between types
By convention, similar functions between the three types have the same style of usage, format, and name:
new MyArray = array_create();
new MyKeytable = keytable_create();
new MyHashtable = hashtable_create();
To reduce the size of this page, these specifications have been created:
- The symbol '*' is used to represent 'array', 'keytable', and 'hashtable'.
The above code reduces to:
new My* = *_create();
Recognize these shortcuts will not work in actual code; they are used to reduce the size of this document. Always be sure to clean them up.
Unit manipulation
These natives allow for manipulation of the dynamic unit structures themselves.
Creation
The basic native for creating dynamic units is:
*_create( arrayid = 0, reserve_id = 0)
The parameters are for backwards compatibility only; they have no true purpose now. They were once used as a form of hard coded communication; you may create a unit with a specified id number, or reserve a specific id number for generic usage. Neither is needed anymore.
The id number that this returned must be stored in some fashion; if it is not, the unit will persist and become a memory leak.
Deletion
The basic native for deleting dynamic units is:
*_delete( arrayid )
This will completely destroy the unit; you will no longer be able to use it at all, and will receive an error if you attempt to.
Reset
The basic native for resetting dynamic units is:
*_clear( arrayid )
This will remove all indexes from the unit, but leave it intact, allowing you to reuse it.
Memory
The basic native for retrieving the amount of memory used by a unit is:
*_memory (arrayid, disable_check = 0);
This will tell you exactly how much memory has been allocated within the unit, including its own overhead. It is useful for debugging.
Count
The basic native for retrieving the amount of units in existence is:
*_count( start = 0, stop = -1);
This will state the amount of units of the specified type in existence; as they are created in sequence, this can also be used to find out the ids of the available units.
Index manipulation
All index manipulation natives include the disable_check parameter; it has been excluded for the purpose of simplification.
Set
The basic native for setting values to dynamic units is:
*_set_(type)(arrayid, index, (type)value)
Where (type) is the type of value you want to set.
Note: in keytables and hashtables, index will be a string.
Types available: int, float, string, vector. Note: With hashtables, types have been cut down for compatibility.
Get
The basic native for getting values to dynamic units is:
*_get_(type)(arrayid, index, (type)value, ret_val)
Where (type) is the type of value you want to set.
Note: in keytables and hashtables, index will be a string.
Types available: int, float, string, vector. Note: With hashtables, types have been cut down for compatibility. Note: For floats and integers, there is no ret_val parameter; the native returns the value directly.
Remove
The basic native for removing indexes completely is:
*_remove (arrayid, index)
Note: in keytables and hashtables, index will be a string.
Note: Removing an index will recover the memory used by it. That index must be reallocated to use again.
Filled
The basic native for getting conformation of indexes in dynamic units is:
*_isfilled(arrayid, index)
Note: in keytables and hashtables, index will be a string.
Will return 1 if the index exists.
Empty
The basic native for getting conformation of indexes in dynamic units is:
*_isempty(arrayid, index)
Note: in keytables and hashtables, index will be a string.
Will return 1 if the index does not exist.
Unit Specific Natives
Some functions are not available to some units, due to the incompatibilities between them.
Saving/Loading
Hashtables lack this feature entirely, while keytables and arrays support it fully.
Saving
This native allows an array or keytable to be directly saved to a file specified:
- _save (arrayid, filename[], disable_check = 0);
Loading
This native allows an array or keytable to be loaded directly from a file.
If an arrayid is provided, the file will be loaded into that unit; if not, it will load into a new unit, and return its id.
- _load (filename[], arrayid = 0, reserve_id = 0);
Convert
This native will convert a binary file into a human readable file:
- _save_ascii(inputfile[], outputfile[]);
Searching
Hashtables lack this feature entirely, while keytables have limited searching capabilities, and arrays has advanced capabilities in searching.
Filled Index Searching
These functions allow the coder to search through filled indexes in arrays and keytables. These functions do not guarantee success, so it is recommended that the success parameter be checked.
*_first (arrayid, index, &success = 0);
- _next (arrayid, index, &success = 0);
- _prev (arrayid, index, &success = 0);
- _last (arrayid, index, &success = 0);
Index parameter: Starting index
Note: in keytables and hashtables, index will be a string.
Empty Index Searching
These functions allow the coder to search through empty indexes in arrays. These functions do not guarantee success, so it is recommended that the success parameter be checked.
*_firstempty (arrayid, index, &success = 0);
- _nextempty (arrayid, index, &success = 0);
- _prevempty (arrayid, index, &success = 0);
- _lastempty (arrayid, index, &success = 0);
Index parameter: Starting index.
Array Information
Arrays have two additional natives, which allow for retrieval of additional information:
Get the size of the array from one index to another
- array_size (arrayid, start = 0, stop = -1, disable_check = 0);
Return the nth filled index, starting at start
- array_get_nth (arrayid, n, start = 0, disable_check = 0);
Unit Compression
As one might notice, an entire dynamic unit is referenced by an integer value. This allows one to create a number of significant structures:
- Units of Units:
- Storing the references to units into an array, allowing for two dimension dynamic unit storage and retrieval
- Use of a keytable and hashtable in conjunction to enhance the properties of both - faster gets + searching and saving -
- Dynamic storage of: functions, units, and much more
The most powerful of these is to create a global variable of type 'public', and use it to reference a dynamic unit. Now any plugin may access that unit as if it was their own, with little to no cost.