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