1010#ifndef PHASAR_PHASARLLVM_UTILS_LATTICEDOMAIN_H
1111#define PHASAR_PHASARLLVM_UTILS_LATTICEDOMAIN_H
1212
13- #include " llvm/Support/ErrorHandling.h"
14-
1513#include < iostream>
14+ #include < type_traits>
1615#include < variant>
1716
17+ #include " llvm/Support/ErrorHandling.h"
18+ #include " llvm/Support/raw_ostream.h"
19+
20+ #include " phasar/Utils/TypeTraits.h"
21+
1822namespace psr {
1923
2024// / Represents the infimum of the lattice:
2125// / Top is the greatest element that is less than or equal to all elements of
2226// / the lattice.
2327struct Top {};
2428
25- static inline std::ostream &operator <<(std::ostream &OS,
26- [[maybe_unused]] const Top &T) {
29+ inline std::ostream &operator <<(std::ostream &OS, Top /* unused*/ ) {
30+ return OS << " Top" ;
31+ }
32+
33+ inline llvm::raw_ostream &operator <<(llvm::raw_ostream &OS, Top /* unused*/ ) {
2734 return OS << " Top" ;
2835}
2936
@@ -32,43 +39,96 @@ static inline std::ostream &operator<<(std::ostream &OS,
3239// / of the lattice.
3340struct Bottom {};
3441
35- static inline std::ostream &operator <<(std::ostream &OS,
36- [[maybe_unused]] const Bottom &B) {
42+ inline std::ostream &operator <<(std::ostream &OS, Bottom /* unused*/ ) {
3743 return OS << " Bottom" ;
3844}
3945
40- // / A easy shorthand to construct a complete lattice of L.
41- template <typename L> using LatticeDomain = std::variant<L, Top, Bottom>;
46+ inline llvm::raw_ostream &operator <<(llvm::raw_ostream &OS, Bottom /* unused*/ ) {
47+ return OS << " Bottom" ;
48+ }
4249
50+ // / A easy shorthand to construct a complete lattice of L.
4351template <typename L>
52+ struct LatticeDomain : public std ::variant<Top, L, Bottom> {
53+ using std::variant<Top, L, Bottom>::variant;
54+
55+ [[nodiscard]] inline bool isBottom () const noexcept {
56+ return std::holds_alternative<Bottom>(*this );
57+ }
58+ [[nodiscard]] inline bool isTop () const noexcept {
59+ return std::holds_alternative<Top>(*this );
60+ }
61+ [[nodiscard]] inline L *getValueOrNull () noexcept {
62+ return std::get_if<L>(this );
63+ }
64+ [[nodiscard]] inline const L *getValueOrNull () const noexcept {
65+ return std::get_if<L>(this );
66+ }
67+ };
68+
69+ template <typename L,
70+ typename = std::void_t <decltype (std::declval<std::ostream &>()
71+ << std::declval<L>())>>
4472inline std::ostream &operator <<(std::ostream &OS, const LatticeDomain<L> &LD) {
45- if (auto T = std::get_if<Top>(&LD )) {
46- return OS << *T ;
73+ if (LD. isBottom ( )) {
74+ return OS << " Bottom " ;
4775 }
48- if (auto B = std::get_if<Bottom>(&LD )) {
49- return OS << *B ;
76+ if (LD. isTop ( )) {
77+ return OS << " Top " ;
5078 }
51- return OS << std::get<L>(LD);
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;
52100}
53101
54102template <typename L>
55103inline bool operator ==(const LatticeDomain<L> &Lhs,
56104 const LatticeDomain<L> &Rhs) {
57- if (std::holds_alternative<Top>( Lhs) && std::holds_alternative<Top>( Rhs)) {
58- return true ;
105+ if (Lhs. index () != Rhs. index ( )) {
106+ return false ;
59107 }
60- if (std::holds_alternative<Bottom>( Lhs) &&
61- std::holds_alternative<Bottom>(Rhs)) {
62- return true ;
108+ if (auto LhsPtr = Lhs. getValueOrNull ()) {
109+ // / No need to check whether Lhs is an L; the indices are already the same
110+ return *LhsPtr == *Rhs. getValueOrNull () ;
63111 }
64- if (auto *LhsPtr = std::get_if<L>(&Lhs)) {
65- if (auto *RhsPtr = std::get_if<L>(&Rhs)) {
66- return *LhsPtr == *RhsPtr;
67- }
112+ return true ;
113+ }
114+
115+ template <
116+ typename L, typename LL,
117+ typename = std::void_t <decltype (std::declval<LL>() == std::declval<L>())>>
118+ inline bool operator ==(const LL &Lhs, const LatticeDomain<L> Rhs) {
119+ if (auto RVal = Rhs.getValueOrNull ()) {
120+ return Lhs == *RVal;
68121 }
69122 return false ;
70123}
71124
125+ template <
126+ typename L, typename LL,
127+ typename = std::void_t <decltype (std::declval<LL>() == std::declval<L>())>>
128+ inline bool operator ==(const LatticeDomain<L> Lhs, const LL &Rhs) {
129+ return Rhs == Lhs;
130+ }
131+
72132template <typename L>
73133inline bool operator !=(const LatticeDomain<L> &Lhs,
74134 const LatticeDomain<L> &Rhs) {
@@ -78,26 +138,24 @@ inline bool operator!=(const LatticeDomain<L> &Lhs,
78138template <typename L>
79139inline bool operator <(const LatticeDomain<L> &Lhs,
80140 const LatticeDomain<L> &Rhs) {
81- // Top < (Lhs::L < Rhs::L) < Bottom
82- if (std::holds_alternative<Top>( Rhs)) {
141+ // / Top < (Lhs::L < Rhs::L) < Bottom
142+ if (Rhs. isTop ( )) {
83143 return false ;
84144 }
85- if (std::holds_alternative<Top>( Lhs)) {
145+ if (Lhs. isTop ( )) {
86146 return true ;
87147 }
88-
89- if (auto *LhsPtr = std::get_if<L>(&Lhs)) {
90- if (auto *RhsPtr = std::get_if<L>(&Rhs)) {
148+ if (auto LhsPtr = Lhs.getValueOrNull ()) {
149+ if (auto RhsPtr = Rhs.getValueOrNull ()) {
91150 return *LhsPtr < *RhsPtr;
92151 }
93152 }
94-
95- if (std::holds_alternative<Bottom>(Rhs)) {
96- return !std::holds_alternative<Bottom>(Lhs);
97- }
98- if (std::holds_alternative<Bottom>(Lhs)) {
153+ if (Lhs.isBottom ()) {
99154 return false ;
100155 }
156+ if (Rhs.isBottom ()) {
157+ return true ;
158+ }
101159 llvm_unreachable (" All comparision cases should be handled above." );
102160}
103161
0 commit comments