xref: /freebsd/contrib/llvm-project/lldb/source/DataFormatters/TypeCategoryMap.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 TypeCategoryImplSP & entry)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 
Delete(KeyType name)40 bool TypeCategoryMap::Delete(KeyType name) {
41   {
42     std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
43     MapIterator iter = m_map.find(name);
44     if (iter == m_map.end())
45       return false;
46     m_map.erase(name);
47     Disable(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 
Enable(KeyType category_name,Position pos)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(category_name, category))
62     return false;
63   return Enable(category, pos);
64 }
65 
Disable(KeyType category_name)66 bool TypeCategoryMap::Disable(KeyType category_name) {
67   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
68   TypeCategoryImplSP category;
69   if (!Get(category_name, category))
70     return false;
71   return Disable(category);
72 }
73 
Enable(TypeCategoryImplSP category,Position pos)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(category);
80     else if (pos == Last || pos == m_active_categories.size())
81       m_active_categories.push_back(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(iter, category);
88     } else
89       return false;
90     category->Enable(true, pos);
91     return true;
92   }
93   return false;
94 }
95 
Disable(TypeCategoryImplSP category)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(delete_matching_categories(category));
100     category->Disable();
101     return true;
102   }
103   return false;
104 }
105 
EnableAllCategories()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           sorted_categories.begin(), sorted_categories.end(),
117           [](const TypeCategoryImplSP &sp) -> bool { return sp.get() == nullptr; });
118       pos = std::distance(sorted_categories.begin(), iter);
119     }
120     sorted_categories.at(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(*viter, Last);
127 }
128 
DisableAllCategories()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(m_active_categories.front());
134   }
135 }
136 
Clear()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 
Get(KeyType name,TypeCategoryImplSP & entry)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(name);
154   if (iter == m_map.end())
155     return false;
156   entry = iter->second;
157   return true;
158 }
159 
AnyMatches(const FormattersMatchCandidate & candidate_type,TypeCategoryImpl::FormatCategoryItems items,bool only_enabled,const char ** matching_category,TypeCategoryImpl::FormatCategoryItems * matching_type)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>
Get(FormattersMatchData & match_data,ImplSP & retval)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(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 
ForEach(ForEachCallback callback)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 
GetAtIndex(uint32_t index)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