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
15using namespace lldb;
16using namespace lldb_private;
17
18TypeCategoryMap::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
27void 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
40bool 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
58bool 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
66bool 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
74bool 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
96bool 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
106void 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
129void 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
137void 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
151bool 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
160bool 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
176template <typename ImplSP>
177void 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/// \{
215template void
216TypeCategoryMap::Get<lldb::TypeFormatImplSP>(FormattersMatchData &match_data,
217 lldb::TypeFormatImplSP &retval);
218template void
219TypeCategoryMap::Get<lldb::TypeSummaryImplSP>(FormattersMatchData &match_data,
220 lldb::TypeSummaryImplSP &retval);
221template void TypeCategoryMap::Get<lldb::SyntheticChildrenSP>(
222 FormattersMatchData &match_data, lldb::SyntheticChildrenSP &retval);
223/// \}
224
225void 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
252TypeCategoryImplSP 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

source code of lldb/source/DataFormatters/TypeCategoryMap.cpp