]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/trackiter.cpp
Use path coercion in track iterators
[r2c2.git] / source / libr2c2 / trackiter.cpp
1 #include <algorithm>
2 #include "blockiter.h"
3 #include "track.h"
4 #include "trackiter.h"
5 #include "tracktype.h"
6
7 using namespace std;
8 using namespace Msp;
9
10 namespace R2C2 {
11
12 TrackIter::TrackIter():
13         _track(0),
14         _entry(0)
15 { }
16
17 TrackIter::TrackIter(Track *t, unsigned e):
18         _track(t),
19         _entry(t ? e : 0)
20 {
21         if(_track && _entry>_track->get_type().get_endpoints().size())
22                 throw out_of_range("TrackIter::TrackIter");
23 }
24
25 BlockIter TrackIter::block_iter() const
26 {
27         if(!_track)
28                 return BlockIter();
29
30         Block &block = _track->get_block();
31         const vector<Block::Endpoint> &beps = block.get_endpoints();
32
33         // See if this track matches an endpoint in the block
34         for(unsigned i=0; i<beps.size(); ++i)
35                 if(beps[i].track==_track && beps[i].track_ep==_entry)
36                         return BlockIter(&block, i);
37
38         if(!_track->get_type().is_turnout())
39         {
40                 /* Since there was no endpoint match, the preceding track can't be in a
41                 different block. */
42                 TrackIter rev = flip();
43                 TrackIter last;
44                 while(rev && &rev.track()->get_block()==&block)
45                 {
46                         last = rev;
47                         rev = rev.next();
48                 }
49
50                 // If we ran out of tracks, return an empty iterator
51                 if(!rev)
52                         return BlockIter();
53
54                 TrackIter fwd = last.reverse();
55                 for(unsigned i=0; i<beps.size(); ++i)
56                         if(beps[i].track==fwd.track() && beps[i].track_ep==fwd.entry())
57                                 return BlockIter(&block, i);
58         }
59
60         throw logic_error("internal error (didn't find block entry endpoint)");
61 }
62
63 const TrackType::Endpoint &TrackIter::endpoint() const
64 {
65         if(!_track)
66                 throw logic_error("null track");
67
68         return _track->get_type().get_endpoint(_entry);
69 }
70
71 int TrackIter::get_exit(unsigned path) const
72 {
73         path = _track->get_type().coerce_path(_entry, path);
74         const vector<TrackType::Endpoint> &eps = _track->get_type().get_endpoints();
75         
76         // Find an endpoint that's connected to the entry and has the requested path
77         for(unsigned i=0; i<eps.size(); ++i)
78                 if(i!=_entry && eps[i].has_path(path) && eps[i].has_common_paths(eps[_entry]))
79                         return i;
80
81         return -1;
82 }
83
84 TrackIter TrackIter::next() const
85 {
86         if(!_track)
87                 return TrackIter();
88
89         return next(_track->get_active_path());
90 }
91
92 TrackIter TrackIter::next(unsigned path) const
93 {
94         if(!_track)
95                 return TrackIter();
96
97         int exit = get_exit(path);
98         if(exit<0)
99                 return TrackIter();
100
101         TrackIter result;
102         result._track = _track->get_link(exit);
103         result._entry = (result._track ? result._track->get_link_slot(*_track) : 0);
104
105         return result;
106 }
107
108 TrackIter TrackIter::reverse() const
109 {
110         if(!_track)
111                 return TrackIter();
112
113         return reverse(_track->get_active_path());
114 }
115
116 TrackIter TrackIter::reverse(unsigned path) const
117 {
118         if(!_track)
119                 return TrackIter();
120
121         int exit = get_exit(path);
122         if(exit<0)
123                 return TrackIter();
124
125         return TrackIter(_track, exit);
126 }
127
128 TrackIter TrackIter::flip() const
129 {
130         if(!_track)
131                 return TrackIter();
132
133         TrackIter result;
134         result._track = _track->get_link(_entry);
135         result._entry = (result._track ? result._track->get_link_slot(*_track) : 0);
136
137         return result;
138 }
139
140 Track &TrackIter::operator*() const
141 {
142         if(!_track)
143                 throw logic_error("null track");
144
145         return *_track;
146 }
147
148 bool TrackIter::operator==(const TrackIter &other) const
149 {
150         return _track==other._track && _entry==other._entry;
151 }
152
153
154 TrackLoopIter::TrackLoopIter():
155         _looped(false)
156 { }
157
158 TrackLoopIter::TrackLoopIter(Track *t, unsigned e):
159         TrackIter(t, e),
160         _visited(new TrackList()),
161         _last(_visited->insert(_visited->end(), track())),
162         _looped(false)
163 { }
164
165 TrackLoopIter::TrackLoopIter(const TrackIter &i):
166         TrackIter(i),
167         _visited(new TrackList()),
168         _last(_visited->insert(_visited->end(), track())),
169         _looped(false)
170 { }
171
172 TrackLoopIter::TrackLoopIter(const TrackIter &i, RefPtr<TrackList> v, const TrackList::iterator &l):
173         TrackIter(i),
174         _looped(false)
175 {
176         if(track())
177         {
178                 _visited = v;
179                 _last = l;
180                 _looped = (_visited && find(_visited->begin(), _last, track())!=_last);
181
182                 ++_last;
183                 if(_last!=_visited->end())
184                 {
185                         _visited = new TrackList(_visited->begin(), _last);
186                         _last = _visited->end();
187                 }
188                 _visited->push_back(track());
189                 --_last;
190         }
191 }
192
193 TrackLoopIter TrackLoopIter::next() const
194 {
195         return TrackLoopIter(TrackIter::next(), _visited, _last);
196 }
197
198 TrackLoopIter TrackLoopIter::next(unsigned path) const
199 {
200         return TrackLoopIter(TrackIter::next(path), _visited, _last);
201 }
202
203 } // namespace R2C2