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