1 /** \file
2 * \brief Implementation of Graph class
3 *
4 * \author Carsten Gutwenger
5 *
6 * \par License:
7 * This file is part of the Open Graph Drawing Framework (OGDF).
8 *
9 * \par
10 * Copyright (C)<br>
11 * See README.md in the OGDF root directory for details.
12 *
13 * \par
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * Version 2 or 3 as published by the Free Software Foundation;
17 * see the file LICENSE.txt included in the packaging of this file
18 * for details.
19 *
20 * \par
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * \par
27 * You should have received a copy of the GNU General Public
28 * License along with this program; if not, see
29 * http://www.gnu.org/copyleft/gpl.html
30 */
31
32 #include <ogdf/basic/Math.h>
33 #include <ogdf/basic/Array.h>
34 #include <ogdf/basic/AdjEntryArray.h>
35 #include <ogdf/fileformats/GmlParser.h>
36 #include <ogdf/basic/simple_graph_alg.h>
37
38 using std::mutex;
39
40 #ifndef OGDF_MEMORY_POOL_NTS
41 using std::lock_guard;
42 #endif
43
44
45 #define MIN_NODE_TABLE_SIZE (1 << 4)
46 #define MIN_EDGE_TABLE_SIZE (1 << 4)
47
48
49 namespace ogdf {
50
51 using Math::nextPower2;
52
Graph()53 Graph::Graph()
54 {
55 m_nodeIdCount = m_edgeIdCount = 0;
56 resetTableSizes();
57 }
58
59
Graph(const Graph & G)60 Graph::Graph(const Graph &G)
61 {
62 m_nodeIdCount = m_edgeIdCount = 0;
63 copy(G);
64 resetTableSizes();
65 }
66
67
~Graph()68 Graph::~Graph()
69 {
70 restoreAllEdges();
71
72 while(!m_regNodeArrays.empty()) {
73 m_regNodeArrays.popFrontRet()->disconnect();
74 }
75
76 while(!m_regEdgeArrays.empty()) {
77 m_regEdgeArrays.popFrontRet()->disconnect();
78 }
79
80 while(!m_regAdjArrays.empty()) {
81 m_regAdjArrays.popFrontRet()->disconnect();
82 }
83
84 for (node v = nodes.head(); v; v = v->succ()) {
85 v->adjEntries.~GraphObjectContainer<AdjElement>();
86 }
87 }
88
89
operator =(const Graph & G)90 Graph &Graph::operator=(const Graph &G)
91 {
92 clear();
93 copy(G);
94 reinitArrays();
95
96 #ifdef OGDF_HEAVY_DEBUG
97 consistencyCheck();
98 #endif
99
100 return *this;
101 }
102
103
assign(const Graph & G,NodeArray<node> & mapNode,EdgeArray<edge> & mapEdge)104 void Graph::assign(const Graph &G, NodeArray<node> &mapNode,
105 EdgeArray<edge> &mapEdge)
106 {
107 clear();
108 copy(G,mapNode,mapEdge);
109 reinitArrays();
110 }
111
112
construct(const Graph & G,NodeArray<node> & mapNode,EdgeArray<edge> & mapEdge)113 void Graph::construct(const Graph &G, NodeArray<node> &mapNode,
114 EdgeArray<edge> &mapEdge)
115 {
116 copy(G,mapNode,mapEdge);
117 resetTableSizes();
118 }
119
120
copy(const Graph & G,NodeArray<node> & mapNode,EdgeArray<edge> & mapEdge)121 void Graph::copy(const Graph &G, NodeArray<node> &mapNode,
122 EdgeArray<edge> &mapEdge)
123 {
124 if (G.nodes.empty()) return;
125
126 mapNode.init(G,nullptr);
127
128 for(node vG : G.nodes) {
129 node v = mapNode[vG] = pureNewNode();
130 v->m_indeg = vG->m_indeg;
131 v->m_outdeg = vG->m_outdeg;
132 }
133
134 if (G.edges.empty()) return;
135
136 mapEdge.init(G,nullptr);
137
138 for(edge e : G.edges) {
139 edge eC;
140 edges.pushBack(eC = mapEdge[e] =
141 new EdgeElement(
142 mapNode[e->source()],mapNode[e->target()],m_edgeIdCount));
143
144 eC->m_adjSrc = new AdjElement(eC,m_edgeIdCount<<1);
145 (eC->m_adjTgt = new AdjElement(eC,(m_edgeIdCount<<1)|1))
146 ->m_twin = eC->m_adjSrc;
147 eC->m_adjSrc->m_twin = eC->m_adjTgt;
148 m_edgeIdCount++;
149 }
150
151 for(node vG : G.nodes) {
152 node v = mapNode[vG];
153 internal::GraphList<AdjElement> &adjEdges = vG->adjEntries;
154 for (AdjElement *adjG = adjEdges.head(); adjG; adjG = adjG->succ()) {
155 edge e = adjG->m_edge;
156 edge eC = mapEdge[e];
157
158 adjEntry adj = adjG->isSource() ? eC->adjSource() : eC->adjTarget();
159 v->adjEntries.pushBack(adj);
160 adj->m_node = v;
161 }
162 }
163 }
164
165
copy(const Graph & G)166 void Graph::copy(const Graph &G)
167 {
168 NodeArray<node> mapNode;
169 EdgeArray<edge> mapEdge;
170 copy(G,mapNode,mapEdge);
171
172 #ifdef OGDF_HEAVY_DEBUG
173 consistencyCheck();
174 #endif
175 }
176
177
constructInitByCC(const CCsInfo & info,int cc,NodeArray<node> & mapNode,EdgeArray<edge> & mapEdge)178 void Graph::constructInitByCC(
179 const CCsInfo &info,
180 int cc,
181 NodeArray<node> &mapNode,
182 EdgeArray<edge> &mapEdge)
183 {
184 // clear
185 for (node v = nodes.head(); v; v = v->succ()) {
186 v->adjEntries.~GraphObjectContainer<AdjElement>();
187 }
188
189 nodes.clear();
190 edges.clear();
191
192 m_nodeIdCount = m_edgeIdCount = 0;
193
194 for(int i = info.startNode(cc); i < info.stopNode(cc); ++i)
195 {
196 node vG = info.v(i);
197
198 #ifdef OGDF_DEBUG
199 node v = new NodeElement(this,m_nodeIdCount++);
200 #else
201 node v = new NodeElement(m_nodeIdCount++);
202 #endif
203 mapNode[vG] = v;
204 nodes.pushBack(v);
205
206 v->m_indeg = vG->m_indeg;
207 v->m_outdeg = vG->m_outdeg;
208 }
209
210 for(int i = info.startEdge(cc); i < info.stopEdge(cc); ++i)
211 {
212 edge eG = info.e(i);
213 node v = mapNode[eG->source()];
214 node w = mapNode[eG->target()];
215
216 edge eC = mapEdge[eG] = new EdgeElement(v, w, m_edgeIdCount);
217 edges.pushBack(eC);
218
219 adjEntry adjSrc = new AdjElement(eC, m_edgeIdCount<<1 );
220 adjEntry adjTgt = new AdjElement(eC, (m_edgeIdCount<<1)|1);
221
222 (eC->m_adjSrc = adjSrc)->m_twin = adjTgt;
223 (eC->m_adjTgt = adjTgt)->m_twin = adjSrc;
224
225 adjSrc->m_node = v;
226 adjTgt->m_node = w;
227
228 ++m_edgeIdCount;
229 }
230
231 for(int i = info.startNode(cc); i < info.stopNode(cc); ++i)
232 {
233 node vG = info.v(i);
234 node v = mapNode[vG];
235
236 for(adjEntry adjG : vG->adjEntries) {
237 edge eG = adjG->theEdge();
238 edge e = mapEdge[eG];
239
240 adjEntry adj = (adjG == eG->adjSource()) ? e->adjSource() : e->adjTarget();
241 v->adjEntries.pushBack(adj);
242 }
243 }
244
245 reinitArrays();
246
247 #ifdef OGDF_HEAVY_DEBUG
248 consistencyCheck();
249 #endif
250 }
251
252
constructInitByNodes(const Graph & G,const List<node> & nodeList,NodeArray<node> & mapNode,EdgeArray<edge> & mapEdge)253 void Graph::constructInitByNodes(
254 const Graph &G,
255 const List<node> &nodeList,
256 NodeArray<node> &mapNode,
257 EdgeArray<edge> &mapEdge)
258 {
259 // clear
260 for (node v = nodes.head(); v; v = v->succ()) {
261 v->adjEntries.~GraphObjectContainer<AdjElement>();
262 }
263
264 nodes.clear();
265 edges.clear();
266
267 m_nodeIdCount = m_edgeIdCount = 0;
268 m_nodeArrayTableSize = MIN_NODE_TABLE_SIZE;
269
270
271 // list of edges adjacent to nodes in nodeList
272 SListPure<edge> adjEdges;
273
274 // create nodes and assemble list of adjEntries
275 for(node vG : nodeList) {
276 node v = mapNode[vG] = pureNewNode();
277
278 v->m_indeg = vG->m_indeg;
279 v->m_outdeg = vG->m_outdeg;
280
281 for(adjEntry adjG : vG->adjEntries) {
282 // corresponding adjacency entries differ by index modulo 2
283 // the following conditions makes sure that each edge is
284 // added only once to adjEntries
285 if ((adjG->m_id & 1) == 0)
286 adjEdges.pushBack(adjG->m_edge);
287 }
288 }
289
290 // create edges
291 for (edge eG : adjEdges)
292 {
293 node v = mapNode[eG->source()];
294 node w = mapNode[eG->target()];
295
296 edge eC = mapEdge[eG] = new EdgeElement(v, w, m_edgeIdCount);
297 edges.pushBack(eC);
298
299 eC->m_adjSrc = new AdjElement(eC, m_edgeIdCount<<1);
300 (eC->m_adjTgt = new AdjElement(eC, (m_edgeIdCount<<1)|1))
301 ->m_twin = eC->m_adjSrc;
302 eC->m_adjSrc->m_twin = eC->m_adjTgt;
303 ++m_edgeIdCount;
304 }
305
306 EdgeArray<bool> mark(G,false);
307 for(node vG : nodeList) {
308 node v = mapNode[vG];
309
310 for (adjEntry adjG: vG->adjEntries) {
311 edge e = adjG->m_edge;
312 edge eC = mapEdge[e];
313
314 adjEntry adj;
315 if (eC->isSelfLoop()) {
316 if (mark[e])
317 adj = eC->m_adjTgt;
318 else {
319 adj = eC->m_adjSrc;
320 mark[e] = true;
321 }
322 } else
323 adj = (v == eC->m_src) ? eC->m_adjSrc : eC->m_adjTgt;
324
325 v->adjEntries.pushBack(adj);
326 adj->m_node = v;
327 }
328 }
329
330 // set size of associated arrays and reinitialize all (we have now a
331 // completely new graph)
332 reinitArrays();
333
334 #ifdef OGDF_HEAVY_DEBUG
335 consistencyCheck();
336 #endif
337 }
338
339
340 //mainly a copy of the above code, remerge this again
constructInitByActiveNodes(const List<node> & nodeList,const NodeArray<bool> & activeNodes,NodeArray<node> & mapNode,EdgeArray<edge> & mapEdge)341 void Graph::constructInitByActiveNodes(
342 const List<node> &nodeList,
343 const NodeArray<bool> &activeNodes,
344 NodeArray<node> &mapNode,
345 EdgeArray<edge> &mapEdge)
346 {
347 // clear
348 for (node v = nodes.head(); v; v = v->succ()) {
349 v->adjEntries.~GraphObjectContainer<AdjElement>();
350 }
351
352 nodes.clear();
353 edges.clear();
354
355 m_nodeIdCount = m_edgeIdCount = 0;
356 m_nodeArrayTableSize = MIN_NODE_TABLE_SIZE;
357
358
359 // list of edges adjacent to nodes in nodeList
360 SListPure<edge> adjEdges;
361
362 // create nodes and assemble list of adjEntries
363 // NOTE: nodeList is a list of ACTIVE nodes
364 for(node vG : nodeList) {
365 node v = mapNode[vG] = pureNewNode();
366
367 int inCount = 0;
368 int outCount = 0;
369 for(adjEntry adjG : vG->adjEntries)
370 {
371 // coresponding adjacency entries differ by index modulo 2
372 // the following conditions makes sure that each edge is
373 // added only once to adjEntries
374 if (activeNodes[adjG->m_edge->opposite(vG)])
375 {
376 if ((adjG->m_id & 1) == 0)
377 {
378 adjEdges.pushBack(adjG->m_edge);
379 }
380 if (adjG->m_edge->source() == vG) outCount++;
381 else inCount++;
382 }
383 }
384 v->m_indeg = inCount;
385 v->m_outdeg = outCount;
386 }
387
388 // create edges
389 for (edge eG : adjEdges)
390 {
391 node v = mapNode[eG->source()];
392 node w = mapNode[eG->target()];
393
394 AdjElement *adjSrc = new AdjElement(v);
395
396 v->adjEntries.pushBack(adjSrc);
397
398 AdjElement *adjTgt = new AdjElement(w);
399
400 w->adjEntries.pushBack(adjTgt);
401
402 adjSrc->m_twin = adjTgt;
403 adjTgt->m_twin = adjSrc;
404
405 adjTgt->m_id = (adjSrc->m_id = m_edgeIdCount << 1) | 1;
406 edge e = new EdgeElement(v,w,adjSrc,adjTgt,m_edgeIdCount++);
407
408 edges.pushBack(e);
409
410 mapEdge[eG] = adjSrc->m_edge = adjTgt->m_edge = e;
411 }
412
413 // set size of associated arrays and reinitialize all (we have now a
414 // completely new graph)
415 reinitArrays();
416
417 #ifdef OGDF_HEAVY_DEBUG
418 consistencyCheck();
419 #endif
420 }
421
newNode()422 node Graph::newNode()
423 {
424 if (m_nodeIdCount == m_nodeArrayTableSize) {
425 m_nodeArrayTableSize <<= 1;
426 for(NodeArrayBase *nab : m_regNodeArrays)
427 nab->enlargeTable(m_nodeArrayTableSize);
428 }
429
430 #ifdef OGDF_DEBUG
431 node v = new NodeElement(this,m_nodeIdCount++);
432 #else
433 node v = new NodeElement(m_nodeIdCount++);
434 #endif
435
436 nodes.pushBack(v);
437
438 // notify all registered observers
439 for(GraphObserver *obs : m_regStructures)
440 obs->nodeAdded(v);
441
442 return v;
443 }
444
445
446 //what about negative index numbers?
newNode(int index)447 node Graph::newNode(int index)
448 {
449 if(index >= m_nodeIdCount) {
450 m_nodeIdCount = index + 1;
451
452 if(index >= m_nodeArrayTableSize) {
453 m_nodeArrayTableSize = nextPower2(m_nodeArrayTableSize, index + 1);
454 for(NodeArrayBase *nab : m_regNodeArrays)
455 nab->enlargeTable(m_nodeArrayTableSize);
456 }
457 }
458
459 #ifdef OGDF_DEBUG
460 node v = new NodeElement(this,index);
461 #else
462 node v = new NodeElement(index);
463 #endif
464
465 nodes.pushBack(v);
466
467 // notify all registered observers
468 for(GraphObserver *obs : m_regStructures)
469 obs->nodeAdded(v);
470
471 return v;
472 }
473
474
pureNewNode()475 node Graph::pureNewNode()
476 {
477 #ifdef OGDF_DEBUG
478 node v = new NodeElement(this,m_nodeIdCount++);
479 #else
480 node v = new NodeElement(m_nodeIdCount++);
481 #endif
482
483 nodes.pushBack(v);
484
485 // notify all registered observers
486 for(GraphObserver *obs : m_regStructures)
487 obs->nodeAdded(v);
488
489 return v;
490 }
491
492
493 // IMPORTANT:
494 // The indices of the two adjacency entries pointing to an edge differ
495 // only in the last bit (adjSrc/2 == adjTgt/2)
496 //
497 // This can be useful sometimes in order to avoid visiting an edge twice.
createEdgeElement(node v,node w,adjEntry adjSrc,adjEntry adjTgt)498 edge Graph::createEdgeElement(node v, node w, adjEntry adjSrc, adjEntry adjTgt)
499 {
500 if (m_edgeIdCount == m_edgeArrayTableSize) {
501 m_edgeArrayTableSize <<= 1;
502
503 for(EdgeArrayBase *eab : m_regEdgeArrays)
504 eab->enlargeTable(m_edgeArrayTableSize);
505
506 for(AdjEntryArrayBase *aab : m_regAdjArrays)
507 aab->enlargeTable(m_edgeArrayTableSize << 1);
508 }
509
510 adjTgt->m_id = (adjSrc->m_id = m_edgeIdCount << 1) | 1;
511 edge e = new EdgeElement(v,w,adjSrc,adjTgt,m_edgeIdCount++);
512 edges.pushBack(e);
513
514 // notify all registered observers
515 for(GraphObserver *obs : m_regStructures)
516 obs->edgeAdded(e);
517
518 return e;
519 }
520
521
newEdge(node v,node w,int index)522 edge Graph::newEdge(node v, node w, int index)
523 {
524 OGDF_ASSERT(v != nullptr);
525 OGDF_ASSERT(w != nullptr);
526 OGDF_ASSERT(v->graphOf() == this);
527 OGDF_ASSERT(w->graphOf() == this);
528
529 AdjElement *adjSrc = new AdjElement(v);
530
531 v->adjEntries.pushBack(adjSrc);
532 v->m_outdeg++;
533
534 AdjElement *adjTgt = new AdjElement(w);
535
536 w->adjEntries.pushBack(adjTgt);
537 w->m_indeg++;
538
539 adjSrc->m_twin = adjTgt;
540 adjTgt->m_twin = adjSrc;
541
542 if(index >= m_edgeIdCount) {
543 m_edgeIdCount = index + 1;
544
545 if(index >= m_edgeArrayTableSize) {
546 m_edgeArrayTableSize = nextPower2(m_edgeArrayTableSize, index + 1);
547
548 for(EdgeArrayBase *eab : m_regEdgeArrays)
549 eab->enlargeTable(m_edgeArrayTableSize);
550
551 for(AdjEntryArrayBase *aab : m_regAdjArrays)
552 aab->enlargeTable(m_edgeArrayTableSize << 1);
553 }
554 }
555
556 adjTgt->m_id = (adjSrc->m_id = index/*m_edgeIdCount*/ << 1) | 1;
557 edge e = new EdgeElement(v,w,adjSrc,adjTgt,index);
558 edges.pushBack(e);
559
560 // notify all registered observers
561 for(GraphObserver *obs : m_regStructures)
562 obs->edgeAdded(e);
563
564 return adjSrc->m_edge = adjTgt->m_edge = e;
565 }
566
567
newEdge(node v,node w)568 edge Graph::newEdge(node v, node w)
569 {
570 OGDF_ASSERT(v != nullptr);
571 OGDF_ASSERT(w != nullptr);
572 OGDF_ASSERT(v->graphOf() == this);
573 OGDF_ASSERT(w->graphOf() == this);
574
575 AdjElement *adjSrc = new AdjElement(v);
576
577 v->adjEntries.pushBack(adjSrc);
578 v->m_outdeg++;
579
580 AdjElement *adjTgt = new AdjElement(w);
581
582 w->adjEntries.pushBack(adjTgt);
583 w->m_indeg++;
584
585 adjSrc->m_twin = adjTgt;
586 adjTgt->m_twin = adjSrc;
587
588 edge e = createEdgeElement(v,w,adjSrc,adjTgt);
589
590 return adjSrc->m_edge = adjTgt->m_edge = e;
591 }
592
593
newEdge(adjEntry adjStart,adjEntry adjEnd,Direction dir)594 edge Graph::newEdge(adjEntry adjStart, adjEntry adjEnd, Direction dir)
595 {
596 OGDF_ASSERT(adjStart != nullptr);
597 OGDF_ASSERT(adjEnd != nullptr);
598 OGDF_ASSERT(adjStart->graphOf() == this);
599 OGDF_ASSERT(adjEnd->graphOf() == this);
600
601 node v = adjStart->theNode(), w = adjEnd->theNode();
602
603 AdjElement *adjTgt = new AdjElement(w);
604 AdjElement *adjSrc = new AdjElement(v);
605
606 if(dir == Direction::after) {
607 w->adjEntries.insertAfter(adjTgt,adjEnd);
608 v->adjEntries.insertAfter(adjSrc,adjStart);
609 } else {
610 w->adjEntries.insertBefore(adjTgt,adjEnd);
611 v->adjEntries.insertBefore(adjSrc,adjStart);
612 }
613
614 w->m_indeg++;
615 v->m_outdeg++;
616
617 adjSrc->m_twin = adjTgt;
618 adjTgt->m_twin = adjSrc;
619
620 edge e = createEdgeElement(v,w,adjSrc,adjTgt);
621
622 return adjSrc->m_edge = adjTgt->m_edge = e;
623 }
624
newEdge(node v,adjEntry adjEnd)625 edge Graph::newEdge(node v, adjEntry adjEnd)
626 {
627 OGDF_ASSERT(v != nullptr);
628 OGDF_ASSERT(adjEnd != nullptr);
629 OGDF_ASSERT(v->graphOf() == this);
630 OGDF_ASSERT(adjEnd->graphOf() == this);
631
632 node w = adjEnd->theNode();
633
634 AdjElement *adjTgt = new AdjElement(w);
635
636 w->adjEntries.insertAfter(adjTgt,adjEnd);
637 w->m_indeg++;
638
639 AdjElement *adjSrc = new AdjElement(v);
640
641 v->adjEntries.pushBack(adjSrc);
642 v->m_outdeg++;
643
644 adjSrc->m_twin = adjTgt;
645 adjTgt->m_twin = adjSrc;
646
647 edge e = createEdgeElement(v,w,adjSrc,adjTgt);
648
649 return adjSrc->m_edge = adjTgt->m_edge = e;
650 }
651
652 //copy of above function with edge ending at v
newEdge(adjEntry adjStart,node v)653 edge Graph::newEdge(adjEntry adjStart, node v)
654 {
655 OGDF_ASSERT(v != nullptr);
656 OGDF_ASSERT(adjStart != nullptr);
657 OGDF_ASSERT(v->graphOf() == this);
658 OGDF_ASSERT(adjStart->graphOf() == this);
659
660 node w = adjStart->theNode();
661
662 AdjElement *adjSrc = new AdjElement(w);
663
664 w->adjEntries.insertAfter(adjSrc, adjStart);
665 w->m_outdeg++;
666
667 AdjElement *adjTgt = new AdjElement(v);
668
669 v->adjEntries.pushBack(adjTgt);
670 v->m_indeg++;
671
672 adjSrc->m_twin = adjTgt;
673 adjTgt->m_twin = adjSrc;
674
675 edge e = createEdgeElement(w,v,adjSrc,adjTgt);
676
677 return adjSrc->m_edge = adjTgt->m_edge = e;
678 }
679
move(edge e,adjEntry adjSrc,Direction dirSrc,adjEntry adjTgt,Direction dirTgt)680 void Graph::move(edge e,
681 adjEntry adjSrc,
682 Direction dirSrc,
683 adjEntry adjTgt,
684 Direction dirTgt)
685 {
686 OGDF_ASSERT(e->graphOf() == this);
687 OGDF_ASSERT(adjSrc->graphOf() == this);
688 OGDF_ASSERT(adjTgt->graphOf() == this);
689 OGDF_ASSERT(adjSrc != e->m_adjSrc);
690 OGDF_ASSERT(adjSrc != e->m_adjTgt);
691 OGDF_ASSERT(adjTgt != e->m_adjSrc);
692 OGDF_ASSERT(adjTgt != e->m_adjTgt);
693
694 node v = adjSrc->m_node, w = adjTgt->m_node;
695 adjEntry adj1 = e->m_adjSrc, adj2 = e->m_adjTgt;
696 e->m_src->adjEntries.move(adj1, v->adjEntries, adjSrc, dirSrc);
697 e->m_tgt->adjEntries.move(adj2, w->adjEntries, adjTgt, dirTgt);
698
699 e->m_src->m_outdeg--;
700 e->m_tgt->m_indeg--;
701
702 adj1->m_node = e->m_src = v;
703 adj2->m_node = e->m_tgt = w;
704
705 v->m_outdeg++;
706 w->m_indeg++;
707 }
708
709
moveTarget(edge e,node v)710 void Graph::moveTarget(edge e, node v)
711 {
712 OGDF_ASSERT(e->graphOf() == this);
713 OGDF_ASSERT(v->graphOf() == this);
714
715 adjEntry adj = e->m_adjTgt;
716 e->m_tgt->adjEntries.move(adj,v->adjEntries);
717
718 e->m_tgt->m_indeg--;
719 adj->m_node = e->m_tgt = v;
720 v->m_indeg++;
721 }
722
moveTarget(edge e,adjEntry adjTgt,Direction dir)723 void Graph::moveTarget(edge e, adjEntry adjTgt, Direction dir)
724 {
725 node v = adjTgt->theNode();
726
727 OGDF_ASSERT(e->graphOf() == this);
728 OGDF_ASSERT(v->graphOf() == this);
729
730 adjEntry adj = e->m_adjTgt;
731 e->m_tgt->adjEntries.move(adj, v->adjEntries, adjTgt, dir);
732
733 e->m_tgt->m_indeg--;
734 adj->m_node = e->m_tgt = v;
735 v->m_indeg++;
736 }
737
738 // By Leipert
moveSource(edge e,node v)739 void Graph::moveSource(edge e, node v)
740 {
741 OGDF_ASSERT(e->graphOf() == this);
742 OGDF_ASSERT(v->graphOf() == this);
743
744 adjEntry adj = e->m_adjSrc;
745 e->m_src->adjEntries.move(adj,v->adjEntries);
746
747 e->m_src->m_outdeg--;
748 adj->m_node = e->m_src = v;
749 v->m_outdeg++;
750 }
751
moveSource(edge e,adjEntry adjSrc,Direction dir)752 void Graph::moveSource(edge e, adjEntry adjSrc, Direction dir)
753 {
754 node v = adjSrc->theNode();
755
756 OGDF_ASSERT(e->graphOf() == this);
757 OGDF_ASSERT(v->graphOf() == this);
758
759 adjEntry adj = e->m_adjSrc;
760 e->m_src->adjEntries.move(adj, v->adjEntries, adjSrc, dir);
761
762 e->m_src->m_outdeg--;
763 adj->m_node = e->m_src = v;
764 v->m_outdeg++;
765 }
766
split(edge e)767 edge Graph::split(edge e)
768 {
769 OGDF_ASSERT(e != nullptr);
770 OGDF_ASSERT(e->graphOf() == this);
771
772 node u = newNode();
773 u->m_indeg = u->m_outdeg = 1;
774
775 adjEntry adjTgt = new AdjElement(u);
776 adjTgt->m_edge = e;
777 adjTgt->m_twin = e->m_adjSrc;
778 e->m_adjSrc->m_twin = adjTgt;
779
780 // adapt adjacency entry index to hold invariant
781 adjTgt->m_id = e->m_adjTgt->m_id;
782
783 u->adjEntries.pushBack(adjTgt);
784
785 adjEntry adjSrc = new AdjElement(u);
786 adjSrc->m_twin = e->m_adjTgt;
787 u->adjEntries.pushBack(adjSrc);
788
789 int oldId = e->m_adjTgt->m_id;
790 edge e2 = createEdgeElement(u,e->m_tgt,adjSrc,e->m_adjTgt);
791 resetAdjEntryIndex(e->m_adjTgt->m_id,oldId);
792
793 e2->m_adjTgt->m_twin = adjSrc;
794 e->m_adjTgt->m_edge = adjSrc->m_edge = e2;
795
796 e->m_tgt = u;
797 e->m_adjTgt = adjTgt;
798 return e2;
799 }
800
801
unsplit(node u)802 void Graph::unsplit(node u)
803 {
804 edge eIn = u->firstAdj()->theEdge();
805 edge eOut = u->lastAdj()->theEdge();
806
807 if (eIn->target() != u)
808 std::swap(eIn,eOut);
809
810 unsplit(eIn,eOut);
811 }
812
813
814
unsplit(edge eIn,edge eOut)815 void Graph::unsplit(edge eIn, edge eOut)
816 {
817 node u = eIn->target();
818
819 // u must be a node with exactly one incoming edge eIn and one outgoing
820 // edge eOut
821 OGDF_ASSERT(u->graphOf() == this);
822 OGDF_ASSERT(u->indeg() == 1);
823 OGDF_ASSERT(u->outdeg() == 1);
824 OGDF_ASSERT(eOut->source() == u);
825
826 // none of them is a self-loop!
827 OGDF_ASSERT(!eIn->isSelfLoop());
828 OGDF_ASSERT(!eOut->isSelfLoop());
829
830 // we reuse these adjacency entries
831 adjEntry adjSrc = eIn ->m_adjSrc;
832 adjEntry adjTgt = eOut->m_adjTgt;
833
834 eIn->m_tgt = eOut->m_tgt;
835
836 // adapt adjacency entry index to hold invariant
837 resetAdjEntryIndex(eIn->m_adjTgt->m_id,adjTgt->m_id);
838 adjTgt->m_id = eIn->m_adjTgt->m_id; // correct id of adjacency entry!
839
840 eIn->m_adjTgt = adjTgt;
841
842 adjSrc->m_twin = adjTgt;
843 adjTgt->m_twin = adjSrc;
844
845 adjTgt->m_edge = eIn;
846
847 // notify all registered observers
848 for(GraphObserver *obs : m_regStructures)
849 obs->edgeDeleted(eOut);
850 for(GraphObserver *obs : m_regStructures)
851 obs->nodeDeleted(u);
852
853 // remove structures that are no longer used
854 edges.del(eOut);
855 nodes.del(u);
856 }
857
858
insert(const Graph & G,NodeArray<node> & nodeMap)859 void Graph::insert(const Graph &G, NodeArray<node> &nodeMap)
860 {
861 for (node v : G.nodes) {
862 nodeMap[v] = newNode();
863 }
864
865 for (edge e: G.edges) {
866 newEdge(nodeMap[e->source()], nodeMap[e->target()]);
867 }
868 }
869
870
insert(const Graph & G)871 void Graph::insert(const Graph &G)
872 {
873 NodeArray<node> nodeMap(G);
874 insert(G, nodeMap);
875 }
876
877
delNode(node v)878 void Graph::delNode(node v)
879 {
880 OGDF_ASSERT(v != nullptr);
881 OGDF_ASSERT(v->graphOf() == this);
882
883 // notify all registered observers
884 for (GraphObserver *obs : m_regStructures)
885 obs->nodeDeleted(v);
886
887 internal::GraphList<AdjElement> &adjEdges = v->adjEntries;
888 AdjElement *adj;
889 while((adj = adjEdges.head()) != nullptr)
890 delEdge(adj->m_edge);
891
892 nodes.del(v);
893 }
894
895
delEdge(edge e)896 void Graph::delEdge(edge e)
897 {
898 OGDF_ASSERT(e != nullptr);
899 OGDF_ASSERT(e->graphOf() == this);
900
901 // notify all registered observers
902 for(GraphObserver *obs : m_regStructures)
903 obs->edgeDeleted(e);
904
905 node src = e->m_src, tgt = e->m_tgt;
906
907 src->adjEntries.del(e->m_adjSrc);
908 src->m_outdeg--;
909 tgt->adjEntries.del(e->m_adjTgt);
910 tgt->m_indeg--;
911
912 edges.del(e);
913 }
914
915
clear()916 void Graph::clear()
917 {
918 // tell all structures to clear their graph-initialized data
919 for(GraphObserver *obs : m_regStructures)
920 obs->cleared();
921
922 for (node v = nodes.head(); v; v = v->succ()) {
923 v->adjEntries.~GraphObjectContainer<AdjElement>();
924 }
925
926 nodes.clear();
927 edges.clear();
928
929 m_nodeIdCount = m_edgeIdCount = 0;
930 m_nodeArrayTableSize = MIN_NODE_TABLE_SIZE;
931 reinitArrays(false);
932
933 #ifdef OGDF_HEAVY_DEBUG
934 consistencyCheck();
935 #endif
936 }
937
938
reverseEdge(edge e)939 void Graph::reverseEdge(edge e)
940 {
941 OGDF_ASSERT(e != nullptr);
942 OGDF_ASSERT(e->graphOf() == this);
943 node &src = e->m_src, &tgt = e->m_tgt;
944
945 std::swap(src,tgt);
946 std::swap(e->m_adjSrc,e->m_adjTgt);
947 src->m_outdeg++; src->m_indeg--;
948 tgt->m_outdeg--; tgt->m_indeg++;
949 }
950
951
reverseAllEdges()952 void Graph::reverseAllEdges()
953 {
954 for (edge e = edges.head(); e; e = e->succ())
955 reverseEdge(e);
956
957 #ifdef OGDF_HEAVY_DEBUG
958 consistencyCheck();
959 #endif
960 }
961
962
reverseAdjEdges()963 void Graph::reverseAdjEdges()
964 {
965 for(node v : nodes)
966 reverseAdjEdges(v);
967 }
968
969
chooseNode(std::function<bool (node)> includeNode,bool isFastTest) const970 node Graph::chooseNode(std::function<bool(node)> includeNode, bool isFastTest) const
971 {
972 return *chooseIteratorFrom<internal::GraphObjectContainer<NodeElement>, node>(
973 const_cast<internal::GraphObjectContainer<NodeElement>&>(nodes),
974 [&](const node &v) { return includeNode(v); },
975 isFastTest
976 );
977 }
978
979
chooseEdge(std::function<bool (edge)> includeEdge,bool isFastTest) const980 edge Graph::chooseEdge(std::function<bool(edge)> includeEdge, bool isFastTest) const
981 {
982 return *chooseIteratorFrom<internal::GraphObjectContainer<EdgeElement>, edge>(
983 const_cast<internal::GraphObjectContainer<EdgeElement>&>(edges),
984 [&](const edge &e) { return includeEdge(e); },
985 isFastTest
986 );
987 }
988
989
searchEdge(node v,node w,bool directed) const990 edge Graph::searchEdge(node v, node w, bool directed) const
991 {
992 OGDF_ASSERT(v != nullptr);
993 OGDF_ASSERT(v->graphOf() == this);
994 OGDF_ASSERT(w != nullptr);
995 OGDF_ASSERT(w->graphOf() == this);
996
997 bool swapped = false;
998 if (w->degree() < v->degree()) {
999 std::swap(v,w);
1000 swapped = true;
1001 }
1002
1003 for(adjEntry adj : v->adjEntries) {
1004 if (adj->twinNode() == w &&
1005 (!directed || swapped != adj->isSource())) {
1006 return adj->theEdge();
1007 }
1008 }
1009 return nullptr;
1010 }
1011
1012
restoreAllEdges()1013 void Graph::restoreAllEdges()
1014 {
1015 while (!m_hiddenEdgeSets.empty()) {
1016 HiddenEdgeSet *set = m_hiddenEdgeSets.popFrontRet();
1017 set->restore();
1018 set->m_graph = nullptr;
1019 }
1020 }
1021
1022
genus() const1023 int Graph::genus() const
1024 {
1025 if (empty()) return 0;
1026
1027 int nIsolated = 0;
1028 for(node v : nodes)
1029 if (v->degree() == 0) ++nIsolated;
1030
1031 NodeArray<int> component(*this);
1032 int nCC = connectedComponents(*this,component);
1033
1034 AdjEntryArray<bool> visited(*this,false);
1035 int nFaceCycles = 0;
1036
1037 for(node v : nodes) {
1038 for(adjEntry adj1 : v->adjEntries) {
1039 if (visited[adj1]) continue;
1040
1041 adjEntry adj = adj1;
1042 do {
1043 visited[adj] = true;
1044 adj = adj->faceCycleSucc();
1045 } while (adj != adj1);
1046
1047 ++nFaceCycles;
1048 }
1049 }
1050
1051 return (numberOfEdges() - numberOfNodes() - nIsolated - nFaceCycles + 2*nCC) / 2;
1052 }
1053
1054
registerArray(NodeArrayBase * pNodeArray) const1055 ListIterator<NodeArrayBase*> Graph::registerArray(
1056 NodeArrayBase *pNodeArray) const
1057 {
1058 #ifndef OGDF_MEMORY_POOL_NTS
1059 lock_guard<mutex> guard(m_mutexRegArrays);
1060 #endif
1061 return m_regNodeArrays.pushBack(pNodeArray);
1062 }
1063
1064
registerArray(EdgeArrayBase * pEdgeArray) const1065 ListIterator<EdgeArrayBase*> Graph::registerArray(
1066 EdgeArrayBase *pEdgeArray) const
1067 {
1068 #ifndef OGDF_MEMORY_POOL_NTS
1069 lock_guard<mutex> guard(m_mutexRegArrays);
1070 #endif
1071 return m_regEdgeArrays.pushBack(pEdgeArray);
1072 }
1073
1074
registerArray(AdjEntryArrayBase * pAdjArray) const1075 ListIterator<AdjEntryArrayBase*> Graph::registerArray(
1076 AdjEntryArrayBase *pAdjArray) const
1077 {
1078 #ifndef OGDF_MEMORY_POOL_NTS
1079 lock_guard<mutex> guard(m_mutexRegArrays);
1080 #endif
1081 return m_regAdjArrays.pushBack(pAdjArray);
1082 }
1083
registerStructure(GraphObserver * pStructure) const1084 ListIterator<GraphObserver*> Graph::registerStructure(
1085 GraphObserver *pStructure) const
1086 {
1087 #ifndef OGDF_MEMORY_POOL_NTS
1088 lock_guard<mutex> guard(m_mutexRegArrays);
1089 #endif
1090 return m_regStructures.pushBack(pStructure);
1091 }
1092
1093
unregisterArray(ListIterator<NodeArrayBase * > it) const1094 void Graph::unregisterArray(ListIterator<NodeArrayBase*> it) const
1095 {
1096 #ifndef OGDF_MEMORY_POOL_NTS
1097 lock_guard<mutex> guard(m_mutexRegArrays);
1098 #endif
1099 m_regNodeArrays.del(it);
1100 }
1101
1102
unregisterArray(ListIterator<EdgeArrayBase * > it) const1103 void Graph::unregisterArray(ListIterator<EdgeArrayBase*> it) const
1104 {
1105 #ifndef OGDF_MEMORY_POOL_NTS
1106 lock_guard<mutex> guard(m_mutexRegArrays);
1107 #endif
1108 m_regEdgeArrays.del(it);
1109 }
1110
1111
unregisterArray(ListIterator<AdjEntryArrayBase * > it) const1112 void Graph::unregisterArray(ListIterator<AdjEntryArrayBase*> it) const
1113 {
1114 #ifndef OGDF_MEMORY_POOL_NTS
1115 lock_guard<mutex> guard(m_mutexRegArrays);
1116 #endif
1117 m_regAdjArrays.del(it);
1118 }
1119
unregisterStructure(ListIterator<GraphObserver * > it) const1120 void Graph::unregisterStructure(ListIterator<GraphObserver*> it) const
1121 {
1122 #ifndef OGDF_MEMORY_POOL_NTS
1123 lock_guard<mutex> guard(m_mutexRegArrays);
1124 #endif
1125 m_regStructures.del(it);
1126 }
1127
resetTableSizes()1128 void Graph::resetTableSizes()
1129 {
1130 m_nodeArrayTableSize = nextPower2(MIN_NODE_TABLE_SIZE, m_nodeIdCount + 1);
1131 m_edgeArrayTableSize = nextPower2(MIN_EDGE_TABLE_SIZE, m_edgeIdCount + 1);
1132 }
1133
reinitArrays(bool doResetTableSizes)1134 void Graph::reinitArrays(bool doResetTableSizes)
1135 {
1136 if(doResetTableSizes) {
1137 resetTableSizes();
1138 }
1139
1140 for(NodeArrayBase *nab : m_regNodeArrays)
1141 nab->reinit(m_nodeArrayTableSize);
1142
1143 for(EdgeArrayBase *eab : m_regEdgeArrays)
1144 eab->reinit(m_edgeArrayTableSize);
1145
1146 for(AdjEntryArrayBase *aab : m_regAdjArrays)
1147 aab->reinit(m_edgeArrayTableSize << 1);
1148 }
1149
1150
reinitStructures()1151 void Graph::reinitStructures()
1152 {
1153 // is there a challenge?
1154 for(GraphObserver *obs : m_regStructures)
1155 obs->reInit();
1156 }
1157
1158
resetAdjEntryIndex(int newIndex,int oldIndex)1159 void Graph::resetAdjEntryIndex(int newIndex, int oldIndex)
1160 {
1161 for(AdjEntryArrayBase *aab : m_regAdjArrays)
1162 aab->resetIndex(newIndex,oldIndex);
1163 }
1164
1165
1166 #ifdef OGDF_DEBUG
consistencyCheck() const1167 void Graph::consistencyCheck() const
1168 {
1169 int n = 0;
1170 for(node v : nodes) {
1171 OGDF_ASSERT(v->graphOf() == this);
1172
1173 n++;
1174 int in = 0, out = 0;
1175
1176 for(adjEntry adj : v->adjEntries) {
1177 edge e = adj->m_edge;
1178 OGDF_ASSERT(adj->m_twin->m_edge == e);
1179
1180 if (e->m_adjSrc == adj) {
1181 out++;
1182 } else {
1183 OGDF_ASSERT(e->m_adjTgt == adj);
1184 in++;
1185 }
1186
1187 OGDF_ASSERT(adj->m_node == v);
1188 OGDF_ASSERT(adj->graphOf() == this);
1189 }
1190
1191 OGDF_ASSERT(v->m_indeg == in);
1192 OGDF_ASSERT(v->m_outdeg == out);
1193 }
1194
1195 OGDF_ASSERT(n == nodes.size());
1196
1197 int m = 0;
1198 for(edge e : edges) {
1199 m++;
1200 OGDF_ASSERT(e->graphOf() == this);
1201 OGDF_ASSERT(e->m_adjSrc != e->m_adjTgt);
1202 OGDF_ASSERT(e->m_adjSrc->m_edge == e);
1203 OGDF_ASSERT(e->m_adjTgt->m_edge == e);
1204 OGDF_ASSERT(e->m_adjSrc->m_node == e->m_src);
1205 OGDF_ASSERT(e->m_adjTgt->m_node == e->m_tgt);
1206 }
1207
1208 OGDF_ASSERT(m == edges.size());
1209 }
1210 #endif
1211
1212
resetEdgeIdCount(int maxId)1213 void Graph::resetEdgeIdCount(int maxId)
1214 {
1215 m_edgeIdCount = maxId+1;
1216
1217 #ifdef OGDF_HEAVY_DEBUG
1218 for(edge e : edges)
1219 {
1220 // if there is an edge with higer index than maxId, we cannot
1221 // set the edge id count to maxId+1
1222 OGDF_ASSERT(e->index() <= maxId);
1223 }
1224 #endif
1225 }
1226
1227
splitNode(adjEntry adjStartLeft,adjEntry adjStartRight)1228 node Graph::splitNode(adjEntry adjStartLeft, adjEntry adjStartRight)
1229 {
1230 OGDF_ASSERT(adjStartLeft != nullptr);
1231 OGDF_ASSERT(adjStartRight != nullptr);
1232 OGDF_ASSERT(adjStartLeft->graphOf() == this);
1233 OGDF_ASSERT(adjStartRight->graphOf() == this);
1234 OGDF_ASSERT(adjStartLeft->theNode() == adjStartRight->theNode());
1235
1236 node w = newNode();
1237
1238 adjEntry adj, adjSucc;
1239 for(adj = adjStartRight; adj != adjStartLeft; adj = adjSucc) {
1240 adjSucc = adj->cyclicSucc();
1241 moveAdj(adj,w);
1242 }
1243
1244 newEdge(adjStartLeft, adjStartRight, Direction::before);
1245
1246 return w;
1247 }
1248
1249
contract(edge e)1250 node Graph::contract(edge e)
1251 {
1252 adjEntry adjSrc = e->adjSource();
1253 adjEntry adjTgt = e->adjTarget();
1254 node v = e->source();
1255 node w = e->target();
1256
1257 adjEntry adjNext;
1258 for (adjEntry adj = adjTgt->cyclicSucc(); adj != adjTgt; adj = adjNext) {
1259 adjNext = adj->cyclicSucc();
1260 if (adj->twinNode() == v) {
1261 continue;
1262 }
1263
1264 edge eAdj = adj->theEdge();
1265 if (w == eAdj->source()) {
1266 moveSource(eAdj, adjSrc, Direction::before);
1267 } else {
1268 moveTarget(eAdj, adjSrc, Direction::before);
1269 }
1270 }
1271
1272 delNode(adjTgt->theNode());
1273
1274 return v;
1275 }
1276
1277
moveAdj(adjEntry adj,node w)1278 void Graph::moveAdj(adjEntry adj, node w)
1279 {
1280 node v = adj->m_node;
1281
1282 v->adjEntries.move(adj,w->adjEntries);
1283 adj->m_node = w;
1284
1285 edge e = adj->m_edge;
1286 if(v == e->m_src) {
1287 --v->m_outdeg;
1288 e->m_src = w;
1289 ++w->m_outdeg;
1290 } else {
1291 --v->m_indeg;
1292 e->m_tgt = w;
1293 ++w->m_indeg;
1294 }
1295 }
1296
1297
operator <<(std::ostream & os,ogdf::node v)1298 std::ostream &operator<<(std::ostream &os, ogdf::node v)
1299 {
1300 if (v) os << v->index(); else os << "nil";
1301 return os;
1302 }
1303
operator <<(std::ostream & os,ogdf::edge e)1304 std::ostream &operator<<(std::ostream &os, ogdf::edge e)
1305 {
1306 if (e) os << "(" << e->source() << "," << e->target() << ")";
1307 else os << "nil";
1308 return os;
1309 }
1310
operator <<(std::ostream & os,ogdf::adjEntry adj)1311 std::ostream &operator<<(std::ostream &os, ogdf::adjEntry adj)
1312 {
1313 if (adj) {
1314 ogdf::edge e = adj->theEdge();
1315 if (adj == e->adjSource())
1316 os << e->source() << "->" << e->target();
1317 else
1318 os << e->target() << "->" << e->source();
1319 } else os << "nil";
1320 return os;
1321 }
1322
1323
CCsInfo(const Graph & G)1324 Graph::CCsInfo::CCsInfo(const Graph& G)
1325 : m_graph(&G), m_nodes(G.numberOfNodes()), m_edges(G.numberOfEdges())
1326 {
1327 NodeArray<int> component(G,-1);
1328
1329 ArrayBuffer<node> S;
1330 SListPure<int> startNodes;
1331 SListPure<int> startEdges;
1332 int nComponent = 0, n = 0, m = 0;
1333
1334 for(node v : G.nodes) {
1335 if (component[v] != -1) continue;
1336
1337 S.push(v);
1338 component[v] = nComponent;
1339
1340 while(!S.empty()) {
1341 node w = S.popRet();
1342 m_nodes[n++] = w;
1343
1344 for(adjEntry adj : w->adjEntries) {
1345 if((adj->index() & 1) == 0)
1346 m_edges[m++] = adj->theEdge();
1347 node x = adj->twinNode();
1348 if (component[x] == -1) {
1349 component[x] = nComponent;
1350 S.push(x);
1351 }
1352 }
1353 }
1354
1355 ++nComponent;
1356 startNodes.pushBack(n);
1357 startEdges.pushBack(m);
1358 }
1359
1360 m_startNode.init(nComponent+1);
1361 m_startNode[0] = 0;
1362
1363 int i = 1;
1364 for (int j : startNodes)
1365 m_startNode[i++] = j;
1366
1367
1368 m_startEdge.init(nComponent+1);
1369 m_startEdge[0] = 0;
1370
1371 i = 1;
1372 for(int j : startEdges)
1373 m_startEdge[i++] = j;
1374
1375 m_numCC = nComponent;
1376 }
1377
hide(edge e)1378 void Graph::HiddenEdgeSet::hide(edge e)
1379 {
1380 OGDF_ASSERT(m_graph == e->graphOf());
1381 OGDF_ASSERT(!e->m_hidden);
1382
1383 node src = e->m_src, tgt = e->m_tgt;
1384
1385 src->adjEntries.delPure(e->m_adjSrc);
1386 src->m_outdeg--;
1387 tgt->adjEntries.delPure(e->m_adjTgt);
1388 tgt->m_indeg--;
1389
1390 m_graph->edges.move(e, m_edges);
1391 #ifdef OGDF_DEBUG
1392 e->m_hidden = true;
1393 #endif
1394 }
1395
restore(edge e)1396 void Graph::HiddenEdgeSet::restore(edge e)
1397 {
1398 OGDF_ASSERT(m_graph == e->graphOf());
1399 OGDF_ASSERT(e->m_hidden);
1400 OGDF_ASSERT(!m_edges.empty());
1401
1402 node v = e->m_src;
1403 v->adjEntries.pushBack(e->m_adjSrc);
1404 ++v->m_outdeg;
1405
1406 node w = e->m_tgt;
1407 w->adjEntries.pushBack(e->m_adjTgt);
1408 ++w->m_indeg;
1409
1410 m_edges.move(e, m_graph->edges);
1411 #ifdef OGDF_DEBUG
1412 e->m_hidden = false;
1413 #endif
1414 }
1415
restore()1416 void Graph::HiddenEdgeSet::restore()
1417 {
1418 OGDF_ASSERT(m_graph != nullptr);
1419
1420 while (!m_edges.empty()) {
1421 restore(m_edges.head());
1422 }
1423 }
1424
size()1425 int Graph::HiddenEdgeSet::size()
1426 {
1427 return m_edges.size();
1428 }
1429
operator <<(std::ostream & os,const Graph::EdgeType & et)1430 std::ostream &operator<<(std::ostream &os, const Graph::EdgeType &et) {
1431 switch (et) {
1432 case Graph::EdgeType::association: os << "association"; break;
1433 case Graph::EdgeType::generalization: os << "generalization"; break;
1434 case Graph::EdgeType::dependency: os << "dependency"; break;
1435 }
1436 return os;
1437 }
1438
1439 }
1440