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/alloc_func.hpp"
14 #include "core/pool_type.hpp"
15 #include "tile_type.h"
18 * Mode switches to the behaviour of persistent storage array.
20 enum PersistentStorageMode
{
21 PSM_ENTER_GAMELOOP
, ///< Enter the gameloop, changes will be permanent.
22 PSM_LEAVE_GAMELOOP
, ///< Leave the gameloop, changes will be temporary.
23 PSM_ENTER_COMMAND
, ///< Enter command scope, changes will be permanent.
24 PSM_LEAVE_COMMAND
, ///< Leave command scope, revert to previous mode.
25 PSM_ENTER_TESTMODE
, ///< Enter command test mode, changes will be temporary.
26 PSM_LEAVE_TESTMODE
, ///< Leave command test mode, revert to previous mode.
30 * Base class for all persistent NewGRF storage arrays. Nothing fancy, only here
31 * so we have a generalised access to the virtual methods.
33 struct BasePersistentStorageArray
{
34 uint32_t grfid
; ///< GRFID associated to this persistent storage. A value of zero means "default".
35 uint8_t feature
; ///< NOSAVE: Used to identify in the owner of the array in debug output.
36 TileIndex tile
; ///< NOSAVE: Used to identify in the owner of the array in debug output.
38 virtual ~BasePersistentStorageArray();
40 static void SwitchMode(PersistentStorageMode mode
, bool ignore_prev_mode
= false);
44 * Discard temporary changes.
46 virtual void ClearChanges() = 0;
49 * Check whether currently changes to the storage shall be persistent or
50 * temporary till the next call to ClearChanges().
52 static bool AreChangesPersistent() { return (gameloop
|| command
) && !testmode
; }
61 * Class for persistent storage of data.
62 * On #ClearChanges that data is either reverted or saved.
63 * @tparam TYPE the type of variable to store.
64 * @tparam SIZE the size of the array.
66 template <typename TYPE
, uint SIZE
>
67 struct PersistentStorageArray
: BasePersistentStorageArray
{
68 using StorageType
= std::array
<TYPE
, SIZE
>;
70 StorageType storage
{}; ///< Memory for the storage array
71 std::unique_ptr
<StorageType
> prev_storage
{}; ///< Temporary memory to store previous state so it can be reverted, e.g. for command tests.
74 * Stores some value at a given position.
75 * If there is no backup of the data that backup is made and then
77 * @param pos the position to write at
78 * @param value the value to write
80 void StoreValue(uint pos
, int32_t value
)
82 /* Out of the scope of the array */
83 if (pos
>= SIZE
) return;
85 /* The value hasn't changed, so we pretend nothing happened.
86 * Saves a few cycles and such and it's pretty easy to check. */
87 if (this->storage
[pos
] == value
) return;
89 /* We do not have made a backup; lets do so */
90 if (AreChangesPersistent()) {
91 assert(!this->prev_storage
);
92 } else if (!this->prev_storage
) {
93 this->prev_storage
= std::make_unique
<StorageType
>(this->storage
);
95 /* We only need to register ourselves when we made the backup
96 * as that is the only time something will have changed */
97 AddChangedPersistentStorage(this);
100 this->storage
[pos
] = value
;
104 * Gets the value from a given position.
105 * @param pos the position to get the data from
106 * @return the data from that position
108 TYPE
GetValue(uint pos
) const
110 /* Out of the scope of the array */
111 if (pos
>= SIZE
) return 0;
113 return this->storage
[pos
];
116 void ClearChanges() override
118 if (this->prev_storage
) {
119 this->storage
= *this->prev_storage
;
120 this->prev_storage
.reset();
127 * Class for temporary storage of data.
128 * On #ClearChanges that data is always zero-ed.
129 * @tparam TYPE the type of variable to store.
130 * @tparam SIZE the size of the array.
132 template <typename TYPE
, uint SIZE
>
133 struct TemporaryStorageArray
{
134 using StorageType
= std::array
<TYPE
, SIZE
>;
135 using StorageInitType
= std::array
<uint16_t, SIZE
>;
137 StorageType storage
{}; ///< Memory for the storage array
138 StorageInitType init
{}; ///< Storage has been assigned, if this equals 'init_key'.
139 uint16_t init_key
= 1; ///< Magic key to 'init'.
142 * Stores some value at a given position.
143 * @param pos the position to write at
144 * @param value the value to write
146 void StoreValue(uint pos
, int32_t value
)
148 /* Out of the scope of the array */
149 if (pos
>= SIZE
) return;
151 this->storage
[pos
] = value
;
152 this->init
[pos
] = this->init_key
;
156 * Gets the value from a given position.
157 * @param pos the position to get the data from
158 * @return the data from that position
160 TYPE
GetValue(uint pos
) const
162 /* Out of the scope of the array */
163 if (pos
>= SIZE
) return 0;
165 if (this->init
[pos
] != this->init_key
) {
166 /* Unassigned since last call to ClearChanges */
170 return this->storage
[pos
];
175 /* Increment init_key to invalidate all storage */
177 if (this->init_key
== 0) {
178 /* When init_key wraps around, we need to reset everything */
185 void AddChangedPersistentStorage(BasePersistentStorageArray
*storage
);
187 typedef PersistentStorageArray
<int32_t, 16> OldPersistentStorage
;
189 typedef uint32_t PersistentStorageID
;
191 struct PersistentStorage
;
192 typedef Pool
<PersistentStorage
, PersistentStorageID
, 1, 0xFF000> PersistentStoragePool
;
194 extern PersistentStoragePool _persistent_storage_pool
;
197 * Class for pooled persistent storage of data.
199 struct PersistentStorage
: PersistentStorageArray
<int32_t, 256>, PersistentStoragePool::PoolItem
<&_persistent_storage_pool
> {
200 /** We don't want GCC to zero our struct! It already is zeroed and has an index! */
201 PersistentStorage(const uint32_t new_grfid
, uint8_t feature
, TileIndex tile
)
203 this->grfid
= new_grfid
;
204 this->feature
= feature
;
209 static_assert(std::tuple_size_v
<decltype(OldPersistentStorage::storage
)> <= std::tuple_size_v
<decltype(PersistentStorage::storage
)>);
211 #endif /* NEWGRF_STORAGE_H */