|
3 | 3 |
|
4 | 4 | #include "phasar/DB/ProjectIRDBBase.h" |
5 | 5 | #include "phasar/Utils/ByRef.h" |
6 | | -#include "phasar/Utils/TypeTraits.h" |
7 | | - |
8 | | -#include "llvm/ADT/DenseMap.h" |
9 | | -#include "llvm/ADT/DenseMapInfo.h" |
10 | | -#include "llvm/ADT/SmallVector.h" |
| 6 | +#include "phasar/Utils/Compressor.h" |
11 | 7 |
|
12 | 8 | #include <cstdint> |
13 | | -#include <deque> |
14 | | -#include <functional> |
15 | | -#include <optional> |
16 | 9 | #include <type_traits> |
17 | 10 |
|
18 | 11 | namespace psr { |
19 | | -template <typename T, typename Enable = void> class Compressor; |
20 | | - |
21 | | -/// \brief A utility class that assigns a sequential Id to every inserted |
22 | | -/// object. |
23 | | -/// |
24 | | -/// This specialization handles types that can be efficiently passed by value |
25 | | -template <typename T> |
26 | | -class Compressor<T, std::enable_if_t<CanEfficientlyPassByValue<T>>> { |
27 | | -public: |
28 | | - void reserve(size_t Capacity) { |
29 | | - assert(Capacity <= UINT32_MAX); |
30 | | - ToInt.reserve(Capacity); |
31 | | - FromInt.reserve(Capacity); |
32 | | - } |
33 | | - |
34 | | - uint32_t getOrInsert(T Elem) { |
35 | | - auto [It, Inserted] = ToInt.try_emplace(Elem, ToInt.size()); |
36 | | - if (Inserted) { |
37 | | - FromInt.push_back(Elem); |
38 | | - } |
39 | | - return It->second; |
40 | | - } |
41 | | - |
42 | | - std::optional<uint32_t> getOrNull(T Elem) const { |
43 | | - if (auto It = ToInt.find(Elem); It != ToInt.end()) { |
44 | | - return It->second; |
45 | | - } |
46 | | - return std::nullopt; |
47 | | - } |
48 | | - |
49 | | - T operator[](size_t Idx) const noexcept { |
50 | | - assert(Idx < FromInt.size()); |
51 | | - return FromInt[Idx]; |
52 | | - } |
53 | | - |
54 | | - [[nodiscard]] size_t size() const noexcept { return FromInt.size(); } |
55 | | - [[nodiscard]] size_t capacity() const noexcept { |
56 | | - return FromInt.capacity() + |
57 | | - ToInt.getMemorySize() / sizeof(typename decltype(ToInt)::value_type); |
58 | | - } |
59 | | - |
60 | | - auto begin() const noexcept { return FromInt.begin(); } |
61 | | - auto end() const noexcept { return FromInt.end(); } |
62 | | - |
63 | | -private: |
64 | | - llvm::DenseMap<T, uint32_t> ToInt; |
65 | | - llvm::SmallVector<T, 0> FromInt; |
66 | | -}; |
67 | | - |
68 | | -/// \brief A utility class that assigns a sequential Id to every inserted |
69 | | -/// object. |
70 | | -/// |
71 | | -/// This specialization handles types that cannot be efficiently passed by value |
72 | | -template <typename T> |
73 | | -class Compressor<T, std::enable_if_t<!CanEfficientlyPassByValue<T>>> { |
74 | | -public: |
75 | | - void reserve(size_t Capacity) { |
76 | | - assert(Capacity <= UINT32_MAX); |
77 | | - ToInt.reserve(Capacity); |
78 | | - } |
79 | | - |
80 | | - /// Returns the index of the given element in the compressors storage. If the |
81 | | - /// element isn't present yet, it will be added first and its index will |
82 | | - /// then be returned. |
83 | | - uint32_t getOrInsert(const T &Elem) { |
84 | | - if (auto It = ToInt.find(&Elem); It != ToInt.end()) { |
85 | | - return It->second; |
86 | | - } |
87 | | - auto Ret = FromInt.size(); |
88 | | - auto *Ins = &FromInt.emplace_back(Elem); |
89 | | - ToInt[Ins] = Ret; |
90 | | - return Ret; |
91 | | - } |
92 | | - |
93 | | - /// Returns the index of the given element in the compressors storage. If the |
94 | | - /// element isn't present yet, it will be added first and its index will |
95 | | - /// then be returned. |
96 | | - uint32_t getOrInsert(T &&Elem) { |
97 | | - if (auto It = ToInt.find(&Elem); It != ToInt.end()) { |
98 | | - return It->second; |
99 | | - } |
100 | | - auto Ret = FromInt.size(); |
101 | | - auto *Ins = &FromInt.emplace_back(std::move(Elem)); |
102 | | - ToInt[Ins] = Ret; |
103 | | - return Ret; |
104 | | - } |
105 | | - |
106 | | - /// Returns the index of the given element in the compressors storage. If the |
107 | | - /// element isn't present, std::nullopt will be returned |
108 | | - std::optional<uint32_t> getOrNull(const T &Elem) const { |
109 | | - if (auto It = ToInt.find(&Elem); It != ToInt.end()) { |
110 | | - return It->second; |
111 | | - } |
112 | | - return std::nullopt; |
113 | | - } |
114 | | - |
115 | | - const T &operator[](size_t Idx) const noexcept { |
116 | | - assert(Idx < FromInt.size()); |
117 | | - return FromInt[Idx]; |
118 | | - } |
119 | | - |
120 | | - [[nodiscard]] size_t size() const noexcept { return FromInt.size(); } |
121 | | - [[nodiscard]] size_t capacity() const noexcept { |
122 | | - return FromInt.size() + |
123 | | - ToInt.getMemorySize() / sizeof(typename decltype(ToInt)::value_type); |
124 | | - } |
125 | | - |
126 | | - auto begin() const noexcept { return FromInt.begin(); } |
127 | | - auto end() const noexcept { return FromInt.end(); } |
128 | | - |
129 | | -private: |
130 | | - struct DSI : llvm::DenseMapInfo<const T *> { |
131 | | - static auto getHashValue(const T *Elem) noexcept { |
132 | | - assert(Elem != nullptr); |
133 | | - if constexpr (has_llvm_dense_map_info<T>) { |
134 | | - return llvm::DenseMapInfo<T>::getHashValue(*Elem); |
135 | | - } else { |
136 | | - return std::hash<T>{}(*Elem); |
137 | | - } |
138 | | - } |
139 | | - static auto isEqual(const T *LHS, const T *RHS) noexcept { |
140 | | - if (LHS == RHS) { |
141 | | - return true; |
142 | | - } |
143 | | - if (LHS == DSI::getEmptyKey() || LHS == DSI::getTombstoneKey() || |
144 | | - RHS == DSI::getEmptyKey() || RHS == DSI::getTombstoneKey()) { |
145 | | - return false; |
146 | | - } |
147 | | - if constexpr (has_llvm_dense_map_info<T>) { |
148 | | - return llvm::DenseMapInfo<T>::isEqual(*LHS, *RHS); |
149 | | - } else { |
150 | | - return *LHS == *RHS; |
151 | | - } |
152 | | - } |
153 | | - }; |
154 | | - |
155 | | - std::deque<T> FromInt; |
156 | | - llvm::DenseMap<const T *, uint32_t, DSI> ToInt; |
157 | | -}; |
158 | 12 |
|
159 | 13 | struct NoneCompressor final { |
160 | 14 | constexpr NoneCompressor() noexcept = default; |
|
0 commit comments