src/hugo/path.h
author deba
Wed, 08 Sep 2004 12:06:45 +0000
changeset 822 88226d9fe821
child 831 b6ae3446098a
permissions -rw-r--r--
The MapFactories have been removed from the code because
if we use macros then they increases only the complexity.

The pair iterators of the maps are separeted from the maps.

Some macros and comments has been changed.
hegyi@819
     1
// -*- c++ -*- //
hegyi@819
     2
hegyi@819
     3
/**
hegyi@819
     4
@defgroup paths Path Structures
hegyi@819
     5
@ingroup datas
hegyi@819
     6
\brief Path structures implemented in Hugo.
hegyi@819
     7
hegyi@819
     8
Hugolib provides flexible data structures
hegyi@819
     9
to work with paths.
hegyi@819
    10
hegyi@819
    11
All of them have the same interface, especially they can be built or extended
hegyi@819
    12
using a standard Builder subclass. This make is easy to have e.g. the Dijkstra
hegyi@819
    13
algorithm to store its result in any kind of path structure.
hegyi@819
    14
hegyi@819
    15
\sa hugo::skeleton::Path
hegyi@819
    16
hegyi@819
    17
*/
hegyi@819
    18
hegyi@819
    19
///\ingroup paths
hegyi@819
    20
///\file
hegyi@819
    21
///\brief Classes for representing paths in graphs.
hegyi@819
    22
hegyi@819
    23
#ifndef HUGO_PATH_H
hegyi@819
    24
#define HUGO_PATH_H
hegyi@819
    25
hegyi@819
    26
#include <deque>
hegyi@819
    27
#include <vector>
hegyi@819
    28
#include <algorithm>
hegyi@819
    29
hegyi@819
    30
#include <hugo/invalid.h>
hegyi@819
    31
#include <hugo/error.h>
hegyi@819
    32
#include <hugo/debug.h>
hegyi@819
    33
hegyi@819
    34
