xref: /aosp_15_r20/external/google-fruit/include/fruit/impl/meta/graph.h (revision a65addddcf69f38db5b288d787b6b7571a57bb8f)
1*a65addddSAndroid Build Coastguard Worker /*
2*a65addddSAndroid Build Coastguard Worker  * Copyright 2014 Google Inc. All rights reserved.
3*a65addddSAndroid Build Coastguard Worker  *
4*a65addddSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*a65addddSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*a65addddSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*a65addddSAndroid Build Coastguard Worker  *
8*a65addddSAndroid Build Coastguard Worker  *     http://www.apache.org/licenses/LICENSE-2.0
9*a65addddSAndroid Build Coastguard Worker  *
10*a65addddSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*a65addddSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*a65addddSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*a65addddSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*a65addddSAndroid Build Coastguard Worker  * limitations under the License.
15*a65addddSAndroid Build Coastguard Worker  */
16*a65addddSAndroid Build Coastguard Worker 
17*a65addddSAndroid Build Coastguard Worker #ifndef FRUIT_META_GRAPH_H
18*a65addddSAndroid Build Coastguard Worker #define FRUIT_META_GRAPH_H
19*a65addddSAndroid Build Coastguard Worker 
20*a65addddSAndroid Build Coastguard Worker #include <fruit/impl/meta/immutable_map.h>
21*a65addddSAndroid Build Coastguard Worker #include <fruit/impl/meta/map.h>
22*a65addddSAndroid Build Coastguard Worker #include <fruit/impl/meta/set.h>
23*a65addddSAndroid Build Coastguard Worker #include <fruit/impl/meta/triplet.h>
24*a65addddSAndroid Build Coastguard Worker 
25*a65addddSAndroid Build Coastguard Worker namespace fruit {
26*a65addddSAndroid Build Coastguard Worker namespace impl {
27*a65addddSAndroid Build Coastguard Worker namespace meta {
28*a65addddSAndroid Build Coastguard Worker 
29*a65addddSAndroid Build Coastguard Worker // A Graph is a Map from each node to a set containing its neighbors.
30*a65addddSAndroid Build Coastguard Worker 
31*a65addddSAndroid Build Coastguard Worker using GetGraphNodes = GetImmutableMapKeys;
32*a65addddSAndroid Build Coastguard Worker 
33*a65addddSAndroid Build Coastguard Worker using GraphFindNeighbors = FindInImmutableMap;
34*a65addddSAndroid Build Coastguard Worker 
35*a65addddSAndroid Build Coastguard Worker using GraphContainsNode = ImmutableMapContainsKey;
36*a65addddSAndroid Build Coastguard Worker 
37*a65addddSAndroid Build Coastguard Worker // Returns a loop in the given graph as a Vector<N1, ..., Nk> such that the graph contains a loop
38*a65addddSAndroid Build Coastguard Worker // N1->...->Nk->N1, or None if there are no loops.
39*a65addddSAndroid Build Coastguard Worker struct GraphFindLoop {
40*a65addddSAndroid Build Coastguard Worker   template <typename G>
41*a65addddSAndroid Build Coastguard Worker   struct apply {
42*a65addddSAndroid Build Coastguard Worker     using ImmutableG = VectorToImmutableMap(G);
43*a65addddSAndroid Build Coastguard Worker 
44*a65addddSAndroid Build Coastguard Worker     // DfsVisit(VisitedSet, VisitingSet, Node) does a DFS visit starting at Node and returns a
45*a65addddSAndroid Build Coastguard Worker     // Triplet<NewVisitedSet, Loop, IsLoopComplete>, where Loop is the Vector representing the part
46*a65addddSAndroid Build Coastguard Worker     // of the loop starting at Node (if any loop was found) or Null otherwise.
47*a65addddSAndroid Build Coastguard Worker     struct DfsVisit {
48*a65addddSAndroid Build Coastguard Worker       template <typename VisitedSet, typename VisitingSet, typename Node>
49*a65addddSAndroid Build Coastguard Worker       struct apply {
50*a65addddSAndroid Build Coastguard Worker         using NewVisitingSet = AddToSetUnchecked(VisitingSet, Node);
51*a65addddSAndroid Build Coastguard Worker 
52*a65addddSAndroid Build Coastguard Worker         struct VisitSingleNeighbor {
53*a65addddSAndroid Build Coastguard Worker           // CurrentResult is a Triplet<VisitedSet, Loop, IsLoopComplete> (where IsLoopComplete
54*a65addddSAndroid Build Coastguard Worker           // is only meaningful when Loop is not None).
55*a65addddSAndroid Build Coastguard Worker           template <typename CurrentResult, typename Neighbor>
56*a65addddSAndroid Build Coastguard Worker           struct apply {
57*a65addddSAndroid Build Coastguard Worker             using type = If(IsNone(typename CurrentResult::Second),
58*a65addddSAndroid Build Coastguard Worker                             // Go ahead, no loop found yet.
59*a65addddSAndroid Build Coastguard Worker                             DfsVisit(typename CurrentResult::First, NewVisitingSet, Neighbor),
60*a65addddSAndroid Build Coastguard Worker                             // Found a loop in another neighbor of the same node, we don't need to
61*a65addddSAndroid Build Coastguard Worker                             // visit this neighbor.
62*a65addddSAndroid Build Coastguard Worker                             CurrentResult);
63*a65addddSAndroid Build Coastguard Worker           };
64*a65addddSAndroid Build Coastguard Worker         };
65*a65addddSAndroid Build Coastguard Worker 
66*a65addddSAndroid Build Coastguard Worker         using NewVisitedSet = AddToSet(VisitedSet, Node);
67*a65addddSAndroid Build Coastguard Worker         using Neighbors = GraphFindNeighbors(ImmutableG, Node);
68*a65addddSAndroid Build Coastguard Worker         using Result = FoldVector(Neighbors, VisitSingleNeighbor, ConsTriplet(NewVisitedSet, None, Bool<false>));
69*a65addddSAndroid Build Coastguard Worker         using type = If(IsNone(Neighbors),
70*a65addddSAndroid Build Coastguard Worker                         // No neighbors.
71*a65addddSAndroid Build Coastguard Worker                         ConsTriplet(NewVisitedSet, None, Bool<false>),
72*a65addddSAndroid Build Coastguard Worker                         If(IsInSet(Node, VisitingSet),
73*a65addddSAndroid Build Coastguard Worker                            // We've just found a loop, since Node is another node that we're currently
74*a65addddSAndroid Build Coastguard Worker                            // visiting
75*a65addddSAndroid Build Coastguard Worker                            Triplet<VisitedSet, Vector<Node>, Bool<false>>,
76*a65addddSAndroid Build Coastguard Worker                            If(IsNone(GetSecond(Result)),
77*a65addddSAndroid Build Coastguard Worker                               // No loop found.
78*a65addddSAndroid Build Coastguard Worker                               Result,
79*a65addddSAndroid Build Coastguard Worker                               // Found a loop
80*a65addddSAndroid Build Coastguard Worker                               If(GetThird(Result) /* IsLoopComplete */, Result,
81*a65addddSAndroid Build Coastguard Worker                                  If(VectorEndsWith(GetSecond(Result) /* Loop */, Node),
82*a65addddSAndroid Build Coastguard Worker                                     // The loop is complete now.
83*a65addddSAndroid Build Coastguard Worker                                     ConsTriplet(GetFirst(Result), GetSecond(Result), Bool<true>),
84*a65addddSAndroid Build Coastguard Worker                                     // Loop still not complete, add the current node.
85*a65addddSAndroid Build Coastguard Worker                                     ConsTriplet(GetFirst(Result), PushFront(GetSecond(Result), Node), Bool<false>))))));
86*a65addddSAndroid Build Coastguard Worker       };
87*a65addddSAndroid Build Coastguard Worker     };
88*a65addddSAndroid Build Coastguard Worker 
89*a65addddSAndroid Build Coastguard Worker     struct VisitStartingAtNode {
90*a65addddSAndroid Build Coastguard Worker       // CurrentResult is a Pair<CurrentVisitedSet, Loop>
91*a65addddSAndroid Build Coastguard Worker       template <typename CurrentResult, typename Node>
92*a65addddSAndroid Build Coastguard Worker       struct apply {
93*a65addddSAndroid Build Coastguard Worker         using DfsResult = DfsVisit(GetFirst(CurrentResult), EmptySet, Node);
94*a65addddSAndroid Build Coastguard Worker         using type = If(IsNone(GetSecond(CurrentResult)),
95*a65addddSAndroid Build Coastguard Worker                         // No loop found yet.
96*a65addddSAndroid Build Coastguard Worker                         MakePair(GetFirst(DfsResult), GetSecond(DfsResult)),
97*a65addddSAndroid Build Coastguard Worker                         // Found a loop, return early
98*a65addddSAndroid Build Coastguard Worker                         CurrentResult);
99*a65addddSAndroid Build Coastguard Worker       };
100*a65addddSAndroid Build Coastguard Worker     };
101*a65addddSAndroid Build Coastguard Worker 
102*a65addddSAndroid Build Coastguard Worker     using type = GetSecond(FoldVector(GetMapKeys(G), VisitStartingAtNode, Pair<EmptySet, None>));
103*a65addddSAndroid Build Coastguard Worker   };
104*a65addddSAndroid Build Coastguard Worker };
105*a65addddSAndroid Build Coastguard Worker 
106*a65addddSAndroid Build Coastguard Worker } // namespace meta
107*a65addddSAndroid Build Coastguard Worker } // namespace impl
108*a65addddSAndroid Build Coastguard Worker } // namespace fruit
109*a65addddSAndroid Build Coastguard Worker 
110*a65addddSAndroid Build Coastguard Worker #endif // FRUIT_META_GRAPH_H
111