#ifndef wasm_analysis_lattices_stack_h
#define wasm_analysis_lattices_stack_h
#include <optional>
#include <vector>
#include "../lattice.h"
#include "bool.h"
namespace wasm::analysis {
template<Lattice L> struct Stack {
using Element = std::vector<typename L::Element>;
L lattice;
Stack(L&& lattice) : lattice(std::move(lattice)) {}
void push(Element& elem, typename L::Element&& element) const noexcept {
if (elem.empty() && element == lattice.getBottom()) {
return;
}
elem.emplace_back(std::move(element));
}
typename L::Element pop(Element& elem) const noexcept {
if (elem.empty()) {
return lattice.getBottom();
}
auto popped = elem.back();
elem.pop_back();
return popped;
}
Element getBottom() const noexcept { return Element{}; }
LatticeComparison compare(const Element& a, const Element& b) const noexcept {
auto result = EQUAL;
for (auto itA = a.rbegin(), itB = b.rbegin();
itA != a.rend() || itB != b.rend();
++itA, ++itB) {
if (itA == a.rend()) {
return LESS;
}
if (itB == b.rend()) {
return GREATER;
}
switch (lattice.compare(*itA, *itB)) {
case NO_RELATION:
return NO_RELATION;
case EQUAL:
continue;
case LESS:
if (result == GREATER) {
return NO_RELATION;
}
result = LESS;
continue;
case GREATER:
if (result == LESS) {
return NO_RELATION;
}
result = GREATER;
continue;
}
}
return result;
}
bool join(Element& joinee, const Element& joiner) const noexcept {
bool result = false;
size_t extraSize = 0;
if (joiner.size() > joinee.size()) {
extraSize = joiner.size() - joinee.size();
auto extraBegin = joiner.begin();
auto extraEnd = joiner.begin() + extraSize;
joinee.insert(joinee.begin(), extraBegin, extraEnd);
result = true;
}
auto joineeIt = joinee.rbegin();
auto joinerIt = joiner.rbegin();
auto joineeEnd = joinee.rend() - extraSize;
for (; joineeIt != joineeEnd && joinerIt != joiner.rend();
++joineeIt, ++joinerIt) {
result |= lattice.join(*joineeIt, *joinerIt);
}
return result;
}
};
template<typename L> Stack(L&&) -> Stack<L>;
#if __cplusplus >= 202002L
static_assert(Lattice<Stack<Bool>>);
#endif
}
#endif