Skip to content

Commit f9f1a3a

Browse files
committed
Made LatticeDomain an own class, such that free functions don't get confused with std::variant
1 parent e670cc2 commit f9f1a3a

1 file changed

Lines changed: 75 additions & 20 deletions

File tree

include/phasar/PhasarLLVM/Utils/LatticeDomain.h

Lines changed: 75 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#define PHASAR_PHASARLLVM_UTILS_LATTICEDOMAIN_H
1212

1313
#include "llvm/Support/ErrorHandling.h"
14+
#include "llvm/Support/raw_ostream.h"
1415

1516
#include <iostream>
1617
#include <type_traits>
@@ -23,7 +24,11 @@ namespace psr {
2324
/// the lattice.
2425
struct Top {};
2526

26-
static inline std::ostream &operator<<(std::ostream &OS, Top /*unused*/) {
27+
inline std::ostream &operator<<(std::ostream &OS, Top /*unused*/) {
28+
return OS << "Top";
29+
}
30+
31+
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Top /*unused*/) {
2732
return OS << "Top";
2833
}
2934

@@ -32,17 +37,66 @@ static inline std::ostream &operator<<(std::ostream &OS, Top /*unused*/) {
3237
/// of the lattice.
3338
struct Bottom {};
3439

35-
static inline std::ostream &operator<<(std::ostream &OS, Bottom /*unused*/) {
40+
inline std::ostream &operator<<(std::ostream &OS, Bottom /*unused*/) {
3641
return OS << "Bottom";
3742
}
3843

39-
/// A easy shorthand to construct a complete lattice of L.
40-
template <typename L> using LatticeDomain = std::variant<L, Top, Bottom>;
44+
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Bottom /*unused*/) {
45+
return OS << "Bottom";
46+
}
4147

48+
/// A easy shorthand to construct a complete lattice of L.
4249
template <typename L>
50+
struct LatticeDomain : public std::variant<Top, L, Bottom> {
51+
using std::variant<Top, L, Bottom>::variant;
52+
53+
[[nodiscard]] inline bool isBottom() const noexcept {
54+
return std::holds_alternative<Bottom>(*this);
55+
}
56+
[[nodiscard]] inline bool isTop() const noexcept {
57+
return std::holds_alternative<Top>(*this);
58+
}
59+
[[nodiscard]] inline L *getValueOrNull() noexcept {
60+
return std::get_if<L>(this);
61+
}
62+
[[nodiscard]] inline const L *getValueOrNull() const noexcept {
63+
return std::get_if<L>(this);
64+
}
65+
};
66+
67+
// template <typename L> using LatticeDomain = std::variant<L, Top, Bottom>;
68+
69+
template <typename L,
70+
typename = std::void_t<decltype(std::declval<std::ostream &>()
71+
<< std::declval<L>())>>
4372
inline std::ostream &operator<<(std::ostream &OS, const LatticeDomain<L> &LD) {
44-
std::visit([&OS](const auto &LVal) { OS << LVal; }, LD);
45-
return OS;
73+
if (LD.isBottom()) {
74+
return OS << "Bottom";
75+
}
76+
if (LD.isTop()) {
77+
return OS << "Top";
78+
}
79+
80+
const auto *Val = LD.getValueOrNull();
81+
assert(Val && "Only alternative remaining is L");
82+
return OS << *Val;
83+
}
84+
85+
template <typename L,
86+
typename = std::void_t<decltype(std::declval<llvm::raw_ostream &>()
87+
<< std::declval<L>())>>
88+
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
89+
const LatticeDomain<L> &LD) {
90+
if (LD.isBottom()) {
91+
return OS << "Bottom";
92+
}
93+
if (LD.isTop()) {
94+
return OS << "Top";
95+
}
96+
97+
const auto *Val = LD.getValueOrNull();
98+
assert(Val && "Only alternative remaining is L");
99+
return OS << *Val;
46100
}
47101

48102
template <typename L>
@@ -52,10 +106,9 @@ inline bool operator==(const LatticeDomain<L> &Lhs,
52106
return false;
53107
}
54108

55-
if (auto LhsPtr = std::get_if<L>(&Lhs)) {
56-
if (auto RhsPtr = std::get_if<L>(&Rhs)) {
57-
return *LhsPtr == *RhsPtr;
58-
}
109+
if (auto LhsPtr = Lhs.getValueOrNull()) {
110+
/// No need to check whether Lhs is an L; the indices are already the same
111+
return *LhsPtr == *Rhs.getValueOrNull();
59112
}
60113

61114
return true;
@@ -65,7 +118,7 @@ template <
65118
typename L, typename LL,
66119
typename = std::void_t<decltype(std::declval<LL>() == std::declval<L>())>>
67120
inline bool operator==(const LL &Lhs, const LatticeDomain<L> Rhs) {
68-
if (const auto *RVal = std::get_if<L>(&Rhs)) {
121+
if (const auto *RVal = Rhs.getValueOrNull()) {
69122
return Lhs == *RVal;
70123
}
71124
return false;
@@ -87,26 +140,28 @@ inline bool operator!=(const LatticeDomain<L> &Lhs,
87140
template <typename L>
88141
inline bool operator<(const LatticeDomain<L> &Lhs,
89142
const LatticeDomain<L> &Rhs) {
90-
// Top < (Lhs::L < Rhs::L) < Bottom
91-
if (std::holds_alternative<Top>(Rhs)) {
143+
/// Top < (Lhs::L < Rhs::L) < Bottom
144+
if (Rhs.isTop()) {
92145
return false;
93146
}
94-
if (std::holds_alternative<Top>(Lhs)) {
147+
if (Lhs.isTop()) {
95148
return true;
96149
}
97150

98-
if (auto LhsPtr = std::get_if<L>(&Lhs)) {
99-
if (auto RhsPtr = std::get_if<L>(&Rhs)) {
151+
if (auto LhsPtr = Lhs.getValueOrNull()) {
152+
if (auto RhsPtr = Rhs.getValueOrNull()) {
100153
return *LhsPtr < *RhsPtr;
101154
}
102155
}
103156

104-
if (std::holds_alternative<Bottom>(Rhs)) {
105-
return !std::holds_alternative<Bottom>(Lhs);
106-
}
107-
if (std::holds_alternative<Bottom>(Lhs)) {
157+
if (Lhs.isBottom()) {
108158
return false;
109159
}
160+
161+
if (Rhs.isBottom()) {
162+
return true;
163+
}
164+
110165
llvm_unreachable("All comparision cases should be handled above.");
111166
}
112167

0 commit comments

Comments
 (0)