newgrf_storage.h

Go to the documentation of this file.
00001 /* $Id: newgrf_storage.h 26371 2014-02-23 22:03:08Z frosch $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * 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.
00006  * 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.
00007  * 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/>.
00008  */
00009 
00012 #ifndef NEWGRF_STORAGE_H
00013 #define NEWGRF_STORAGE_H
00014 
00015 #include "core/pool_type.hpp"
00016 #include "tile_type.h"
00017 
00021 enum PersistentStorageMode {
00022   PSM_ENTER_GAMELOOP,   
00023   PSM_LEAVE_GAMELOOP,   
00024   PSM_ENTER_COMMAND,    
00025   PSM_LEAVE_COMMAND,    
00026   PSM_ENTER_TESTMODE,   
00027   PSM_LEAVE_TESTMODE,   
00028 };
00029 
00034 struct BasePersistentStorageArray {
00035   uint32 grfid;    
00036   byte feature;    
00037   TileIndex tile;  
00038 
00039   virtual ~BasePersistentStorageArray();
00040 
00041   static void SwitchMode(PersistentStorageMode mode, bool ignore_prev_mode = false);
00042 
00043 protected:
00047   virtual void ClearChanges() = 0;
00048 
00053   static bool AreChangesPersistent() { return (gameloop || command) && !testmode; }
00054 
00055 private:
00056   static bool gameloop;
00057   static bool command;
00058   static bool testmode;
00059 };
00060 
00067 template <typename TYPE, uint SIZE>
00068 struct PersistentStorageArray : BasePersistentStorageArray {
00069   TYPE storage[SIZE]; 
00070   TYPE *prev_storage; 
00071 
00073   PersistentStorageArray() : prev_storage(NULL)
00074   {
00075     memset(this->storage, 0, sizeof(this->storage));
00076   }
00077 
00079   ~PersistentStorageArray()
00080   {
00081     free(this->prev_storage);
00082   }
00083 
00085   void ResetToZero()
00086   {
00087     memset(this->storage, 0, sizeof(this->storage));
00088   }
00089 
00097   void StoreValue(uint pos, int32 value)
00098   {
00099     /* Out of the scope of the array */
00100     if (pos >= SIZE) return;
00101 
00102     /* The value hasn't changed, so we pretend nothing happened.
00103      * Saves a few cycles and such and it's pretty easy to check. */
00104     if (this->storage[pos] == value) return;
00105 
00106     /* We do not have made a backup; lets do so */
00107     if (AreChangesPersistent()) {
00108       assert(this->prev_storage == NULL);
00109     } else if (this->prev_storage == NULL) {
00110       this->prev_storage = MallocT<TYPE>(SIZE);
00111       memcpy(this->prev_storage, this->storage, sizeof(this->storage));
00112 
00113       /* We only need to register ourselves when we made the backup
00114        * as that is the only time something will have changed */
00115       AddChangedPersistentStorage(this);
00116     }
00117 
00118     this->storage[pos] = value;
00119   }
00120 
00126   TYPE GetValue(uint pos) const
00127   {
00128     /* Out of the scope of the array */
00129     if (pos >= SIZE) return 0;
00130 
00131     return this->storage[pos];
00132   }
00133 
00134   void ClearChanges()
00135   {
00136     if (this->prev_storage != NULL) {
00137       memcpy(this->storage, this->prev_storage, sizeof(this->storage));
00138       free(this->prev_storage);
00139       this->prev_storage = NULL;
00140     }
00141   }
00142 };
00143 
00144 
00151 template <typename TYPE, uint SIZE>
00152 struct TemporaryStorageArray {
00153   TYPE storage[SIZE]; 
00154   uint16 init[SIZE];  
00155   uint16 init_key;    
00156 
00158   TemporaryStorageArray()
00159   {
00160     memset(this->storage, 0, sizeof(this->storage)); // not exactly needed, but makes code analysers happy
00161     memset(this->init, 0, sizeof(this->init));
00162     this->init_key = 1;
00163   }
00164 
00170   void StoreValue(uint pos, int32 value)
00171   {
00172     /* Out of the scope of the array */
00173     if (pos >= SIZE) return;
00174 
00175     this->storage[pos] = value;
00176     this->init[pos] = this->init_key;
00177   }
00178 
00184   TYPE GetValue(uint pos) const
00185   {
00186     /* Out of the scope of the array */
00187     if (pos >= SIZE) return 0;
00188 
00189     if (this->init[pos] != this->init_key) {
00190       /* Unassigned since last call to ClearChanges */
00191       return 0;
00192     }
00193 
00194     return this->storage[pos];
00195   }
00196 
00197   void ClearChanges()
00198   {
00199     /* Increment init_key to invalidate all storage */
00200     this->init_key++;
00201     if (this->init_key == 0) {
00202       /* When init_key wraps around, we need to reset everything */
00203       memset(this->init, 0, sizeof(this->init));
00204       this->init_key = 1;
00205     }
00206   }
00207 };
00208 
00209 void AddChangedPersistentStorage(BasePersistentStorageArray *storage);
00210 
00211 typedef PersistentStorageArray<int32, 16> OldPersistentStorage;
00212 
00213 typedef uint32 PersistentStorageID;
00214 
00215 struct PersistentStorage;
00216 typedef Pool<PersistentStorage, PersistentStorageID, 1, 0xFF000> PersistentStoragePool;
00217 
00218 extern PersistentStoragePool _persistent_storage_pool;
00219 
00223 struct PersistentStorage : PersistentStorageArray<int32, 16>, PersistentStoragePool::PoolItem<&_persistent_storage_pool> {
00225   PersistentStorage(const uint32 new_grfid, byte feature, TileIndex tile)
00226   {
00227     this->grfid = new_grfid;
00228     this->feature = feature;
00229     this->tile = tile;
00230   }
00231 };
00232 
00233 assert_compile(cpp_lengthof(OldPersistentStorage, storage) == cpp_lengthof(PersistentStorage, storage));
00234 
00235 #define FOR_ALL_STORAGES_FROM(var, start) FOR_ALL_ITEMS_FROM(PersistentStorage, storage_index, var, start)
00236 #define FOR_ALL_STORAGES(var) FOR_ALL_STORAGES_FROM(var, 0)
00237 
00238 #endif /* NEWGRF_STORAGE_H */