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