16.10.2017, 21:26
(
Last edited by IllidanS4; 19/10/2017 at 08:36 PM.
)
i_foreach 1.1
Download
AboutDownload
This is a very small include that adds a new syntactical element to Pawn - the foreach statement. You probably know it from other languages (or y_foreach), the statement is used to iterate over a collection of elements. Unlike y_foreach however, this is merely a syntactic sugar for a fancy for loop, and doesn't contain functions for modifying custom collections. You can, however, create a custom iterator using this, and it also supports returning any number of values, even arrays.
Introduction
In the past, I faced the same thing as anyone who develops a gamemode would eventually face - the repetition of per-player or other loops. Lines like "for(new i = 0; i < MAX_PLAYERS; i++)if(IsPlayerConnected(i))" became numerous, and so I decided to make a simple macro "ForAllPlayers(i)" that would be simply be replaced with the former.
After learning C#, I wondered if maybe the "foreach" statement from it would be portable to Pawn. At that time, I am not sure if I knew YSI or y_foreach, but I decided to make my own simple one. My foreach is extensible, small, and uses no hooks.
Usage
Usage is simple:
Code:
foreach(new player in players) { SetPlayerColor(player, -1); }
Code:
for(new player = 0, __top_player = GetPlayerPoolSize(); player <= __top_player; player++)if(IsPlayerConnected(player)&&!IsPlayerNPC(player)) { SetPlayerColor(player, -1); }
You should include this after standard SA-MP libraries, because it checks for availability of some functions.
Iterators
The include provides a number of iterators (like players) for enumerating various collections. The iterator's name is only valid in the foreach statement, and can be used for something else outside of it.
total_players
All connected players, including NPCs.
players
All real players (i.e. not NPCs).
npcs
All connected NPCs.
vehicles
All created vehicles.
objects
All created objects.
pickups
All created pickups.
actors
All created actors.
chars(str)
All character and their indices in a string, which can be specified in str.
Code:
new str[]= "Hello!"; foreach(new i, c in chars(str)) { printf("str[%d]=%c", i, c); }
All PVars indices defined for a player, which can be specified in plr. You still have to check if the PVar index is actually valid, because there is no GetPVarTypeFromIndex.
range(a, b)
Iterates over a range of numbers, starting at a and ending at b (inclusive).
Custom iterators
In addition to these pre-defined iterators, you can create your own ones! An iterator has five components: the initial value, the final value, the filter, the values selector, and the name selector (more about these later, you can set them to default). See the example:
Code:
#define iter_initial_total_players 0 #define iter_check_total_players(%0) IsPlayerConnected(%0) #define iter_top_total_players GetPlayerPoolSize() #define iter_selector_total_players(%1)(%2) iter_selector_default(%1)(%2) #define iter_name_total_players(%1)(%2) iter_name_default(%1)(%2)
Parametrized iterators can be also created; see the code for the "range" iterator:
Code:
#define iter_initial_range(%0,%1) %0 #define iter_top_range(%0,%1) %1 #define iter_check_range(%0,%1)(%2) iter_check_true #define iter_selector_range(%0,%1)(%2)(%3) iter_selector_default(%2)(%3) #define iter_name_range(%0,%1)(%2)(%3) iter_name_default(%2)(%3) foreach(new i in range(5, 15)) { printf("%d", i); //prints 5 to 15 }
The two additional macros, specifying the selectors, allow you to define iterators that return any number of values of any type. To illustrate an iterator with tags, let's try to create an iterator that returns all the powers of 0.5:
Code:
#define iter_initial_halves 0 #define iter_top_halves cellmax #define iter_check_halves(%1) iter_check_true #define iter_selector_halves(%1)(Float:%2) %2=(floatpower(0.5,%1)) #define iter_name_halves(%1)(Float:%2) %1%2
This is the default implementation of the selectors:
Code:
#define iter_selector_default(%1)(%2) %2=%1 #define iter_name_default(%1)(%2) %1%2
The value selector need not specify only one assignment; it can do any number of assignments, thanks to the "," operator. See the definition for chars:
Code:
#define iter_initial_chars(%0) 0 #define iter_top_chars(%0) strlen(%0)-1 #define iter_check_chars(%0)(%1) iter_check_true #define iter_selector_chars(%0)(%1)(%2,%3) %2=%1,%3=%0[%1] #define iter_name_chars(%0)(%1)(%2,%3) iter_name_default(%1)(%2)
There are no limits to the kind of output variables you want to use, as long as you specify the value and name selector correctly. You can even return arrays or strings from the iterator!
Code:
#define iter_initial_player_names iter_initial_players #define iter_top_player_names iter_top_players #define iter_check_player_names(%1) iter_check_players(%1) #define iter_selector_player_names(%1)(%2,%3[MAX_PLAYER_NAME]) %2=%1,GetPlayerName(%1,%3,MAX_PLAYER_NAME) #define iter_name_player_names(%1)(%2,%3[MAX_PLAYER_NAME]) %1%2 foreach(new plr, name[MAX_PLAYER_NAME] in player_names) { printf("%s (%d)", name, plr); }
Download
At the top of this topic.
Changelog
1.1.1 - Space before new is now allowed.
1.1 - Added the range iterator, chars iterator modified to also yield the character values, and added the support for multiple and tagged values and arrays. The macro definition is also more benevolent to spacing in the foreach statement.
1.0 - Initial version.