1 | //===-- TypeCategoryMap.cpp -----------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "lldb/DataFormatters/TypeCategoryMap.h" |
10 | |
11 | #include "lldb/DataFormatters/FormatClasses.h" |
12 | #include "lldb/Utility/LLDBLog.h" |
13 | #include "lldb/Utility/Log.h" |
14 | |
15 | using namespace lldb; |
16 | using namespace lldb_private; |
17 | |
18 | TypeCategoryMap::TypeCategoryMap(IFormatChangeListener *lst) |
19 | : m_map_mutex(), listener(lst), m_map(), m_active_categories() { |
20 | ConstString default_cs("default" ); |
21 | lldb::TypeCategoryImplSP default_sp = |
22 | lldb::TypeCategoryImplSP(new TypeCategoryImpl(listener, default_cs)); |
23 | Add(name: default_cs, entry: default_sp); |
24 | Enable(category_name: default_cs, pos: First); |
25 | } |
26 | |
27 | void TypeCategoryMap::Add(KeyType name, const TypeCategoryImplSP &entry) { |
28 | { |
29 | std::lock_guard<std::recursive_mutex> guard(m_map_mutex); |
30 | m_map[name] = entry; |
31 | } |
32 | // Release the mutex to avoid a potential deadlock between |
33 | // TypeCategoryMap::m_map_mutex and |
34 | // FormatManager::m_language_categories_mutex which can be acquired in |
35 | // reverse order when calling FormatManager::Changed. |
36 | if (listener) |
37 | listener->Changed(); |
38 | } |
39 | |
40 | bool TypeCategoryMap::Delete(KeyType name) { |
41 | { |
42 | std::lock_guard<std::recursive_mutex> guard(m_map_mutex); |
43 | MapIterator iter = m_map.find(x: name); |
44 | if (iter == m_map.end()) |
45 | return false; |
46 | m_map.erase(x: name); |
47 | Disable(category_name: name); |
48 | } |
49 | // Release the mutex to avoid a potential deadlock between |
50 | // TypeCategoryMap::m_map_mutex and |
51 | // FormatManager::m_language_categories_mutex which can be acquired in |
52 | // reverse order when calling FormatManager::Changed. |
53 | if (listener) |
54 | listener->Changed(); |
55 | return true; |
56 | } |
57 | |
58 | bool TypeCategoryMap::Enable(KeyType category_name, Position pos) { |
59 | std::lock_guard<std::recursive_mutex> guard(m_map_mutex); |
60 | TypeCategoryImplSP category; |
61 | if (!Get(name: category_name, entry&: category)) |
62 | return false; |
63 | return Enable(category, pos); |
64 | } |
65 | |
66 | bool TypeCategoryMap::Disable(KeyType category_name) { |
67 | std::lock_guard<std::recursive_mutex> guard(m_map_mutex); |
68 | TypeCategoryImplSP category; |
69 | if (!Get(name: category_name, entry&: category)) |
70 | return false; |
71 | return Disable(category); |
72 | } |
73 | |
74 | bool TypeCategoryMap::Enable(TypeCategoryImplSP category, Position pos) { |
75 | std::lock_guard<std::recursive_mutex> guard(m_map_mutex); |
76 | if (category.get()) { |
77 | Position pos_w = pos; |
78 | if (pos == First || m_active_categories.size() == 0) |
79 | m_active_categories.push_front(x: category); |
80 | else if (pos == Last || pos == m_active_categories.size()) |
81 | m_active_categories.push_back(x: category); |
82 | else if (pos < m_active_categories.size()) { |
83 | ActiveCategoriesList::iterator iter = m_active_categories.begin(); |
84 | while (pos_w) { |
85 | pos_w--, iter++; |
86 | } |
87 | m_active_categories.insert(position: iter, x: category); |
88 | } else |
89 | return false; |
90 | category->Enable(value: true, position: pos); |
91 | return true; |
92 | } |
93 | return false; |
94 | } |
95 | |
96 | bool TypeCategoryMap::Disable(TypeCategoryImplSP category) { |
97 | std::lock_guard<std::recursive_mutex> guard(m_map_mutex); |
98 | if (category.get()) { |
99 | m_active_categories.remove_if(pred: delete_matching_categories(category)); |
100 | category->Disable(); |
101 | return true; |
102 | } |
103 | return false; |
104 | } |
105 | |
106 | void TypeCategoryMap::EnableAllCategories() { |
107 | std::lock_guard<std::recursive_mutex> guard(m_map_mutex); |
108 | std::vector<TypeCategoryImplSP> sorted_categories(m_map.size(), TypeCategoryImplSP()); |
109 | MapType::iterator iter = m_map.begin(), end = m_map.end(); |
110 | for (; iter != end; ++iter) { |
111 | if (iter->second->IsEnabled()) |
112 | continue; |
113 | auto pos = iter->second->GetLastEnabledPosition(); |
114 | if (pos >= sorted_categories.size()) { |
115 | auto iter = std::find_if( |
116 | first: sorted_categories.begin(), last: sorted_categories.end(), |
117 | pred: [](const TypeCategoryImplSP &sp) -> bool { return sp.get() == nullptr; }); |
118 | pos = std::distance(first: sorted_categories.begin(), last: iter); |
119 | } |
120 | sorted_categories.at(n: pos) = iter->second; |
121 | } |
122 | decltype(sorted_categories)::iterator viter = sorted_categories.begin(), |
123 | vend = sorted_categories.end(); |
124 | for (; viter != vend; viter++) |
125 | if (*viter) |
126 | Enable(category: *viter, pos: Last); |
127 | } |
128 | |
129 | void TypeCategoryMap::DisableAllCategories() { |
130 | std::lock_guard<std::recursive_mutex> guard(m_map_mutex); |
131 | for (Position p = First; !m_active_categories.empty(); p++) { |
132 | m_active_categories.front()->SetEnabledPosition(p); |
133 | Disable(category: m_active_categories.front()); |
134 | } |
135 | } |
136 | |
137 | void TypeCategoryMap::Clear() { |
138 | { |
139 | std::lock_guard<std::recursive_mutex> guard(m_map_mutex); |
140 | m_map.clear(); |
141 | m_active_categories.clear(); |
142 | } |
143 | // Release the mutex to avoid a potential deadlock between |
144 | // TypeCategoryMap::m_map_mutex and |
145 | // FormatManager::m_language_categories_mutex which can be acquired in |
146 | // reverse order when calling FormatManager::Changed. |
147 | if (listener) |
148 | listener->Changed(); |
149 | } |
150 | |
151 | bool TypeCategoryMap::Get(KeyType name, TypeCategoryImplSP &entry) { |
152 | std::lock_guard<std::recursive_mutex> guard(m_map_mutex); |
153 | MapIterator iter = m_map.find(x: name); |
154 | if (iter == m_map.end()) |
155 | return false; |
156 | entry = iter->second; |
157 | return true; |
158 | } |
159 | |
160 | bool TypeCategoryMap::AnyMatches( |
161 | const FormattersMatchCandidate &candidate_type, |
162 | TypeCategoryImpl::FormatCategoryItems items, bool only_enabled, |
163 | const char **matching_category, |
164 | TypeCategoryImpl::FormatCategoryItems *matching_type) { |
165 | std::lock_guard<std::recursive_mutex> guard(m_map_mutex); |
166 | |
167 | MapIterator pos, end = m_map.end(); |
168 | for (pos = m_map.begin(); pos != end; pos++) { |
169 | if (pos->second->AnyMatches(candidate_type, items, only_enabled, |
170 | matching_category, matching_type)) |
171 | return true; |
172 | } |
173 | return false; |
174 | } |
175 | |
176 | template <typename ImplSP> |
177 | void TypeCategoryMap::Get(FormattersMatchData &match_data, ImplSP &retval) { |
178 | std::lock_guard<std::recursive_mutex> guard(m_map_mutex); |
179 | |
180 | ActiveCategoriesIterator begin, end = m_active_categories.end(); |
181 | |
182 | Log *log = GetLog(mask: LLDBLog::DataFormatters); |
183 | |
184 | if (log) { |
185 | for (auto match : match_data.GetMatchesVector()) { |
186 | LLDB_LOGF( |
187 | log, |
188 | "[%s] candidate match = %s %s %s %s" , |
189 | __FUNCTION__, |
190 | match.GetTypeName().GetCString(), |
191 | match.DidStripPointer() ? "strip-pointers" : "no-strip-pointers" , |
192 | match.DidStripReference() ? "strip-reference" : "no-strip-reference" , |
193 | match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef" ); |
194 | } |
195 | } |
196 | |
197 | for (begin = m_active_categories.begin(); begin != end; begin++) { |
198 | lldb::TypeCategoryImplSP category_sp = *begin; |
199 | ImplSP current_format; |
200 | LLDB_LOGF(log, "[%s] Trying to use category %s" , __FUNCTION__, |
201 | category_sp->GetName()); |
202 | if (!category_sp->Get( |
203 | match_data.GetValueObject().GetObjectRuntimeLanguage(), |
204 | match_data.GetMatchesVector(), current_format)) |
205 | continue; |
206 | |
207 | retval = std::move(current_format); |
208 | return; |
209 | } |
210 | LLDB_LOGF(log, "[%s] nothing found - returning empty SP" , __FUNCTION__); |
211 | } |
212 | |
213 | /// Explicit instantiations for the three types. |
214 | /// \{ |
215 | template void |
216 | TypeCategoryMap::Get<lldb::TypeFormatImplSP>(FormattersMatchData &match_data, |
217 | lldb::TypeFormatImplSP &retval); |
218 | template void |
219 | TypeCategoryMap::Get<lldb::TypeSummaryImplSP>(FormattersMatchData &match_data, |
220 | lldb::TypeSummaryImplSP &retval); |
221 | template void TypeCategoryMap::Get<lldb::SyntheticChildrenSP>( |
222 | FormattersMatchData &match_data, lldb::SyntheticChildrenSP &retval); |
223 | /// \} |
224 | |
225 | void TypeCategoryMap::ForEach(ForEachCallback callback) { |
226 | if (callback) { |
227 | std::lock_guard<std::recursive_mutex> guard(m_map_mutex); |
228 | |
229 | // loop through enabled categories in respective order |
230 | { |
231 | ActiveCategoriesIterator begin, end = m_active_categories.end(); |
232 | for (begin = m_active_categories.begin(); begin != end; begin++) { |
233 | lldb::TypeCategoryImplSP category = *begin; |
234 | if (!callback(category)) |
235 | break; |
236 | } |
237 | } |
238 | |
239 | // loop through disabled categories in just any order |
240 | { |
241 | MapIterator pos, end = m_map.end(); |
242 | for (pos = m_map.begin(); pos != end; pos++) { |
243 | if (pos->second->IsEnabled()) |
244 | continue; |
245 | if (!callback(pos->second)) |
246 | break; |
247 | } |
248 | } |
249 | } |
250 | } |
251 | |
252 | TypeCategoryImplSP TypeCategoryMap::GetAtIndex(uint32_t index) { |
253 | std::lock_guard<std::recursive_mutex> guard(m_map_mutex); |
254 | |
255 | if (index < m_map.size()) { |
256 | MapIterator pos, end = m_map.end(); |
257 | for (pos = m_map.begin(); pos != end; pos++) { |
258 | if (index == 0) |
259 | return pos->second; |
260 | index--; |
261 | } |
262 | } |
263 | |
264 | return TypeCategoryImplSP(); |
265 | } |
266 | |