1/*
2 * Copyright (C) 2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include <wtf/GraphNodeWorklist.h>
29
30template<typename Graph>
31class SpanningTree {
32public:
33 SpanningTree(Graph& graph)
34 : m_graph(graph)
35 , m_data(graph.template newMap<Data>())
36 {
37 ExtendedGraphNodeWorklist<typename Graph::Node, unsigned, typename Graph::Set> worklist;
38 worklist.push(m_graph.root(), 0);
39
40 size_t number = 0;
41
42 while (GraphNodeWith<typename Graph::Node, unsigned> item = worklist.pop()) {
43 typename Graph::Node block = item.node;
44 unsigned successorIndex = item.data;
45
46 // We initially push with successorIndex = 0 regardless of whether or not we have any
47 // successors. This is so that we can assign our prenumber. Subsequently we get pushed
48 // with higher successorIndex values. We finally push successorIndex == # successors
49 // to calculate our post number.
50 ASSERT(!successorIndex || successorIndex <= m_graph.successors(block).size());
51
52 if (!successorIndex)
53 m_data[block].pre = number++;
54
55 if (successorIndex < m_graph.successors(block).size()) {
56 unsigned nextSuccessorIndex = successorIndex + 1;
57 // We need to push this even if this is out of bounds so we can compute
58 // the post number.
59 worklist.forcePush(block, nextSuccessorIndex);
60
61 typename Graph::Node successorBlock = m_graph.successors(block)[successorIndex];
62 worklist.push(successorBlock, 0);
63 } else
64 m_data[block].post = number++;
65 }
66 }
67
68 // Returns true if a is a descendent of b.
69 // Note a is a descendent of b if they're equal.
70 bool isDescendent(typename Graph::Node a, typename Graph::Node b)
71 {
72 return m_data[b].pre <= m_data[a].pre
73 && m_data[b].post >= m_data[a].post;
74 }
75
76private:
77 struct Data {
78 size_t pre;
79 size_t post;
80 };
81
82 Graph& m_graph;
83 typename Graph::template Map<Data> m_data;
84};
85