Array Module (AMX Mod X)
Array module, created and maintained by Twilight Suzuka and Anpheus, brings fast, easy, and effecient 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 implimentation, 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 implimentation.
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. Sparce, 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 ineffecient linked list design.
While searching for an appropriately sparce vector design for the new ArrayX, Anpheus chanced upon the Judy library. It offered unparrallel speed, effeciency, and sparce capabilities compared to any other system we could find. Implimenting Judy's trie design, they created ArrayX 2.0, which was basically the same then as it is now. It was eventually implimented into the CVS.
Description
Array module, originally ArrayX, provides dynamic storage units in the form of three generic types: Array, Keytable, 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 implimentation to allow for sparce and effecient data structures.
In effect, all three units allow for sparce settings, as well as providing huge speed and memory increases over other implimentations.
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 sparce; 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 effecient 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 effecient 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 assosiative array properties.
Basics:
- Method
- bind a value to a string key, decompiled through a hash.
- Allows
- Fastest possible retreival.
- Useful for vault-like programming and fast retreival
- 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
- Vault
Persistance
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 nessasary 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 inadvised 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 nessasarily 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 are 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 indexs from the unit, but leave it intact, allowing you to reuse it.
Memory
The basic native for retreiving 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. Useful for debugging.
Count
The basic native for retreiving the amount of units in existance is:
*_count( start = 0, stop = -1);
This will state the amount of units of the specified type in existance; as they are created in sequence, this can also be used to find out the ids of the availiable 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 indexs 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 indexs 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 indexs 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.