1dda28197Spatrick //===-- TypeCategoryMap.cpp -----------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "lldb/DataFormatters/TypeCategoryMap.h"
10061da546Spatrick 
11061da546Spatrick #include "lldb/DataFormatters/FormatClasses.h"
12*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
13061da546Spatrick #include "lldb/Utility/Log.h"
14061da546Spatrick 
15061da546Spatrick using namespace lldb;
16061da546Spatrick using namespace lldb_private;
17061da546Spatrick 
TypeCategoryMap(IFormatChangeListener * lst)18061da546Spatrick TypeCategoryMap::TypeCategoryMap(IFormatChangeListener *lst)
19061da546Spatrick     : m_map_mutex(), listener(lst), m_map(), m_active_categories() {
20061da546Spatrick   ConstString default_cs("default");
21061da546Spatrick   lldb::TypeCategoryImplSP default_sp =
22061da546Spatrick       lldb::TypeCategoryImplSP(new TypeCategoryImpl(listener, default_cs));
23061da546Spatrick   Add(default_cs, default_sp);
24061da546Spatrick   Enable(default_cs, First);
25061da546Spatrick }
26061da546Spatrick 
Add(KeyType name,const ValueSP & entry)27061da546Spatrick void TypeCategoryMap::Add(KeyType name, const ValueSP &entry) {
28061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
29061da546Spatrick   m_map[name] = entry;
30061da546Spatrick   if (listener)
31061da546Spatrick     listener->Changed();
32061da546Spatrick }
33061da546Spatrick 
Delete(KeyType name)34061da546Spatrick bool TypeCategoryMap::Delete(KeyType name) {
35061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
36061da546Spatrick   MapIterator iter = m_map.find(name);
37061da546Spatrick   if (iter == m_map.end())
38061da546Spatrick     return false;
39061da546Spatrick   m_map.erase(name);
40061da546Spatrick   Disable(name);
41061da546Spatrick   if (listener)
42061da546Spatrick     listener->Changed();
43061da546Spatrick   return true;
44061da546Spatrick }
45061da546Spatrick 
Enable(KeyType category_name,Position pos)46061da546Spatrick bool TypeCategoryMap::Enable(KeyType category_name, Position pos) {
47061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
48061da546Spatrick   ValueSP category;
49061da546Spatrick   if (!Get(category_name, category))
50061da546Spatrick     return false;
51061da546Spatrick   return Enable(category, pos);
52061da546Spatrick }
53061da546Spatrick 
Disable(KeyType category_name)54061da546Spatrick bool TypeCategoryMap::Disable(KeyType category_name) {
55061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
56061da546Spatrick   ValueSP category;
57061da546Spatrick   if (!Get(category_name, category))
58061da546Spatrick     return false;
59061da546Spatrick   return Disable(category);
60061da546Spatrick }
61061da546Spatrick 
Enable(ValueSP category,Position pos)62061da546Spatrick bool TypeCategoryMap::Enable(ValueSP category, Position pos) {
63061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
64061da546Spatrick   if (category.get()) {
65061da546Spatrick     Position pos_w = pos;
66061da546Spatrick     if (pos == First || m_active_categories.size() == 0)
67061da546Spatrick       m_active_categories.push_front(category);
68061da546Spatrick     else if (pos == Last || pos == m_active_categories.size())
69061da546Spatrick       m_active_categories.push_back(category);
70061da546Spatrick     else if (pos < m_active_categories.size()) {
71061da546Spatrick       ActiveCategoriesList::iterator iter = m_active_categories.begin();
72061da546Spatrick       while (pos_w) {
73061da546Spatrick         pos_w--, iter++;
74061da546Spatrick       }
75061da546Spatrick       m_active_categories.insert(iter, category);
76061da546Spatrick     } else
77061da546Spatrick       return false;
78061da546Spatrick     category->Enable(true, pos);
79061da546Spatrick     return true;
80061da546Spatrick   }
81061da546Spatrick   return false;
82061da546Spatrick }
83061da546Spatrick 
Disable(ValueSP category)84061da546Spatrick bool TypeCategoryMap::Disable(ValueSP category) {
85061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
86061da546Spatrick   if (category.get()) {
87061da546Spatrick     m_active_categories.remove_if(delete_matching_categories(category));
88061da546Spatrick     category->Disable();
89061da546Spatrick     return true;
90061da546Spatrick   }
91061da546Spatrick   return false;
92061da546Spatrick }
93061da546Spatrick 
EnableAllCategories()94061da546Spatrick void TypeCategoryMap::EnableAllCategories() {
95061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
96061da546Spatrick   std::vector<ValueSP> sorted_categories(m_map.size(), ValueSP());
97061da546Spatrick   MapType::iterator iter = m_map.begin(), end = m_map.end();
98061da546Spatrick   for (; iter != end; ++iter) {
99061da546Spatrick     if (iter->second->IsEnabled())
100061da546Spatrick       continue;
101061da546Spatrick     auto pos = iter->second->GetLastEnabledPosition();
102061da546Spatrick     if (pos >= sorted_categories.size()) {
103061da546Spatrick       auto iter = std::find_if(
104061da546Spatrick           sorted_categories.begin(), sorted_categories.end(),
105061da546Spatrick           [](const ValueSP &sp) -> bool { return sp.get() == nullptr; });
106061da546Spatrick       pos = std::distance(sorted_categories.begin(), iter);
107061da546Spatrick     }
108061da546Spatrick     sorted_categories.at(pos) = iter->second;
109061da546Spatrick   }
110061da546Spatrick   decltype(sorted_categories)::iterator viter = sorted_categories.begin(),
111061da546Spatrick                                         vend = sorted_categories.end();
112061da546Spatrick   for (; viter != vend; viter++)
113061da546Spatrick     if (*viter)
114061da546Spatrick       Enable(*viter, Last);
115061da546Spatrick }
116061da546Spatrick 
DisableAllCategories()117061da546Spatrick void TypeCategoryMap::DisableAllCategories() {
118061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
119061da546Spatrick   for (Position p = First; !m_active_categories.empty(); p++) {
120061da546Spatrick     m_active_categories.front()->SetEnabledPosition(p);
121061da546Spatrick     Disable(m_active_categories.front());
122061da546Spatrick   }
123061da546Spatrick }
124061da546Spatrick 
Clear()125061da546Spatrick void TypeCategoryMap::Clear() {
126061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
127061da546Spatrick   m_map.clear();
128061da546Spatrick   m_active_categories.clear();
129061da546Spatrick   if (listener)
130061da546Spatrick     listener->Changed();
131061da546Spatrick }
132061da546Spatrick 
Get(KeyType name,ValueSP & entry)133061da546Spatrick bool TypeCategoryMap::Get(KeyType name, ValueSP &entry) {
134061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
135061da546Spatrick   MapIterator iter = m_map.find(name);
136061da546Spatrick   if (iter == m_map.end())
137061da546Spatrick     return false;
138061da546Spatrick   entry = iter->second;
139061da546Spatrick   return true;
140061da546Spatrick }
141061da546Spatrick 
Get(uint32_t pos,ValueSP & entry)142061da546Spatrick bool TypeCategoryMap::Get(uint32_t pos, ValueSP &entry) {
143061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
144061da546Spatrick   MapIterator iter = m_map.begin();
145061da546Spatrick   MapIterator end = m_map.end();
146061da546Spatrick   while (pos > 0) {
147061da546Spatrick     iter++;
148061da546Spatrick     pos--;
149061da546Spatrick     if (iter == end)
150061da546Spatrick       return false;
151061da546Spatrick   }
152061da546Spatrick   entry = iter->second;
153061da546Spatrick   return false;
154061da546Spatrick }
155061da546Spatrick 
AnyMatches(const FormattersMatchCandidate & candidate_type,TypeCategoryImpl::FormatCategoryItems items,bool only_enabled,const char ** matching_category,TypeCategoryImpl::FormatCategoryItems * matching_type)156061da546Spatrick bool TypeCategoryMap::AnyMatches(
157*f6aab3d8Srobert     const FormattersMatchCandidate &candidate_type,
158*f6aab3d8Srobert     TypeCategoryImpl::FormatCategoryItems items, bool only_enabled,
159*f6aab3d8Srobert     const char **matching_category,
160061da546Spatrick     TypeCategoryImpl::FormatCategoryItems *matching_type) {
161061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
162061da546Spatrick 
163061da546Spatrick   MapIterator pos, end = m_map.end();
164061da546Spatrick   for (pos = m_map.begin(); pos != end; pos++) {
165*f6aab3d8Srobert     if (pos->second->AnyMatches(candidate_type, items, only_enabled,
166061da546Spatrick                                 matching_category, matching_type))
167061da546Spatrick       return true;
168061da546Spatrick   }
169061da546Spatrick   return false;
170061da546Spatrick }
171061da546Spatrick 
172061da546Spatrick template <typename ImplSP>
Get(FormattersMatchData & match_data,ImplSP & retval)173061da546Spatrick void TypeCategoryMap::Get(FormattersMatchData &match_data, ImplSP &retval) {
174061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
175061da546Spatrick 
176061da546Spatrick   ActiveCategoriesIterator begin, end = m_active_categories.end();
177061da546Spatrick 
178*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::DataFormatters);
179061da546Spatrick 
180061da546Spatrick   if (log) {
181061da546Spatrick     for (auto match : match_data.GetMatchesVector()) {
182061da546Spatrick       LLDB_LOGF(
183061da546Spatrick           log,
184dda28197Spatrick           "[%s] candidate match = %s %s %s %s",
185061da546Spatrick           __FUNCTION__,
186061da546Spatrick           match.GetTypeName().GetCString(),
187061da546Spatrick           match.DidStripPointer() ? "strip-pointers" : "no-strip-pointers",
188061da546Spatrick           match.DidStripReference() ? "strip-reference" : "no-strip-reference",
189dda28197Spatrick           match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef");
190061da546Spatrick     }
191061da546Spatrick   }
192061da546Spatrick 
193061da546Spatrick   for (begin = m_active_categories.begin(); begin != end; begin++) {
194061da546Spatrick     lldb::TypeCategoryImplSP category_sp = *begin;
195061da546Spatrick     ImplSP current_format;
196061da546Spatrick     LLDB_LOGF(log, "[%s] Trying to use category %s", __FUNCTION__,
197061da546Spatrick               category_sp->GetName());
198061da546Spatrick     if (!category_sp->Get(
199061da546Spatrick             match_data.GetValueObject().GetObjectRuntimeLanguage(),
200dda28197Spatrick             match_data.GetMatchesVector(), current_format))
201061da546Spatrick       continue;
202061da546Spatrick 
203061da546Spatrick     retval = std::move(current_format);
204061da546Spatrick     return;
205061da546Spatrick   }
206061da546Spatrick   LLDB_LOGF(log, "[%s] nothing found - returning empty SP", __FUNCTION__);
207061da546Spatrick }
208061da546Spatrick 
209061da546Spatrick /// Explicit instantiations for the three types.
210061da546Spatrick /// \{
211061da546Spatrick template void
212061da546Spatrick TypeCategoryMap::Get<lldb::TypeFormatImplSP>(FormattersMatchData &match_data,
213061da546Spatrick                                              lldb::TypeFormatImplSP &retval);
214061da546Spatrick template void
215061da546Spatrick TypeCategoryMap::Get<lldb::TypeSummaryImplSP>(FormattersMatchData &match_data,
216061da546Spatrick                                               lldb::TypeSummaryImplSP &retval);
217061da546Spatrick template void TypeCategoryMap::Get<lldb::SyntheticChildrenSP>(
218061da546Spatrick     FormattersMatchData &match_data, lldb::SyntheticChildrenSP &retval);
219061da546Spatrick /// \}
220061da546Spatrick 
ForEach(ForEachCallback callback)221061da546Spatrick void TypeCategoryMap::ForEach(ForEachCallback callback) {
222061da546Spatrick   if (callback) {
223061da546Spatrick     std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
224061da546Spatrick 
225061da546Spatrick     // loop through enabled categories in respective order
226061da546Spatrick     {
227061da546Spatrick       ActiveCategoriesIterator begin, end = m_active_categories.end();
228061da546Spatrick       for (begin = m_active_categories.begin(); begin != end; begin++) {
229061da546Spatrick         lldb::TypeCategoryImplSP category = *begin;
230061da546Spatrick         if (!callback(category))
231061da546Spatrick           break;
232061da546Spatrick       }
233061da546Spatrick     }
234061da546Spatrick 
235061da546Spatrick     // loop through disabled categories in just any order
236061da546Spatrick     {
237061da546Spatrick       MapIterator pos, end = m_map.end();
238061da546Spatrick       for (pos = m_map.begin(); pos != end; pos++) {
239061da546Spatrick         if (pos->second->IsEnabled())
240061da546Spatrick           continue;
241061da546Spatrick         if (!callback(pos->second))
242061da546Spatrick           break;
243061da546Spatrick       }
244061da546Spatrick     }
245061da546Spatrick   }
246061da546Spatrick }
247061da546Spatrick 
GetAtIndex(uint32_t index)248061da546Spatrick TypeCategoryImplSP TypeCategoryMap::GetAtIndex(uint32_t index) {
249061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
250061da546Spatrick 
251061da546Spatrick   if (index < m_map.size()) {
252061da546Spatrick     MapIterator pos, end = m_map.end();
253061da546Spatrick     for (pos = m_map.begin(); pos != end; pos++) {
254061da546Spatrick       if (index == 0)
255061da546Spatrick         return pos->second;
256061da546Spatrick       index--;
257061da546Spatrick     }
258061da546Spatrick   }
259061da546Spatrick 
260061da546Spatrick   return TypeCategoryImplSP();
261061da546Spatrick }
262