1314564Sdim//===-- TypeCategoryMap.cpp ----------------------------------------*- C++
2314564Sdim//-*-===//
3254721Semaste//
4353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5353358Sdim// See https://llvm.org/LICENSE.txt for license information.
6353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7254721Semaste//
8254721Semaste//===----------------------------------------------------------------------===//
9254721Semaste
10254721Semaste#include "lldb/DataFormatters/TypeCategoryMap.h"
11254721Semaste
12258884Semaste#include "lldb/DataFormatters/FormatClasses.h"
13321369Sdim#include "lldb/Utility/Log.h"
14258884Semaste
15254721Semaste
16254721Semasteusing namespace lldb;
17254721Semasteusing namespace lldb_private;
18254721Semaste
19309124SdimTypeCategoryMap::TypeCategoryMap(IFormatChangeListener *lst)
20314564Sdim    : m_map_mutex(), listener(lst), m_map(), m_active_categories() {
21314564Sdim  ConstString default_cs("default");
22314564Sdim  lldb::TypeCategoryImplSP default_sp =
23314564Sdim      lldb::TypeCategoryImplSP(new TypeCategoryImpl(listener, default_cs));
24314564Sdim  Add(default_cs, default_sp);
25314564Sdim  Enable(default_cs, First);
26254721Semaste}
27254721Semaste
28314564Sdimvoid TypeCategoryMap::Add(KeyType name, const ValueSP &entry) {
29314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
30314564Sdim  m_map[name] = entry;
31314564Sdim  if (listener)
32314564Sdim    listener->Changed();
33254721Semaste}
34254721Semaste
35314564Sdimbool TypeCategoryMap::Delete(KeyType name) {
36314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
37314564Sdim  MapIterator iter = m_map.find(name);
38314564Sdim  if (iter == m_map.end())
39314564Sdim    return false;
40314564Sdim  m_map.erase(name);
41314564Sdim  Disable(name);
42314564Sdim  if (listener)
43314564Sdim    listener->Changed();
44314564Sdim  return true;
45254721Semaste}
46254721Semaste
47314564Sdimbool TypeCategoryMap::Enable(KeyType category_name, Position pos) {
48314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
49314564Sdim  ValueSP category;
50314564Sdim  if (!Get(category_name, category))
51314564Sdim    return false;
52314564Sdim  return Enable(category, pos);
53254721Semaste}
54254721Semaste
55314564Sdimbool TypeCategoryMap::Disable(KeyType category_name) {
56314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
57314564Sdim  ValueSP category;
58314564Sdim  if (!Get(category_name, category))
59254721Semaste    return false;
60314564Sdim  return Disable(category);
61254721Semaste}
62254721Semaste
63314564Sdimbool TypeCategoryMap::Enable(ValueSP category, Position pos) {
64314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
65314564Sdim  if (category.get()) {
66314564Sdim    Position pos_w = pos;
67314564Sdim    if (pos == First || m_active_categories.size() == 0)
68314564Sdim      m_active_categories.push_front(category);
69314564Sdim    else if (pos == Last || pos == m_active_categories.size())
70314564Sdim      m_active_categories.push_back(category);
71314564Sdim    else if (pos < m_active_categories.size()) {
72314564Sdim      ActiveCategoriesList::iterator iter = m_active_categories.begin();
73314564Sdim      while (pos_w) {
74314564Sdim        pos_w--, iter++;
75314564Sdim      }
76314564Sdim      m_active_categories.insert(iter, category);
77314564Sdim    } else
78314564Sdim      return false;
79314564Sdim    category->Enable(true, pos);
80314564Sdim    return true;
81314564Sdim  }
82314564Sdim  return false;
83254721Semaste}
84254721Semaste
85314564Sdimbool TypeCategoryMap::Disable(ValueSP category) {
86314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
87314564Sdim  if (category.get()) {
88314564Sdim    m_active_categories.remove_if(delete_matching_categories(category));
89314564Sdim    category->Disable();
90314564Sdim    return true;
91314564Sdim  }
92314564Sdim  return false;
93280031Sdim}
94280031Sdim
95314564Sdimvoid TypeCategoryMap::EnableAllCategories() {
96314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
97314564Sdim  std::vector<ValueSP> sorted_categories(m_map.size(), ValueSP());
98314564Sdim  MapType::iterator iter = m_map.begin(), end = m_map.end();
99314564Sdim  for (; iter != end; ++iter) {
100314564Sdim    if (iter->second->IsEnabled())
101314564Sdim      continue;
102314564Sdim    auto pos = iter->second->GetLastEnabledPosition();
103314564Sdim    if (pos >= sorted_categories.size()) {
104314564Sdim      auto iter = std::find_if(
105314564Sdim          sorted_categories.begin(), sorted_categories.end(),
106314564Sdim          [](const ValueSP &sp) -> bool { return sp.get() == nullptr; });
107314564Sdim      pos = std::distance(sorted_categories.begin(), iter);
108280031Sdim    }
109314564Sdim    sorted_categories.at(pos) = iter->second;
110314564Sdim  }
111314564Sdim  decltype(sorted_categories)::iterator viter = sorted_categories.begin(),
112314564Sdim                                        vend = sorted_categories.end();
113314564Sdim  for (; viter != vend; viter++)
114353358Sdim    if (*viter)
115314564Sdim      Enable(*viter, Last);
116280031Sdim}
117280031Sdim
118314564Sdimvoid TypeCategoryMap::DisableAllCategories() {
119314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
120344779Sdim  for (Position p = First; !m_active_categories.empty(); p++) {
121314564Sdim    m_active_categories.front()->SetEnabledPosition(p);
122314564Sdim    Disable(m_active_categories.front());
123314564Sdim  }
124254721Semaste}
125254721Semaste
126314564Sdimvoid TypeCategoryMap::Clear() {
127314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
128314564Sdim  m_map.clear();
129314564Sdim  m_active_categories.clear();
130314564Sdim  if (listener)
131314564Sdim    listener->Changed();
132254721Semaste}
133254721Semaste
134314564Sdimbool TypeCategoryMap::Get(KeyType name, ValueSP &entry) {
135314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
136314564Sdim  MapIterator iter = m_map.find(name);
137314564Sdim  if (iter == m_map.end())
138254721Semaste    return false;
139314564Sdim  entry = iter->second;
140314564Sdim  return true;
141254721Semaste}
142254721Semaste
143314564Sdimbool TypeCategoryMap::Get(uint32_t pos, ValueSP &entry) {
144314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
145314564Sdim  MapIterator iter = m_map.begin();
146314564Sdim  MapIterator end = m_map.end();
147314564Sdim  while (pos > 0) {
148314564Sdim    iter++;
149314564Sdim    pos--;
150314564Sdim    if (iter == end)
151314564Sdim      return false;
152314564Sdim  }
153314564Sdim  entry = iter->second;
154314564Sdim  return false;
155314564Sdim}
156309124Sdim
157314564Sdimbool TypeCategoryMap::AnyMatches(
158314564Sdim    ConstString type_name, TypeCategoryImpl::FormatCategoryItems items,
159314564Sdim    bool only_enabled, const char **matching_category,
160314564Sdim    TypeCategoryImpl::FormatCategoryItems *matching_type) {
161314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
162314564Sdim
163314564Sdim  MapIterator pos, end = m_map.end();
164314564Sdim  for (pos = m_map.begin(); pos != end; pos++) {
165314564Sdim    if (pos->second->AnyMatches(type_name, items, only_enabled,
166314564Sdim                                matching_category, matching_type))
167314564Sdim      return true;
168314564Sdim  }
169314564Sdim  return false;
170254721Semaste}
171254721Semaste
172360784Sdimtemplate <typename ImplSP>
173360784Sdimvoid TypeCategoryMap::Get(FormattersMatchData &match_data, ImplSP &retval) {
174314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
175309124Sdim
176314564Sdim  uint32_t reason_why;
177314564Sdim  ActiveCategoriesIterator begin, end = m_active_categories.end();
178314564Sdim
179314564Sdim  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS));
180314564Sdim
181314564Sdim  if (log) {
182314564Sdim    for (auto match : match_data.GetMatchesVector()) {
183360784Sdim      LLDB_LOGF(
184360784Sdim          log,
185360784Sdim          "[%s] candidate match = %s %s %s %s reason = %" PRIu32,
186360784Sdim          __FUNCTION__,
187314564Sdim          match.GetTypeName().GetCString(),
188314564Sdim          match.DidStripPointer() ? "strip-pointers" : "no-strip-pointers",
189314564Sdim          match.DidStripReference() ? "strip-reference" : "no-strip-reference",
190314564Sdim          match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef",
191314564Sdim          match.GetReason());
192296417Sdim    }
193314564Sdim  }
194296417Sdim
195314564Sdim  for (begin = m_active_categories.begin(); begin != end; begin++) {
196314564Sdim    lldb::TypeCategoryImplSP category_sp = *begin;
197360784Sdim    ImplSP current_format;
198360784Sdim    LLDB_LOGF(log, "[%s] Trying to use category %s", __FUNCTION__,
199360784Sdim              category_sp->GetName());
200360784Sdim    if (!category_sp->Get(
201360784Sdim            match_data.GetValueObject().GetObjectRuntimeLanguage(),
202360784Sdim            match_data.GetMatchesVector(), current_format, &reason_why))
203314564Sdim      continue;
204258054Semaste
205360784Sdim    retval = std::move(current_format);
206360784Sdim    return;
207314564Sdim  }
208360784Sdim  LLDB_LOGF(log, "[%s] nothing found - returning empty SP", __FUNCTION__);
209254721Semaste}
210254721Semaste
211360784Sdim/// Explicit instantiations for the three types.
212360784Sdim/// \{
213360784Sdimtemplate void
214360784SdimTypeCategoryMap::Get<lldb::TypeFormatImplSP>(FormattersMatchData &match_data,
215360784Sdim                                             lldb::TypeFormatImplSP &retval);
216360784Sdimtemplate void
217360784SdimTypeCategoryMap::Get<lldb::TypeSummaryImplSP>(FormattersMatchData &match_data,
218360784Sdim                                              lldb::TypeSummaryImplSP &retval);
219360784Sdimtemplate void TypeCategoryMap::Get<lldb::SyntheticChildrenSP>(
220360784Sdim    FormattersMatchData &match_data, lldb::SyntheticChildrenSP &retval);
221360784Sdim/// \}
222309124Sdim
223314564Sdimvoid TypeCategoryMap::ForEach(ForEachCallback callback) {
224314564Sdim  if (callback) {
225314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
226314564Sdim
227314564Sdim    // loop through enabled categories in respective order
228254721Semaste    {
229314564Sdim      ActiveCategoriesIterator begin, end = m_active_categories.end();
230314564Sdim      for (begin = m_active_categories.begin(); begin != end; begin++) {
231314564Sdim        lldb::TypeCategoryImplSP category = *begin;
232314564Sdim        if (!callback(category))
233314564Sdim          break;
234314564Sdim      }
235314564Sdim    }
236309124Sdim
237314564Sdim    // loop through disabled categories in just any order
238314564Sdim    {
239314564Sdim      MapIterator pos, end = m_map.end();
240314564Sdim      for (pos = m_map.begin(); pos != end; pos++) {
241314564Sdim        if (pos->second->IsEnabled())
242314564Sdim          continue;
243314564Sdim        if (!callback(pos->second))
244314564Sdim          break;
245314564Sdim      }
246254721Semaste    }
247314564Sdim  }
248254721Semaste}
249254721Semaste
250314564SdimTypeCategoryImplSP TypeCategoryMap::GetAtIndex(uint32_t index) {
251314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
252309124Sdim
253314564Sdim  if (index < m_map.size()) {
254314564Sdim    MapIterator pos, end = m_map.end();
255314564Sdim    for (pos = m_map.begin(); pos != end; pos++) {
256314564Sdim      if (index == 0)
257314564Sdim        return pos->second;
258314564Sdim      index--;
259254721Semaste    }
260314564Sdim  }
261314564Sdim
262314564Sdim  return TypeCategoryImplSP();
263254721Semaste}
264