rubidium@9703: /* $Id$ */ rubidium@9703: rubidium@9703: /** @file newgrf_storage.h Functionality related to the temporary and persistent storage arrays for NewGRFs. */ rubidium@9703: rubidium@9703: #ifndef NEWGRF_STORAGE_H rubidium@9703: #define NEWGRF_STORAGE_H rubidium@9703: rubidium@9723: #include "core/alloc_func.hpp" rubidium@9723: rubidium@9703: /** rubidium@9703: * Base class for all NewGRF storage arrays. Nothing fancy, only here rubidium@9703: * so we have a generalised class to use. rubidium@9703: */ rubidium@9703: struct BaseStorageArray rubidium@9703: { rubidium@9703: /** The needed destructor */ rubidium@9703: virtual ~BaseStorageArray() {} rubidium@9703: rubidium@9703: /** rubidium@9703: * Clear the changes made since the last ClearChanges. rubidium@9703: * This can be done in two ways: rubidium@9703: * - saving the changes permanently rubidium@9703: * - reverting to the previous version rubidium@9703: * @param keep_changes do we save or revert the changes since the last ClearChanges? rubidium@9703: */ rubidium@9703: virtual void ClearChanges(bool keep_changes) = 0; rubidium@9703: rubidium@9703: /** rubidium@9703: * Stores some value at a given position. rubidium@9703: * @param pos the position to write at rubidium@9703: * @param value the value to write rubidium@9703: */ rubidium@9703: virtual void Store(uint pos, uint32 value) = 0; rubidium@9703: }; rubidium@9703: rubidium@9703: /** rubidium@9703: * Class for persistent storage of data. rubidium@9703: * On ClearChanges that data is either reverted or saved. rubidium@9703: * @param TYPE the type of variable to store. rubidium@9703: * @param SIZE the size of the array. rubidium@9703: */ rubidium@9703: template rubidium@9703: struct PersistentStorageArray : BaseStorageArray { rubidium@9703: TYPE storage[SIZE]; ///< Memory to for the storage array rubidium@9703: TYPE *prev_storage; ///< Memory to store "old" states so we can revert them on the performance of test cases for commands etc. rubidium@9703: rubidium@9703: /** Simply construct the array */ rubidium@9703: PersistentStorageArray() : prev_storage(NULL) rubidium@9703: { rubidium@9703: memset(this->storage, 0, sizeof(this->storage)); rubidium@9703: } rubidium@9703: rubidium@9703: /** And free all data related to it */ rubidium@9703: ~PersistentStorageArray() rubidium@9703: { rubidium@9703: free(this->prev_storage); rubidium@9703: } rubidium@9703: rubidium@9703: /** rubidium@9703: * Stores some value at a given position. rubidium@9703: * If there is no backup of the data that backup is made and then rubidium@9703: * we write the data. rubidium@9703: * @param pos the position to write at rubidium@9703: * @param value the value to write rubidium@9703: */ rubidium@9703: void Store(uint pos, uint32 value) rubidium@9703: { rubidium@9703: /* Out of the scope of the array */ rubidium@9703: if (pos >= SIZE) return; rubidium@9703: rubidium@9703: /* The value hasn't changed, so we pretend nothing happened. rubidium@9703: * Saves a few cycles and such and it's pretty easy to check. */ rubidium@9703: if (this->storage[pos] == value) return; rubidium@9703: rubidium@9703: /* We do not have made a backup; lets do so */ rubidium@9703: if (this->prev_storage != NULL) { rubidium@9703: this->prev_storage = MallocT(SIZE); rubidium@9703: if (this->prev_storage == NULL) return; rubidium@9703: rubidium@9703: memcpy(this->prev_storage, this->storage, sizeof(this->storage)); rubidium@9703: rubidium@9703: /* We only need to register ourselves when we made the backup rubidium@9703: * as that is the only time something will have changed */ rubidium@9703: AddChangedStorage(this); rubidium@9703: } rubidium@9703: rubidium@9703: this->storage[pos] = value; rubidium@9703: } rubidium@9703: rubidium@9703: /** rubidium@9703: * Gets the value from a given position. rubidium@9703: * @param pos the position to get the data from rubidium@9703: * @return the data from that position rubidium@9703: */ rubidium@9703: TYPE Get(uint pos) const rubidium@9703: { rubidium@9703: /* Out of the scope of the array */ rubidium@9703: if (pos >= SIZE) return 0; rubidium@9703: rubidium@9703: return this->storage[pos]; rubidium@9703: } rubidium@9703: rubidium@9703: void ClearChanges(bool keep_changes) rubidium@9703: { rubidium@9703: assert(this->prev_storage != NULL); rubidium@9703: rubidium@9703: if (!keep_changes) { rubidium@9703: memcpy(this->storage, this->prev_storage, sizeof(this->storage)); rubidium@9703: } rubidium@9703: free(this->prev_storage); rubidium@9703: } rubidium@9703: }; rubidium@9703: rubidium@9703: rubidium@9703: /** rubidium@9703: * Class for temporary storage of data. rubidium@9703: * On ClearChanges that data is always zero-ed. rubidium@9703: * @param TYPE the type of variable to store. rubidium@9703: * @param SIZE the size of the array. rubidium@9703: */ rubidium@9703: template rubidium@9703: struct TemporaryStorageArray : BaseStorageArray { rubidium@9703: TYPE storage[SIZE]; ///< Memory to for the storage array rubidium@9703: rubidium@9703: /** Simply construct the array */ rubidium@9703: TemporaryStorageArray() rubidium@9703: { rubidium@9703: memset(this->storage, 0, sizeof(this->storage)); rubidium@9703: } rubidium@9703: rubidium@9703: /** rubidium@9703: * Stores some value at a given position. rubidium@9703: * @param pos the position to write at rubidium@9703: * @param value the value to write rubidium@9703: */ rubidium@9703: void Store(uint pos, uint32 value) rubidium@9703: { rubidium@9703: /* Out of the scope of the array */ rubidium@9703: if (pos >= SIZE) return; rubidium@9703: rubidium@9703: this->storage[pos] = value; rubidium@9703: AddChangedStorage(this); rubidium@9703: } rubidium@9703: rubidium@9703: /** rubidium@9703: * Gets the value from a given position. rubidium@9703: * @param pos the position to get the data from rubidium@9703: * @return the data from that position rubidium@9703: */ rubidium@9703: TYPE Get(uint pos) const rubidium@9703: { rubidium@9703: /* Out of the scope of the array */ rubidium@9703: if (pos >= SIZE) return 0; rubidium@9703: rubidium@9703: return this->storage[pos]; rubidium@9703: } rubidium@9703: rubidium@9703: void ClearChanges(bool keep_changes) rubidium@9703: { rubidium@9703: memset(this->storage, 0, sizeof(this->storage)); rubidium@9703: } rubidium@9703: }; rubidium@9703: rubidium@9703: /** rubidium@9703: * Add the changed storage array to the list of changed arrays. rubidium@9703: * This is done so we only have to revert/save the changed rubidium@9703: * arrays, which saves quite a few clears, etc. after callbacks. rubidium@9703: * @param storage the array that has changed rubidium@9703: */ rubidium@9703: void AddChangedStorage(BaseStorageArray *storage); rubidium@9703: rubidium@9703: rubidium@9703: /** rubidium@9703: * Clear the changes made since the last ClearStorageChanges. rubidium@9703: * This is done for *all* storages that have been registered to with rubidium@9703: * AddChangedStorage since the previous ClearStorageChanges. rubidium@9703: * rubidium@9703: * This can be done in two ways: rubidium@9703: * - saving the changes permanently rubidium@9703: * - reverting to the previous version rubidium@9703: * @param keep_changes do we save or revert the changes since the last ClearChanges? rubidium@9703: */ rubidium@9703: void ClearStorageChanges(bool keep_changes); rubidium@9703: rubidium@9703: #endif /* NEWGRF_STORAGE_H */