# yapf_node_rail.hpp

Go to the documentation of this file.

    00001 /* $Id$ */
    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  YAPF_NODE_RAIL_HPP
    00013 #define  YAPF_NODE_RAIL_HPP
    00014
    00016 struct CYapfRailSegmentKey
    00017 {
    00018   uint32    m_value;
    00019
    00020   FORCEINLINE CYapfRailSegmentKey(const CYapfRailSegmentKey& src) : m_value(src.m_value) {}
    00021
    00022   FORCEINLINE CYapfRailSegmentKey(const CYapfNodeKeyTrackDir& node_key)
    00023   {
    00024     Set(node_key);
    00025   }
    00026
    00027   FORCEINLINE void Set(const CYapfRailSegmentKey& src)
    00028   {
    00029     m_value = src.m_value;
    00030   }
    00031
    00032   FORCEINLINE void Set(const CYapfNodeKeyTrackDir& node_key)
    00033   {
    00034     m_value = (((int)node_key.m_tile) << 4) | node_key.m_td;
    00035   }
    00036
    00037   FORCEINLINE int32 CalcHash() const
    00038   {
    00039     return m_value;
    00040   }
    00041
    00042   FORCEINLINE TileIndex GetTile() const
    00043   {
    00044     return (TileIndex)(m_value >> 4);
    00045   }
    00046
    00047   FORCEINLINE Trackdir GetTrackdir() const
    00048   {
    00049     return (Trackdir)(m_value & 0x0F);
    00050   }
    00051
    00052   FORCEINLINE bool operator == (const CYapfRailSegmentKey& other) const
    00053   {
    00054     return m_value == other.m_value;
    00055   }
    00056
    00057   void Dump(DumpTarget &dmp) const
    00058   {
    00059     dmp.WriteTile("tile", GetTile());
    00060     dmp.WriteEnumT("td", GetTrackdir());
    00061   }
    00062 };
    00063
    00064 /* Enum used in PfCalcCost() to see why was the segment closed. */
    00065 enum EndSegmentReason {
    00066   /* The following reasons can be saved into cached segment */
    00067   ESR_DEAD_END = 0,
    00068   ESR_RAIL_TYPE,
    00069   ESR_INFINITE_LOOP,
    00070   ESR_SEGMENT_TOO_LONG,
    00071   ESR_CHOICE_FOLLOWS,
    00072   ESR_DEPOT,
    00073   ESR_WAYPOINT,
    00074   ESR_STATION,
    00075   ESR_SAFE_TILE,
    00076
    00077   /* The following reasons are used only internally by PfCalcCost().
    00078    *  They should not be found in the cached segment. */
    00079   ESR_PATH_TOO_LONG,
    00080   ESR_FIRST_TWO_WAY_RED,
    00081   ESR_LOOK_AHEAD_END,
    00082   ESR_TARGET_REACHED,
    00083
    00084   /* Special values */
    00085   ESR_NONE = 0xFF,
    00086 };
    00087
    00088 enum EndSegmentReasonBits {
    00089   ESRB_NONE = 0,
    00090
    00091   ESRB_DEAD_END          = 1 << ESR_DEAD_END,
    00092   ESRB_RAIL_TYPE         = 1 << ESR_RAIL_TYPE,
    00093   ESRB_INFINITE_LOOP     = 1 << ESR_INFINITE_LOOP,
    00094   ESRB_SEGMENT_TOO_LONG  = 1 << ESR_SEGMENT_TOO_LONG,
    00095   ESRB_CHOICE_FOLLOWS    = 1 << ESR_CHOICE_FOLLOWS,
    00096   ESRB_DEPOT             = 1 << ESR_DEPOT,
    00097   ESRB_WAYPOINT          = 1 << ESR_WAYPOINT,
    00098   ESRB_STATION           = 1 << ESR_STATION,
    00099   ESRB_SAFE_TILE         = 1 << ESR_SAFE_TILE,
    00100
    00101   ESRB_PATH_TOO_LONG     = 1 << ESR_PATH_TOO_LONG,
    00102   ESRB_FIRST_TWO_WAY_RED = 1 << ESR_FIRST_TWO_WAY_RED,
    00103   ESRB_LOOK_AHEAD_END    = 1 << ESR_LOOK_AHEAD_END,
    00104   ESRB_TARGET_REACHED    = 1 << ESR_TARGET_REACHED,
    00105
    00106   /* Additional (composite) values. */
    00107
    00108   /* What reasons mean that the target can be found and needs to be detected. */
    00109   ESRB_POSSIBLE_TARGET = ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION | ESRB_SAFE_TILE,
    00110
    00111   /* What reasons can be stored back into cached segment. */
    00112   ESRB_CACHED_MASK = ESRB_DEAD_END | ESRB_RAIL_TYPE | ESRB_INFINITE_LOOP | ESRB_SEGMENT_TOO_LONG | ESRB_CHOICE_FOLLOWS | ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION | ESRB_SAFE_TILE,
    00113
    00114   /* Reasons to abort pathfinding in this direction. */
    00115   ESRB_ABORT_PF_MASK = ESRB_DEAD_END | ESRB_PATH_TOO_LONG | ESRB_INFINITE_LOOP | ESRB_FIRST_TWO_WAY_RED,
    00116 };
    00117
    00118 DECLARE_ENUM_AS_BIT_SET(EndSegmentReasonBits);
    00119
    00120 inline CStrA ValueStr(EndSegmentReasonBits bits)
    00121 {
    00122   static const char * const end_segment_reason_names[] = {
    00123     "DEAD_END", "RAIL_TYPE", "INFINITE_LOOP", "SEGMENT_TOO_LONG", "CHOICE_FOLLOWS",
    00124     "DEPOT", "WAYPOINT", "STATION", "SAFE_TILE",
    00125     "PATH_TOO_LONG", "FIRST_TWO_WAY_RED", "LOOK_AHEAD_END", "TARGET_REACHED"
    00126   };
    00127
    00128   CStrA out;
    00129   out.Format("0x%04X (%s)", bits, ComposeNameT(bits, end_segment_reason_names, "UNK", ESRB_NONE, "NONE").Data());
    00130   return out.Transfer();
    00131 }
    00132
    00134 struct CYapfRailSegment
    00135 {
    00136   typedef CYapfRailSegmentKey Key;
    00137
    00138   CYapfRailSegmentKey    m_key;
    00139   TileIndex              m_last_tile;
    00140   Trackdir               m_last_td;
    00141   int                    m_cost;
    00142   TileIndex              m_last_signal_tile;
    00143   Trackdir               m_last_signal_td;
    00144   EndSegmentReasonBits   m_end_segment_reason;
    00145   CYapfRailSegment      *m_hash_next;
    00146
    00147   FORCEINLINE CYapfRailSegment(const CYapfRailSegmentKey& key)
    00148     : m_key(key)
    00149     , m_last_tile(INVALID_TILE)
    00150     , m_last_td(INVALID_TRACKDIR)
    00151     , m_cost(-1)
    00152     , m_last_signal_tile(INVALID_TILE)
    00153     , m_last_signal_td(INVALID_TRACKDIR)
    00154     , m_end_segment_reason(ESRB_NONE)
    00155     , m_hash_next(NULL)
    00156   {}
    00157
    00158   FORCEINLINE const Key& GetKey() const
    00159   {
    00160     return m_key;
    00161   }
    00162
    00163   FORCEINLINE TileIndex GetTile() const
    00164   {
    00165     return m_key.GetTile();
    00166   }
    00167
    00168   FORCEINLINE CYapfRailSegment *GetHashNext()
    00169   {
    00170     return m_hash_next;
    00171   }
    00172
    00173   FORCEINLINE void SetHashNext(CYapfRailSegment *next)
    00174   {
    00175     m_hash_next = next;
    00176   }
    00177
    00178   void Dump(DumpTarget &dmp) const
    00179   {
    00180     dmp.WriteStructT("m_key", &m_key);
    00181     dmp.WriteTile("m_last_tile", m_last_tile);
    00182     dmp.WriteEnumT("m_last_td", m_last_td);
    00183     dmp.WriteLine("m_cost = %d", m_cost);
    00184     dmp.WriteTile("m_last_signal_tile", m_last_signal_tile);
    00185     dmp.WriteEnumT("m_last_signal_td", m_last_signal_td);
    00186     dmp.WriteEnumT("m_end_segment_reason", m_end_segment_reason);
    00187   }
    00188 };
    00189
    00191 template <class Tkey_>
    00192 struct CYapfRailNodeT
    00193   : CYapfNodeT<Tkey_, CYapfRailNodeT<Tkey_> >
    00194 {
    00195   typedef CYapfNodeT<Tkey_, CYapfRailNodeT<Tkey_> > base;
    00196   typedef CYapfRailSegment CachedData;
    00197
    00198   CYapfRailSegment *m_segment;
    00199   uint16            m_num_signals_passed;
    00200   union {
    00201     uint32          m_inherited_flags;
    00202     struct {
    00203       bool          m_targed_seen : 1;
    00204       bool          m_choice_seen : 1;
    00205       bool          m_last_signal_was_red : 1;
    00206     } flags_s;
    00207   } flags_u;
    00208   SignalType        m_last_red_signal_type;
    00209   SignalType        m_last_signal_type;
    00210
    00211   FORCEINLINE void Set(CYapfRailNodeT *parent, TileIndex tile, Trackdir td, bool is_choice)
    00212   {
    00213     base::Set(parent, tile, td, is_choice);
    00214     m_segment = NULL;
    00215     if (parent == NULL) {
    00216       m_num_signals_passed      = 0;
    00217       flags_u.m_inherited_flags = 0;
    00218       m_last_red_signal_type    = SIGTYPE_NORMAL;
    00219       /* We use PBS as initial signal type because if we are in
    00220        * a PBS section and need to route, i.e. we're at a safe
    00221        * waiting point of a station, we need to account for the
    00222        * reservation costs. If we are in a normal block then we
    00223        * should be alone in there and as such the reservation
    00224        * costs should be 0 anyway. If there would be another
    00225        * train in the block, i.e. passing signals at danger
    00226        * then avoiding that train with help of the reservation
    00227        * costs is not a bad thing, actually it would probably
    00228        * be a good thing to do. */
    00229       m_last_signal_type        = SIGTYPE_PBS;
    00230     } else {
    00231       m_num_signals_passed      = parent->m_num_signals_passed;
    00232       flags_u.m_inherited_flags = parent->flags_u.m_inherited_flags;
    00233       m_last_red_signal_type    = parent->m_last_red_signal_type;
    00234       m_last_signal_type        = parent->m_last_signal_type;
    00235     }
    00236     flags_u.flags_s.m_choice_seen |= is_choice;
    00237   }
    00238
    00239   FORCEINLINE TileIndex GetLastTile() const
    00240   {
    00241     assert(m_segment != NULL);
    00242     return m_segment->m_last_tile;
    00243   }
    00244
    00245   FORCEINLINE Trackdir GetLastTrackdir() const
    00246   {
    00247     assert(m_segment != NULL);
    00248     return m_segment->m_last_td;
    00249   }
    00250
    00251   FORCEINLINE void SetLastTileTrackdir(TileIndex tile, Trackdir td)
    00252   {
    00253     assert(m_segment != NULL);
    00254     m_segment->m_last_tile = tile;
    00255     m_segment->m_last_td = td;
    00256   }
    00257
    00258   template <class Tbase, class Tfunc, class Tpf>
    00259   bool IterateTiles(const Train *v, Tpf &yapf, Tbase &obj, bool (Tfunc::*func)(TileIndex, Trackdir)) const
    00260   {
    00261     typename Tbase::TrackFollower ft(v, yapf.GetCompatibleRailTypes());
    00262     TileIndex cur = base::GetTile();
    00263     Trackdir  cur_td = base::GetTrackdir();
    00264
    00265     while (cur != GetLastTile() || cur_td != GetLastTrackdir()) {
    00266       if (!((obj.*func)(cur, cur_td))) return false;
    00267
    00268       ft.Follow(cur, cur_td);
    00269       cur = ft.m_new_tile;
    00270       assert(KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE);
    00271       cur_td = FindFirstTrackdir(ft.m_new_td_bits);
    00272     }
    00273
    00274     return (obj.*func)(cur, cur_td);
    00275   }
    00276
    00277   void Dump(DumpTarget &dmp) const
    00278   {
    00279     base::Dump(dmp);
    00280     dmp.WriteStructT("m_segment", m_segment);
    00281     dmp.WriteLine("m_num_signals_passed = %d", m_num_signals_passed);
    00282     dmp.WriteLine("m_targed_seen = %s", flags_u.flags_s.m_targed_seen ? "Yes" : "No");
    00283     dmp.WriteLine("m_choice_seen = %s", flags_u.flags_s.m_choice_seen ? "Yes" : "No");
    00284     dmp.WriteLine("m_last_signal_was_red = %s", flags_u.flags_s.m_last_signal_was_red ? "Yes" : "No");
    00285     dmp.WriteEnumT("m_last_red_signal_type", m_last_red_signal_type);
    00286   }
    00287 };
    00288
    00289 /* now define two major node types (that differ by key type) */
    00290 typedef CYapfRailNodeT<CYapfNodeKeyExitDir>  CYapfRailNodeExitDir;
    00291 typedef CYapfRailNodeT<CYapfNodeKeyTrackDir> CYapfRailNodeTrackDir;
    00292
    00293 /* Default NodeList types */
    00294 typedef CNodeList_HashTableT<CYapfRailNodeExitDir , 10, 12> CRailNodeListExitDir;
    00295 typedef CNodeList_HashTableT<CYapfRailNodeTrackDir, 12, 16> CRailNodeListTrackDir;
    00296
    00297 #endif /* YAPF_NODE_RAIL_HPP */