#include <map>
#include "dfa_minimization.h"
namespace wasm::DFA {
namespace {
using InputGraph = std::vector<std::vector<std::vector<size_t>>>;
struct Partitions {
size_t sets = 0;
std::vector<size_t> elements;
std::vector<size_t> elementIndices;
std::vector<size_t> setIndices;
std::vector<size_t> beginnings;
std::vector<size_t> endings;
std::vector<size_t> pivots;
Partitions() = default;
Partitions(size_t size)
: elements(size), elementIndices(size), setIndices(size), beginnings(size),
endings(size), pivots(size) {}
struct Set {
using Iterator = std::vector<size_t>::iterator;
Partitions& partitions;
size_t index;
Set(Partitions& partitions, size_t index)
: partitions(partitions), index(index) {}
Iterator begin() {
return partitions.elements.begin() + partitions.beginnings[index];
}
Iterator end() {
return partitions.elements.begin() + partitions.endings[index];
}
size_t size() {
return partitions.endings[index] - partitions.beginnings[index];
}
bool hasMarks() {
return partitions.pivots[index] != partitions.beginnings[index];
}
size_t split() {
size_t begin = partitions.beginnings[index];
size_t end = partitions.endings[index];
size_t pivot = partitions.pivots[index];
if (pivot == begin) {
return 0;
}
if (pivot == end) {
partitions.pivots[index] = begin;
return 0;
}
size_t newIndex = partitions.sets++;
partitions.beginnings[newIndex] = begin;
partitions.pivots[newIndex] = begin;
partitions.endings[newIndex] = pivot;
for (size_t i = begin; i < pivot; ++i) {
partitions.setIndices[partitions.elements[i]] = newIndex;
}
partitions.beginnings[index] = pivot;
return newIndex;
}
};
Set getSet(size_t index) { return {*this, index}; }
Set getSetForElem(size_t element) { return getSet(setIndices[element]); }
void mark(size_t element) {
size_t index = elementIndices[element];
size_t set = setIndices[element];
size_t pivot = pivots[set];
if (index >= pivot) {
elements[index] = elements[pivot];
elementIndices[elements[index]] = index;
elements[pivot] = element;
elementIndices[element] = pivot;
++pivots[set];
}
}
};
Partitions initializeStatePartitions(const InputGraph& inputGraph,
size_t numElements) {
Partitions partitions(numElements);
size_t elementIndex = 0;
for (const auto& partition : inputGraph) {
size_t set = partitions.sets++;
partitions.beginnings[set] = elementIndex;
partitions.pivots[set] = elementIndex;
for (size_t i = 0; i < partition.size(); ++i) {
partitions.elements[elementIndex] = elementIndex;
partitions.elementIndices[elementIndex] = elementIndex;
partitions.setIndices[elementIndex] = set;
++elementIndex;
}
partitions.endings[set] = elementIndex;
}
return partitions;
}
struct Transition {
size_t pred;
size_t label;
};
void initializeTransitions(const InputGraph& inputGraph,
size_t numElements,
size_t numTransitions,
std::vector<Transition>& transitions,
std::vector<size_t>& transitionIndices) {
std::map<size_t, std::vector<Transition>> transitionMap;
size_t elementIndex = 0;
for (const auto& partition : inputGraph) {
for (const auto& elem : partition) {
size_t label = 0;
for (const auto& succ : elem) {
transitionMap[succ].push_back({elementIndex, label++});
}
++elementIndex;
}
}
transitions.reserve(numTransitions);
transitionIndices.reserve(numElements + 1);
for (size_t dest = 0; dest < numElements; ++dest) {
transitionIndices.push_back(transitions.size());
if (auto it = transitionMap.find(dest); it != transitionMap.end()) {
transitions.insert(
transitions.end(), it->second.begin(), it->second.end());
}
}
transitionIndices.push_back(transitions.size());
}
Partitions
initializeSplitterPartitions(Partitions& partitions,
const std::vector<Transition>& transitions,
const std::vector<size_t>& transitionIndices) {
Partitions splitters(transitions.size());
size_t elementIndex = 0;
for (size_t statePartition = 0; statePartition < partitions.sets;
++statePartition) {
std::map<size_t, std::vector<size_t>> currTransitions;
for (size_t state : partitions.getSet(statePartition)) {
for (size_t transition = transitionIndices[state],
end = transitionIndices[state + 1];
transition < end;
++transition) {
currTransitions[transitions[transition].label].push_back(transition);
}
}
for (auto& pair : currTransitions) {
size_t set = splitters.sets++;
splitters.beginnings[set] = elementIndex;
splitters.pivots[set] = elementIndex;
for (size_t transition : pair.second) {
splitters.elements[elementIndex] = transition;
splitters.elementIndices[transition] = elementIndex;
splitters.setIndices[transition] = set;
++elementIndex;
}
splitters.endings[set] = elementIndex;
}
}
return splitters;
}
}
namespace Internal {
std::vector<std::vector<size_t>>
refinePartitionsImpl(const InputGraph& inputGraph) {
size_t numElements = 0;
size_t numTransitions = 0;
for (const auto& partition : inputGraph) {
numElements += partition.size();
for (const auto& elem : partition) {
numTransitions += elem.size();
}
}
Partitions partitions = initializeStatePartitions(inputGraph, numElements);
std::vector<Transition> transitions;
std::vector<size_t> transitionIndices;
initializeTransitions(
inputGraph, numElements, numTransitions, transitions, transitionIndices);
Partitions splitters =
initializeSplitterPartitions(partitions, transitions, transitionIndices);
std::vector<size_t> potentialSplitters;
potentialSplitters.reserve(splitters.sets);
for (size_t i = 0; i < splitters.sets; ++i) {
potentialSplitters.push_back(i);
}
while (!potentialSplitters.empty()) {
size_t potentialSplitter = potentialSplitters.back();
potentialSplitters.pop_back();
std::vector<size_t> markedPartitions;
for (size_t transition : splitters.getSet(potentialSplitter)) {
size_t state = transitions[transition].pred;
auto partition = partitions.getSetForElem(state);
if (!partition.hasMarks()) {
markedPartitions.push_back(partition.index);
}
partitions.mark(state);
}
for (size_t partition : markedPartitions) {
size_t newPartition = partitions.getSet(partition).split();
if (!newPartition) {
continue;
}
if (partitions.getSet(newPartition).size() <
partitions.getSet(partition).size()) {
newPartition = partition;
}
std::vector<size_t> markedSplitters;
for (size_t state : partitions.getSet(newPartition)) {
for (size_t t = transitionIndices[state],
end = transitionIndices[state + 1];
t < end;
++t) {
auto splitter = splitters.getSetForElem(t);
if (!splitter.hasMarks()) {
markedSplitters.push_back(splitter.index);
}
splitters.mark(t);
}
}
for (size_t splitter : markedSplitters) {
size_t newSplitter = splitters.getSet(splitter).split();
if (newSplitter) {
potentialSplitters.push_back(newSplitter);
}
}
}
}
std::vector<std::vector<size_t>> resultPartitions;
resultPartitions.reserve(partitions.sets);
for (size_t p = 0; p < partitions.sets; ++p) {
auto partition = partitions.getSet(p);
std::vector<size_t> resultPartition;
resultPartition.reserve(partition.size());
for (size_t elem : partition) {
resultPartition.push_back(elem);
}
resultPartitions.emplace_back(std::move(resultPartition));
}
return resultPartitions;
}
}
}