Fix #8316: Make sort industries by production and transported with a cargo filter...
[openttd-github.git] / src / newgrf_storage.h
blob819e8d9394a8195c323dc067c583419da3da99be
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 */
8 /** @file newgrf_storage.h Functionality related to the temporary and persistent storage arrays for NewGRFs. */
10 #ifndef NEWGRF_STORAGE_H
11 #define NEWGRF_STORAGE_H
13 #include "core/pool_type.hpp"
14 #include "tile_type.h"
16 /**
17 * Mode switches to the behaviour of persistent storage array.
19 enum PersistentStorageMode {
20 PSM_ENTER_GAMELOOP, ///< Enter the gameloop, changes will be permanent.
21 PSM_LEAVE_GAMELOOP, ///< Leave the gameloop, changes will be temporary.
22 PSM_ENTER_COMMAND, ///< Enter command scope, changes will be permanent.
23 PSM_LEAVE_COMMAND, ///< Leave command scope, revert to previous mode.
24 PSM_ENTER_TESTMODE, ///< Enter command test mode, changes will be temporary.
25 PSM_LEAVE_TESTMODE, ///< Leave command test mode, revert to previous mode.
28 /**
29 * Base class for all persistent NewGRF storage arrays. Nothing fancy, only here
30 * so we have a generalised access to the virtual methods.
32 struct BasePersistentStorageArray {
33 uint32 grfid; ///< GRFID associated to this persistent storage. A value of zero means "default".
34 byte feature; ///< NOSAVE: Used to identify in the owner of the array in debug output.
35 TileIndex tile; ///< NOSAVE: Used to identify in the owner of the array in debug output.
37 virtual ~BasePersistentStorageArray();
39 static void SwitchMode(PersistentStorageMode mode, bool ignore_prev_mode = false);
41 protected:
42 /**
43 * Discard temporary changes.
45 virtual void ClearChanges() = 0;
47 /**
48 * Check whether currently changes to the storage shall be persistent or
49 * temporary till the next call to ClearChanges().
51 static bool AreChangesPersistent() { return (gameloop || command) && !testmode; }
53 private:
54 static bool gameloop;
55 static bool command;
56 static bool testmode;
59 /**
60 * Class for persistent storage of data.
61 * On #ClearChanges that data is either reverted or saved.
62 * @tparam TYPE the type of variable to store.
63 * @tparam SIZE the size of the array.
65 template <typename TYPE, uint SIZE>
66 struct PersistentStorageArray : BasePersistentStorageArray {
67 TYPE storage[SIZE]; ///< Memory to for the storage array
68 TYPE *prev_storage; ///< Memory to store "old" states so we can revert them on the performance of test cases for commands etc.
70 /** Simply construct the array */
71 PersistentStorageArray() : prev_storage(nullptr)
73 memset(this->storage, 0, sizeof(this->storage));
76 /** And free all data related to it */
77 ~PersistentStorageArray()
79 free(this->prev_storage);
82 /** Resets all values to zero. */
83 void ResetToZero()
85 memset(this->storage, 0, sizeof(this->storage));
88 /**
89 * Stores some value at a given position.
90 * If there is no backup of the data that backup is made and then
91 * we write the data.
92 * @param pos the position to write at
93 * @param value the value to write
95 void StoreValue(uint pos, int32 value)
97 /* Out of the scope of the array */
98 if (pos >= SIZE) return;
100 /* The value hasn't changed, so we pretend nothing happened.
101 * Saves a few cycles and such and it's pretty easy to check. */
102 if (this->storage[pos] == value) return;
104 /* We do not have made a backup; lets do so */
105 if (AreChangesPersistent()) {
106 assert(this->prev_storage == nullptr);
107 } else if (this->prev_storage == nullptr) {
108 this->prev_storage = MallocT<TYPE>(SIZE);
109 memcpy(this->prev_storage, this->storage, sizeof(this->storage));
111 /* We only need to register ourselves when we made the backup
112 * as that is the only time something will have changed */
113 AddChangedPersistentStorage(this);
116 this->storage[pos] = value;
120 * Gets the value from a given position.
121 * @param pos the position to get the data from
122 * @return the data from that position
124 TYPE GetValue(uint pos) const
126 /* Out of the scope of the array */
127 if (pos >= SIZE) return 0;
129 return this->storage[pos];
132 void ClearChanges()
134 if (this->prev_storage != nullptr) {
135 memcpy(this->storage, this->prev_storage, sizeof(this->storage));
136 free(this->prev_storage);
137 this->prev_storage = nullptr;
144 * Class for temporary storage of data.
145 * On #ClearChanges that data is always zero-ed.
146 * @tparam TYPE the type of variable to store.
147 * @tparam SIZE the size of the array.
149 template <typename TYPE, uint SIZE>
150 struct TemporaryStorageArray {
151 TYPE storage[SIZE]; ///< Memory to for the storage array
152 uint16 init[SIZE]; ///< Storage has been assigned, if this equals 'init_key'.
153 uint16 init_key; ///< Magic key to 'init'.
155 /** Simply construct the array */
156 TemporaryStorageArray()
158 memset(this->storage, 0, sizeof(this->storage)); // not exactly needed, but makes code analysers happy
159 memset(this->init, 0, sizeof(this->init));
160 this->init_key = 1;
164 * Stores some value at a given position.
165 * @param pos the position to write at
166 * @param value the value to write
168 void StoreValue(uint pos, int32 value)
170 /* Out of the scope of the array */
171 if (pos >= SIZE) return;
173 this->storage[pos] = value;
174 this->init[pos] = this->init_key;
178 * Gets the value from a given position.
179 * @param pos the position to get the data from
180 * @return the data from that position
182 TYPE GetValue(uint pos) const
184 /* Out of the scope of the array */
185 if (pos >= SIZE) return 0;
187 if (this->init[pos] != this->init_key) {
188 /* Unassigned since last call to ClearChanges */
189 return 0;
192 return this->storage[pos];
195 void ClearChanges()
197 /* Increment init_key to invalidate all storage */
198 this->init_key++;
199 if (this->init_key == 0) {
200 /* When init_key wraps around, we need to reset everything */
201 memset(this->init, 0, sizeof(this->init));
202 this->init_key = 1;
207 void AddChangedPersistentStorage(BasePersistentStorageArray *storage);
209 typedef PersistentStorageArray<int32, 16> OldPersistentStorage;
211 typedef uint32 PersistentStorageID;
213 struct PersistentStorage;
214 typedef Pool<PersistentStorage, PersistentStorageID, 1, 0xFF000> PersistentStoragePool;
216 extern PersistentStoragePool _persistent_storage_pool;
219 * Class for pooled persistent storage of data.
221 struct PersistentStorage : PersistentStorageArray<int32, 256>, PersistentStoragePool::PoolItem<&_persistent_storage_pool> {
222 /** We don't want GCC to zero our struct! It already is zeroed and has an index! */
223 PersistentStorage(const uint32 new_grfid, byte feature, TileIndex tile)
225 this->grfid = new_grfid;
226 this->feature = feature;
227 this->tile = tile;
231 static_assert(cpp_lengthof(OldPersistentStorage, storage) <= cpp_lengthof(PersistentStorage, storage));
233 #endif /* NEWGRF_STORAGE_H */