]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/trackiter.cpp
Fix a problem with TrackIter::block_iter at end of line
[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                 TrackIter rev = reverse();
41                 TrackIter last;
42                 while(rev && &rev.track()->get_block()==&block)
43                 {
44                         last = rev;
45                         rev = rev.next();
46                 }
47
48                 // If we ran out of tracks, return an empty iterator
49                 if(!rev)
50                         return BlockIter();
51
52                 TrackIter fwd = last.reverse();
53                 for(unsigned i=0; i<beps.size(); ++i)
54                         if(beps[i].track==fwd.track() && beps[i].track_ep==fwd.entry())
55                                 return BlockIter(&block, i);
56         }
57
58         throw logic_error("internal error (didn't find block entry endpoint)");
59 }
60
61 const TrackType::Endpoint &TrackIter::endpoint() const
62 {
63         if(!_track)
64                 throw logic_error("null track");
65
66         return _track->get_type().get_endpoint(_entry);
67 }
68
69 int TrackIter::get_exit(unsigned path) const
70 {
71         const vector<TrackType::Endpoint> &eps = _track->get_type().get_endpoints();
72         
73         // Find an endpoint that's connected to the entry and has the requested path
74         for(unsigned i=0; i<eps.size(); ++i)
75                 if(i!=_entry && eps[i].has_path(path) && eps[i].has_common_paths(eps[_entry]))
76                         return i;
77
78         return -1;
79 }
80
81 TrackIter TrackIter::next() const
82 {
83         if(!_track)
84                 return TrackIter();
85
86         return next(_track->get_active_path());
87 }
88
89 TrackIter TrackIter::next(unsigned path) const
90 {
91         if(!_track)
92                 return TrackIter();
93
94         int exit = get_exit(path);
95         if(exit<0)
96                 return TrackIter();
97
98         TrackIter result;
99         result._track = _track->get_link(exit);
100         result._entry = (result._track ? result._track->get_link_slot(*_track) : 0);
101
102         return result;
103 }
104
105 TrackIter TrackIter::reverse() const
106 {
107         if(!_track)
108                 return TrackIter();
109
110         return reverse(_track->get_active_path());
111 }
112
113 TrackIter TrackIter::reverse(unsigned path) const
114 {
115         if(!_track)
116                 return TrackIter();
117
118         int exit = get_exit(path);
119         if(exit<0)
120                 return TrackIter();
121
122         return TrackIter(_track, exit);
123 }
124
125 TrackIter TrackIter::flip() const
126 {
127         if(!_track)
128                 return TrackIter();
129
130         TrackIter result;
131         result._track = _track->get_link(_entry);
132         result._entry = (result._track ? result._track->get_link_slot(*_track) : 0);
133
134         return result;
135 }
136
137 Track &TrackIter::operator*() const
138 {
139         if(!_track)
140                 throw logic_error("null track");
141
142         return *_track;
143 }
144
145 bool TrackIter::operator==(const TrackIter &other) const
146 {
147         return _track==other._track && _entry==other._entry;
148 }
149
150
151 TrackLoopIter::TrackLoopIter():
152         _looped(false)
153 { }
154
155 TrackLoopIter::TrackLoopIter(Track *t, unsigned e):
156         TrackIter(t, e),
157         _visited(new TrackList()),
158         _last(_visited->insert(_visited->end(), track())),
159         _looped(false)
160 { }
161
162 TrackLoopIter::TrackLoopIter(const TrackIter &i):
163         TrackIter(i),
164         _visited(new TrackList()),
165         _last(_visited->insert(_visited->end(), track())),
166         _looped(false)
167 { }
168
169 TrackLoopIter::TrackLoopIter(const TrackIter &i, RefPtr<TrackList> v, const TrackList::iterator &l):
170         TrackIter(i),
171         _looped(false)
172 {
173         if(track())
174         {
175                 _visited = v;
176                 _last = l;
177                 _looped = (_visited && find(_visited->begin(), _last, track())!=_last);
178
179                 ++_last;
180                 if(_last!=_visited->end())
181                 {
182                         _visited = new TrackList(_visited->begin(), _last);
183                         _last = _visited->end();
184                 }
185                 _visited->push_back(track());
186                 --_last;
187         }
188 }
189
190 TrackLoopIter TrackLoopIter::next() const
191 {
192         return TrackLoopIter(TrackIter::next(), _visited, _last);
193 }
194
195 TrackLoopIter TrackLoopIter::next(unsigned path) const
196 {
197         return TrackLoopIter(TrackIter::next(path), _visited, _last);
198 }
199
200 } // namespace R2C2