namespace hugo {
hegyi@819
    35
hegyi@819
    36
  /// \addtogroup paths
hegyi@819
    37
  /// @{
hegyi@819
    38
hegyi@819
    39
hegyi@819
    40
  //! \brief A structure for representing directed paths in a graph.
hegyi@819
    41
  //!
hegyi@819
    42
  //! A structure for representing directed path in a graph.
hegyi@819
    43
  //! \param Graph The graph type in which the path is.
hegyi@819
    44
  //! \param DM DebugMode, defaults to DefaultDebugMode.
hegyi@819
    45
  //! 
hegyi@819
    46
  //! In a sense, the path can be treated as a graph, for is has \c NodeIt
hegyi@819
    47
  //! and \c EdgeIt with the same usage. These types converts to the \c Node
hegyi@819
    48
  //! and \c Edge of the original graph.
hegyi@819
    49
  //!
hegyi@819
    50
  //! \todo Thoroughfully check all the range and consistency tests.
hegyi@819
    51
  template<typename Graph, typename DM = DefaultDebugMode>
hegyi@819
    52
  class DirPath {
hegyi@819
    53
  public:
hegyi@819
    54
    /// Edge type of the underlying graph.
hegyi@819
    55
    typedef typename Graph::Edge GraphEdge; 
hegyi@819
    56
    /// Node type of the underlying graph.
hegyi@819
    57
    typedef typename Graph::Node GraphNode;
hegyi@819
    58
    class NodeIt;
hegyi@819
    59
    class EdgeIt;
hegyi@819
    60
hegyi@819
    61
  protected:
hegyi@819
    62
    const Graph *gr;
hegyi@819
    63
    typedef std::vector<GraphEdge> Container;
hegyi@819
    64
    Container edges;
hegyi@819
    65
hegyi@819
    66
  public:
hegyi@819
    67
hegyi@819
    68
    /// \param _G The graph in which the path is.
hegyi@819
    69
    ///
hegyi@819
    70
    DirPath(const Graph &_G) : gr(&_G) {}
hegyi@819
    71
hegyi@819
    72
    /// \brief Subpath constructor.
hegyi@819
    73
    ///
hegyi@819
    74
    /// Subpath defined by two nodes.
hegyi@819
    75
    /// \warning It is an error if the two edges are not in order!
hegyi@819
    76
    DirPath(const DirPath &P, const NodeIt &a, const NodeIt &b) {
hegyi@819
    77
      if( DM::range_check && (!a.valid() || !b.valid) ) {
hegyi@819
    78
	// FIXME: this check should be more elaborate...
hegyi@819
    79
	fault("DirPath, subpath ctor: invalid bounding nodes");
hegyi@819
    80
      }
hegyi@819
    81
      gr = P.gr;
hegyi@819
    82
      edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
hegyi@819
    83
    }
hegyi@819
    84
hegyi@819
    85
    /// \brief Subpath constructor.
hegyi@819
    86
    ///
hegyi@819
    87
    /// Subpath defined by two edges. Contains edges in [a,b)
hegyi@819
    88
    /// \warning It is an error if the two edges are not in order!
hegyi@819
    89
    DirPath(const DirPath &P, const EdgeIt &a, const EdgeIt &b) {
hegyi@819
    90
      if( DM::range_check && (!a.valid() || !b.valid) ) {
hegyi@819
    91
	// FIXME: this check should be more elaborate...
hegyi@819
    92
	fault("DirPath, subpath ctor: invalid bounding nodes");
hegyi@819
    93
      }
hegyi@819
    94
      gr = P.gr;
hegyi@819
    95
      edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
hegyi@819
    96
    }
hegyi@819
    97
hegyi@819
    98
    /// Length of the path.
hegyi@819
    99
    size_t length() const { return edges.size(); }
hegyi@819
   100
    /// Returns whether the path is empty.
hegyi@819
   101
    bool empty() const { return edges.empty(); }
hegyi@819
   102
hegyi@819
   103
    /// Resets the path to an empty path.
hegyi@819
   104
    void clear() { edges.clear(); }
hegyi@819
   105
hegyi@819
   106
    /// \brief Starting point of the path.
hegyi@819
   107
    ///
hegyi@819
   108
    /// Starting point of the path.
hegyi@819
   109
    /// Returns INVALID if the path is empty.
hegyi@819
   110
    GraphNode from() const {
hegyi@819
   111
      return empty() ? INVALID : gr->tail(edges[0]);
hegyi@819
   112
    }
hegyi@819
   113
    /// \brief End point of the path.
hegyi@819
   114
    ///
hegyi@819
   115
    /// End point of the path.
hegyi@819
   116
    /// Returns INVALID if the path is empty.
hegyi@819
   117
    GraphNode to() const {
hegyi@819
   118
      return empty() ? INVALID : gr->head(edges[length()-1]);
hegyi@819
   119
    }
hegyi@819
   120
hegyi@819
   121
    /// \brief Initializes node or edge iterator to point to the first
hegyi@819
   122
    /// node or edge.
hegyi@819
   123
    ///
hegyi@819
   124
    /// \sa nth
hegyi@819
   125
    template<typename It>
hegyi@819
   126
    It& first(It &i) const { return i=It(*this); }
hegyi@819
   127
hegyi@819
   128
    /// \brief Initializes node iterator to point to the node of a given index.
hegyi@819
   129
    NodeIt& nth(NodeIt &i, int n) const {
hegyi@819
   130
      if( DM::range_check && (n<0 || n>int(length())) )
hegyi@819
   131
	fault("DirPath::nth: index out of range");
hegyi@819
   132
      return i=NodeIt(*this, n);
hegyi@819
   133
    }
hegyi@819
   134
hegyi@819
   135
    /// \brief Initializes edge iterator to point to the edge of a given index.
hegyi@819
   136
    EdgeIt& nth(EdgeIt &i, int n) const {
hegyi@819
   137
      if( DM::range_check && (n<0 || n>=int(length())) )
hegyi@819
   138
	fault("DirPath::nth: index out of range");
hegyi@819
   139
      return i=EdgeIt(*this, n);
hegyi@819
   140
    }
hegyi@819
   141
hegyi@819
   142
    /// Checks validity of a node or edge iterator.
hegyi@819
   143
    template<typename It>
hegyi@819
   144
    static
hegyi@819
   145
    bool valid(const It &i) { return i.valid(); }
hegyi@819
   146
hegyi@819
   147
    /// Steps the given node or edge iterator.
hegyi@819
   148
    template<typename It>
hegyi@819
   149
    static
hegyi@819
   150
    It& next(It &e) {
hegyi@819
   151
      if( DM::range_check && !e.valid() )
hegyi@819
   152
	fault("DirPath::next() on invalid iterator");
hegyi@819
   153
      return ++e;
hegyi@819
   154
    }
hegyi@819
   155
hegyi@819
   156
    /// \brief Returns node iterator pointing to the head node of the
hegyi@819
   157
    /// given edge iterator.
hegyi@819
   158
    NodeIt head(const EdgeIt& e) const {
hegyi@819
   159
      if( DM::range_check && !e.valid() )
hegyi@819
   160
	fault("DirPath::head() on invalid iterator");
hegyi@819
   161
      return NodeIt(*this, e.idx+1);
hegyi@819
   162
    }
hegyi@819
   163
hegyi@819
   164
    /// \brief Returns node iterator pointing to the tail node of the
hegyi@819
   165
    /// given edge iterator.
hegyi@819
   166
    NodeIt tail(const EdgeIt& e) const {
hegyi@819
   167
      if( DM::range_check && !e.valid() )
hegyi@819
   168
	fault("DirPath::tail() on invalid iterator");
hegyi@819
   169
      return NodeIt(*this, e.idx);
hegyi@819
   170
    }
hegyi@819
   171
hegyi@819
   172
hegyi@819
   173
    /* Iterator classes */
hegyi@819
   174
hegyi@819
   175
    /**
hegyi@819
   176
     * \brief Iterator class to iterate on the edges of the paths
hegyi@819
   177
     * 
hegyi@819
   178
     * \ingroup paths
hegyi@819
   179
     * This class is used to iterate on the edges of the paths
hegyi@819
   180
     *
hegyi@819
   181
     * Of course it converts to Graph::Edge
hegyi@819
   182
     * 
hegyi@819
   183
     * \todo Its interface differs from the standard edge iterator.
hegyi@819
   184
     * Yes, it shouldn't.
hegyi@819
   185
     */
hegyi@819
   186
    class EdgeIt {
hegyi@819
   187
      friend class DirPath;
hegyi@819
   188
hegyi@819
   189
      int idx;
hegyi@819
   190
      const DirPath *p;
hegyi@819
   191
    public:
hegyi@819
   192
      /// Default constructor
hegyi@819
   193
      EdgeIt() {}
hegyi@819
   194
      /// Invalid constructor
hegyi@819
   195
      EdgeIt(Invalid) : idx(-1), p(0) {}
hegyi@819
   196
      /// Constructor with starting point
hegyi@819
   197
      EdgeIt(const DirPath &_p, int _idx = 0) :
hegyi@819
   198
	idx(_idx), p(&_p) { validate(); }
hegyi@819
   199
hegyi@819
   200
      ///Validity check
hegyi@819
   201
      bool valid() const { return idx!=-1; }
hegyi@819
   202
hegyi@819
   203
      ///Conversion to Graph::Edge
hegyi@819
   204
      operator GraphEdge () const {
hegyi@819
   205
	return valid() ? p->edges[idx] : INVALID;
hegyi@819
   206
      }
hegyi@819
   207
hegyi@819
   208
      /// Next edge
hegyi@819
   209
      EdgeIt& operator++() { ++idx; validate(); return *this; }
hegyi@819
   210
hegyi@819
   211
      /// Comparison operator
hegyi@819
   212
      bool operator==(const EdgeIt& e) const { return idx==e.idx; }
hegyi@819
   213
      /// Comparison operator
hegyi@819
   214
      bool operator!=(const EdgeIt& e) const { return idx!=e.idx; }
hegyi@819
   215
      /// Comparison operator
hegyi@819
   216
      bool operator<(const EdgeIt& e) const { return idx<e.idx; }
hegyi@819
   217
hegyi@819
   218
    private:
hegyi@819
   219
      // FIXME: comparison between signed and unsigned...
hegyi@819
   220
      // Jo ez igy? Vagy esetleg legyen a length() int?
hegyi@819
   221
      void validate() { if( size_t(idx) >= p->length() ) idx=-1; }
hegyi@819
   222
    };
hegyi@819
   223
hegyi@819
   224
    /**
hegyi@819
   225
     * \brief Iterator class to iterate on the nodes of the paths
hegyi@819
   226
     * 
hegyi@819
   227
     * \ingroup paths
hegyi@819
   228
     * This class is used to iterate on the nodes of the paths
hegyi@819
   229
     *
hegyi@819
   230
     * Of course it converts to Graph::Node
hegyi@819
   231
     * 
hegyi@819
   232
     * \todo Its interface differs from the standard node iterator.
hegyi@819
   233
     * Yes, it shouldn't.
hegyi@819
   234
     */
hegyi@819
   235
    class NodeIt {
hegyi@819
   236
      friend class DirPath;
hegyi@819
   237
hegyi@819
   238
      int idx;
hegyi@819
   239
      const DirPath *p;
hegyi@819
   240
    public:
hegyi@819
   241
      /// Default constructor
hegyi@819
   242
      NodeIt() {}
hegyi@819
   243
      /// Invalid constructor
hegyi@819
   244
      NodeIt(Invalid) : idx(-1), p(0) {}
hegyi@819
   245
      /// Constructor with starting point
hegyi@819
   246
      NodeIt(const DirPath &_p, int _idx = 0) :
hegyi@819
   247
	idx(_idx), p(&_p) { validate(); }
hegyi@819
   248
hegyi@819
   249
      ///Validity check
hegyi@819
   250
      bool valid() const { return idx!=-1; }
hegyi@819
   251
hegyi@819
   252
      ///Conversion to Graph::Node
hegyi@819
   253
      operator const GraphNode& () const {
hegyi@819
   254
	if(idx >= p->length())
hegyi@819
   255
	  return p->to();
hegyi@819
   256
	else if(idx >= 0)
hegyi@819
   257
	  return p->gr->tail(p->edges[idx]);
hegyi@819
   258
	else
hegyi@819
   259
	  return INVALID;
hegyi@819
   260
      }
hegyi@819
   261
      /// Next node
hegyi@819
   262
      NodeIt& operator++() { ++idx; validate(); return *this; }
hegyi@819
   263
hegyi@819
   264
      /// Comparison operator
hegyi@819
   265
      bool operator==(const NodeIt& e) const { return idx==e.idx; }
hegyi@819
   266
      /// Comparison operator
hegyi@819
   267
      bool operator!=(const NodeIt& e) const { return idx!=e.idx; }
hegyi@819
   268
      /// Comparison operator
hegyi@819
   269
      bool operator<(const NodeIt& e) const { return idx<e.idx; }
hegyi@819
   270
hegyi@819
   271
    private:
hegyi@819
   272
      void validate() { if( size_t(idx) > p->length() ) idx=-1; }
hegyi@819
   273
    };
hegyi@819
   274
hegyi@819
   275
    friend class Builder;    
hegyi@819
   276
hegyi@819
   277
    /**
hegyi@819
   278
     * \brief Class to build paths
hegyi@819
   279
     * 
hegyi@819
   280
     * \ingroup paths
hegyi@819
   281
     * This class is used to fill a path with edges.
hegyi@819
   282
     *
hegyi@819
   283
     * You can push new edges to the front and to the back of the path in
hegyi@819
   284
     * arbitrary order then you should commit these changes to the graph.
hegyi@819
   285
     *
hegyi@819
   286
     * Fundamentally, for most "Paths" (classes fulfilling the
hegyi@819
   287
     * PathConcept) while the builder is active (after the first modifying
hegyi@819
   288
     * operation and until the commit()) the original Path is in a
hegyi@819
   289
     * "transitional" state (operations on it have undefined result). But
hegyi@819
   290
     * in the case of DirPath the original path remains unchanged until the
hegyi@819
   291
     * commit. However we don't recomend that you use this feature.
hegyi@819
   292
     */
hegyi@819
   293
    class Builder {
hegyi@819
   294
      DirPath &P;
hegyi@819
   295
      Container front, back;
hegyi@819
   296
hegyi@819
   297
    public:
hegyi@819
   298
      ///\param _P the path you want to fill in.
hegyi@819
   299
      ///
hegyi@819
   300
      Builder(DirPath &_P) : P(_P) {}
hegyi@819
   301
hegyi@819
   302
      /// Sets the starting node of the path.
hegyi@819
   303
      
hegyi@819
   304
      /// Sets the starting node of the path. Edge added to the path
hegyi@819
   305
      /// afterwards have to be incident to this node.
hegyi@819
   306
      /// It should be called iff the path is empty and before any call to
hegyi@819
   307
      /// \ref pushFront() or \ref pushBack()
hegyi@819
   308
      void setStartNode(const GraphNode &) {}
hegyi@819
   309
hegyi@819
   310
      ///Push a new edge to the front of the path
hegyi@819
   311
hegyi@819
   312
      ///Push a new edge to the front of the path.
hegyi@819
   313
      ///\sa setStartNode
hegyi@819
   314
      void pushFront(const GraphEdge& e) {
hegyi@819
   315
	if( DM::consistensy_check && !empty() && P.gr->head(e)!=from() ) {
hegyi@819
   316
	  fault("DirPath::Builder::pushFront: nonincident edge");
hegyi@819
   317
	}
hegyi@819
   318
	front.push_back(e);
hegyi@819
   319
      }
hegyi@819
   320
hegyi@819
   321
      ///Push a new edge to the back of the path
hegyi@819
   322
hegyi@819
   323
      ///Push a new edge to the back of the path.
hegyi@819
   324
      ///\sa setStartNode
hegyi@819
   325
      void pushBack(const GraphEdge& e) {
hegyi@819
   326
	if( DM::consistensy_check && !empty() && P.gr->tail(e)!=to() ) {
hegyi@819
   327
	  fault("DirPath::Builder::pushBack: nonincident edge");
hegyi@819
   328
	}
hegyi@819
   329
	back.push_back(e);
hegyi@819
   330
      }
hegyi@819
   331
hegyi@819
   332
      ///Commit the changes to the path.
hegyi@819
   333
      void commit() {
hegyi@819
   334
	if( !(front.empty() && back.empty()) ) {
hegyi@819
   335
	  Container tmp;
hegyi@819
   336
	  tmp.reserve(front.size()+back.size()+P.length());
hegyi@819
   337
	  tmp.insert(tmp.end(), front.rbegin(), front.rend());
hegyi@819
   338
	  tmp.insert(tmp.end(), P.edges.begin(), P.edges.end());
hegyi@819
   339
	  tmp.insert(tmp.end(), back.begin(), back.end());
hegyi@819
   340
	  P.edges.swap(tmp);
hegyi@819
   341
	  front.clear();
hegyi@819
   342
	  back.clear();
hegyi@819
   343
	}
hegyi@819
   344
      }
hegyi@819
   345
hegyi@819
   346
      // FIXME: Hmm, pontosan hogy is kene ezt csinalni?
hegyi@819
   347
      // Hogy kenyelmes egy ilyet hasznalni?
hegyi@819
   348
  
hegyi@819
   349
      ///Reserve storage for the builder in advance.
hegyi@819
   350
hegyi@819
   351
      ///If you know an reasonable upper bound of the number of the edges
hegyi@819
   352
      ///to add, using this function you can speed up the building.
hegyi@819
   353
      void reserve(size_t r) {
hegyi@819
   354
	front.reserve(r);
hegyi@819
   355
	back.reserve(r);
hegyi@819
   356
      }
hegyi@819
   357
hegyi@819
   358
    private:
hegyi@819
   359
      bool empty() {
hegyi@819
   360
	return front.empty() && back.empty() && P.empty();
hegyi@819
   361
      }
hegyi@819
   362
hegyi@819
   363
      GraphNode from() const {
hegyi@819
   364
	if( ! front.empty() )
hegyi@819
   365
	  return P.gr->tail(front[front.size()-1]);
hegyi@819
   366
	else if( ! P.empty() )
hegyi@819
   367
	  return P.gr->tail(P.edges[0]);
hegyi@819
   368
	else if( ! back.empty() )
hegyi@819
   369
	  return P.gr->tail(back[0]);
hegyi@819
   370
	else
hegyi@819
   371
	  return INVALID;
hegyi@819
   372
      }
hegyi@819
   373
      GraphNode to() const {
hegyi@819
   374
	if( ! back.empty() )
hegyi@819
   375
	  return P.gr->head(back[back.size()-1]);
hegyi@819
   376
	else if( ! P.empty() )
hegyi@819
   377
	  return P.gr->head(P.edges[P.length()-1]);
hegyi@819
   378
	else if( ! front.empty() )
hegyi@819
   379
	  return P.gr->head(front[0]);
hegyi@819
   380
	else
hegyi@819
   381
	  return INVALID;
hegyi@819
   382
      }
hegyi@819
   383
hegyi@819
   384
    };
hegyi@819
   385
hegyi@819
   386
  };
hegyi@819
   387
hegyi@819
   388
hegyi@819
   389
hegyi@819
   390
hegyi@819
   391
hegyi@819
   392
hegyi@819
   393
hegyi@819
   394
hegyi@819
   395
hegyi@819
   396
hegyi@819
   397
  /**********************************************************************/
hegyi@819
   398
hegyi@819
   399
hegyi@819
   400
  //! \brief A structure for representing undirected path in a graph.
hegyi@819
   401
  //!
hegyi@819
   402
  //! A structure for representing undirected path in a graph. Ie. this is
hegyi@819
   403
  //! a path in a \e directed graph but the edges should not be directed
hegyi@819
   404
  //! forward.
hegyi@819
   405
  //!
hegyi@819
   406
  //! \param Graph The graph type in which the path is.
hegyi@819
   407
  //! \param DM DebugMode, defaults to DefaultDebugMode.
hegyi@819
   408
  //! 
hegyi@819
   409
  //! In a sense, the path can be treated as a graph, for is has \c NodeIt
hegyi@819
   410
  //! and \c EdgeIt with the same usage. These types converts to the \c Node
hegyi@819
   411
  //! and \c Edge of the original graph.
hegyi@819
   412
  //!
hegyi@819
   413
  //! \todo Thoroughfully check all the range and consistency tests.
hegyi@819
   414
  template<typename Graph, typename DM = DefaultDebugMode>
hegyi@819
   415
  class UndirPath {
hegyi@819
   416
  public:
hegyi@819
   417
    /// Edge type of the underlying graph.
hegyi@819
   418
    typedef typename Graph::Edge GraphEdge;
hegyi@819
   419
     /// Node type of the underlying graph.
hegyi@819
   420
   typedef typename Graph::Node GraphNode;
hegyi@819
   421
    class NodeIt;
hegyi@819
   422
    class EdgeIt;
hegyi@819
   423
hegyi@819
   424
  protected:
hegyi@819
   425
    const Graph *gr;
hegyi@819
   426
    typedef std::vector<GraphEdge> Container;
hegyi@819
   427
    Container edges;
hegyi@819
   428
hegyi@819
   429
  public:
hegyi@819
   430
hegyi@819
   431
    /// \param _G The graph in which the path is.
hegyi@819
   432
    ///
hegyi@819
   433
    UndirPath(const Graph &_G) : gr(&_G) {}
hegyi@819
   434
hegyi@819
   435
    /// \brief Subpath constructor.
hegyi@819
   436
    ///
hegyi@819
   437
    /// Subpath defined by two nodes.
hegyi@819
   438
    /// \warning It is an error if the two edges are not in order!
hegyi@819
   439
    UndirPath(const UndirPath &P, const NodeIt &a, const NodeIt &b) {
hegyi@819
   440
      if( DM::range_check && (!a.valid() || !b.valid) ) {
hegyi@819
   441
	// FIXME: this check should be more elaborate...
hegyi@819
   442
	fault("UndirPath, subpath ctor: invalid bounding nodes");
hegyi@819
   443
      }
hegyi@819
   444
      gr = P.gr;
hegyi@819
   445
      edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
hegyi@819
   446
    }
hegyi@819
   447
hegyi@819
   448
    /// \brief Subpath constructor.
hegyi@819
   449
    ///
hegyi@819
   450
    /// Subpath defined by two edges. Contains edges in [a,b)
hegyi@819
   451
    /// \warning It is an error if the two edges are not in order!
hegyi@819
   452
    UndirPath(const UndirPath &P, const EdgeIt &a, const EdgeIt &b) {
hegyi@819
   453
      if( DM::range_check && (!a.valid() || !b.valid) ) {
hegyi@819
   454
	// FIXME: this check should be more elaborate...
hegyi@819
   455
	fault("UndirPath, subpath ctor: invalid bounding nodes");
hegyi@819
   456
      }
hegyi@819
   457
      gr = P.gr;
hegyi@819
   458
      edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
hegyi@819
   459
    }
hegyi@819
   460
hegyi@819
   461
    /// Length of the path.
hegyi@819
   462
    size_t length() const { return edges.size(); }
hegyi@819
   463
    /// Returns whether the path is empty.
hegyi@819
   464
    bool empty() const { return edges.empty(); }
hegyi@819
   465
hegyi@819
   466
    /// Resets the path to an empty path.
hegyi@819
   467
    void clear() { edges.clear(); }
hegyi@819
   468
hegyi@819
   469
    /// \brief Starting point of the path.
hegyi@819
   470
    ///
hegyi@819
   471
    /// Starting point of the path.
hegyi@819
   472
    /// Returns INVALID if the path is empty.
hegyi@819
   473
    GraphNode from() const {
hegyi@819
   474
      return empty() ? INVALID : gr->tail(edges[0]);
hegyi@819
   475
    }
hegyi@819
   476
    /// \brief End point of the path.
hegyi@819
   477
    ///
hegyi@819
   478
    /// End point of the path.
hegyi@819
   479
    /// Returns INVALID if the path is empty.
hegyi@819
   480
    GraphNode to() const {
hegyi@819
   481
      return empty() ? INVALID : gr->head(edges[length()-1]);
hegyi@819
   482
    }
hegyi@819
   483
hegyi@819
   484
    /// \brief Initializes node or edge iterator to point to the first
hegyi@819
   485
    /// node or edge.
hegyi@819
   486
    ///
hegyi@819
   487
    /// \sa nth
hegyi@819
   488
    template<typename It>
hegyi@819
   489
    It& first(It &i) const { return i=It(*this); }
hegyi@819
   490
hegyi@819
   491
    /// \brief Initializes node iterator to point to the node of a given index.
hegyi@819
   492
    NodeIt& nth(NodeIt &i, int n) const {
hegyi@819
   493
      if( DM::range_check && (n<0 || n>int(length())) )
hegyi@819
   494
	fault("UndirPath::nth: index out of range");
hegyi@819
   495
      return i=NodeIt(*this, n);
hegyi@819
   496
    }
hegyi@819
   497
hegyi@819
   498
    /// \brief Initializes edge iterator to point to the edge of a given index.
hegyi@819
   499
    EdgeIt& nth(EdgeIt &i, int n) const {
hegyi@819
   500
      if( DM::range_check && (n<0 || n>=int(length())) )
hegyi@819
   501
	fault("UndirPath::nth: index out of range");
hegyi@819
   502
      return i=EdgeIt(*this, n);
hegyi@819
   503
    }
hegyi@819
   504
hegyi@819
   505
    /// Checks validity of a node or edge iterator.
hegyi@819
   506
    template<typename It>
hegyi@819
   507
    static
hegyi@819
   508
    bool valid(const It &i) { return i.valid(); }
hegyi@819
   509
hegyi@819
   510
    /// Steps the given node or edge iterator.
hegyi@819
   511
    template<typename It>
hegyi@819
   512
    static
hegyi@819
   513
    It& next(It &e) {
hegyi@819
   514
      if( DM::range_check && !e.valid() )
hegyi@819
   515
	fault("UndirPath::next() on invalid iterator");
hegyi@819
   516
      return ++e;
hegyi@819
   517
    }
hegyi@819
   518
hegyi@819
   519
    /// \brief Returns node iterator pointing to the head node of the
hegyi@819
   520
    /// given edge iterator.
hegyi@819
   521
    NodeIt head(const EdgeIt& e) const {
hegyi@819
   522
      if( DM::range_check && !e.valid() )
hegyi@819
   523
	fault("UndirPath::head() on invalid iterator");
hegyi@819
   524
      return NodeIt(*this, e.idx+1);
hegyi@819
   525
    }
hegyi@819
   526
hegyi@819
   527
    /// \brief Returns node iterator pointing to the tail node of the
hegyi@819
   528
    /// given edge iterator.
hegyi@819
   529
    NodeIt tail(const EdgeIt& e) const {
hegyi@819
   530
      if( DM::range_check && !e.valid() )
hegyi@819
   531
	fault("UndirPath::tail() on invalid iterator");
hegyi@819
   532
      return NodeIt(*this, e.idx);
hegyi@819
   533
    }
hegyi@819
   534
hegyi@819
   535
hegyi@819
   536
hegyi@819
   537
    /**
hegyi@819
   538
     * \brief Iterator class to iterate on the edges of the paths
hegyi@819
   539
     * 
hegyi@819
   540
     * \ingroup paths
hegyi@819
   541
     * This class is used to iterate on the edges of the paths
hegyi@819
   542
     *
hegyi@819
   543
     * Of course it converts to Graph::Edge
hegyi@819
   544
     * 
hegyi@819
   545
     * \todo Its interface differs from the standard edge iterator.
hegyi@819
   546
     * Yes, it shouldn't.
hegyi@819
   547
     */
hegyi@819
   548
    class EdgeIt {
hegyi@819
   549
      friend class UndirPath;
hegyi@819
   550
hegyi@819
   551
      int idx;
hegyi@819
   552
      const UndirPath *p;
hegyi@819
   553
    public:
hegyi@819
   554
      /// Default constructor
hegyi@819
   555
      EdgeIt() {}
hegyi@819
   556
      /// Invalid constructor
hegyi@819
   557
      EdgeIt(Invalid) : idx(-1), p(0) {}
hegyi@819
   558
      /// Constructor with starting point
hegyi@819
   559
      EdgeIt(const UndirPath &_p, int _idx = 0) :
hegyi@819
   560
	idx(_idx), p(&_p) { validate(); }
hegyi@819
   561
hegyi@819
   562
      ///Validity check
hegyi@819
   563
      bool valid() const { return idx!=-1; }
hegyi@819
   564
hegyi@819
   565
      ///Conversion to Graph::Edge
hegyi@819
   566
      operator GraphEdge () const {
hegyi@819
   567
	return valid() ? p->edges[idx] : INVALID;
hegyi@819
   568
      }
hegyi@819
   569
      /// Next edge
hegyi@819
   570
     EdgeIt& operator++() { ++idx; validate(); return *this; }
hegyi@819
   571
hegyi@819
   572
      /// Comparison operator
hegyi@819
   573
      bool operator==(const EdgeIt& e) const { return idx==e.idx; }
hegyi@819
   574
      /// Comparison operator
hegyi@819
   575
      bool operator!=(const EdgeIt& e) const { return idx!=e.idx; }
hegyi@819
   576
      /// Comparison operator
hegyi@819
   577
      bool operator<(const EdgeIt& e) const { return idx<e.idx; }
hegyi@819
   578
hegyi@819
   579
    private:
hegyi@819
   580
      // FIXME: comparison between signed and unsigned...
hegyi@819
   581
      // Jo ez igy? Vagy esetleg legyen a length() int?
hegyi@819
   582
      void validate() { if( size_t(idx) >= p->length() ) idx=-1; }
hegyi@819
   583
    };
hegyi@819
   584
hegyi@819
   585
    /**
hegyi@819
   586
     * \brief Iterator class to iterate on the nodes of the paths
hegyi@819
   587
     * 
hegyi@819
   588
     * \ingroup paths
hegyi@819
   589
     * This class is used to iterate on the nodes of the paths
hegyi@819
   590
     *
hegyi@819
   591
     * Of course it converts to Graph::Node
hegyi@819
   592
     * 
hegyi@819
   593
     * \todo Its interface differs from the standard node iterator.
hegyi@819
   594
     * Yes, it shouldn't.
hegyi@819
   595
     */
hegyi@819
   596
    class NodeIt {
hegyi@819
   597
      friend class UndirPath;
hegyi@819
   598
hegyi@819
   599
      int idx;
hegyi@819
   600
      const UndirPath *p;
hegyi@819
   601
    public:
hegyi@819
   602
      /// Default constructor
hegyi@819
   603
      NodeIt() {}
hegyi@819
   604
      /// Invalid constructor
hegyi@819
   605
      NodeIt(Invalid) : idx(-1), p(0) {}
hegyi@819
   606
      /// Constructor with starting point
hegyi@819
   607
      NodeIt(const UndirPath &_p, int _idx = 0) :
hegyi@819
   608
	idx(_idx), p(&_p) { validate(); }
hegyi@819
   609
hegyi@819
   610
      ///Validity check
hegyi@819
   611
      bool valid() const { return idx!=-1; }
hegyi@819
   612
hegyi@819
   613
      ///Conversion to Graph::Node
hegyi@819
   614
      operator const GraphNode& () const {
hegyi@819
   615
	if(idx >= p->length())
hegyi@819
   616
	  return p->to();
hegyi@819
   617
	else if(idx >= 0)
hegyi@819
   618
	  return p->gr->tail(p->edges[idx]);
hegyi@819
   619
	else
hegyi@819
   620
	  return INVALID;
hegyi@819
   621
      }
hegyi@819
   622
      /// Next node
hegyi@819
   623
      NodeIt& operator++() { ++idx; validate(); return *this; }
hegyi@819
   624
hegyi@819
   625
      /// Comparison operator
hegyi@819
   626
      bool operator==(const NodeIt& e) const { return idx==e.idx; }
hegyi@819
   627
      /// Comparison operator
hegyi@819
   628
      bool operator!=(const NodeIt& e) const { return idx!=e.idx; }
hegyi@819
   629
       /// Comparison operator
hegyi@819
   630
     bool operator<(const NodeIt& e) const { return idx<e.idx; }
hegyi@819
   631
hegyi@819
   632
    private:
hegyi@819
   633
      void validate() { if( size_t(idx) > p->length() ) idx=-1; }
hegyi@819
   634
    };
hegyi@819
   635
hegyi@819
   636
    friend class Builder;    
hegyi@819
   637
hegyi@819
   638
    /**
hegyi@819
   639
     * \brief Class to build paths
hegyi@819
   640
     * 
hegyi@819
   641
     * \ingroup paths
hegyi@819
   642
     * This class is used to fill a path with edges.
hegyi@819
   643
     *
hegyi@819
   644
     * You can push new edges to the front and to the back of the path in
hegyi@819
   645
     * arbitrary order then you should commit these changes to the graph.
hegyi@819
   646
     *
hegyi@819
   647
     * Fundamentally, for most "Paths" (classes fulfilling the
hegyi@819
   648
     * PathConcept) while the builder is active (after the first modifying
hegyi@819
   649
     * operation and until the commit()) the original Path is in a
hegyi@819
   650
     * "transitional" state (operations ot it have undefined result). But
hegyi@819
   651
     * in the case of UndirPath the original path is unchanged until the
hegyi@819
   652
     * commit. However we don't recomend that you use this feature.
hegyi@819
   653
     */
hegyi@819
   654
    class Builder {
hegyi@819
   655
      UndirPath &P;
hegyi@819
   656
      Container front, back;
hegyi@819
   657
hegyi@819
   658
    public:
hegyi@819
   659
      ///\param _P the path you want to fill in.
hegyi@819
   660
      ///
hegyi@819
   661
      Builder(UndirPath &_P) : P(_P) {}
hegyi@819
   662
hegyi@819
   663
      /// Sets the starting node of the path.
hegyi@819
   664
      
hegyi@819
   665
      /// Sets the starting node of the path. Edge added to the path
hegyi@819
   666
      /// afterwards have to be incident to this node.
hegyi@819
   667
      /// It should be called iff the path is empty and before any call to
hegyi@819
   668
      /// \ref pushFront() or \ref pushBack()
hegyi@819
   669
      void setStartNode(const GraphNode &) {}
hegyi@819
   670
hegyi@819
   671
      ///Push a new edge to the front of the path
hegyi@819
   672
hegyi@819
   673
      ///Push a new edge to the front of the path.
hegyi@819
   674
      ///\sa setStartNode
hegyi@819
   675
      void pushFront(const GraphEdge& e) {
hegyi@819
   676
	if( DM::consistensy_check && !empty() && P.gr->head(e)!=from() ) {
hegyi@819
   677
	  fault("UndirPath::Builder::pushFront: nonincident edge");
hegyi@819
   678
	}
hegyi@819
   679
	front.push_back(e);
hegyi@819
   680
      }
hegyi@819
   681
hegyi@819
   682
      ///Push a new edge to the back of the path
hegyi@819
   683
hegyi@819
   684
      ///Push a new edge to the back of the path.
hegyi@819
   685
      ///\sa setStartNode
hegyi@819
   686
      void pushBack(const GraphEdge& e) {
hegyi@819
   687
	if( DM::consistensy_check && !empty() && P.gr->tail(e)!=to() ) {
hegyi@819
   688
	  fault("UndirPath::Builder::pushBack: nonincident edge");
hegyi@819
   689
	}
hegyi@819
   690
	back.push_back(e);
hegyi@819
   691
      }
hegyi@819
   692
hegyi@819
   693
      ///Commit the changes to the path.
hegyi@819
   694
      void commit() {
hegyi@819
   695
	if( !(front.empty() && back.empty()) ) {
hegyi@819
   696
	  Container tmp;
hegyi@819
   697
	  tmp.reserve(front.size()+back.size()+P.length());
hegyi@819
   698
	  tmp.insert(tmp.end(), front.rbegin(), front.rend());
hegyi@819
   699
	  tmp.insert(tmp.end(), P.edges.begin(), P.edges.end());
hegyi@819
   700
	  tmp.insert(tmp.end(), back.begin(), back.end());
hegyi@819
   701
	  P.edges.swap(tmp);
hegyi@819
   702
	  front.clear();
hegyi@819
   703
	  back.clear();
hegyi@819
   704
	}
hegyi@819
   705
      }
hegyi@819
   706
hegyi@819
   707
      // FIXME: Hmm, pontosan hogy is kene ezt csinalni?
hegyi@819
   708
      // Hogy kenyelmes egy ilyet hasznalni?
hegyi@819
   709
hegyi@819
   710
      ///Reserve storage for the builder in advance.
hegyi@819
   711
hegyi@819
   712
      ///If you know an reasonable upper bound of the number of the edges
hegyi@819
   713
      ///to add, using this function you can speed up the building.
hegyi@819
   714
       void reserve(size_t r) {
hegyi@819
   715
	front.reserve(r);
hegyi@819
   716
	back.reserve(r);
hegyi@819
   717
      }
hegyi@819
   718
hegyi@819
   719
    private:
hegyi@819
   720
      bool empty() {
hegyi@819
   721
	return front.empty() && back.empty() && P.empty();
hegyi@819
   722
      }
hegyi@819
   723
hegyi@819
   724
      GraphNode from() const {
hegyi@819
   725
	if( ! front.empty() )
hegyi@819
   726
	  return P.gr->tail(front[front.size()-1]);
hegyi@819
   727
	else if( ! P.empty() )
hegyi@819
   728
	  return P.gr->tail(P.edges[0]);
hegyi@819
   729
	else if( ! back.empty() )
hegyi@819
   730
	  return P.gr->tail(back[0]);
hegyi@819
   731
	else
hegyi@819
   732
	  return INVALID;
hegyi@819
   733
      }
hegyi@819
   734
      GraphNode to() const {
hegyi@819
   735
	if( ! back.empty() )
hegyi@819
   736
	  return P.gr->head(back[back.size()-1]);
hegyi@819
   737
	else if( ! P.empty() )
hegyi@819
   738
	  return P.gr->head(P.edges[P.length()-1]);
hegyi@819
   739
	else if( ! front.empty() )
hegyi@819
   740
	  return P.gr->head(front[0]);
hegyi@819
   741
	else
hegyi@819
   742
	  return INVALID;
hegyi@819
   743
      }
hegyi@819
   744
hegyi@819
   745
    };
hegyi@819
   746
hegyi@819
   747
  };
hegyi@819
   748
hegyi@819
   749
hegyi@819
   750
hegyi@819
   751
hegyi@819
   752
hegyi@819
   753
hegyi@819
   754
hegyi@819
   755
hegyi@819
   756
hegyi@819
   757
hegyi@819
   758
  /**********************************************************************/
hegyi@819
   759
hegyi@819
   760
hegyi@819
   761
  /* Ennek az allocatorosdinak sokkal jobban utana kene nezni a hasznalata
hegyi@819
   762
     elott. Eleg bonyinak nez ki, ahogyan azokat az STL-ben hasznaljak. */
hegyi@819
   763
hegyi@819
   764
  template<typename Graph>
hegyi@819
   765
  class DynamicPath {
hegyi@819
   766
hegyi@819
   767
  public:
hegyi@819
   768
    typedef typename Graph::Edge GraphEdge;
hegyi@819
   769
    typedef typename Graph::Node GraphNode;
hegyi@819
   770
    class NodeIt;
hegyi@819
   771
    class EdgeIt;
hegyi@819
   772
hegyi@819
   773
  protected:
hegyi@819
   774
    Graph& G;
hegyi@819
   775
    // FIXME: ehelyett eleg lenne tarolni ket boolt: a ket szelso el
hegyi@819
   776
    // iranyitasat:
hegyi@819
   777
    GraphNode _first, _last;
hegyi@819
   778
    typedef std::deque<GraphEdge> Container;
hegyi@819
   779
    Container edges;
hegyi@819
   780
hegyi@819
   781
  public:
hegyi@819
   782
hegyi@819
   783
    DynamicPath(Graph &_G) : G(_G), _first(INVALID), _last(INVALID) {}
hegyi@819
   784
hegyi@819
   785
    /// Subpath defined by two nodes.
hegyi@819
   786
    /// Nodes may be in reversed order, then
hegyi@819
   787
    /// we contstruct the reversed path.
hegyi@819
   788
    DynamicPath(const DynamicPath &P, const NodeIt &a, const NodeIt &b);
hegyi@819
   789
    /// Subpath defined by two edges. Contains edges in [a,b)
hegyi@819
   790
    /// It is an error if the two edges are not in order!
hegyi@819
   791
    DynamicPath(const DynamicPath &P, const EdgeIt &a, const EdgeIt &b);
hegyi@819
   792
    
hegyi@819
   793
    size_t length() const { return edges.size(); }
hegyi@819
   794
    GraphNode from() const { return _first; }
hegyi@819
   795
    GraphNode to() const { return _last; }
hegyi@819
   796
hegyi@819
   797
    NodeIt& first(NodeIt &n) const { return nth(n, 0); }
hegyi@819
   798
    EdgeIt& first(EdgeIt &e) const { return nth(e, 0); }
hegyi@819
   799
    template<typename It>
hegyi@819
   800
    It first() const { 
hegyi@819
   801
      It e;
hegyi@819
   802
      first(e);
hegyi@819
   803
      return e; 
hegyi@819
   804
    }
hegyi@819
   805
hegyi@819
   806
    NodeIt& nth(NodeIt &, size_t) const;
hegyi@819
   807
    EdgeIt& nth(EdgeIt &, size_t) const;
hegyi@819
   808
    template<typename It>
hegyi@819
   809
    It nth(size_t n) const { 
hegyi@819
   810
      It e;
hegyi@819
   811
      nth(e, n);
hegyi@819
   812
      return e; 
hegyi@819
   813
    }
hegyi@819
   814
hegyi@819
   815
    bool valid(const NodeIt &n) const { return n.idx <= length(); }
hegyi@819
   816
    bool valid(const EdgeIt &e) const { return e.it < edges.end(); }
hegyi@819
   817
hegyi@819
   818
    bool isForward(const EdgeIt &e) const { return e.forw; }
hegyi@819
   819
hegyi@819
   820
    /// index of a node on the path. Returns length+2 for the invalid NodeIt
hegyi@819
   821
    int index(const NodeIt &n) const { return n.idx; }
hegyi@819
   822
    /// index of an edge on the path. Returns length+1 for the invalid EdgeIt
hegyi@819
   823
    int index(const EdgeIt &e) const { return e.it - edges.begin(); }
hegyi@819
   824
hegyi@819
   825
    EdgeIt& next(EdgeIt &e) const;
hegyi@819
   826
    NodeIt& next(NodeIt &n) const;
hegyi@819
   827
    template <typename It>
hegyi@819
   828
    It getNext(It it) const {
hegyi@819
   829
      It tmp(it); return next(tmp);
hegyi@819
   830
    }
hegyi@819
   831
hegyi@819
   832
    // A path is constructed using the following four functions.
hegyi@819
   833
    // They return false if the requested operation is inconsistent
hegyi@819
   834
    // with the path constructed so far.
hegyi@819
   835
    // If your path has only one edge you MUST set either "from" or "to"!
hegyi@819
   836
    // So you probably SHOULD call it in any case to be safe (and check the
hegyi@819
   837
    // returned value to check if your path is consistent with your idea).
hegyi@819
   838
    bool pushFront(const GraphEdge &e);
hegyi@819
   839
    bool pushBack(const GraphEdge &e);
hegyi@819
   840
    bool setFrom(const GraphNode &n);
hegyi@819
   841
    bool setTo(const GraphNode &n);
hegyi@819
   842
hegyi@819
   843
    // WARNING: these two functions return the head/tail of an edge with
hegyi@819
   844
    // respect to the direction of the path!
hegyi@819
   845
    // So G.head(P.graphEdge(e)) == P.graphNode(P.head(e)) holds only if 
hegyi@819
   846
    // P.forward(e) is true (or the edge is a loop)!
hegyi@819
   847
    NodeIt head(const EdgeIt& e) const;
hegyi@819
   848
    NodeIt tail(const EdgeIt& e) const;
hegyi@819
   849
hegyi@819
   850
    // FIXME: ezeknek valami jobb nev kellene!!!
hegyi@819
   851
    GraphEdge graphEdge(const EdgeIt& e) const;
hegyi@819
   852
    GraphNode graphNode(const NodeIt& n) const;
hegyi@819
   853
hegyi@819
   854
hegyi@819
   855
    /*** Iterator classes ***/
hegyi@819
   856
    class EdgeIt {
hegyi@819
   857
      friend class DynamicPath;
hegyi@819
   858
hegyi@819
   859
      typename Container::const_iterator it;
hegyi@819
   860
      bool forw;
hegyi@819
   861
    public:
hegyi@819
   862
      // FIXME: jarna neki ilyen is...
hegyi@819
   863
      // EdgeIt(Invalid);
hegyi@819
   864
hegyi@819
   865
      bool forward() const { return forw; }
hegyi@819
   866
hegyi@819
   867
      bool operator==(const EdgeIt& e) const { return it==e.it; }
hegyi@819
   868
      bool operator!=(const EdgeIt& e) const { return it!=e.it; }
hegyi@819
   869
      bool operator<(const EdgeIt& e) const { return it<e.it; }
hegyi@819
   870
    };
hegyi@819
   871
hegyi@819
   872
    class NodeIt {
hegyi@819
   873
      friend class DynamicPath;
hegyi@819
   874
hegyi@819
   875
      size_t idx;
hegyi@819
   876
      bool tail;  // Is this node the tail of the edge with same idx?
hegyi@819
   877
hegyi@819
   878
    public:
hegyi@819
   879
      // FIXME: jarna neki ilyen is...
hegyi@819
   880
      // NodeIt(Invalid);
hegyi@819
   881
hegyi@819
   882
      bool operator==(const NodeIt& n) const { return idx==n.idx; }
hegyi@819
   883
      bool operator!=(const NodeIt& n) const { return idx!=n.idx; }
hegyi@819
   884
      bool operator<(const NodeIt& n) const { return idx<n.idx; }
hegyi@819
   885
    };
hegyi@819
   886
hegyi@819
   887
  private:
hegyi@819
   888
    bool edgeIncident(const GraphEdge &e, const GraphNode &a,
hegyi@819
   889
		      GraphNode &b);
hegyi@819
   890
    bool connectTwoEdges(const GraphEdge &e, const GraphEdge &f);
hegyi@819
   891
  };
hegyi@819
   892
hegyi@819
   893
  template<typename Gr>
hegyi@819
   894
  typename DynamicPath<Gr>::EdgeIt&
hegyi@819
   895
  DynamicPath<Gr>::next(DynamicPath::EdgeIt &e) const {
hegyi@819
   896
    if( e.it == edges.end() ) 
hegyi@819
   897
      return e;
hegyi@819
   898
hegyi@819
   899
    GraphNode common_node = ( e.forw ? G.head(*e.it) : G.tail(*e.it) );
hegyi@819
   900
    ++e.it;
hegyi@819
   901
hegyi@819
   902
    // Invalid edgeit is always forward :)
hegyi@819
   903
    if( e.it == edges.end() ) {
hegyi@819
   904
      e.forw = true;
hegyi@819
   905
      return e;
hegyi@819
   906
    }
hegyi@819
   907
hegyi@819
   908
    e.forw = ( G.tail(*e.it) == common_node );
hegyi@819
   909
    return e;
hegyi@819
   910
  }
hegyi@819
   911
hegyi@819
   912
  template<typename Gr>
hegyi@819
   913
  typename DynamicPath<Gr>::NodeIt& DynamicPath<Gr>::next(NodeIt &n) const {
hegyi@819
   914
    if( n.idx >= length() ) {
hegyi@819
   915
      // FIXME: invalid
hegyi@819
   916
      n.idx = length()+1;
hegyi@819
   917
      return n;
hegyi@819
   918
    }
hegyi@819
   919
hegyi@819
   920
    
hegyi@819
   921
    GraphNode next_node = ( n.tail ? G.head(edges[n.idx]) :
hegyi@819
   922
			      G.tail(edges[n.idx]) );
hegyi@819
   923
    ++n.idx;
hegyi@819
   924
    if( n.idx < length() ) {
hegyi@819
   925
      n.tail = ( next_node == G.tail(edges[n.idx]) );
hegyi@819
   926
    }
hegyi@819
   927
    else {
hegyi@819
   928
      n.tail = true;
hegyi@819
   929
    }
hegyi@819
   930
hegyi@819
   931
    return n;
hegyi@819
   932
  }
hegyi@819
   933
hegyi@819
   934
  template<typename Gr>
hegyi@819
   935
  bool DynamicPath<Gr>::edgeIncident(const GraphEdge &e, const GraphNode &a,
hegyi@819
   936
			  GraphNode &b) {
hegyi@819
   937
    if( G.tail(e) == a ) {
hegyi@819
   938
      b=G.head(e);
hegyi@819
   939
      return true;
hegyi@819
   940
    }
hegyi@819
   941
    if( G.head(e) == a ) {
hegyi@819
   942
      b=G.tail(e);
hegyi@819
   943
      return true;
hegyi@819
   944
    }
hegyi@819
   945
    return false;
hegyi@819
   946
  }
hegyi@819
   947
hegyi@819
   948
  template<typename Gr>
hegyi@819
   949
  bool DynamicPath<Gr>::connectTwoEdges(const GraphEdge &e,
hegyi@819
   950
			     const GraphEdge &f) {
hegyi@819
   951
    if( edgeIncident(f, G.tail(e), _last) ) {
hegyi@819
   952
      _first = G.head(e);
hegyi@819
   953
      return true;
hegyi@819
   954
    }
hegyi@819
   955
    if( edgeIncident(f, G.head(e), _last) ) {
hegyi@819
   956
      _first = G.tail(e);
hegyi@819
   957
      return true;
hegyi@819
   958
    }
hegyi@819
   959
    return false;
hegyi@819
   960
  }
hegyi@819
   961
hegyi@819
   962
  template<typename Gr>
hegyi@819
   963
  bool DynamicPath<Gr>::pushFront(const GraphEdge &e) {
hegyi@819
   964
    if( G.valid(_first) ) {
hegyi@819
   965
	if( edgeIncident(e, _first, _first) ) {
hegyi@819
   966
	  edges.push_front(e);
hegyi@819
   967
	  return true;
hegyi@819
   968
	}
hegyi@819
   969
	else
hegyi@819
   970
	  return false;
hegyi@819
   971
    }
hegyi@819
   972
    else if( length() < 1 || connectTwoEdges(e, edges[0]) ) {
hegyi@819
   973
      edges.push_front(e);
hegyi@819
   974
      return true;
hegyi@819
   975
    }
hegyi@819
   976
    else
hegyi@819
   977
      return false;
hegyi@819
   978
  }
hegyi@819
   979
hegyi@819
   980
  template<typename Gr>
hegyi@819
   981
  bool DynamicPath<Gr>::pushBack(const GraphEdge &e) {
hegyi@819
   982
    if( G.valid(_last) ) {
hegyi@819
   983
	if( edgeIncident(e, _last, _last) ) {
hegyi@819
   984
	  edges.push_back(e);
hegyi@819
   985
	  return true;
hegyi@819
   986
	}
hegyi@819
   987
	else
hegyi@819
   988
	  return false;
hegyi@819
   989
    }
hegyi@819
   990
    else if( length() < 1 || connectTwoEdges(edges[0], e) ) {
hegyi@819
   991
      edges.push_back(e);
hegyi@819
   992
      return true;
hegyi@819
   993
    }
hegyi@819
   994
    else
hegyi@819
   995
      return false;
hegyi@819
   996
  }
hegyi@819
   997
hegyi@819
   998
hegyi@819
   999
  template<typename Gr>
hegyi@819
  1000
  bool DynamicPath<Gr>::setFrom(const GraphNode &n) {
hegyi@819
  1001
    if( G.valid(_first) ) {
hegyi@819
  1002
      return _first == n;
hegyi@819
  1003
    }
hegyi@819
  1004
    else {
hegyi@819
  1005
      if( length() > 0) {
hegyi@819
  1006
	if( edgeIncident(edges[0], n, _last) ) {
hegyi@819
  1007
	  _first = n;
hegyi@819
  1008
	  return true;
hegyi@819
  1009
	}
hegyi@819
  1010
	else return false;
hegyi@819
  1011
      }
hegyi@819
  1012
      else {
hegyi@819
  1013
	_first = _last = n;
hegyi@819
  1014
	return true;
hegyi@819
  1015
      }
hegyi@819
  1016
    }
hegyi@819
  1017
  }
hegyi@819
  1018
hegyi@819
  1019
  template<typename Gr>
hegyi@819
  1020
  bool DynamicPath<Gr>::setTo(const GraphNode &n) {
hegyi@819
  1021
    if( G.valid(_last) ) {
hegyi@819
  1022
      return _last == n;
hegyi@819
  1023
    }
hegyi@819
  1024
    else {
hegyi@819
  1025
      if( length() > 0) {
hegyi@819
  1026
	if( edgeIncident(edges[0], n, _first) ) {
hegyi@819
  1027
	  _last = n;
hegyi@819
  1028
	  return true;
hegyi@819
  1029
	}
hegyi@819
  1030
	else return false;
hegyi@819
  1031
      }
hegyi@819
  1032
      else {
hegyi@819
  1033
	_first = _last = n;
hegyi@819
  1034
	return true;
hegyi@819
  1035
      }
hegyi@819
  1036
    }
hegyi@819
  1037
  }
hegyi@819
  1038
hegyi@819
  1039
hegyi@819
  1040
  template<typename Gr>
hegyi@819
  1041
  typename DynamicPath<Gr>::NodeIt
hegyi@819
  1042
  DynamicPath<Gr>::tail(const EdgeIt& e) const {
hegyi@819
  1043
    NodeIt n;
hegyi@819
  1044
hegyi@819
  1045
    if( e.it == edges.end() ) {
hegyi@819
  1046
      // FIXME: invalid-> invalid
hegyi@819
  1047
      n.idx = length() + 1;
hegyi@819
  1048
      n.tail = true;
hegyi@819
  1049
      return n;
hegyi@819
  1050
    }
hegyi@819
  1051
hegyi@819
  1052
    n.idx = e.it-edges.begin();
hegyi@819
  1053
    n.tail = e.forw;
hegyi@819
  1054
    return n;
hegyi@819
  1055
  }
hegyi@819
  1056
hegyi@819
  1057
  template<typename Gr>
hegyi@819
  1058
  typename DynamicPath<Gr>::NodeIt
hegyi@819
  1059
  DynamicPath<Gr>::head(const EdgeIt& e) const {
hegyi@819
  1060
    if( e.it == edges.end()-1 ) {
hegyi@819
  1061
      return _last;
hegyi@819
  1062
    }
hegyi@819
  1063
hegyi@819
  1064
    EdgeIt next_edge = e;
hegyi@819
  1065
    next(next_edge);
hegyi@819
  1066
    return tail(next_edge);
hegyi@819
  1067
  }
hegyi@819
  1068
      
hegyi@819
  1069
  template<typename Gr>
hegyi@819
  1070
  typename DynamicPath<Gr>::GraphEdge
hegyi@819
  1071
  DynamicPath<Gr>::graphEdge(const EdgeIt& e) const {
hegyi@819
  1072
    if( e.it != edges.end() ) {
hegyi@819
  1073
      return *e.it;
hegyi@819
  1074
    }
hegyi@819
  1075
    else {
hegyi@819
  1076
      return INVALID;
hegyi@819
  1077
    }
hegyi@819
  1078
  }
hegyi@819
  1079
  
hegyi@819
  1080
  template<typename Gr>
hegyi@819
  1081
  typename DynamicPath<Gr>::GraphNode
hegyi@819
  1082
  DynamicPath<Gr>::graphNode(const NodeIt& n) const {
hegyi@819
  1083
    if( n.idx < length() ) {
hegyi@819
  1084
      return n.tail ? G.tail(edges[n.idx]) : G.head(edges[n.idx]);
hegyi@819
  1085
    }
hegyi@819
  1086
    else if( n.idx == length() ) {
hegyi@819
  1087
      return _last;
hegyi@819
  1088
    }
hegyi@819
  1089
    else {
hegyi@819
  1090
      return INVALID;
hegyi@819
  1091
    }
hegyi@819
  1092
  }
hegyi@819
  1093
hegyi@819
  1094
  template<typename Gr>
hegyi@819
  1095
  typename DynamicPath<Gr>::EdgeIt&
hegyi@819
  1096
  DynamicPath<Gr>::nth(EdgeIt &e, size_t k) const {
hegyi@819
  1097
    if( k>=length() ) {
hegyi@819
  1098
      // FIXME: invalid EdgeIt
hegyi@819
  1099
      e.it = edges.end();
hegyi@819
  1100
      e.forw = true;
hegyi@819
  1101
      return e;
hegyi@819
  1102
    }
hegyi@819
  1103
hegyi@819
  1104
    e.it = edges.begin()+k;
hegyi@819
  1105
    if(k==0) {
hegyi@819
  1106
      e.forw = ( G.tail(*e.it) == _first );
hegyi@819
  1107
    }
hegyi@819
  1108
    else {
hegyi@819
  1109
      e.forw = ( G.tail(*e.it) == G.tail(edges[k-1]) ||
hegyi@819
  1110
		 G.tail(*e.it) == G.head(edges[k-1]) );
hegyi@819
  1111
    }
hegyi@819
  1112
    return e;
hegyi@819
  1113
  }
hegyi@819
  1114
    
hegyi@819
  1115
  template<typename Gr>
hegyi@819
  1116
  typename DynamicPath<Gr>::NodeIt&
hegyi@819
  1117
  DynamicPath<Gr>::nth(NodeIt &n, size_t k) const {
hegyi@819
  1118
    if( k>length() ) {
hegyi@819
  1119
      // FIXME: invalid NodeIt
hegyi@819
  1120
      n.idx = length()+1;
hegyi@819
  1121
      n.tail = true;
hegyi@819
  1122
      return n;
hegyi@819
  1123
    }
hegyi@819
  1124
    if( k==length() ) {
hegyi@819
  1125
      n.idx = length();
hegyi@819
  1126
      n.tail = true;
hegyi@819
  1127
      return n;
hegyi@819
  1128
    }
hegyi@819
  1129
    n = tail(nth<EdgeIt>(k));
hegyi@819
  1130
    return n;
hegyi@819
  1131
  }
hegyi@819
  1132
hegyi@819
  1133
  // Reszut konstruktorok:
hegyi@819
  1134
hegyi@819
  1135
hegyi@819
  1136
  template<typename Gr>
hegyi@819
  1137
  DynamicPath<Gr>::DynamicPath(const DynamicPath &P, const EdgeIt &a,
hegyi@819
  1138
			       const EdgeIt &b) :
hegyi@819
  1139
    G(P.G), edges(a.it, b.it)    // WARNING: if b.it < a.it this will blow up! 
hegyi@819
  1140
  {
hegyi@819
  1141
    if( G.valid(P._first) && a.it < P.edges.end() ) {
hegyi@819
  1142
      _first = ( a.forw ? G.tail(*a.it) : G.head(*a.it) );
hegyi@819
  1143
      if( b.it < P.edges.end() ) {
hegyi@819
  1144
	_last = ( b.forw ? G.tail(*b.it) : G.head(*b.it) );
hegyi@819
  1145
      }
hegyi@819
  1146
      else {
hegyi@819
  1147
	_last = P._last;
hegyi@819
  1148
      }
hegyi@819
  1149
    }
hegyi@819
  1150
  }
hegyi@819
  1151
hegyi@819
  1152
  template<typename Gr>
hegyi@819
  1153
  DynamicPath<Gr>::DynamicPath(const DynamicPath &P, const NodeIt &a,
hegyi@819
  1154
			       const NodeIt &b) : G(P.G)
hegyi@819
  1155
  {
hegyi@819
  1156
    if( !P.valid(a) || !P.valid(b) )
hegyi@819
  1157
      return;
hegyi@819
  1158
hegyi@819
  1159
    int ai = a.idx, bi = b.idx;
hegyi@819
  1160
    if( bi<ai )
hegyi@819
  1161
      std::swap(ai,bi);
hegyi@819
  1162
    
hegyi@819
  1163
    edges.resize(bi-ai);
hegyi@819
  1164
    copy(P.edges.begin()+ai, P.edges.begin()+bi, edges.begin());
hegyi@819
  1165
hegyi@819
  1166
    _first = P.graphNode(a);
hegyi@819
  1167
    _last = P.graphNode(b);
hegyi@819
  1168
  }
hegyi@819
  1169
hegyi@819
  1170
  ///@}
hegyi@819
  1171
hegyi@819
  1172
} // namespace hugo
hegyi@819
  1173
hegyi@819
  1174
#endif // HUGO_PATH_H