#ifndef wasm_analysis_lattices_flat_h
#define wasm_analysis_lattices_flat_h
#include <variant>
#if __cplusplus >= 202002L
#include <concepts>
#endif
#include "../lattice.h"
#include "support/utilities.h"
namespace wasm::analysis {
#if __cplusplus >= 202002L
template<typename T>
concept Flattenable = std::copyable<T> && std::equality_comparable<T>;
template<Flattenable T>
#else
template<typename T>
#endif
struct Flat {
private:
struct Bot {};
struct Top {};
public:
struct Element : std::variant<Bot, T, Top> {
bool isBottom() const noexcept { return std::get_if<Bot>(this); }
bool isTop() const noexcept { return std::get_if<Top>(this); }
const T* getVal() const noexcept { return std::get_if<T>(this); }
T* getVal() noexcept { return std::get_if<T>(this); }
bool operator==(const Element& other) const noexcept {
return ((isBottom() && other.isBottom()) || (isTop() && other.isTop()) ||
(getVal() && other.getVal() && *getVal() == *other.getVal()));
}
bool operator!=(const Element& other) const noexcept {
return !(*this == other);
}
};
Element getBottom() const noexcept { return Element{Bot{}}; }
Element getTop() const noexcept { return Element{Top{}}; }
Element get(T&& val) const noexcept { return Element{std::move(val)}; }
LatticeComparison compare(const Element& a, const Element& b) const noexcept {
if (a.index() < b.index()) {
return LESS;
} else if (a.index() > b.index()) {
return GREATER;
} else if (auto pA = a.getVal(); pA && *pA != *b.getVal()) {
return NO_RELATION;
} else {
return EQUAL;
}
}
bool join(Element& joinee, const Element& joiner) const noexcept {
switch (compare(joinee, joiner)) {
case LESS:
joinee = joiner;
return true;
case NO_RELATION:
joinee = Element{Top{}};
return true;
case GREATER:
case EQUAL:
return false;
}
WASM_UNREACHABLE("unexpected comparison result");
}
};
#if __cplusplus >= 202002L
static_assert(Lattice<Flat<int>>);
#endif
}
#endif