KUDr@3900: /* $Id$ */ KUDr@3900: #ifndef YAPF_COSTCACHE_HPP KUDr@3900: #define YAPF_COSTCACHE_HPP KUDr@3900: KUDr@3900: KUDr@3900: /** CYapfSegmentCostCacheNoneT - the formal only yapf cost cache provider that implements rubidium@4549: * PfNodeCacheFetch() and PfNodeCacheFlush() callbacks. Used when nodes don't have CachedData rubidium@4549: * defined (they don't count with any segment cost caching). rubidium@4549: */ KUDr@3900: template KUDr@3900: class CYapfSegmentCostCacheNoneT KUDr@3900: { KUDr@3900: public: KUDr@3914: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) KUDr@3900: typedef typename Types::NodeList::Titem Node; ///< this will be our node type KUDr@3900: KUDr@3914: /** Called by YAPF to attach cached or local segment cost data to the given node. rubidium@4549: * @return true if globally cached data were used or false if local data was used */ KUDr@3900: FORCEINLINE bool PfNodeCacheFetch(Node& n) KUDr@3900: { KUDr@3900: return false; KUDr@3900: }; KUDr@3900: KUDr@3914: /** Called by YAPF to flush the cached segment cost data back into cache storage. rubidium@4549: * Current cache implementation doesn't use that. */ KUDr@3900: FORCEINLINE void PfNodeCacheFlush(Node& n) KUDr@3900: { KUDr@3900: }; KUDr@3900: }; KUDr@3900: KUDr@3900: KUDr@3900: /** CYapfSegmentCostCacheLocalT - the yapf cost cache provider that implements fake segment rubidium@4549: * cost caching functionality for yapf. Used when node needs caching, but you don't want to rubidium@4549: * cache the segment costs. rubidium@4549: */ KUDr@3900: template KUDr@3900: class CYapfSegmentCostCacheLocalT KUDr@3900: { KUDr@3900: public: KUDr@3914: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) KUDr@3900: typedef typename Types::NodeList::Titem Node; ///< this will be our node type KUDr@3914: typedef typename Node::Key Key; ///< key to hash tables KUDr@3900: typedef typename Node::CachedData CachedData; KUDr@3900: typedef typename CachedData::Key CacheKey; KUDr@3900: typedef CArrayT LocalCache; KUDr@3900: KUDr@3900: protected: KUDr@3900: LocalCache m_local_cache; KUDr@3900: KUDr@3914: /// to access inherited path finder KUDr@3900: FORCEINLINE Tpf& Yapf() {return *static_cast(this);} KUDr@3900: KUDr@3900: public: KUDr@3914: /** Called by YAPF to attach cached or local segment cost data to the given node. rubidium@4549: * @return true if globally cached data were used or false if local data was used */ KUDr@3900: FORCEINLINE bool PfNodeCacheFetch(Node& n) KUDr@3900: { KUDr@3900: CacheKey key(n.GetKey()); KUDr@3900: Yapf().ConnectNodeToCachedData(n, *new (&m_local_cache.AddNC()) CachedData(key)); KUDr@3900: return false; KUDr@3900: }; KUDr@3900: KUDr@3914: /** Called by YAPF to flush the cached segment cost data back into cache storage. rubidium@4549: * Current cache implementation doesn't use that. */ KUDr@3900: FORCEINLINE void PfNodeCacheFlush(Node& n) KUDr@3900: { KUDr@3900: }; KUDr@3900: }; KUDr@3900: KUDr@3900: KUDr@3914: /** Base class for segment cost cache providers. Contains global counter rubidium@4549: * of track layout changes and static notification function called whenever rubidium@4549: * the track layout changes. It is implemented as base class because it needs rubidium@4549: * to be shared between all rail YAPF types (one shared counter, one notification rubidium@4549: * function. */ KUDr@3900: struct CSegmentCostCacheBase KUDr@3900: { KUDr@3900: static int s_rail_change_counter; KUDr@3900: KUDr@3900: static void NotifyTrackLayoutChange(TileIndex tile, Track track) {s_rail_change_counter++;} KUDr@3900: }; KUDr@3900: KUDr@3900: KUDr@3900: /** CSegmentCostCacheT - template class providing hash-map and storage (heap) rubidium@4549: * of Tsegment structures. Each rail node contains pointer to the segment rubidium@4549: * that contains cached (or non-cached) segment cost information. Nodes can rubidium@4549: * differ by key type, but they use the same segment type. Segment key should rubidium@4549: * be always the same (TileIndex + DiagDirection) that represent the beginning rubidium@4549: * of the segment (origin tile and exit-dir from this tile). rubidium@4549: * Different CYapfCachedCostT types can share the same type of CSegmentCostCacheT. rubidium@4549: * Look at CYapfRailSegment (yapf_node_rail.hpp) for the segment example */ KUDr@3900: template KUDr@3900: struct CSegmentCostCacheT KUDr@3900: : public CSegmentCostCacheBase KUDr@3900: { KUDr@3900: enum {c_hash_bits = 14}; KUDr@3900: KUDr@3900: typedef CHashTableT HashTable; KUDr@3900: typedef CArrayT Heap; KUDr@3900: typedef typename Tsegment::Key Key; ///< key to hash table KUDr@3900: KUDr@3900: HashTable m_map; KUDr@3900: Heap m_heap; KUDr@3900: KUDr@3900: FORCEINLINE CSegmentCostCacheT() {} KUDr@3900: KUDr@5129: /** flush (clear) the cache */ KUDr@5129: FORCEINLINE void Flush() {m_map.Clear(); m_heap.Clear();}; KUDr@5129: KUDr@3900: FORCEINLINE Tsegment& Get(Key& key, bool *found) KUDr@3900: { KUDr@5083: Tsegment* item = m_map.Find(key); KUDr@3900: if (item == NULL) { KUDr@3900: *found = false; KUDr@3900: item = new (&m_heap.AddNC()) Tsegment(key); KUDr@3900: m_map.Push(*item); KUDr@3900: } else { KUDr@3900: *found = true; KUDr@3900: } KUDr@3900: return *item; KUDr@3900: } KUDr@3900: }; KUDr@3900: KUDr@3900: /** CYapfSegmentCostCacheGlobalT - the yapf cost cache provider that adds the segment cost rubidium@4549: * caching functionality to yapf. Using this class as base of your will provide the global rubidium@4549: * segment cost caching services for your Nodes. KUDr@3900: */ KUDr@3900: template KUDr@3900: class CYapfSegmentCostCacheGlobalT KUDr@3900: : public CYapfSegmentCostCacheLocalT KUDr@3900: { KUDr@3900: public: KUDr@3900: typedef CYapfSegmentCostCacheLocalT Tlocal; KUDr@3914: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) KUDr@3900: typedef typename Types::NodeList::Titem Node; ///< this will be our node type KUDr@3900: typedef typename Node::Key Key; ///< key to hash tables KUDr@3900: typedef typename Node::CachedData CachedData; KUDr@3900: typedef typename CachedData::Key CacheKey; KUDr@3900: typedef CSegmentCostCacheT Cache; KUDr@3900: KUDr@3900: protected: KUDr@3900: Cache& m_global_cache; KUDr@3900: KUDr@3900: FORCEINLINE CYapfSegmentCostCacheGlobalT() : m_global_cache(stGetGlobalCache()) {}; KUDr@3900: KUDr@3914: /// to access inherited path finder KUDr@3900: FORCEINLINE Tpf& Yapf() {return *static_cast(this);} KUDr@3900: KUDr@3900: FORCEINLINE static Cache& stGetGlobalCache() KUDr@3900: { KUDr@3900: static int last_rail_change_counter = 0; rubidium@4297: static Date last_date = 0; KUDr@5129: static Cache C; KUDr@3900: KUDr@3900: // some statistics rubidium@4297: if (last_date != _date) { rubidium@4297: last_date = _date; Darkvater@5015: DEBUG(yapf, 1) ("pf time today:%5d ms", _total_pf_time_us / 1000); KUDr@3900: _total_pf_time_us = 0; KUDr@3900: } KUDr@3900: KUDr@3900: // delete the cache sometimes... KUDr@5129: if (last_rail_change_counter != Cache::s_rail_change_counter) { KUDr@3900: last_rail_change_counter = Cache::s_rail_change_counter; KUDr@5129: C.Flush(); KUDr@3900: } KUDr@5129: return C; KUDr@3900: } KUDr@3900: KUDr@3900: public: KUDr@3914: /** Called by YAPF to attach cached or local segment cost data to the given node. rubidium@4549: * @return true if globally cached data were used or false if local data was used */ KUDr@3900: FORCEINLINE bool PfNodeCacheFetch(Node& n) KUDr@3900: { KUDr@3900: if (!Yapf().CanUseGlobalCache(n)) { KUDr@3900: return Tlocal::PfNodeCacheFetch(n); KUDr@3900: } KUDr@3900: CacheKey key(n.GetKey()); KUDr@3900: bool found; KUDr@3900: CachedData& item = m_global_cache.Get(key, &found); KUDr@3900: Yapf().ConnectNodeToCachedData(n, item); KUDr@3900: return found; KUDr@3900: }; KUDr@3900: KUDr@3914: /** Called by YAPF to flush the cached segment cost data back into cache storage. rubidium@4549: * Current cache implementation doesn't use that. */ KUDr@3900: FORCEINLINE void PfNodeCacheFlush(Node& n) KUDr@3900: { KUDr@3900: }; KUDr@3900: KUDr@3900: }; KUDr@3900: KUDr@3900: KUDr@3900: KUDr@3900: KUDr@3900: #endif /* YAPF_COSTCACHE_HPP */