Update readme.md
[openttd-joker.git] / src / newgrf_storage.h
blobcae85a283fa8bf1c8b6783752887aec4e8ed2bf1
1 /* $Id: newgrf_storage.h 26371 2014-02-23 22:03:08Z frosch $ */
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
10 /** @file newgrf_storage.h Functionality related to the temporary and persistent storage arrays for NewGRFs. */
12 #ifndef NEWGRF_STORAGE_H
13 #define NEWGRF_STORAGE_H
15 #include "core/pool_type.hpp"
16 #include "tile_type.h"
18 /**
19 * Mode switches to the behaviour of persistent storage array.
21 enum PersistentStorageMode {
22 PSM_ENTER_GAMELOOP, ///< Enter the gameloop, changes will be permanent.
23 PSM_LEAVE_GAMELOOP, ///< Leave the gameloop, changes will be temporary.
24 PSM_ENTER_COMMAND, ///< Enter command scope, changes will be permanent.
25 PSM_LEAVE_COMMAND, ///< Leave command scope, revert to previous mode.
26 PSM_ENTER_TESTMODE, ///< Enter command test mode, changes will be tempoary.
27 PSM_LEAVE_TESTMODE, ///< Leave command test mode, revert to previous mode.
30 /**
31 * Base class for all persistent NewGRF storage arrays. Nothing fancy, only here
32 * so we have a generalised access to the virtual methods.
34 struct BasePersistentStorageArray {
35 uint32 grfid; ///< GRFID associated to this persistent storage. A value of zero means "default".
36 byte feature; ///< NOSAVE: Used to identify in the owner of the array in debug output.
37 TileIndex tile; ///< NOSAVE: Used to identify in the owner of the array in debug output.
39 virtual ~BasePersistentStorageArray();
41 static void SwitchMode(PersistentStorageMode mode, bool ignore_prev_mode = false);
43 protected:
44 /**
45 * Discard temporary changes.
47 virtual void ClearChanges() = 0;
49 /**
50 * Check whether currently changes to the storage shall be persistent or
51 * temporary till the next call to ClearChanges().
53 static bool AreChangesPersistent() { return (gameloop || command) && !testmode; }
55 private:
56 static bool gameloop;
57 static bool command;
58 static bool testmode;
61 /**
62 * Class for persistent storage of data.
63 * On #ClearChanges that data is either reverted or saved.
64 * @tparam TYPE the type of variable to store.
65 * @tparam SIZE the size of the array.
67 template <typename TYPE, uint SIZE>
68 struct PersistentStorageArray : BasePersistentStorageArray {
69 TYPE storage[SIZE]; ///< Memory to for the storage array
70 TYPE *prev_storage; ///< Memory to store "old" states so we can revert them on the performance of test cases for commands etc.
72 /** Simply construct the array */
73 PersistentStorageArray() : prev_storage(nullptr)
75 memset(this->storage, 0, sizeof(this->storage));
78 /** And free all data related to it */
79 ~PersistentStorageArray()
81 free(this->prev_storage);
84 /** Resets all values to zero. */
85 void ResetToZero()
87 memset(this->storage, 0, sizeof(this->storage));
90 /**
91 * Stores some value at a given position.
92 * If there is no backup of the data that backup is made and then
93 * we write the data.
94 * @param pos the position to write at
95 * @param value the value to write
97 void StoreValue(uint pos, int32 value)
99 /* Out of the scope of the array */
100 if (pos >= SIZE) return;
102 /* The value hasn't changed, so we pretend nothing happened.
103 * Saves a few cycles and such and it's pretty easy to check. */
104 if (this->storage[pos] == value) return;
106 /* We do not have made a backup; lets do so */
107 if (AreChangesPersistent()) {
108 assert(this->prev_storage == nullptr);
109 } else if (this->prev_storage == nullptr) {
110 this->prev_storage = MallocT<TYPE>(SIZE);
111 memcpy(this->prev_storage, this->storage, sizeof(this->storage));
113 /* We only need to register ourselves when we made the backup
114 * as that is the only time something will have changed */
115 AddChangedPersistentStorage(this);
118 this->storage[pos] = value;
122 * Gets the value from a given position.
123 * @param pos the position to get the data from
124 * @return the data from that position
126 TYPE GetValue(uint pos) const
128 /* Out of the scope of the array */
129 if (pos >= SIZE) return 0;
131 return this->storage[pos];
134 void ClearChanges()
136 if (this->prev_storage != nullptr) {
137 memcpy(this->storage, this->prev_storage, sizeof(this->storage));
138 free(this->prev_storage);
139 this->prev_storage = nullptr;
146 * Class for temporary storage of data.
147 * On #ClearChanges that data is always zero-ed.
148 * @tparam TYPE the type of variable to store.
149 * @tparam SIZE the size of the array.
151 template <typename TYPE, uint SIZE>
152 struct TemporaryStorageArray {
153 TYPE storage[SIZE]; ///< Memory to for the storage array
154 uint16 init[SIZE]; ///< Storage has been assigned, if this equals 'init_key'.
155 uint16 init_key; ///< Magic key to 'init'.
157 /** Simply construct the array */
158 TemporaryStorageArray()
160 memset(this->storage, 0, sizeof(this->storage)); // not exactly needed, but makes code analysers happy
161 memset(this->init, 0, sizeof(this->init));
162 this->init_key = 1;
166 * Stores some value at a given position.
167 * @param pos the position to write at
168 * @param value the value to write
170 void StoreValue(uint pos, int32 value)
172 /* Out of the scope of the array */
173 if (pos >= SIZE) return;
175 this->storage[pos] = value;
176 this->init[pos] = this->init_key;
180 * Gets the value from a given position.
181 * @param pos the position to get the data from
182 * @return the data from that position
184 TYPE GetValue(uint pos) const
186 /* Out of the scope of the array */
187 if (pos >= SIZE) return 0;
189 if (this->init[pos] != this->init_key) {
190 /* Unassigned since last call to ClearChanges */
191 return 0;
194 return this->storage[pos];
197 void ClearChanges()
199 /* Increment init_key to invalidate all storage */
200 this->init_key++;
201 if (this->init_key == 0) {
202 /* When init_key wraps around, we need to reset everything */
203 memset(this->init, 0, sizeof(this->init));
204 this->init_key = 1;
209 void AddChangedPersistentStorage(BasePersistentStorageArray *storage);
211 typedef PersistentStorageArray<int32, 16> OldPersistentStorage;
213 typedef uint32 PersistentStorageID;
215 struct PersistentStorage;
216 typedef Pool<PersistentStorage, PersistentStorageID, 1, 0xFF000> PersistentStoragePool;
218 extern PersistentStoragePool _persistent_storage_pool;
221 * Class for pooled persistent storage of data.
223 struct PersistentStorage : PersistentStorageArray<int32, 16>, PersistentStoragePool::PoolItem<&_persistent_storage_pool> {
224 /** We don't want GCC to zero our struct! It already is zeroed and has an index! */
225 PersistentStorage(const uint32 new_grfid, byte feature, TileIndex tile)
227 this->grfid = new_grfid;
228 this->feature = feature;
229 this->tile = tile;
233 assert_compile(cpp_lengthof(OldPersistentStorage, storage) == cpp_lengthof(PersistentStorage, storage));
235 #define FOR_ALL_STORAGES_FROM(var, start) FOR_ALL_ITEMS_FROM(PersistentStorage, storage_index, var, start)
236 #define FOR_ALL_STORAGES(var) FOR_ALL_STORAGES_FROM(var, 0)
238 #endif /* NEWGRF_STORAGE_H */