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