1*ab11e3c9SKudo Chien #include "MapperRegistry.h"
2*ab11e3c9SKudo Chien #include "Mapper.h"
3*ab11e3c9SKudo Chien 
4*ab11e3c9SKudo Chien #include <array>
5*ab11e3c9SKudo Chien #include <map>
6*ab11e3c9SKudo Chien #include <set>
7*ab11e3c9SKudo Chien #include <utility>
8*ab11e3c9SKudo Chien 
9*ab11e3c9SKudo Chien namespace reanimated {
10*ab11e3c9SKudo Chien 
startMapper(std::shared_ptr<Mapper> mapper)11*ab11e3c9SKudo Chien void MapperRegistry::startMapper(std::shared_ptr<Mapper> mapper) {
12*ab11e3c9SKudo Chien   mappers[mapper->id] = mapper;
13*ab11e3c9SKudo Chien   updatedSinceLastExecute = true;
14*ab11e3c9SKudo Chien }
15*ab11e3c9SKudo Chien 
stopMapper(unsigned long id)16*ab11e3c9SKudo Chien void MapperRegistry::stopMapper(unsigned long id) {
17*ab11e3c9SKudo Chien   mappers.erase(id);
18*ab11e3c9SKudo Chien   updatedSinceLastExecute = true;
19*ab11e3c9SKudo Chien }
20*ab11e3c9SKudo Chien 
execute(jsi::Runtime & rt)21*ab11e3c9SKudo Chien void MapperRegistry::execute(jsi::Runtime &rt) {
22*ab11e3c9SKudo Chien   if (updatedSinceLastExecute) {
23*ab11e3c9SKudo Chien     updateOrder();
24*ab11e3c9SKudo Chien     updatedSinceLastExecute = false;
25*ab11e3c9SKudo Chien   }
26*ab11e3c9SKudo Chien   for (auto &mapper : sortedMappers) {
27*ab11e3c9SKudo Chien     if (mapper->dirty) {
28*ab11e3c9SKudo Chien       mapper->execute(rt);
29*ab11e3c9SKudo Chien     }
30*ab11e3c9SKudo Chien   }
31*ab11e3c9SKudo Chien }
32*ab11e3c9SKudo Chien 
needRunOnRender()33*ab11e3c9SKudo Chien bool MapperRegistry::needRunOnRender() {
34*ab11e3c9SKudo Chien   return updatedSinceLastExecute; // TODO: also run if input nodes are dirty
35*ab11e3c9SKudo Chien }
36*ab11e3c9SKudo Chien 
updateOrder()37*ab11e3c9SKudo Chien void MapperRegistry::updateOrder() { // Topological sorting
38*ab11e3c9SKudo Chien   sortedMappers.clear();
39*ab11e3c9SKudo Chien 
40*ab11e3c9SKudo Chien   struct NodeID {
41*ab11e3c9SKudo Chien     std::shared_ptr<Mapper> mapper;
42*ab11e3c9SKudo Chien     std::shared_ptr<MutableValue> mutableValue;
43*ab11e3c9SKudo Chien 
44*ab11e3c9SKudo Chien     explicit NodeID(std::shared_ptr<Mapper> mapper) {
45*ab11e3c9SKudo Chien       if (mapper == nullptr) {
46*ab11e3c9SKudo Chien         throw std::runtime_error(
47*ab11e3c9SKudo Chien             "Graph couldn't be sorted (Mapper cannot be nullptr)");
48*ab11e3c9SKudo Chien       }
49*ab11e3c9SKudo Chien       this->mapper = mapper;
50*ab11e3c9SKudo Chien     }
51*ab11e3c9SKudo Chien 
52*ab11e3c9SKudo Chien     explicit NodeID(std::shared_ptr<MutableValue> mutableValue) {
53*ab11e3c9SKudo Chien       if (mutableValue == nullptr) {
54*ab11e3c9SKudo Chien         throw std::runtime_error(
55*ab11e3c9SKudo Chien             "Graph couldn't be sorted (Mutable cannot be nullptr)");
56*ab11e3c9SKudo Chien       }
57*ab11e3c9SKudo Chien       this->mutableValue = mutableValue;
58*ab11e3c9SKudo Chien     }
59*ab11e3c9SKudo Chien 
60*ab11e3c9SKudo Chien     bool isMutable() const {
61*ab11e3c9SKudo Chien       return mutableValue != nullptr;
62*ab11e3c9SKudo Chien     }
63*ab11e3c9SKudo Chien 
64*ab11e3c9SKudo Chien     bool operator<(const NodeID &other) const {
65*ab11e3c9SKudo Chien       if (isMutable() != other.isMutable())
66*ab11e3c9SKudo Chien         return isMutable() < other.isMutable();
67*ab11e3c9SKudo Chien 
68*ab11e3c9SKudo Chien       if (isMutable()) {
69*ab11e3c9SKudo Chien         return mutableValue < other.mutableValue;
70*ab11e3c9SKudo Chien       }
71*ab11e3c9SKudo Chien 
72*ab11e3c9SKudo Chien       return mapper < other.mapper;
73*ab11e3c9SKudo Chien     }
74*ab11e3c9SKudo Chien   };
75*ab11e3c9SKudo Chien 
76*ab11e3c9SKudo Chien   std::map<NodeID, int> deg;
77*ab11e3c9SKudo Chien 
78*ab11e3c9SKudo Chien   std::map<std::shared_ptr<MutableValue>, std::vector<std::shared_ptr<Mapper>>>
79*ab11e3c9SKudo Chien       mappersThatUseSharedValue;
80*ab11e3c9SKudo Chien 
81*ab11e3c9SKudo Chien   std::set<std::pair<int, NodeID>> nodes;
82*ab11e3c9SKudo Chien 
83*ab11e3c9SKudo Chien   std::function<void(NodeID)> update = [&](NodeID id) {
84*ab11e3c9SKudo Chien     auto entry = std::make_pair(deg[id], id);
85*ab11e3c9SKudo Chien     if (nodes.find(entry) == nodes.end())
86*ab11e3c9SKudo Chien       return;
87*ab11e3c9SKudo Chien     nodes.erase(entry);
88*ab11e3c9SKudo Chien     entry.first--;
89*ab11e3c9SKudo Chien     deg[id]--;
90*ab11e3c9SKudo Chien     nodes.insert(entry);
91*ab11e3c9SKudo Chien   };
92*ab11e3c9SKudo Chien 
93*ab11e3c9SKudo Chien   for (auto &entry : mappers) {
94*ab11e3c9SKudo Chien     auto id = NodeID(entry.second);
95*ab11e3c9SKudo Chien     auto &mapper = entry.second;
96*ab11e3c9SKudo Chien     deg[id] = mapper->inputs.size();
97*ab11e3c9SKudo Chien     nodes.insert(std::make_pair(deg[id], id));
98*ab11e3c9SKudo Chien 
99*ab11e3c9SKudo Chien     for (auto sharedValue : mapper->inputs) {
100*ab11e3c9SKudo Chien       auto sharedValueID = NodeID(sharedValue);
101*ab11e3c9SKudo Chien       mappersThatUseSharedValue[sharedValue].push_back(mapper);
102*ab11e3c9SKudo Chien       if (deg.count(sharedValueID) == 0) {
103*ab11e3c9SKudo Chien         deg[sharedValueID] = 0;
104*ab11e3c9SKudo Chien       }
105*ab11e3c9SKudo Chien     }
106*ab11e3c9SKudo Chien 
107*ab11e3c9SKudo Chien     for (auto sharedValue : mapper->outputs) {
108*ab11e3c9SKudo Chien       deg[NodeID(sharedValue)]++;
109*ab11e3c9SKudo Chien     }
110*ab11e3c9SKudo Chien   }
111*ab11e3c9SKudo Chien 
112*ab11e3c9SKudo Chien   for (auto &entry : deg) {
113*ab11e3c9SKudo Chien     auto id = entry.first;
114*ab11e3c9SKudo Chien     if (id.isMutable()) {
115*ab11e3c9SKudo Chien       nodes.insert(std::make_pair(entry.second, id));
116*ab11e3c9SKudo Chien     }
117*ab11e3c9SKudo Chien   }
118*ab11e3c9SKudo Chien 
119*ab11e3c9SKudo Chien   while (nodes.size() > 0 && nodes.begin()->first == 0) {
120*ab11e3c9SKudo Chien     auto entry = *nodes.begin();
121*ab11e3c9SKudo Chien     nodes.erase(entry);
122*ab11e3c9SKudo Chien 
123*ab11e3c9SKudo Chien     auto id = entry.second;
124*ab11e3c9SKudo Chien     std::vector<NodeID> toUpdate;
125*ab11e3c9SKudo Chien 
126*ab11e3c9SKudo Chien     if (id.isMutable()) {
127*ab11e3c9SKudo Chien       for (auto id : mappersThatUseSharedValue[id.mutableValue]) {
128*ab11e3c9SKudo Chien         toUpdate.push_back(NodeID(id));
129*ab11e3c9SKudo Chien       }
130*ab11e3c9SKudo Chien     } else {
131*ab11e3c9SKudo Chien       for (auto sharedValue : id.mapper->outputs) {
132*ab11e3c9SKudo Chien         toUpdate.push_back(NodeID(sharedValue));
133*ab11e3c9SKudo Chien       }
134*ab11e3c9SKudo Chien 
135*ab11e3c9SKudo Chien       sortedMappers.push_back(id.mapper);
136*ab11e3c9SKudo Chien     }
137*ab11e3c9SKudo Chien 
138*ab11e3c9SKudo Chien     for (auto &id : toUpdate)
139*ab11e3c9SKudo Chien       update(id);
140*ab11e3c9SKudo Chien   }
141*ab11e3c9SKudo Chien 
142*ab11e3c9SKudo Chien   if (nodes.size() > 0) {
143*ab11e3c9SKudo Chien     throw std::runtime_error("Cycle in mappers graph!");
144*ab11e3c9SKudo Chien   }
145*ab11e3c9SKudo Chien }
146*ab11e3c9SKudo Chien 
147*ab11e3c9SKudo Chien } // namespace reanimated
148