src/work/klao/path.h
author klao
Wed, 21 Apr 2004 19:10:59 +0000
changeset 366 be6fe0ea99b5
parent 226 616bc397c83a
child 369 dc9c19f4ca9a
permissions -rw-r--r--
Test for the new style iter
klao@225
     1
// -*- c++ -*- //
klao@225
     2
klao@225
     3
/**
klao@225
     4
 *
klao@225
     5
 * Class for representing paths in graphs.
klao@225
     6
 *
klao@225
     7
 */
klao@225
     8
klao@225
     9
#ifndef HUGO_PATH_H
klao@225
    10
#define HUGO_PATH_H
klao@225
    11
klao@225
    12
#include <deque>
klao@226
    13
#include <algorithm>
klao@225
    14
klao@225
    15
#include <invalid.h>
klao@225
    16
klao@225
    17
namespace hugo {
klao@225
    18
klao@225
    19
  /* Ennek az allocatorosdinak sokkal jobban utana kene nezni a hasznalata
klao@225
    20
     elott. Eleg bonyinak nez ki, ahogyan azokat az STL-ben hasznaljak. */
klao@225
    21
klao@225
    22
  template<typename Graph>
klao@225
    23
  class Path {
klao@225
    24
klao@225
    25
  public:
klao@225
    26
    typedef typename Graph::Edge GraphEdge;
klao@225
    27
    typedef typename Graph::Node GraphNode;
klao@225
    28
    class NodeIt;
klao@225
    29
    class EdgeIt;
klao@225
    30
klao@225
    31
  protected:
klao@225
    32
    Graph& G;
klao@225
    33
    // FIXME: ehelyett eleg lenne tarolni ket boolt: a ket szelso el
klao@225
    34
    // iranyitasat:
klao@225
    35
    GraphNode _first, _last;
klao@225
    36
    typedef std::deque<GraphEdge> Container;
klao@225
    37
    Container edges;
klao@225
    38
klao@225
    39
  public:
klao@225
    40
klao@225
    41
    Path(Graph &_G) : G(_G), _first(INVALID), _last(INVALID) {}
klao@225
    42
klao@226
    43
    /// Subpath defined by two nodes.
klao@226
    44
    /// Nodes may be in reversed order, then
klao@226
    45
    /// we contstruct the reversed path.
klao@226
    46
    Path(const Path &P, const NodeIt &a, const NodeIt &b);
klao@226
    47
    /// Subpath defined by two edges. Contains edges in [a,b)
klao@226
    48
    /// It is an error if the two edges are not in order!
klao@226
    49
    Path(const Path &P, const EdgeIt &a, const EdgeIt &b);
klao@225
    50
    
klao@225
    51
    size_t length() const { return edges.size(); }
klao@225
    52
    GraphNode from() const { return _first; }
klao@225
    53
    GraphNode to() const { return _last; }
klao@225
    54
klao@225
    55
    NodeIt& first(NodeIt &n) const { return nth(n, 0); }
klao@225
    56
    EdgeIt& first(EdgeIt &e) const { return nth(e, 0); }
klao@225
    57
    template<typename It>
klao@225
    58
    It first() const { 
klao@225
    59
      It e;
klao@225
    60
      first(e);
klao@225
    61
      return e; 
klao@225
    62
    }
klao@225
    63
klao@225
    64
    NodeIt& nth(NodeIt &, size_t) const;
klao@225
    65
    EdgeIt& nth(EdgeIt &, size_t) const;
klao@225
    66
    template<typename It>
klao@225
    67
    It nth(size_t n) const { 
klao@225
    68
      It e;
klao@225
    69
      nth(e, n);
klao@225
    70
      return e; 
klao@225
    71
    }
klao@225
    72
klao@225
    73
    bool valid(const NodeIt &n) const { return n.idx <= length(); }
klao@225
    74
    bool valid(const EdgeIt &e) const { return e.it < edges.end(); }
klao@225
    75
klao@225
    76
    bool isForward(const EdgeIt &e) const { return e.forw; }
klao@225
    77
klao@226
    78
    /// index of a node on the path. Returns length+2 for the invalid NodeIt
klao@226
    79
    int index(const NodeIt &n) const { return n.idx; }
klao@226
    80
    /// index of an edge on the path. Returns length+1 for the invalid EdgeIt
klao@226
    81
    int index(const EdgeIt &e) const { return e.it - edges.begin(); }
klao@226
    82
klao@225
    83
    EdgeIt& next(EdgeIt &e) const;
klao@225
    84
    NodeIt& next(NodeIt &n) const;
klao@225
    85
    template <typename It>
klao@225
    86
    It getNext(It it) const {
klao@225
    87
      It tmp(it); return next(tmp);
klao@225
    88
    }
klao@225
    89
klao@225
    90
    // A path is constructed using the following four functions.
klao@225
    91
    // They return false if the requested operation is inconsistent
klao@225
    92
    // with the path constructed so far.
klao@225
    93
    // If your path has only one edge you MUST set either "from" or "to"!
klao@225
    94
    // So you probably SHOULD call it in any case to be safe (and check the
klao@225
    95
    // returned value to check if your path is consistent with your idea).
klao@225
    96
    bool pushFront(const GraphEdge &e);
klao@225
    97
    bool pushBack(const GraphEdge &e);
klao@225
    98
    bool setFrom(const GraphNode &n);
klao@225
    99
    bool setTo(const GraphNode &n);
klao@225
   100
klao@225
   101
    // WARNING: these two functions return the head/tail of an edge with
klao@225
   102
    // respect to the direction of the path!
klao@225
   103
    // So G.head(P.graphEdge(e)) == P.graphNode(P.head(e)) holds only if 
klao@225
   104
    // P.forward(e) is true (or the edge is a loop)!
klao@225
   105
    NodeIt head(const EdgeIt& e) const;
klao@225
   106
    NodeIt tail(const EdgeIt& e) const;
klao@225
   107
klao@225
   108
    // FIXME: ezeknek valami jobb nev kellene!!!
klao@225
   109
    GraphEdge graphEdge(const EdgeIt& e) const;
klao@225
   110
    GraphNode graphNode(const NodeIt& n) const;
klao@225
   111
klao@225
   112
klao@225
   113
    /*** Iterator classes ***/
klao@225
   114
    class EdgeIt {
klao@225
   115
      friend class Path;
klao@225
   116
klao@225
   117
      typename Container::const_iterator it;
klao@225
   118
      bool forw;
klao@225
   119
    public:
klao@225
   120
      // FIXME: jarna neki ilyen is...
klao@225
   121
      // EdgeIt(Invalid);
klao@225
   122
klao@225
   123
      bool forward() const { return forw; }
klao@225
   124
klao@225
   125
      bool operator==(const EdgeIt& e) const { return it==e.it; }
klao@225
   126
      bool operator!=(const EdgeIt& e) const { return it!=e.it; }
klao@225
   127
      bool operator<(const EdgeIt& e) const { return it<e.it; }
klao@225
   128
    };
klao@225
   129
klao@225
   130
    class NodeIt {
klao@225
   131
      friend class Path;
klao@225
   132
      friend class EdgeIt;
klao@225
   133
klao@226
   134
      size_t idx;
klao@225
   135
      bool tail;  // Is this node the tail of the edge with same idx?
klao@225
   136
klao@225
   137
    public:
klao@225
   138
      // FIXME: jarna neki ilyen is...
klao@225
   139
      // NodeIt(Invalid);
klao@225
   140
klao@225
   141
      bool operator==(const NodeIt& n) const { return idx==n.idx; }
klao@225
   142
      bool operator!=(const NodeIt& n) const { return idx!=n.idx; }
klao@225
   143
      bool operator<(const NodeIt& n) const { return idx<n.idx; }
klao@225
   144
    };
klao@225
   145
klao@225
   146
  private:
klao@225
   147
    bool edgeIncident(const GraphEdge &e, const GraphNode &a,
klao@225
   148
		      GraphNode &b);
klao@225
   149
    bool connectTwoEdges(const GraphEdge &e, const GraphEdge &f);
klao@225
   150
  };
klao@225
   151
klao@225
   152
  template<typename Gr>
klao@225
   153
  typename Path<Gr>::EdgeIt&
klao@225
   154
  Path<Gr>::next(Path::EdgeIt &e) const {
klao@225
   155
    if( e.it == edges.end() ) 
klao@225
   156
      return e;
klao@225
   157
klao@225
   158
    GraphNode common_node = ( e.forw ? G.head(*e.it) : G.tail(*e.it) );
klao@225
   159
    ++e.it;
klao@225
   160
klao@225
   161
    // Invalid edgeit is always forward :)
klao@225
   162
    if( e.it == edges.end() ) {
klao@225
   163
      e.forw = true;
klao@225
   164
      return e;
klao@225
   165
    }
klao@225
   166
klao@225
   167
    e.forw = ( G.tail(*e.it) == common_node );
klao@225
   168
    return e;
klao@225
   169
  }
klao@225
   170
klao@225
   171
  template<typename Gr>
klao@225
   172
  typename Path<Gr>::NodeIt& Path<Gr>::next(NodeIt &n) const {
klao@225
   173
    if( n.idx >= length() ) {
klao@225
   174
      // FIXME: invalid
klao@225
   175
      n.idx = length()+1;
klao@225
   176
      return n;
klao@225
   177
    }
klao@225
   178
klao@225
   179
    
klao@225
   180
    GraphNode next_node = ( n.tail ? G.head(edges[n.idx]) :
klao@225
   181
			      G.tail(edges[n.idx]) );
klao@225
   182
    ++n.idx;
klao@225
   183
    if( n.idx < length() ) {
klao@225
   184
      n.tail = ( next_node == G.tail(edges[n.idx]) );
klao@225
   185
    }
klao@225
   186
    else {
klao@225
   187
      n.tail = true;
klao@225
   188
    }
klao@225
   189
klao@225
   190
    return n;
klao@225
   191
  }
klao@225
   192
klao@225
   193
  template<typename Gr>
klao@225
   194
  bool Path<Gr>::edgeIncident(const GraphEdge &e, const GraphNode &a,
klao@225
   195
			  GraphNode &b) {
klao@225
   196
    if( G.tail(e) == a ) {
klao@225
   197
      b=G.head(e);
klao@225
   198
      return true;
klao@225
   199
    }
klao@225
   200
    if( G.head(e) == a ) {
klao@225
   201
      b=G.tail(e);
klao@225
   202
      return true;
klao@225
   203
    }
klao@225
   204
    return false;
klao@225
   205
  }
klao@225
   206
klao@225
   207
  template<typename Gr>
klao@225
   208
  bool Path<Gr>::connectTwoEdges(const GraphEdge &e,
klao@225
   209
			     const GraphEdge &f) {
klao@225
   210
    if( edgeIncident(f, G.tail(e), _last) ) {
klao@225
   211
      _first = G.head(e);
klao@225
   212
      return true;
klao@225
   213
    }
klao@225
   214
    if( edgeIncident(f, G.head(e), _last) ) {
klao@225
   215
      _first = G.tail(e);
klao@225
   216
      return true;
klao@225
   217
    }
klao@225
   218
    return false;
klao@225
   219
  }
klao@225
   220
klao@225
   221
  template<typename Gr>
klao@225
   222
  bool Path<Gr>::pushFront(const GraphEdge &e) {
klao@225
   223
    if( G.valid(_first) ) {
klao@225
   224
	if( edgeIncident(e, _first, _first) ) {
klao@225
   225
	  edges.push_front(e);
klao@225
   226
	  return true;
klao@225
   227
	}
klao@225
   228
	else
klao@225
   229
	  return false;
klao@225
   230
    }
klao@225
   231
    else if( length() < 1 || connectTwoEdges(e, edges[0]) ) {
klao@225
   232
      edges.push_front(e);
klao@225
   233
      return true;
klao@225
   234
    }
klao@225
   235
    else
klao@225
   236
      return false;
klao@225
   237
  }
klao@225
   238
klao@225
   239
  template<typename Gr>
klao@225
   240
  bool Path<Gr>::pushBack(const GraphEdge &e) {
klao@225
   241
    if( G.valid(_last) ) {
klao@225
   242
	if( edgeIncident(e, _last, _last) ) {
klao@225
   243
	  edges.push_back(e);
klao@225
   244
	  return true;
klao@225
   245
	}
klao@225
   246
	else
klao@225
   247
	  return false;
klao@225
   248
    }
klao@225
   249
    else if( length() < 1 || connectTwoEdges(edges[0], e) ) {
klao@225
   250
      edges.push_back(e);
klao@225
   251
      return true;
klao@225
   252
    }
klao@225
   253
    else
klao@225
   254
      return false;
klao@225
   255
  }
klao@225
   256
klao@225
   257
klao@225
   258
  template<typename Gr>
klao@225
   259
  bool Path<Gr>::setFrom(const GraphNode &n) {
klao@225
   260
    if( G.valid(_first) ) {
klao@225
   261
      return _first == n;
klao@225
   262
    }
klao@225
   263
    else {
klao@225
   264
      if( length() > 0) {
klao@225
   265
	if( edgeIncident(edges[0], n, _last) ) {
klao@225
   266
	  _first = n;
klao@225
   267
	  return true;
klao@225
   268
	}
klao@225
   269
	else return false;
klao@225
   270
      }
klao@225
   271
      else {
klao@225
   272
	_first = _last = n;
klao@225
   273
	return true;
klao@225
   274
      }
klao@225
   275
    }
klao@225
   276
  }
klao@225
   277
klao@225
   278
  template<typename Gr>
klao@225
   279
  bool Path<Gr>::setTo(const GraphNode &n) {
klao@225
   280
    if( G.valid(_last) ) {
klao@225
   281
      return _last == n;
klao@225
   282
    }
klao@225
   283
    else {
klao@225
   284
      if( length() > 0) {
klao@225
   285
	if( edgeIncident(edges[0], n, _first) ) {
klao@225
   286
	  _last = n;
klao@225
   287
	  return true;
klao@225
   288
	}
klao@225
   289
	else return false;
klao@225
   290
      }
klao@225
   291
      else {
klao@225
   292
	_first = _last = n;
klao@225
   293
	return true;
klao@225
   294
      }
klao@225
   295
    }
klao@225
   296
  }
klao@225
   297
klao@225
   298
klao@225
   299
  template<typename Gr>
klao@225
   300
  typename Path<Gr>::NodeIt
klao@225
   301
  Path<Gr>::tail(const EdgeIt& e) const {
klao@225
   302
    NodeIt n;
klao@225
   303
klao@225
   304
    if( e.it == edges.end() ) {
klao@225
   305
      // FIXME: invalid-> invalid
klao@225
   306
      n.idx = length() + 1;
klao@225
   307
      n.tail = true;
klao@225
   308
      return n;
klao@225
   309
    }
klao@225
   310
klao@225
   311
    n.idx = e.it-edges.begin();
klao@225
   312
    n.tail = e.forw;
klao@226
   313
    return n;
klao@225
   314
  }
klao@225
   315
klao@225
   316
  template<typename Gr>
klao@225
   317
  typename Path<Gr>::NodeIt
klao@225
   318
  Path<Gr>::head(const EdgeIt& e) const {
klao@225
   319
    if( e.it == edges.end()-1 ) {
klao@225
   320
      return _last;
klao@225
   321
    }
klao@225
   322
klao@225
   323
    EdgeIt next_edge = e;
klao@225
   324
    next(next_edge);
klao@225
   325
    return tail(next_edge);
klao@225
   326
  }
klao@225
   327
      
klao@225
   328
  template<typename Gr>
klao@225
   329
  typename Path<Gr>::GraphEdge
klao@225
   330
  Path<Gr>::graphEdge(const EdgeIt& e) const {
klao@225
   331
    if( e.it != edges.end() ) {
klao@225
   332
      return *e.it;
klao@225
   333
    }
klao@225
   334
    else {
klao@225
   335
      return INVALID;
klao@225
   336
    }
klao@225
   337
  }
klao@225
   338
  
klao@225
   339
  template<typename Gr>
klao@225
   340
  typename Path<Gr>::GraphNode
klao@225
   341
  Path<Gr>::graphNode(const NodeIt& n) const {
klao@225
   342
    if( n.idx < length() ) {
klao@225
   343
      return n.tail ? G.tail(edges[n.idx]) : G.head(edges[n.idx]);
klao@225
   344
    }
klao@225
   345
    else if( n.idx == length() ) {
klao@225
   346
      return _last;
klao@225
   347
    }
klao@225
   348
    else {
klao@225
   349
      return INVALID;
klao@225
   350
    }
klao@225
   351
  }
klao@225
   352
klao@225
   353
  template<typename Gr>
klao@225
   354
  typename Path<Gr>::EdgeIt& Path<Gr>::nth(EdgeIt &e, size_t k) const {
klao@225
   355
    if( k<0 || k>=length() ) {
klao@225
   356
      // FIXME: invalid EdgeIt
klao@225
   357
      e.it = edges.end();
klao@225
   358
      e.forw = true;
klao@225
   359
      return e;
klao@225
   360
    }
klao@225
   361
klao@225
   362
    e.it = edges.begin()+k;
klao@225
   363
    if(k==0) {
klao@225
   364
      e.forw = ( G.tail(*e.it) == _first );
klao@225
   365
    }
klao@225
   366
    else {
klao@225
   367
      e.forw = ( G.tail(*e.it) == G.tail(edges[k-1]) ||
klao@225
   368
		 G.tail(*e.it) == G.head(edges[k-1]) );
klao@225
   369
    }
klao@225
   370
    return e;
klao@225
   371
  }
klao@225
   372
    
klao@225
   373
  template<typename Gr>
klao@225
   374
  typename Path<Gr>::NodeIt& Path<Gr>::nth(NodeIt &n, size_t k) const {
klao@225
   375
    if( k<0 || k>length() ) {
klao@225
   376
      // FIXME: invalid NodeIt
klao@225
   377
      n.idx = length()+1;
klao@225
   378
      n.tail = true;
klao@225
   379
      return n;
klao@225
   380
    }
klao@225
   381
    if( k==length() ) {
klao@225
   382
      n.idx = length();
klao@225
   383
      n.tail = true;
klao@225
   384
      return n;
klao@225
   385
    }
klao@225
   386
    n = tail(nth<EdgeIt>(k));
klao@225
   387
    return n;
klao@225
   388
  }
klao@225
   389
klao@226
   390
  // Reszut konstruktorok:
klao@226
   391
klao@226
   392
klao@226
   393
  template<typename Gr>
klao@226
   394
  Path<Gr>::Path(const Path &P, const EdgeIt &a, const EdgeIt &b) :
klao@226
   395
    G(P.G), edges(a.it, b.it)    // WARNING: if b.it < a.it this will blow up! 
klao@226
   396
  {
klao@226
   397
    if( G.valid(P._first) && a.it < P.edges.end() ) {
klao@226
   398
      _first = ( a.forw ? G.tail(*a.it) : G.head(*a.it) );
klao@226
   399
      if( b.it < P.edges.end() ) {
klao@226
   400
	_last = ( b.forw ? G.tail(*b.it) : G.head(*b.it) );
klao@226
   401
      }
klao@226
   402
      else {
klao@226
   403
	_last = P._last;
klao@226
   404
      }
klao@226
   405
    }
klao@226
   406
  }
klao@226
   407
klao@226
   408
  template<typename Gr>
klao@226
   409
  Path<Gr>::Path(const Path &P, const NodeIt &a, const NodeIt &b) :
klao@226
   410
    G(P.G)
klao@226
   411
  {
klao@226
   412
    if( !P.valid(a) || !P.valid(b) )
klao@226
   413
      return;
klao@226
   414
klao@226
   415
    int ai = a.idx, bi = b.idx;
klao@226
   416
    if( bi<ai )
klao@226
   417
      swap(ai,bi);
klao@226
   418
    
klao@226
   419
    edges.resize(bi-ai);
klao@226
   420
    copy(P.edges.begin()+ai, P.edges.begin()+bi, edges.begin());
klao@226
   421
klao@226
   422
    _first = P.graphNode(a);
klao@226
   423
    _last = P.graphNode(b);
klao@226
   424
  }
klao@226
   425
klao@225
   426
klao@225
   427
} // namespace hugo
klao@225
   428
klao@225
   429
#endif // HUGO_PATH_H