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
16using namespace lldb;
17using namespace lldb_private;
18
19TypeCategoryMap::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
28void 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
35bool 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
47bool 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
55bool 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
63bool 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
85bool 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
95void 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
118void 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
126void 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
134bool 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
143bool 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
157bool 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
172template <typename ImplSP>
173void 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/// \{
213template void
214TypeCategoryMap::Get<lldb::TypeFormatImplSP>(FormattersMatchData &match_data,
215                                             lldb::TypeFormatImplSP &retval);
216template void
217TypeCategoryMap::Get<lldb::TypeSummaryImplSP>(FormattersMatchData &match_data,
218                                              lldb::TypeSummaryImplSP &retval);
219template void TypeCategoryMap::Get<lldb::SyntheticChildrenSP>(
220    FormattersMatchData &match_data, lldb::SyntheticChildrenSP &retval);
221/// \}
222
223void 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
250TypeCategoryImplSP 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