| [819] | 1 | // -*- c++ -*- // | 
|---|
|  | 2 |  | 
|---|
|  | 3 | /** | 
|---|
|  | 4 | @defgroup paths Path Structures | 
|---|
|  | 5 | @ingroup datas | 
|---|
|  | 6 | \brief Path structures implemented in Hugo. | 
|---|
|  | 7 |  | 
|---|
|  | 8 | Hugolib provides flexible data structures | 
|---|
|  | 9 | to work with paths. | 
|---|
|  | 10 |  | 
|---|
|  | 11 | All of them have the same interface, especially they can be built or extended | 
|---|
|  | 12 | using a standard Builder subclass. This make is easy to have e.g. the Dijkstra | 
|---|
|  | 13 | algorithm to store its result in any kind of path structure. | 
|---|
|  | 14 |  | 
|---|
|  | 15 | \sa hugo::skeleton::Path | 
|---|
|  | 16 |  | 
|---|
|  | 17 | */ | 
|---|
|  | 18 |  | 
|---|
|  | 19 | ///\ingroup paths | 
|---|
|  | 20 | ///\file | 
|---|
|  | 21 | ///\brief Classes for representing paths in graphs. | 
|---|
|  | 22 |  | 
|---|
|  | 23 | #ifndef HUGO_PATH_H | 
|---|
|  | 24 | #define HUGO_PATH_H | 
|---|
|  | 25 |  | 
|---|
|  | 26 | #include <deque> | 
|---|
|  | 27 | #include <vector> | 
|---|
|  | 28 | #include <algorithm> | 
|---|
|  | 29 |  | 
|---|
|  | 30 | #include <hugo/invalid.h> | 
|---|
|  | 31 |  | 
|---|
|  | 32 | namespace hugo { | 
|---|
|  | 33 |  | 
|---|
|  | 34 | /// \addtogroup paths | 
|---|
|  | 35 | /// @{ | 
|---|
|  | 36 |  | 
|---|
|  | 37 |  | 
|---|
|  | 38 | //! \brief A structure for representing directed paths in a graph. | 
|---|
|  | 39 | //! | 
|---|
|  | 40 | //! A structure for representing directed path in a graph. | 
|---|
|  | 41 | //! \param Graph The graph type in which the path is. | 
|---|
|  | 42 | //! \param DM DebugMode, defaults to DefaultDebugMode. | 
|---|
| [837] | 43 | //! | 
|---|
| [819] | 44 | //! In a sense, the path can be treated as a graph, for is has \c NodeIt | 
|---|
|  | 45 | //! and \c EdgeIt with the same usage. These types converts to the \c Node | 
|---|
|  | 46 | //! and \c Edge of the original graph. | 
|---|
|  | 47 | //! | 
|---|
|  | 48 | //! \todo Thoroughfully check all the range and consistency tests. | 
|---|
| [831] | 49 | template<typename Graph> | 
|---|
| [819] | 50 | class DirPath { | 
|---|
|  | 51 | public: | 
|---|
|  | 52 | /// Edge type of the underlying graph. | 
|---|
| [837] | 53 | typedef typename Graph::Edge GraphEdge; | 
|---|
| [819] | 54 | /// Node type of the underlying graph. | 
|---|
|  | 55 | typedef typename Graph::Node GraphNode; | 
|---|
|  | 56 | class NodeIt; | 
|---|
|  | 57 | class EdgeIt; | 
|---|
|  | 58 |  | 
|---|
|  | 59 | protected: | 
|---|
|  | 60 | const Graph *gr; | 
|---|
|  | 61 | typedef std::vector<GraphEdge> Container; | 
|---|
|  | 62 | Container edges; | 
|---|
|  | 63 |  | 
|---|
|  | 64 | public: | 
|---|
|  | 65 |  | 
|---|
|  | 66 | /// \param _G The graph in which the path is. | 
|---|
|  | 67 | /// | 
|---|
|  | 68 | DirPath(const Graph &_G) : gr(&_G) {} | 
|---|
|  | 69 |  | 
|---|
|  | 70 | /// \brief Subpath constructor. | 
|---|
|  | 71 | /// | 
|---|
|  | 72 | /// Subpath defined by two nodes. | 
|---|
|  | 73 | /// \warning It is an error if the two edges are not in order! | 
|---|
|  | 74 | DirPath(const DirPath &P, const NodeIt &a, const NodeIt &b) { | 
|---|
|  | 75 | gr = P.gr; | 
|---|
|  | 76 | edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx); | 
|---|
|  | 77 | } | 
|---|
|  | 78 |  | 
|---|
|  | 79 | /// \brief Subpath constructor. | 
|---|
|  | 80 | /// | 
|---|
|  | 81 | /// Subpath defined by two edges. Contains edges in [a,b) | 
|---|
|  | 82 | /// \warning It is an error if the two edges are not in order! | 
|---|
|  | 83 | DirPath(const DirPath &P, const EdgeIt &a, const EdgeIt &b) { | 
|---|
|  | 84 | gr = P.gr; | 
|---|
|  | 85 | edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx); | 
|---|
|  | 86 | } | 
|---|
|  | 87 |  | 
|---|
|  | 88 | /// Length of the path. | 
|---|
|  | 89 | size_t length() const { return edges.size(); } | 
|---|
|  | 90 | /// Returns whether the path is empty. | 
|---|
|  | 91 | bool empty() const { return edges.empty(); } | 
|---|
|  | 92 |  | 
|---|
|  | 93 | /// Resets the path to an empty path. | 
|---|
|  | 94 | void clear() { edges.clear(); } | 
|---|
|  | 95 |  | 
|---|
|  | 96 | /// \brief Starting point of the path. | 
|---|
|  | 97 | /// | 
|---|
|  | 98 | /// Starting point of the path. | 
|---|
|  | 99 | /// Returns INVALID if the path is empty. | 
|---|
| [831] | 100 | GraphNode tail() const { | 
|---|
| [819] | 101 | return empty() ? INVALID : gr->tail(edges[0]); | 
|---|
|  | 102 | } | 
|---|
|  | 103 | /// \brief End point of the path. | 
|---|
|  | 104 | /// | 
|---|
|  | 105 | /// End point of the path. | 
|---|
|  | 106 | /// Returns INVALID if the path is empty. | 
|---|
| [831] | 107 | GraphNode head() const { | 
|---|
| [819] | 108 | return empty() ? INVALID : gr->head(edges[length()-1]); | 
|---|
|  | 109 | } | 
|---|
|  | 110 |  | 
|---|
|  | 111 | /// \brief Initializes node or edge iterator to point to the first | 
|---|
|  | 112 | /// node or edge. | 
|---|
|  | 113 | /// | 
|---|
|  | 114 | /// \sa nth | 
|---|
|  | 115 | template<typename It> | 
|---|
|  | 116 | It& first(It &i) const { return i=It(*this); } | 
|---|
|  | 117 |  | 
|---|
|  | 118 | /// \brief Initializes node iterator to point to the node of a given index. | 
|---|
|  | 119 | NodeIt& nth(NodeIt &i, int n) const { | 
|---|
|  | 120 | return i=NodeIt(*this, n); | 
|---|
|  | 121 | } | 
|---|
|  | 122 |  | 
|---|
|  | 123 | /// \brief Initializes edge iterator to point to the edge of a given index. | 
|---|
|  | 124 | EdgeIt& nth(EdgeIt &i, int n) const { | 
|---|
|  | 125 | return i=EdgeIt(*this, n); | 
|---|
|  | 126 | } | 
|---|
|  | 127 |  | 
|---|
|  | 128 | /// \brief Returns node iterator pointing to the head node of the | 
|---|
|  | 129 | /// given edge iterator. | 
|---|
|  | 130 | NodeIt head(const EdgeIt& e) const { | 
|---|
|  | 131 | return NodeIt(*this, e.idx+1); | 
|---|
|  | 132 | } | 
|---|
|  | 133 |  | 
|---|
|  | 134 | /// \brief Returns node iterator pointing to the tail node of the | 
|---|
|  | 135 | /// given edge iterator. | 
|---|
|  | 136 | NodeIt tail(const EdgeIt& e) const { | 
|---|
|  | 137 | return NodeIt(*this, e.idx); | 
|---|
|  | 138 | } | 
|---|
|  | 139 |  | 
|---|
|  | 140 |  | 
|---|
|  | 141 | /* Iterator classes */ | 
|---|
|  | 142 |  | 
|---|
|  | 143 | /** | 
|---|
|  | 144 | * \brief Iterator class to iterate on the edges of the paths | 
|---|
| [837] | 145 | * | 
|---|
| [819] | 146 | * \ingroup paths | 
|---|
|  | 147 | * This class is used to iterate on the edges of the paths | 
|---|
|  | 148 | * | 
|---|
|  | 149 | * Of course it converts to Graph::Edge | 
|---|
| [837] | 150 | * | 
|---|
| [819] | 151 | */ | 
|---|
|  | 152 | class EdgeIt { | 
|---|
|  | 153 | friend class DirPath; | 
|---|
|  | 154 |  | 
|---|
|  | 155 | int idx; | 
|---|
|  | 156 | const DirPath *p; | 
|---|
|  | 157 | public: | 
|---|
|  | 158 | /// Default constructor | 
|---|
|  | 159 | EdgeIt() {} | 
|---|
|  | 160 | /// Invalid constructor | 
|---|
|  | 161 | EdgeIt(Invalid) : idx(-1), p(0) {} | 
|---|
|  | 162 | /// Constructor with starting point | 
|---|
|  | 163 | EdgeIt(const DirPath &_p, int _idx = 0) : | 
|---|
|  | 164 | idx(_idx), p(&_p) { validate(); } | 
|---|
|  | 165 |  | 
|---|
|  | 166 | ///Validity check | 
|---|
|  | 167 | bool valid() const { return idx!=-1; } | 
|---|
|  | 168 |  | 
|---|
|  | 169 | ///Conversion to Graph::Edge | 
|---|
|  | 170 | operator GraphEdge () const { | 
|---|
|  | 171 | return valid() ? p->edges[idx] : INVALID; | 
|---|
|  | 172 | } | 
|---|
|  | 173 |  | 
|---|
|  | 174 | /// Next edge | 
|---|
|  | 175 | EdgeIt& operator++() { ++idx; validate(); return *this; } | 
|---|
|  | 176 |  | 
|---|
|  | 177 | /// Comparison operator | 
|---|
|  | 178 | bool operator==(const EdgeIt& e) const { return idx==e.idx; } | 
|---|
|  | 179 | /// Comparison operator | 
|---|
|  | 180 | bool operator!=(const EdgeIt& e) const { return idx!=e.idx; } | 
|---|
|  | 181 | /// Comparison operator | 
|---|
|  | 182 | bool operator<(const EdgeIt& e) const { return idx<e.idx; } | 
|---|
|  | 183 |  | 
|---|
|  | 184 | private: | 
|---|
|  | 185 | // FIXME: comparison between signed and unsigned... | 
|---|
|  | 186 | // Jo ez igy? Vagy esetleg legyen a length() int? | 
|---|
|  | 187 | void validate() { if( size_t(idx) >= p->length() ) idx=-1; } | 
|---|
|  | 188 | }; | 
|---|
|  | 189 |  | 
|---|
|  | 190 | /** | 
|---|
|  | 191 | * \brief Iterator class to iterate on the nodes of the paths | 
|---|
| [837] | 192 | * | 
|---|
| [819] | 193 | * \ingroup paths | 
|---|
|  | 194 | * This class is used to iterate on the nodes of the paths | 
|---|
|  | 195 | * | 
|---|
|  | 196 | * Of course it converts to Graph::Node | 
|---|
| [837] | 197 | * | 
|---|
| [819] | 198 | */ | 
|---|
|  | 199 | class NodeIt { | 
|---|
|  | 200 | friend class DirPath; | 
|---|
|  | 201 |  | 
|---|
|  | 202 | int idx; | 
|---|
|  | 203 | const DirPath *p; | 
|---|
|  | 204 | public: | 
|---|
|  | 205 | /// Default constructor | 
|---|
|  | 206 | NodeIt() {} | 
|---|
|  | 207 | /// Invalid constructor | 
|---|
|  | 208 | NodeIt(Invalid) : idx(-1), p(0) {} | 
|---|
|  | 209 | /// Constructor with starting point | 
|---|
|  | 210 | NodeIt(const DirPath &_p, int _idx = 0) : | 
|---|
|  | 211 | idx(_idx), p(&_p) { validate(); } | 
|---|
|  | 212 |  | 
|---|
|  | 213 | ///Validity check | 
|---|
|  | 214 | bool valid() const { return idx!=-1; } | 
|---|
|  | 215 |  | 
|---|
|  | 216 | ///Conversion to Graph::Node | 
|---|
|  | 217 | operator const GraphNode& () const { | 
|---|
|  | 218 | if(idx >= p->length()) | 
|---|
| [831] | 219 | return p->head(); | 
|---|
| [819] | 220 | else if(idx >= 0) | 
|---|
|  | 221 | return p->gr->tail(p->edges[idx]); | 
|---|
|  | 222 | else | 
|---|
|  | 223 | return INVALID; | 
|---|
|  | 224 | } | 
|---|
|  | 225 | /// Next node | 
|---|
|  | 226 | NodeIt& operator++() { ++idx; validate(); return *this; } | 
|---|
|  | 227 |  | 
|---|
|  | 228 | /// Comparison operator | 
|---|
|  | 229 | bool operator==(const NodeIt& e) const { return idx==e.idx; } | 
|---|
|  | 230 | /// Comparison operator | 
|---|
|  | 231 | bool operator!=(const NodeIt& e) const { return idx!=e.idx; } | 
|---|
|  | 232 | /// Comparison operator | 
|---|
|  | 233 | bool operator<(const NodeIt& e) const { return idx<e.idx; } | 
|---|
|  | 234 |  | 
|---|
|  | 235 | private: | 
|---|
|  | 236 | void validate() { if( size_t(idx) > p->length() ) idx=-1; } | 
|---|
|  | 237 | }; | 
|---|
|  | 238 |  | 
|---|
| [837] | 239 | friend class Builder; | 
|---|
| [819] | 240 |  | 
|---|
|  | 241 | /** | 
|---|
|  | 242 | * \brief Class to build paths | 
|---|
| [837] | 243 | * | 
|---|
| [819] | 244 | * \ingroup paths | 
|---|
|  | 245 | * This class is used to fill a path with edges. | 
|---|
|  | 246 | * | 
|---|
|  | 247 | * You can push new edges to the front and to the back of the path in | 
|---|
|  | 248 | * arbitrary order then you should commit these changes to the graph. | 
|---|
|  | 249 | * | 
|---|
|  | 250 | * Fundamentally, for most "Paths" (classes fulfilling the | 
|---|
|  | 251 | * PathConcept) while the builder is active (after the first modifying | 
|---|
|  | 252 | * operation and until the commit()) the original Path is in a | 
|---|
|  | 253 | * "transitional" state (operations on it have undefined result). But | 
|---|
|  | 254 | * in the case of DirPath the original path remains unchanged until the | 
|---|
|  | 255 | * commit. However we don't recomend that you use this feature. | 
|---|
|  | 256 | */ | 
|---|
|  | 257 | class Builder { | 
|---|
|  | 258 | DirPath &P; | 
|---|
|  | 259 | Container front, back; | 
|---|
|  | 260 |  | 
|---|
|  | 261 | public: | 
|---|
|  | 262 | ///\param _P the path you want to fill in. | 
|---|
|  | 263 | /// | 
|---|
|  | 264 | Builder(DirPath &_P) : P(_P) {} | 
|---|
|  | 265 |  | 
|---|
|  | 266 | /// Sets the starting node of the path. | 
|---|
| [837] | 267 |  | 
|---|
| [819] | 268 | /// Sets the starting node of the path. Edge added to the path | 
|---|
|  | 269 | /// afterwards have to be incident to this node. | 
|---|
| [900] | 270 | /// It should be called if and only if | 
|---|
|  | 271 | /// the path is empty and before any call to | 
|---|
| [819] | 272 | /// \ref pushFront() or \ref pushBack() | 
|---|
|  | 273 | void setStartNode(const GraphNode &) {} | 
|---|
|  | 274 |  | 
|---|
|  | 275 | ///Push a new edge to the front of the path | 
|---|
|  | 276 |  | 
|---|
|  | 277 | ///Push a new edge to the front of the path. | 
|---|
|  | 278 | ///\sa setStartNode | 
|---|
|  | 279 | void pushFront(const GraphEdge& e) { | 
|---|
|  | 280 | front.push_back(e); | 
|---|
|  | 281 | } | 
|---|
|  | 282 |  | 
|---|
|  | 283 | ///Push a new edge to the back of the path | 
|---|
|  | 284 |  | 
|---|
|  | 285 | ///Push a new edge to the back of the path. | 
|---|
|  | 286 | ///\sa setStartNode | 
|---|
|  | 287 | void pushBack(const GraphEdge& e) { | 
|---|
|  | 288 | back.push_back(e); | 
|---|
|  | 289 | } | 
|---|
|  | 290 |  | 
|---|
|  | 291 | ///Commit the changes to the path. | 
|---|
|  | 292 | void commit() { | 
|---|
| [837] | 293 | if( !front.empty() || !back.empty() ) { | 
|---|
| [819] | 294 | Container tmp; | 
|---|
|  | 295 | tmp.reserve(front.size()+back.size()+P.length()); | 
|---|
|  | 296 | tmp.insert(tmp.end(), front.rbegin(), front.rend()); | 
|---|
|  | 297 | tmp.insert(tmp.end(), P.edges.begin(), P.edges.end()); | 
|---|
|  | 298 | tmp.insert(tmp.end(), back.begin(), back.end()); | 
|---|
|  | 299 | P.edges.swap(tmp); | 
|---|
|  | 300 | front.clear(); | 
|---|
|  | 301 | back.clear(); | 
|---|
|  | 302 | } | 
|---|
|  | 303 | } | 
|---|
|  | 304 |  | 
|---|
|  | 305 | ///Reserve storage for the builder in advance. | 
|---|
|  | 306 |  | 
|---|
| [837] | 307 | ///If you know a reasonable upper bound of the number of the edges | 
|---|
|  | 308 | ///to add to the front, using this function you can speed up the building. | 
|---|
| [819] | 309 |  | 
|---|
| [837] | 310 | void reserveFront(size_t r) {front.reserve(r);} | 
|---|
|  | 311 |  | 
|---|
|  | 312 | ///Reserve storage for the builder in advance. | 
|---|
|  | 313 |  | 
|---|
|  | 314 | ///If you know a reasonable upper bound of the number of the edges | 
|---|
|  | 315 | ///to add to the back, using this function you can speed up the building. | 
|---|
|  | 316 |  | 
|---|
|  | 317 | void reserveBack(size_t r) {back.reserve(r);} | 
|---|
| [831] | 318 |  | 
|---|
| [819] | 319 | private: | 
|---|
|  | 320 | bool empty() { | 
|---|
|  | 321 | return front.empty() && back.empty() && P.empty(); | 
|---|
|  | 322 | } | 
|---|
|  | 323 |  | 
|---|
| [831] | 324 | GraphNode tail() const { | 
|---|
| [819] | 325 | if( ! front.empty() ) | 
|---|
|  | 326 | return P.gr->tail(front[front.size()-1]); | 
|---|
|  | 327 | else if( ! P.empty() ) | 
|---|
|  | 328 | return P.gr->tail(P.edges[0]); | 
|---|
|  | 329 | else if( ! back.empty() ) | 
|---|
|  | 330 | return P.gr->tail(back[0]); | 
|---|
|  | 331 | else | 
|---|
|  | 332 | return INVALID; | 
|---|
|  | 333 | } | 
|---|
| [831] | 334 | GraphNode head() const { | 
|---|
| [819] | 335 | if( ! back.empty() ) | 
|---|
|  | 336 | return P.gr->head(back[back.size()-1]); | 
|---|
|  | 337 | else if( ! P.empty() ) | 
|---|
|  | 338 | return P.gr->head(P.edges[P.length()-1]); | 
|---|
|  | 339 | else if( ! front.empty() ) | 
|---|
|  | 340 | return P.gr->head(front[0]); | 
|---|
|  | 341 | else | 
|---|
|  | 342 | return INVALID; | 
|---|
|  | 343 | } | 
|---|
|  | 344 |  | 
|---|
|  | 345 | }; | 
|---|
|  | 346 |  | 
|---|
|  | 347 | }; | 
|---|
|  | 348 |  | 
|---|
|  | 349 |  | 
|---|
|  | 350 |  | 
|---|
|  | 351 |  | 
|---|
|  | 352 |  | 
|---|
|  | 353 |  | 
|---|
|  | 354 |  | 
|---|
|  | 355 |  | 
|---|
|  | 356 |  | 
|---|
|  | 357 |  | 
|---|
|  | 358 | /**********************************************************************/ | 
|---|
|  | 359 |  | 
|---|
|  | 360 |  | 
|---|
|  | 361 | //! \brief A structure for representing undirected path in a graph. | 
|---|
|  | 362 | //! | 
|---|
|  | 363 | //! A structure for representing undirected path in a graph. Ie. this is | 
|---|
|  | 364 | //! a path in a \e directed graph but the edges should not be directed | 
|---|
|  | 365 | //! forward. | 
|---|
|  | 366 | //! | 
|---|
|  | 367 | //! \param Graph The graph type in which the path is. | 
|---|
|  | 368 | //! \param DM DebugMode, defaults to DefaultDebugMode. | 
|---|
| [837] | 369 | //! | 
|---|
| [819] | 370 | //! In a sense, the path can be treated as a graph, for is has \c NodeIt | 
|---|
|  | 371 | //! and \c EdgeIt with the same usage. These types converts to the \c Node | 
|---|
|  | 372 | //! and \c Edge of the original graph. | 
|---|
|  | 373 | //! | 
|---|
|  | 374 | //! \todo Thoroughfully check all the range and consistency tests. | 
|---|
| [831] | 375 | template<typename Graph> | 
|---|
| [819] | 376 | class UndirPath { | 
|---|
|  | 377 | public: | 
|---|
|  | 378 | /// Edge type of the underlying graph. | 
|---|
|  | 379 | typedef typename Graph::Edge GraphEdge; | 
|---|
|  | 380 | /// Node type of the underlying graph. | 
|---|
|  | 381 | typedef typename Graph::Node GraphNode; | 
|---|
|  | 382 | class NodeIt; | 
|---|
|  | 383 | class EdgeIt; | 
|---|
|  | 384 |  | 
|---|
|  | 385 | protected: | 
|---|
|  | 386 | const Graph *gr; | 
|---|
|  | 387 | typedef std::vector<GraphEdge> Container; | 
|---|
|  | 388 | Container edges; | 
|---|
|  | 389 |  | 
|---|
|  | 390 | public: | 
|---|
|  | 391 |  | 
|---|
|  | 392 | /// \param _G The graph in which the path is. | 
|---|
|  | 393 | /// | 
|---|
|  | 394 | UndirPath(const Graph &_G) : gr(&_G) {} | 
|---|
|  | 395 |  | 
|---|
|  | 396 | /// \brief Subpath constructor. | 
|---|
|  | 397 | /// | 
|---|
|  | 398 | /// Subpath defined by two nodes. | 
|---|
|  | 399 | /// \warning It is an error if the two edges are not in order! | 
|---|
|  | 400 | UndirPath(const UndirPath &P, const NodeIt &a, const NodeIt &b) { | 
|---|
|  | 401 | gr = P.gr; | 
|---|
|  | 402 | edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx); | 
|---|
|  | 403 | } | 
|---|
|  | 404 |  | 
|---|
|  | 405 | /// \brief Subpath constructor. | 
|---|
|  | 406 | /// | 
|---|
|  | 407 | /// Subpath defined by two edges. Contains edges in [a,b) | 
|---|
|  | 408 | /// \warning It is an error if the two edges are not in order! | 
|---|
|  | 409 | UndirPath(const UndirPath &P, const EdgeIt &a, const EdgeIt &b) { | 
|---|
|  | 410 | gr = P.gr; | 
|---|
|  | 411 | edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx); | 
|---|
|  | 412 | } | 
|---|
|  | 413 |  | 
|---|
|  | 414 | /// Length of the path. | 
|---|
|  | 415 | size_t length() const { return edges.size(); } | 
|---|
|  | 416 | /// Returns whether the path is empty. | 
|---|
|  | 417 | bool empty() const { return edges.empty(); } | 
|---|
|  | 418 |  | 
|---|
|  | 419 | /// Resets the path to an empty path. | 
|---|
|  | 420 | void clear() { edges.clear(); } | 
|---|
|  | 421 |  | 
|---|
|  | 422 | /// \brief Starting point of the path. | 
|---|
|  | 423 | /// | 
|---|
|  | 424 | /// Starting point of the path. | 
|---|
|  | 425 | /// Returns INVALID if the path is empty. | 
|---|
| [831] | 426 | GraphNode tail() const { | 
|---|
| [819] | 427 | return empty() ? INVALID : gr->tail(edges[0]); | 
|---|
|  | 428 | } | 
|---|
|  | 429 | /// \brief End point of the path. | 
|---|
|  | 430 | /// | 
|---|
|  | 431 | /// End point of the path. | 
|---|
|  | 432 | /// Returns INVALID if the path is empty. | 
|---|
| [831] | 433 | GraphNode head() const { | 
|---|
| [819] | 434 | return empty() ? INVALID : gr->head(edges[length()-1]); | 
|---|
|  | 435 | } | 
|---|
|  | 436 |  | 
|---|
|  | 437 | /// \brief Initializes node or edge iterator to point to the first | 
|---|
|  | 438 | /// node or edge. | 
|---|
|  | 439 | /// | 
|---|
|  | 440 | /// \sa nth | 
|---|
|  | 441 | template<typename It> | 
|---|
|  | 442 | It& first(It &i) const { return i=It(*this); } | 
|---|
|  | 443 |  | 
|---|
|  | 444 | /// \brief Initializes node iterator to point to the node of a given index. | 
|---|
|  | 445 | NodeIt& nth(NodeIt &i, int n) const { | 
|---|
|  | 446 | return i=NodeIt(*this, n); | 
|---|
|  | 447 | } | 
|---|
|  | 448 |  | 
|---|
|  | 449 | /// \brief Initializes edge iterator to point to the edge of a given index. | 
|---|
|  | 450 | EdgeIt& nth(EdgeIt &i, int n) const { | 
|---|
|  | 451 | return i=EdgeIt(*this, n); | 
|---|
|  | 452 | } | 
|---|
|  | 453 |  | 
|---|
|  | 454 | /// Checks validity of a node or edge iterator. | 
|---|
|  | 455 | template<typename It> | 
|---|
|  | 456 | static | 
|---|
|  | 457 | bool valid(const It &i) { return i.valid(); } | 
|---|
|  | 458 |  | 
|---|
|  | 459 | /// Steps the given node or edge iterator. | 
|---|
|  | 460 | template<typename It> | 
|---|
|  | 461 | static | 
|---|
|  | 462 | It& next(It &e) { | 
|---|
|  | 463 | return ++e; | 
|---|
|  | 464 | } | 
|---|
|  | 465 |  | 
|---|
|  | 466 | /// \brief Returns node iterator pointing to the head node of the | 
|---|
|  | 467 | /// given edge iterator. | 
|---|
|  | 468 | NodeIt head(const EdgeIt& e) const { | 
|---|
|  | 469 | return NodeIt(*this, e.idx+1); | 
|---|
|  | 470 | } | 
|---|
|  | 471 |  | 
|---|
|  | 472 | /// \brief Returns node iterator pointing to the tail node of the | 
|---|
|  | 473 | /// given edge iterator. | 
|---|
|  | 474 | NodeIt tail(const EdgeIt& e) const { | 
|---|
|  | 475 | return NodeIt(*this, e.idx); | 
|---|
|  | 476 | } | 
|---|
|  | 477 |  | 
|---|
|  | 478 |  | 
|---|
|  | 479 |  | 
|---|
|  | 480 | /** | 
|---|
|  | 481 | * \brief Iterator class to iterate on the edges of the paths | 
|---|
| [837] | 482 | * | 
|---|
| [819] | 483 | * \ingroup paths | 
|---|
|  | 484 | * This class is used to iterate on the edges of the paths | 
|---|
|  | 485 | * | 
|---|
|  | 486 | * Of course it converts to Graph::Edge | 
|---|
| [837] | 487 | * | 
|---|
| [819] | 488 | * \todo Its interface differs from the standard edge iterator. | 
|---|
|  | 489 | * Yes, it shouldn't. | 
|---|
|  | 490 | */ | 
|---|
|  | 491 | class EdgeIt { | 
|---|
|  | 492 | friend class UndirPath; | 
|---|
|  | 493 |  | 
|---|
|  | 494 | int idx; | 
|---|
|  | 495 | const UndirPath *p; | 
|---|
|  | 496 | public: | 
|---|
|  | 497 | /// Default constructor | 
|---|
|  | 498 | EdgeIt() {} | 
|---|
|  | 499 | /// Invalid constructor | 
|---|
|  | 500 | EdgeIt(Invalid) : idx(-1), p(0) {} | 
|---|
|  | 501 | /// Constructor with starting point | 
|---|
|  | 502 | EdgeIt(const UndirPath &_p, int _idx = 0) : | 
|---|
|  | 503 | idx(_idx), p(&_p) { validate(); } | 
|---|
|  | 504 |  | 
|---|
|  | 505 | ///Validity check | 
|---|
|  | 506 | bool valid() const { return idx!=-1; } | 
|---|
|  | 507 |  | 
|---|
|  | 508 | ///Conversion to Graph::Edge | 
|---|
|  | 509 | operator GraphEdge () const { | 
|---|
|  | 510 | return valid() ? p->edges[idx] : INVALID; | 
|---|
|  | 511 | } | 
|---|
|  | 512 | /// Next edge | 
|---|
|  | 513 | EdgeIt& operator++() { ++idx; validate(); return *this; } | 
|---|
|  | 514 |  | 
|---|
|  | 515 | /// Comparison operator | 
|---|
|  | 516 | bool operator==(const EdgeIt& e) const { return idx==e.idx; } | 
|---|
|  | 517 | /// Comparison operator | 
|---|
|  | 518 | bool operator!=(const EdgeIt& e) const { return idx!=e.idx; } | 
|---|
|  | 519 | /// Comparison operator | 
|---|
|  | 520 | bool operator<(const EdgeIt& e) const { return idx<e.idx; } | 
|---|
|  | 521 |  | 
|---|
|  | 522 | private: | 
|---|
|  | 523 | // FIXME: comparison between signed and unsigned... | 
|---|
|  | 524 | // Jo ez igy? Vagy esetleg legyen a length() int? | 
|---|
|  | 525 | void validate() { if( size_t(idx) >= p->length() ) idx=-1; } | 
|---|
|  | 526 | }; | 
|---|
|  | 527 |  | 
|---|
|  | 528 | /** | 
|---|
|  | 529 | * \brief Iterator class to iterate on the nodes of the paths | 
|---|
| [837] | 530 | * | 
|---|
| [819] | 531 | * \ingroup paths | 
|---|
|  | 532 | * This class is used to iterate on the nodes of the paths | 
|---|
|  | 533 | * | 
|---|
|  | 534 | * Of course it converts to Graph::Node | 
|---|
| [837] | 535 | * | 
|---|
| [819] | 536 | * \todo Its interface differs from the standard node iterator. | 
|---|
|  | 537 | * Yes, it shouldn't. | 
|---|
|  | 538 | */ | 
|---|
|  | 539 | class NodeIt { | 
|---|
|  | 540 | friend class UndirPath; | 
|---|
|  | 541 |  | 
|---|
|  | 542 | int idx; | 
|---|
|  | 543 | const UndirPath *p; | 
|---|
|  | 544 | public: | 
|---|
|  | 545 | /// Default constructor | 
|---|
|  | 546 | NodeIt() {} | 
|---|
|  | 547 | /// Invalid constructor | 
|---|
|  | 548 | NodeIt(Invalid) : idx(-1), p(0) {} | 
|---|
|  | 549 | /// Constructor with starting point | 
|---|
|  | 550 | NodeIt(const UndirPath &_p, int _idx = 0) : | 
|---|
|  | 551 | idx(_idx), p(&_p) { validate(); } | 
|---|
|  | 552 |  | 
|---|
|  | 553 | ///Validity check | 
|---|
|  | 554 | bool valid() const { return idx!=-1; } | 
|---|
|  | 555 |  | 
|---|
|  | 556 | ///Conversion to Graph::Node | 
|---|
|  | 557 | operator const GraphNode& () const { | 
|---|
|  | 558 | if(idx >= p->length()) | 
|---|
| [831] | 559 | return p->head(); | 
|---|
| [819] | 560 | else if(idx >= 0) | 
|---|
|  | 561 | return p->gr->tail(p->edges[idx]); | 
|---|
|  | 562 | else | 
|---|
|  | 563 | return INVALID; | 
|---|
|  | 564 | } | 
|---|
|  | 565 | /// Next node | 
|---|
|  | 566 | NodeIt& operator++() { ++idx; validate(); return *this; } | 
|---|
|  | 567 |  | 
|---|
|  | 568 | /// Comparison operator | 
|---|
|  | 569 | bool operator==(const NodeIt& e) const { return idx==e.idx; } | 
|---|
|  | 570 | /// Comparison operator | 
|---|
|  | 571 | bool operator!=(const NodeIt& e) const { return idx!=e.idx; } | 
|---|
|  | 572 | /// Comparison operator | 
|---|
|  | 573 | bool operator<(const NodeIt& e) const { return idx<e.idx; } | 
|---|
|  | 574 |  | 
|---|
|  | 575 | private: | 
|---|
|  | 576 | void validate() { if( size_t(idx) > p->length() ) idx=-1; } | 
|---|
|  | 577 | }; | 
|---|
|  | 578 |  | 
|---|
| [837] | 579 | friend class Builder; | 
|---|
| [819] | 580 |  | 
|---|
|  | 581 | /** | 
|---|
|  | 582 | * \brief Class to build paths | 
|---|
| [837] | 583 | * | 
|---|
| [819] | 584 | * \ingroup paths | 
|---|
|  | 585 | * This class is used to fill a path with edges. | 
|---|
|  | 586 | * | 
|---|
|  | 587 | * You can push new edges to the front and to the back of the path in | 
|---|
|  | 588 | * arbitrary order then you should commit these changes to the graph. | 
|---|
|  | 589 | * | 
|---|
|  | 590 | * Fundamentally, for most "Paths" (classes fulfilling the | 
|---|
|  | 591 | * PathConcept) while the builder is active (after the first modifying | 
|---|
|  | 592 | * operation and until the commit()) the original Path is in a | 
|---|
|  | 593 | * "transitional" state (operations ot it have undefined result). But | 
|---|
|  | 594 | * in the case of UndirPath the original path is unchanged until the | 
|---|
|  | 595 | * commit. However we don't recomend that you use this feature. | 
|---|
|  | 596 | */ | 
|---|
|  | 597 | class Builder { | 
|---|
|  | 598 | UndirPath &P; | 
|---|
|  | 599 | Container front, back; | 
|---|
|  | 600 |  | 
|---|
|  | 601 | public: | 
|---|
|  | 602 | ///\param _P the path you want to fill in. | 
|---|
|  | 603 | /// | 
|---|
|  | 604 | Builder(UndirPath &_P) : P(_P) {} | 
|---|
|  | 605 |  | 
|---|
|  | 606 | /// Sets the starting node of the path. | 
|---|
| [837] | 607 |  | 
|---|
| [819] | 608 | /// Sets the starting node of the path. Edge added to the path | 
|---|
|  | 609 | /// afterwards have to be incident to this node. | 
|---|
| [900] | 610 | /// It should be called if and only if | 
|---|
|  | 611 | /// the path is empty and before any call to | 
|---|
| [819] | 612 | /// \ref pushFront() or \ref pushBack() | 
|---|
|  | 613 | void setStartNode(const GraphNode &) {} | 
|---|
|  | 614 |  | 
|---|
|  | 615 | ///Push a new edge to the front of the path | 
|---|
|  | 616 |  | 
|---|
|  | 617 | ///Push a new edge to the front of the path. | 
|---|
|  | 618 | ///\sa setStartNode | 
|---|
|  | 619 | void pushFront(const GraphEdge& e) { | 
|---|
|  | 620 | front.push_back(e); | 
|---|
|  | 621 | } | 
|---|
|  | 622 |  | 
|---|
|  | 623 | ///Push a new edge to the back of the path | 
|---|
|  | 624 |  | 
|---|
|  | 625 | ///Push a new edge to the back of the path. | 
|---|
|  | 626 | ///\sa setStartNode | 
|---|
|  | 627 | void pushBack(const GraphEdge& e) { | 
|---|
|  | 628 | back.push_back(e); | 
|---|
|  | 629 | } | 
|---|
|  | 630 |  | 
|---|
|  | 631 | ///Commit the changes to the path. | 
|---|
|  | 632 | void commit() { | 
|---|
|  | 633 | if( !(front.empty() && back.empty()) ) { | 
|---|
|  | 634 | Container tmp; | 
|---|
|  | 635 | tmp.reserve(front.size()+back.size()+P.length()); | 
|---|
|  | 636 | tmp.insert(tmp.end(), front.rbegin(), front.rend()); | 
|---|
|  | 637 | tmp.insert(tmp.end(), P.edges.begin(), P.edges.end()); | 
|---|
|  | 638 | tmp.insert(tmp.end(), back.begin(), back.end()); | 
|---|
|  | 639 | P.edges.swap(tmp); | 
|---|
|  | 640 | front.clear(); | 
|---|
|  | 641 | back.clear(); | 
|---|
|  | 642 | } | 
|---|
|  | 643 | } | 
|---|
|  | 644 |  | 
|---|
|  | 645 |  | 
|---|
|  | 646 | ///Reserve storage for the builder in advance. | 
|---|
|  | 647 |  | 
|---|
| [837] | 648 | ///If you know a reasonable upper bound of the number of the edges | 
|---|
|  | 649 | ///to add to the front, using this function you can speed up the building. | 
|---|
| [819] | 650 |  | 
|---|
| [837] | 651 | void reserveFront(size_t r) {front.reserve(r);} | 
|---|
|  | 652 |  | 
|---|
|  | 653 | ///Reserve storage for the builder in advance. | 
|---|
|  | 654 |  | 
|---|
|  | 655 | ///If you know a reasonable upper bound of the number of the edges | 
|---|
|  | 656 | ///to add to the back, using this function you can speed up the building. | 
|---|
|  | 657 |  | 
|---|
|  | 658 | void reserveBack(size_t r) {back.reserve(r);} | 
|---|
| [831] | 659 |  | 
|---|
| [819] | 660 | private: | 
|---|
|  | 661 | bool empty() { | 
|---|
|  | 662 | return front.empty() && back.empty() && P.empty(); | 
|---|
|  | 663 | } | 
|---|
|  | 664 |  | 
|---|
| [831] | 665 | GraphNode tail() const { | 
|---|
| [819] | 666 | if( ! front.empty() ) | 
|---|
|  | 667 | return P.gr->tail(front[front.size()-1]); | 
|---|
|  | 668 | else if( ! P.empty() ) | 
|---|
|  | 669 | return P.gr->tail(P.edges[0]); | 
|---|
|  | 670 | else if( ! back.empty() ) | 
|---|
|  | 671 | return P.gr->tail(back[0]); | 
|---|
|  | 672 | else | 
|---|
|  | 673 | return INVALID; | 
|---|
|  | 674 | } | 
|---|
| [831] | 675 | GraphNode head() const { | 
|---|
| [819] | 676 | if( ! back.empty() ) | 
|---|
|  | 677 | return P.gr->head(back[back.size()-1]); | 
|---|
|  | 678 | else if( ! P.empty() ) | 
|---|
|  | 679 | return P.gr->head(P.edges[P.length()-1]); | 
|---|
|  | 680 | else if( ! front.empty() ) | 
|---|
|  | 681 | return P.gr->head(front[0]); | 
|---|
|  | 682 | else | 
|---|
|  | 683 | return INVALID; | 
|---|
|  | 684 | } | 
|---|
|  | 685 |  | 
|---|
|  | 686 | }; | 
|---|
|  | 687 |  | 
|---|
|  | 688 | }; | 
|---|
|  | 689 |  | 
|---|
|  | 690 |  | 
|---|
|  | 691 | ///@} | 
|---|
|  | 692 |  | 
|---|
|  | 693 | } // namespace hugo | 
|---|
|  | 694 |  | 
|---|
|  | 695 | #endif // HUGO_PATH_H | 
|---|