|
1 /* $Id$ */ |
|
2 #ifndef YAPF_COSTCACHE_HPP |
|
3 #define YAPF_COSTCACHE_HPP |
|
4 |
|
5 |
|
6 /** CYapfSegmentCostCacheNoneT - the formal only yapf cost cache provider that implements |
|
7 PfNodeCacheFetch() and PfNodeCacheFlush() callbacks. Used when nodes don't have CachedData |
|
8 defined (they don't count with any segment cost caching). |
|
9 */ |
|
10 template <class Types> |
|
11 class CYapfSegmentCostCacheNoneT |
|
12 { |
|
13 public: |
|
14 typedef typename Types::Tpf Tpf; |
|
15 typedef typename Types::NodeList::Titem Node; ///< this will be our node type |
|
16 |
|
17 FORCEINLINE bool PfNodeCacheFetch(Node& n) |
|
18 { |
|
19 return false; |
|
20 }; |
|
21 |
|
22 FORCEINLINE void PfNodeCacheFlush(Node& n) |
|
23 { |
|
24 }; |
|
25 }; |
|
26 |
|
27 |
|
28 /** CYapfSegmentCostCacheLocalT - the yapf cost cache provider that implements fake segment |
|
29 cost caching functionality for yapf. Used when node needs caching, but you don't want to |
|
30 cache the segment costs. |
|
31 */ |
|
32 template <class Types> |
|
33 class CYapfSegmentCostCacheLocalT |
|
34 { |
|
35 public: |
|
36 typedef typename Types::Tpf Tpf; |
|
37 typedef typename Types::NodeList::Titem Node; ///< this will be our node type |
|
38 typedef typename Node::Key Key; ///< key to hash tables |
|
39 typedef typename Node::CachedData CachedData; |
|
40 typedef typename CachedData::Key CacheKey; |
|
41 typedef CArrayT<CachedData> LocalCache; |
|
42 |
|
43 protected: |
|
44 LocalCache m_local_cache; |
|
45 |
|
46 FORCEINLINE Tpf& Yapf() {return *static_cast<Tpf*>(this);} |
|
47 |
|
48 public: |
|
49 FORCEINLINE bool PfNodeCacheFetch(Node& n) |
|
50 { |
|
51 CacheKey key(n.GetKey()); |
|
52 Yapf().ConnectNodeToCachedData(n, *new (&m_local_cache.AddNC()) CachedData(key)); |
|
53 return false; |
|
54 }; |
|
55 |
|
56 FORCEINLINE void PfNodeCacheFlush(Node& n) |
|
57 { |
|
58 }; |
|
59 }; |
|
60 |
|
61 |
|
62 |
|
63 struct CSegmentCostCacheBase |
|
64 { |
|
65 static int s_rail_change_counter; |
|
66 |
|
67 static void NotifyTrackLayoutChange(TileIndex tile, Track track) {s_rail_change_counter++;} |
|
68 }; |
|
69 |
|
70 |
|
71 /** CSegmentCostCacheT - template class providing hash-map and storage (heap) |
|
72 of Tsegment structures. Each rail node contains pointer to the segment |
|
73 that contains cached (or non-cached) segment cost information. Nodes can |
|
74 differ by key type, but they use the same segment type. Segment key should |
|
75 be always the same (TileIndex + DiagDirection) that represent the beginning |
|
76 of the segment (origin tile and exit-dir from this tile). |
|
77 Different CYapfCachedCostT types can share the same type of CSegmentCostCacheT. |
|
78 Look at CYapfRailSegment (yapf_node_rail.hpp) for the segment example */ |
|
79 |
|
80 template <class Tsegment> |
|
81 struct CSegmentCostCacheT |
|
82 : public CSegmentCostCacheBase |
|
83 { |
|
84 enum {c_hash_bits = 14}; |
|
85 |
|
86 typedef CHashTableT<Tsegment, c_hash_bits> HashTable; |
|
87 typedef CArrayT<Tsegment> Heap; |
|
88 typedef typename Tsegment::Key Key; ///< key to hash table |
|
89 |
|
90 HashTable m_map; |
|
91 Heap m_heap; |
|
92 |
|
93 FORCEINLINE CSegmentCostCacheT() {} |
|
94 |
|
95 FORCEINLINE Tsegment& Get(Key& key, bool *found) |
|
96 { |
|
97 Tsegment* item = &m_map.Find(key); |
|
98 if (item == NULL) { |
|
99 *found = false; |
|
100 item = new (&m_heap.AddNC()) Tsegment(key); |
|
101 m_map.Push(*item); |
|
102 } else { |
|
103 *found = true; |
|
104 } |
|
105 return *item; |
|
106 } |
|
107 }; |
|
108 |
|
109 /** CYapfSegmentCostCacheGlobalT - the yapf cost cache provider that adds the segment cost |
|
110 caching functionality to yapf. Using this class as base of your will provide the global |
|
111 segment cost caching services for your Nodes. |
|
112 */ |
|
113 template <class Types> |
|
114 class CYapfSegmentCostCacheGlobalT |
|
115 : public CYapfSegmentCostCacheLocalT<Types> |
|
116 { |
|
117 public: |
|
118 typedef CYapfSegmentCostCacheLocalT<Types> Tlocal; |
|
119 typedef typename Types::Tpf Tpf; |
|
120 typedef typename Types::NodeList::Titem Node; ///< this will be our node type |
|
121 typedef typename Node::Key Key; ///< key to hash tables |
|
122 typedef typename Node::CachedData CachedData; |
|
123 typedef typename CachedData::Key CacheKey; |
|
124 typedef CSegmentCostCacheT<CachedData> Cache; |
|
125 |
|
126 protected: |
|
127 Cache& m_global_cache; |
|
128 |
|
129 FORCEINLINE CYapfSegmentCostCacheGlobalT() : m_global_cache(stGetGlobalCache()) {}; |
|
130 |
|
131 FORCEINLINE Tpf& Yapf() {return *static_cast<Tpf*>(this);} |
|
132 |
|
133 FORCEINLINE static Cache*& stGlobalCachePtr() {static Cache* pC = NULL; return pC;} |
|
134 |
|
135 FORCEINLINE static Cache& stGetGlobalCache() |
|
136 { |
|
137 static int last_rail_change_counter = 0; |
|
138 static uint32 last_day = 0; |
|
139 |
|
140 // some statistics |
|
141 if (last_day != _date) { |
|
142 last_day = _date; |
|
143 DEBUG(yapf, 1)("pf time today:%5d ms\n", _total_pf_time_us / 1000); |
|
144 _total_pf_time_us = 0; |
|
145 } |
|
146 |
|
147 Cache*& pC = stGlobalCachePtr(); |
|
148 |
|
149 // delete the cache sometimes... |
|
150 if (pC != NULL && last_rail_change_counter != Cache::s_rail_change_counter) { |
|
151 last_rail_change_counter = Cache::s_rail_change_counter; |
|
152 delete pC; |
|
153 pC = NULL; |
|
154 } |
|
155 |
|
156 if (pC == NULL) |
|
157 pC = new Cache(); |
|
158 return *pC; |
|
159 } |
|
160 |
|
161 public: |
|
162 FORCEINLINE bool PfNodeCacheFetch(Node& n) |
|
163 { |
|
164 if (!Yapf().CanUseGlobalCache(n)) { |
|
165 return Tlocal::PfNodeCacheFetch(n); |
|
166 } |
|
167 CacheKey key(n.GetKey()); |
|
168 bool found; |
|
169 CachedData& item = m_global_cache.Get(key, &found); |
|
170 Yapf().ConnectNodeToCachedData(n, item); |
|
171 return found; |
|
172 }; |
|
173 |
|
174 FORCEINLINE void PfNodeCacheFlush(Node& n) |
|
175 { |
|
176 }; |
|
177 |
|
178 }; |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 #endif /* YAPF_COSTCACHE_HPP */ |