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/>.
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 "map/coord.h"
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.
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);
45 * Discard temporary changes.
47 virtual void ClearChanges() = 0;
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
; }
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(NULL
)
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. */
87 memset(this->storage
, 0, sizeof(this->storage
));
91 * Stores some value at a given position.
92 * If there is no backup of the data that backup is made and then
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
== NULL
);
109 } else if (this->prev_storage
== NULL
) {
110 this->prev_storage
= xmemdupt (this->storage
, SIZE
);
112 /* We only need to register ourselves when we made the backup
113 * as that is the only time something will have changed */
114 AddChangedPersistentStorage(this);
117 this->storage
[pos
] = value
;
121 * Gets the value from a given position.
122 * @param pos the position to get the data from
123 * @return the data from that position
125 TYPE
GetValue(uint pos
) const
127 /* Out of the scope of the array */
128 if (pos
>= SIZE
) return 0;
130 return this->storage
[pos
];
135 if (this->prev_storage
!= NULL
) {
136 memcpy(this->storage
, this->prev_storage
, sizeof(this->storage
));
137 free(this->prev_storage
);
138 this->prev_storage
= NULL
;
145 * Class for temporary storage of data.
146 * On #ClearChanges that data is always zero-ed.
147 * @tparam TYPE the type of variable to store.
148 * @tparam SIZE the size of the array.
150 template <typename TYPE
, uint SIZE
>
151 struct TemporaryStorageArray
{
152 TYPE storage
[SIZE
]; ///< Memory to for the storage array
153 uint16 init
[SIZE
]; ///< Storage has been assigned, if this equals 'init_key'.
154 uint16 init_key
; ///< Magic key to 'init'.
156 /** Simply construct the array */
157 TemporaryStorageArray()
159 memset(this->storage
, 0, sizeof(this->storage
)); // not exactly needed, but makes code analysers happy
160 memset(this->init
, 0, sizeof(this->init
));
165 * Stores some value at a given position.
166 * @param pos the position to write at
167 * @param value the value to write
169 void StoreValue(uint pos
, int32 value
)
171 /* Out of the scope of the array */
172 if (pos
>= SIZE
) return;
174 this->storage
[pos
] = value
;
175 this->init
[pos
] = this->init_key
;
179 * Gets the value from a given position.
180 * @param pos the position to get the data from
181 * @return the data from that position
183 TYPE
GetValue(uint pos
) const
185 /* Out of the scope of the array */
186 if (pos
>= SIZE
) return 0;
188 if (this->init
[pos
] != this->init_key
) {
189 /* Unassigned since last call to ClearChanges */
193 return this->storage
[pos
];
198 /* Increment init_key to invalidate all storage */
200 if (this->init_key
== 0) {
201 /* When init_key wraps around, we need to reset everything */
202 memset(this->init
, 0, sizeof(this->init
));
208 void AddChangedPersistentStorage(BasePersistentStorageArray
*storage
);
210 typedef PersistentStorageArray
<int32
, 16> OldPersistentStorage
;
212 typedef uint32 PersistentStorageID
;
215 * Class for pooled persistent storage of data.
217 struct PersistentStorage
: PersistentStorageArray
<int32
, 16>, PooledItem
<PersistentStorage
, PersistentStorageID
, 1, 0xFF000> {
218 /** We don't want GCC to zero our struct! It already is zeroed and has an index! */
219 PersistentStorage(const uint32 new_grfid
, byte feature
, TileIndex tile
)
221 this->grfid
= new_grfid
;
222 this->feature
= feature
;
227 assert_compile(cpp_lengthof(OldPersistentStorage
, storage
) == cpp_lengthof(PersistentStorage
, storage
));
229 #define FOR_ALL_STORAGES_FROM(var, start) FOR_ALL_ITEMS_FROM(PersistentStorage, storage_index, var, start)
230 #define FOR_ALL_STORAGES(var) FOR_ALL_STORAGES_FROM(var, 0)
232 #endif /* NEWGRF_STORAGE_H */