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(default_cs, default_sp);
24   Enable(default_cs, First);
25 }
26 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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>
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 
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 
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