1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
8 /** @file script_list.hpp A list which can keep item/value pairs, which you can walk. */
9 /** @defgroup ScriptList Classes that create a list of items. */
10 
11 #ifndef SCRIPT_LIST_HPP
12 #define SCRIPT_LIST_HPP
13 
14 #include "script_object.hpp"
15 #include <map>
16 #include <set>
17 
18 class ScriptListSorter;
19 
20 /**
21  * Class that creates a list which can keep item/value pairs, which you can walk.
22  * @api ai game
23  */
24 class ScriptList : public ScriptObject {
25 public:
26 	/** Type of sorter */
27 	enum SorterType {
28 		SORT_BY_VALUE, ///< Sort the list based on the value of the item.
29 		SORT_BY_ITEM,  ///< Sort the list based on the item itself.
30 	};
31 
32 	/** Sort ascending */
33 	static const bool SORT_ASCENDING = true;
34 	/** Sort descending */
35 	static const bool SORT_DESCENDING = false;
36 
37 private:
38 	ScriptListSorter *sorter;     ///< Sorting algorithm
39 	SorterType sorter_type;       ///< Sorting type
40 	bool sort_ascending;          ///< Whether to sort ascending or descending
41 	bool initialized;             ///< Whether an iteration has been started
42 	int modifications;            ///< Number of modification that has been done. To prevent changing data while valuating.
43 
44 public:
45 	typedef std::set<int64> ScriptItemList;                   ///< The list of items inside the bucket
46 	typedef std::map<int64, ScriptItemList> ScriptListBucket; ///< The bucket list per value
47 	typedef std::map<int64, int64> ScriptListMap;             ///< List per item
48 
49 	ScriptListMap items;           ///< The items in the list
50 	ScriptListBucket buckets;      ///< The items in the list, sorted by value
51 
52 	ScriptList();
53 	~ScriptList();
54 
55 #ifdef DOXYGEN_API
56 	/**
57 	 * Add a single item to the list.
58 	 * @param item the item to add. Should be unique, otherwise it is ignored.
59 	 * @param value the value to assign.
60 	 */
61 	void AddItem(int64 item, int64 value);
62 #else
63 	void AddItem(int64 item, int64 value = 0);
64 #endif /* DOXYGEN_API */
65 
66 	/**
67 	 * Remove a single item from the list.
68 	 * @param item the item to remove. If not existing, it is ignored.
69 	 */
70 	void RemoveItem(int64 item);
71 
72 	/**
73 	 * Clear the list, making Count() returning 0 and IsEmpty() returning true.
74 	 */
75 	void Clear();
76 
77 	/**
78 	 * Check if an item is in the list.
79 	 * @param item the item to check for.
80 	 * @return true if the item is in the list.
81 	 */
82 	bool HasItem(int64 item);
83 
84 	/**
85 	 * Go to the beginning of the list and return the item. To get the value use list.GetValue(list.Begin()).
86 	 * @return the first item.
87 	 * @note returns 0 if beyond end-of-list. Use IsEnd() to check for end-of-list.
88 	 */
89 	int64 Begin();
90 
91 	/**
92 	 * Go to the next item in the list and return the item. To get the value use list.GetValue(list.Next()).
93 	 * @return the next item.
94 	 * @note returns 0 if beyond end-of-list. Use IsEnd() to check for end-of-list.
95 	 */
96 	int64 Next();
97 
98 	/**
99 	 * Check if a list is empty.
100 	 * @return true if the list is empty.
101 	 */
102 	bool IsEmpty();
103 
104 	/**
105 	 * Check if there is a element left. In other words, if this is false,
106 	 * the last call to Begin() or Next() returned a valid item.
107 	 * @return true if the current item is beyond end-of-list.
108 	 */
109 	bool IsEnd();
110 
111 	/**
112 	 * Returns the amount of items in the list.
113 	 * @return amount of items in the list.
114 	 */
115 	int32 Count();
116 
117 	/**
118 	 * Get the value that belongs to this item.
119 	 * @param item the item to get the value from
120 	 * @return the value that belongs to this item.
121 	 */
122 	int64 GetValue(int64 item);
123 
124 	/**
125 	 * Set a value of an item directly.
126 	 * @param item the item to set the value for.
127 	 * @param value the value to give to the item
128 	 * @return true if we could set the item to value, false otherwise.
129 	 * @note Changing values of items while looping through a list might cause
130 	 *  entries to be skipped. Be very careful with such operations.
131 	 */
132 	bool SetValue(int64 item, int64 value);
133 
134 	/**
135 	 * Sort this list by the given sorter and direction.
136 	 * @param sorter    the type of sorter to use
137 	 * @param ascending if true, lowest value is on top, else at bottom.
138 	 * @note the current item stays at the same place.
139 	 * @see SORT_ASCENDING SORT_DESCENDING
140 	 */
141 	void Sort(SorterType sorter, bool ascending);
142 
143 	/**
144 	 * Add one list to another one.
145 	 * @param list The list that will be added to the caller.
146 	 * @post The list to be added ('list') stays unmodified.
147 	 * @note All added items keep their value as it was in 'list'.
148 	 * @note If the item already exists inside the caller, the value of the
149 	 *  list that is added is set on the item.
150 	 */
151 	void AddList(ScriptList *list);
152 
153 	/**
154 	 * Swap the contents of two lists.
155 	 * @param list The list that will be swapped with.
156 	 */
157 	void SwapList(ScriptList *list);
158 
159 	/**
160 	 * Removes all items with a higher value than 'value'.
161 	 * @param value the value above which all items are removed.
162 	 */
163 	void RemoveAboveValue(int64 value);
164 
165 	/**
166 	 * Removes all items with a lower value than 'value'.
167 	 * @param value the value below which all items are removed.
168 	 */
169 	void RemoveBelowValue(int64 value);
170 
171 	/**
172 	 * Removes all items with a value above start and below end.
173 	 * @param start the lower bound of the to be removed values (exclusive).
174 	 * @param end   the upper bound of the to be removed values (exclusive).
175 	 */
176 	void RemoveBetweenValue(int64 start, int64 end);
177 
178 	/**
179 	 * Remove all items with this value.
180 	 * @param value the value to remove.
181 	 */
182 	void RemoveValue(int64 value);
183 
184 	/**
185 	 * Remove the first count items.
186 	 * @param count the amount of items to remove.
187 	 */
188 	void RemoveTop(int32 count);
189 
190 	/**
191 	 * Remove the last count items.
192 	 * @param count the amount of items to remove.
193 	 */
194 	void RemoveBottom(int32 count);
195 
196 	/**
197 	 * Remove everything that is in the given list from this list (same item index that is).
198 	 * @param list the list of items to remove.
199 	 * @pre list != nullptr
200 	 */
201 	void RemoveList(ScriptList *list);
202 
203 	/**
204 	 * Keep all items with a higher value than 'value'.
205 	 * @param value the value above which all items are kept.
206 	 */
207 	void KeepAboveValue(int64 value);
208 
209 	/**
210 	 * Keep all items with a lower value than 'value'.
211 	 * @param value the value below which all items are kept.
212 	 */
213 	void KeepBelowValue(int64 value);
214 
215 	/**
216 	 * Keep all items with a value above start and below end.
217 	 * @param start the lower bound of the to be kept values (exclusive).
218 	 * @param end   the upper bound of the to be kept values (exclusive).
219 	 */
220 	void KeepBetweenValue(int64 start, int64 end);
221 
222 	/**
223 	 * Keep all items with this value.
224 	 * @param value the value to keep.
225 	 */
226 	void KeepValue(int64 value);
227 
228 	/**
229 	 * Keep the first count items, i.e. remove everything except the first count items.
230 	 * @param count the amount of items to keep.
231 	 */
232 	void KeepTop(int32 count);
233 
234 	/**
235 	 * Keep the last count items, i.e. remove everything except the last count items.
236 	 * @param count the amount of items to keep.
237 	 */
238 	void KeepBottom(int32 count);
239 
240 	/**
241 	 * Keeps everything that is in the given list from this list (same item index that is).
242 	 * @param list the list of items to keep.
243 	 * @pre list != nullptr
244 	 */
245 	void KeepList(ScriptList *list);
246 
247 #ifndef DOXYGEN_API
248 	/**
249 	 * Used for 'foreach()' and [] get from Squirrel.
250 	 */
251 	SQInteger _get(HSQUIRRELVM vm);
252 
253 	/**
254 	 * Used for [] set from Squirrel.
255 	 */
256 	SQInteger _set(HSQUIRRELVM vm);
257 
258 	/**
259 	 * Used for 'foreach()' from Squirrel.
260 	 */
261 	SQInteger _nexti(HSQUIRRELVM vm);
262 
263 	/**
264 	 * The Valuate() wrapper from Squirrel.
265 	 */
266 	SQInteger Valuate(HSQUIRRELVM vm);
267 #else
268 	/**
269 	 * Give all items a value defined by the valuator you give.
270 	 * @param valuator_function The function which will be doing the valuation.
271 	 * @param params The params to give to the valuators (minus the first param,
272 	 *  which is always the index-value we are valuating).
273 	 * @note You may not add, remove or change (setting the value of) items while
274 	 *  valuating. You may also not (re)sort while valuating.
275 	 * @note You can write your own valuators and use them. Just remember that
276 	 *  the first parameter should be the index-value, and it should return
277 	 *  an integer.
278 	 * @note Example:
279 	 *  list.Valuate(ScriptBridge.GetPrice, 5);
280 	 *  list.Valuate(ScriptBridge.GetMaxLength);
281 	 *  function MyVal(bridge_id, myparam)
282 	 *  {
283 	 *    return myparam * bridge_id; // This is silly
284 	 *  }
285 	 *  list.Valuate(MyVal, 12);
286 	 */
287 	void Valuate(void *valuator_function, int params, ...);
288 #endif /* DOXYGEN_API */
289 };
290 
291 #endif /* SCRIPT_LIST_HPP */
292