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