alliedmodders/amxmodx — pull request #11 by Nextra (2014-05-09 11:31:13+00:00)
Title: Introduce Trie Iterators

This series of commits adds new natives around exposing actual iterators for a hashmap, instead of the compromise that snapshots provide.

I don't know if adding this kind of API has been considered before, so this is as much a request for discussion (is this even a good idea?) as it is a request for review.

Iterators have the obvious drawback of possible breakage after mutating changes to the hashtable have occured. I have added a very strict safety guard for determining an iterators validity. The hashtable now contains a modification counter that is incremented whenever internalAdd and removeEntry have to do work. Iterators store the current modification counter upon creation, so it is possible to detect when a key has been added or removed. I wanted very simple guarantees when exposing iterators, so this strict check (**any** modification breaks the iterator) seemed appropriate.

With this set of natives I wanted to reach a secondary goal: Iterators should provide full read access to a map, but no writing should be possible without actually knowing the handle to the map. This also makes them unlike snapshots which, at least currently, can only extract the keys and have to work together with the default TrieGet* and TrieSet* natives to be useful. Since I've been working on a set of plugins with their own API the idea for read-only access to Tries without having to hand out the original handle (or clone the data) seemed valuable to me. This is also why, although it might seem weird at first, there is the possibility to set the iterator position to a known key.

The test suite has been extended and covers basic usage of the new natives. Arkshine has done a bunch of additional testing and thus far everything looks fine.

In total this adds 11 new natives that are extensively documented in celltrie.inc:
```sourcepawn
enum TrieIter
{
Invalid_Iter = 0
};
enum TrieIterStatus
{
IterStatus_Valid = 0,	// Iterator is in a usable state
IterStatus_Outdated = 1,	// Iterator has to be refreshed
IterStatus_Closed = 2,	// Iterator map has been closed, iterator should be destroyed
};
native TrieIter:TrieIterCreate(Trie:handle);
native bool:TrieIterNext(TrieIter:handle, key[] = "", outputsize = 0, &size = 0);
native bool:TrieIterGetKey(TrieIter:handle, key[] = "", outputsize = 0, &size = 0);
native TrieIterStatus:TrieIterGetStatus(TrieIter:handle);
native bool:TrieIterRefresh(TrieIter:handle);
native TrieIterGetSize(TrieIter:handle);
native bool:TrieIterSetPos(TrieIter:handle, const key[]);
native bool:TrieIterGetCell(TrieIter:handle, &any:value);
native bool:TrieIterGetString(TrieIter:handle, buffer[], outputsize, &size = 0);
native bool:TrieIterGetArray(TrieIter:handle, any:array[], outputsize, &size = 0);
native TrieIterDestroy(&TrieIter:handle);
```