// Streamed execution. void Stage::execute(StreamPointTable& table) { typedef std::list<Stage *> StageList; std::list<StageList> lists; StageList stages; table.finalize(); // Walk from the current stage backwards. As we add each input, copy // the list of stages and push it on a list. We then pull a list from the // front of list and keep going. Placing on the back and pulling from the // front insures that the stages will be executed in the order that they // were added. If we hit stage with no previous stages, we execute // the stage list. // All this often amounts to a bunch of list copying for // no reason, but it's more simple than what we might otherwise do and // this should be a nit in the grand scheme of execution time. // // As an example, if there are four paths from the end stage (writer) to // reader stages, there will be four stage lists and execute(table, stages) // will be called four times. Stage *s = this; stages.push_front(s); while (true) { if (s->m_inputs.empty()) execute(table, stages); else { for (auto s2 : s->m_inputs) { StageList newStages(stages); newStages.push_front(s2); lists.push_front(newStages); } } if (lists.empty()) break; stages = lists.back(); lists.pop_back(); s = stages.front(); } }
void Stage::execute(StreamPointTable& table, std::list<Stage *>& stages) { std::vector<bool> skips(table.capacity()); std::list<Stage *> filters; SpatialReference srs; // Separate out the first stage. Stage *reader = stages.front(); // Build a list of all stages except the first. We may have a writer in // this list in addition to filters, but we treat them in the same way. auto begin = stages.begin(); begin++; std::copy(begin, stages.end(), std::back_inserter(filters)); for (Stage *s : stages) { s->ready(table); srs = s->getSpatialReference(); if (!srs.empty()) table.setSpatialReference(srs); } // Loop until we're finished. We handle the number of points up to // the capacity of the StreamPointTable that we've been provided. bool finished = false; while (!finished) { // Clear the spatial reference when processing starts. table.clearSpatialReferences(); PointId idx = 0; PointRef point(table, idx); point_count_t pointLimit = table.capacity(); // When we get false back from a reader, we're done, so set // the point limit to the number of points processed in this loop // of the table. for (PointId idx = 0; idx < pointLimit; idx++) { point.setPointId(idx); finished = !reader->processOne(point); if (finished) pointLimit = idx; } srs = reader->getSpatialReference(); if (!srs.empty()) table.setSpatialReference(srs); // When we get a false back from a filter, we're filtering out a // point, so add it to the list of skips so that it doesn't get // processed by subsequent filters. for (Stage *s : filters) { for (PointId idx = 0; idx < pointLimit; idx++) { if (skips[idx]) continue; point.setPointId(idx); if (!s->processOne(point)) skips[idx] = true; } srs = s->getSpatialReference(); if (!srs.empty()) table.setSpatialReference(srs); } // Yes, vector<bool> is terrible. Can do something better later. for (size_t i = 0; i < skips.size(); ++i) skips[i] = false; table.reset(); } for (Stage *s : stages) s->done(table); }
// Streamed execution. void Stage::execute(StreamPointTable& table) { typedef std::list<Stage *> StageList; SpatialReference srs; std::list<StageList> lists; StageList stages; StageList readies; table.finalize(); // Walk from the current stage backwards. As we add each input, copy // the list of stages and push it on a list. We then pull a list from the // back of list and keep going. Pushing on the front and pulling from the // back insures that the stages will be executed in the order that they // were added. If we hit stage with no previous stages, we execute // the stage list. // All this often amounts to a bunch of list copying for // no reason, but it's more simple than what we might otherwise do and // this should be a nit in the grand scheme of execution time. // // As an example, if there are four paths from the end stage (writer) to // reader stages, there will be four stage lists and execute(table, stages) // will be called four times. Stage *s = this; stages.push_front(s); while (true) { if (s->m_inputs.empty()) { // Ready stages before we execute. for (auto s2 : stages) if (!Utils::contains(readies, s2)) { s2->pushLogLeader(); s2->ready(table); s2->pushLogLeader(); readies.push_back(s2); srs = s2->getSpatialReference(); if (!srs.empty()) table.setSpatialReference(srs); } execute(table, stages); } else { for (auto s2 : s->m_inputs) { StageList newStages(stages); newStages.push_front(s2); lists.push_front(newStages); } } if (lists.empty()) break; stages = lists.back(); lists.pop_back(); s = stages.front(); } for (auto s2 : stages) { s2->pushLogLeader(); s2->l_done(table); s2->popLogLeader(); } }