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