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/>.
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"
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.
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);
43 * Discard temporary changes.
45 virtual void ClearChanges() = 0;
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
; }
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. */
85 memset(this->storage
, 0, sizeof(this->storage
));
89 * Stores some value at a given position.
90 * If there is no backup of the data that backup is made and then
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
];
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
));
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 */
192 return this->storage
[pos
];
197 /* Increment init_key to invalidate all storage */
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
));
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
;
231 static_assert(cpp_lengthof(OldPersistentStorage
, storage
) <= cpp_lengthof(PersistentStorage
, storage
));
233 #endif /* NEWGRF_STORAGE_H */