mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-11-17 21:25:40 +00:00
184 lines
4.8 KiB
C++
184 lines
4.8 KiB
C++
|
/* $Id$ */
|
||
|
#ifndef YAPF_COSTCACHE_HPP
|
||
|
#define YAPF_COSTCACHE_HPP
|
||
|
|
||
|
|
||
|
/** CYapfSegmentCostCacheNoneT - the formal only yapf cost cache provider that implements
|
||
|
PfNodeCacheFetch() and PfNodeCacheFlush() callbacks. Used when nodes don't have CachedData
|
||
|
defined (they don't count with any segment cost caching).
|
||
|
*/
|
||
|
template <class Types>
|
||
|
class CYapfSegmentCostCacheNoneT
|
||
|
{
|
||
|
public:
|
||
|
typedef typename Types::Tpf Tpf;
|
||
|
typedef typename Types::NodeList::Titem Node; ///< this will be our node type
|
||
|
|
||
|
FORCEINLINE bool PfNodeCacheFetch(Node& n)
|
||
|
{
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
FORCEINLINE void PfNodeCacheFlush(Node& n)
|
||
|
{
|
||
|
};
|
||
|
};
|
||
|
|
||
|
|
||
|
/** CYapfSegmentCostCacheLocalT - the yapf cost cache provider that implements fake segment
|
||
|
cost caching functionality for yapf. Used when node needs caching, but you don't want to
|
||
|
cache the segment costs.
|
||
|
*/
|
||
|
template <class Types>
|
||
|
class CYapfSegmentCostCacheLocalT
|
||
|
{
|
||
|
public:
|
||
|
typedef typename Types::Tpf Tpf;
|
||
|
typedef typename Types::NodeList::Titem Node; ///< this will be our node type
|
||
|
typedef typename Node::Key Key; ///< key to hash tables
|
||
|
typedef typename Node::CachedData CachedData;
|
||
|
typedef typename CachedData::Key CacheKey;
|
||
|
typedef CArrayT<CachedData> LocalCache;
|
||
|
|
||
|
protected:
|
||
|
LocalCache m_local_cache;
|
||
|
|
||
|
FORCEINLINE Tpf& Yapf() {return *static_cast<Tpf*>(this);}
|
||
|
|
||
|
public:
|
||
|
FORCEINLINE bool PfNodeCacheFetch(Node& n)
|
||
|
{
|
||
|
CacheKey key(n.GetKey());
|
||
|
Yapf().ConnectNodeToCachedData(n, *new (&m_local_cache.AddNC()) CachedData(key));
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
FORCEINLINE void PfNodeCacheFlush(Node& n)
|
||
|
{
|
||
|
};
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
struct CSegmentCostCacheBase
|
||
|
{
|
||
|
static int s_rail_change_counter;
|
||
|
|
||
|
static void NotifyTrackLayoutChange(TileIndex tile, Track track) {s_rail_change_counter++;}
|
||
|
};
|
||
|
|
||
|
|
||
|
/** CSegmentCostCacheT - template class providing hash-map and storage (heap)
|
||
|
of Tsegment structures. Each rail node contains pointer to the segment
|
||
|
that contains cached (or non-cached) segment cost information. Nodes can
|
||
|
differ by key type, but they use the same segment type. Segment key should
|
||
|
be always the same (TileIndex + DiagDirection) that represent the beginning
|
||
|
of the segment (origin tile and exit-dir from this tile).
|
||
|
Different CYapfCachedCostT types can share the same type of CSegmentCostCacheT.
|
||
|
Look at CYapfRailSegment (yapf_node_rail.hpp) for the segment example */
|
||
|
|
||
|
template <class Tsegment>
|
||
|
struct CSegmentCostCacheT
|
||
|
: public CSegmentCostCacheBase
|
||
|
{
|
||
|
enum {c_hash_bits = 14};
|
||
|
|
||
|
typedef CHashTableT<Tsegment, c_hash_bits> HashTable;
|
||
|
typedef CArrayT<Tsegment> Heap;
|
||
|
typedef typename Tsegment::Key Key; ///< key to hash table
|
||
|
|
||
|
HashTable m_map;
|
||
|
Heap m_heap;
|
||
|
|
||
|
FORCEINLINE CSegmentCostCacheT() {}
|
||
|
|
||
|
FORCEINLINE Tsegment& Get(Key& key, bool *found)
|
||
|
{
|
||
|
Tsegment* item = &m_map.Find(key);
|
||
|
if (item == NULL) {
|
||
|
*found = false;
|
||
|
item = new (&m_heap.AddNC()) Tsegment(key);
|
||
|
m_map.Push(*item);
|
||
|
} else {
|
||
|
*found = true;
|
||
|
}
|
||
|
return *item;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/** CYapfSegmentCostCacheGlobalT - the yapf cost cache provider that adds the segment cost
|
||
|
caching functionality to yapf. Using this class as base of your will provide the global
|
||
|
segment cost caching services for your Nodes.
|
||
|
*/
|
||
|
template <class Types>
|
||
|
class CYapfSegmentCostCacheGlobalT
|
||
|
: public CYapfSegmentCostCacheLocalT<Types>
|
||
|
{
|
||
|
public:
|
||
|
typedef CYapfSegmentCostCacheLocalT<Types> Tlocal;
|
||
|
typedef typename Types::Tpf Tpf;
|
||
|
typedef typename Types::NodeList::Titem Node; ///< this will be our node type
|
||
|
typedef typename Node::Key Key; ///< key to hash tables
|
||
|
typedef typename Node::CachedData CachedData;
|
||
|
typedef typename CachedData::Key CacheKey;
|
||
|
typedef CSegmentCostCacheT<CachedData> Cache;
|
||
|
|
||
|
protected:
|
||
|
Cache& m_global_cache;
|
||
|
|
||
|
FORCEINLINE CYapfSegmentCostCacheGlobalT() : m_global_cache(stGetGlobalCache()) {};
|
||
|
|
||
|
FORCEINLINE Tpf& Yapf() {return *static_cast<Tpf*>(this);}
|
||
|
|
||
|
FORCEINLINE static Cache*& stGlobalCachePtr() {static Cache* pC = NULL; return pC;}
|
||
|
|
||
|
FORCEINLINE static Cache& stGetGlobalCache()
|
||
|
{
|
||
|
static int last_rail_change_counter = 0;
|
||
|
static uint32 last_day = 0;
|
||
|
|
||
|
// some statistics
|
||
|
if (last_day != _date) {
|
||
|
last_day = _date;
|
||
|
DEBUG(yapf, 1)("pf time today:%5d ms\n", _total_pf_time_us / 1000);
|
||
|
_total_pf_time_us = 0;
|
||
|
}
|
||
|
|
||
|
Cache*& pC = stGlobalCachePtr();
|
||
|
|
||
|
// delete the cache sometimes...
|
||
|
if (pC != NULL && last_rail_change_counter != Cache::s_rail_change_counter) {
|
||
|
last_rail_change_counter = Cache::s_rail_change_counter;
|
||
|
delete pC;
|
||
|
pC = NULL;
|
||
|
}
|
||
|
|
||
|
if (pC == NULL)
|
||
|
pC = new Cache();
|
||
|
return *pC;
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
FORCEINLINE bool PfNodeCacheFetch(Node& n)
|
||
|
{
|
||
|
if (!Yapf().CanUseGlobalCache(n)) {
|
||
|
return Tlocal::PfNodeCacheFetch(n);
|
||
|
}
|
||
|
CacheKey key(n.GetKey());
|
||
|
bool found;
|
||
|
CachedData& item = m_global_cache.Get(key, &found);
|
||
|
Yapf().ConnectNodeToCachedData(n, item);
|
||
|
return found;
|
||
|
};
|
||
|
|
||
|
FORCEINLINE void PfNodeCacheFlush(Node& n)
|
||
|
{
|
||
|
};
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#endif /* YAPF_COSTCACHE_HPP */
|