15ffd83dbSDimitry Andric //===-- TypeCategoryMap.cpp -----------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/DataFormatters/TypeCategoryMap.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "lldb/DataFormatters/FormatClasses.h"
1281ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
130b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric using namespace lldb;
160b57cec5SDimitry Andric using namespace lldb_private;
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric TypeCategoryMap::TypeCategoryMap(IFormatChangeListener *lst)
190b57cec5SDimitry Andric     : m_map_mutex(), listener(lst), m_map(), m_active_categories() {
200b57cec5SDimitry Andric   ConstString default_cs("default");
210b57cec5SDimitry Andric   lldb::TypeCategoryImplSP default_sp =
220b57cec5SDimitry Andric       lldb::TypeCategoryImplSP(new TypeCategoryImpl(listener, default_cs));
230b57cec5SDimitry Andric   Add(default_cs, default_sp);
240b57cec5SDimitry Andric   Enable(default_cs, First);
250b57cec5SDimitry Andric }
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric void TypeCategoryMap::Add(KeyType name, const ValueSP &entry) {
280b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
290b57cec5SDimitry Andric   m_map[name] = entry;
300b57cec5SDimitry Andric   if (listener)
310b57cec5SDimitry Andric     listener->Changed();
320b57cec5SDimitry Andric }
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric bool TypeCategoryMap::Delete(KeyType name) {
350b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
360b57cec5SDimitry Andric   MapIterator iter = m_map.find(name);
370b57cec5SDimitry Andric   if (iter == m_map.end())
380b57cec5SDimitry Andric     return false;
390b57cec5SDimitry Andric   m_map.erase(name);
400b57cec5SDimitry Andric   Disable(name);
410b57cec5SDimitry Andric   if (listener)
420b57cec5SDimitry Andric     listener->Changed();
430b57cec5SDimitry Andric   return true;
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric bool TypeCategoryMap::Enable(KeyType category_name, Position pos) {
470b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
480b57cec5SDimitry Andric   ValueSP category;
490b57cec5SDimitry Andric   if (!Get(category_name, category))
500b57cec5SDimitry Andric     return false;
510b57cec5SDimitry Andric   return Enable(category, pos);
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric bool TypeCategoryMap::Disable(KeyType category_name) {
550b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
560b57cec5SDimitry Andric   ValueSP category;
570b57cec5SDimitry Andric   if (!Get(category_name, category))
580b57cec5SDimitry Andric     return false;
590b57cec5SDimitry Andric   return Disable(category);
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric bool TypeCategoryMap::Enable(ValueSP category, Position pos) {
630b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
640b57cec5SDimitry Andric   if (category.get()) {
650b57cec5SDimitry Andric     Position pos_w = pos;
660b57cec5SDimitry Andric     if (pos == First || m_active_categories.size() == 0)
670b57cec5SDimitry Andric       m_active_categories.push_front(category);
680b57cec5SDimitry Andric     else if (pos == Last || pos == m_active_categories.size())
690b57cec5SDimitry Andric       m_active_categories.push_back(category);
700b57cec5SDimitry Andric     else if (pos < m_active_categories.size()) {
710b57cec5SDimitry Andric       ActiveCategoriesList::iterator iter = m_active_categories.begin();
720b57cec5SDimitry Andric       while (pos_w) {
730b57cec5SDimitry Andric         pos_w--, iter++;
740b57cec5SDimitry Andric       }
750b57cec5SDimitry Andric       m_active_categories.insert(iter, category);
760b57cec5SDimitry Andric     } else
770b57cec5SDimitry Andric       return false;
780b57cec5SDimitry Andric     category->Enable(true, pos);
790b57cec5SDimitry Andric     return true;
800b57cec5SDimitry Andric   }
810b57cec5SDimitry Andric   return false;
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric bool TypeCategoryMap::Disable(ValueSP category) {
850b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
860b57cec5SDimitry Andric   if (category.get()) {
870b57cec5SDimitry Andric     m_active_categories.remove_if(delete_matching_categories(category));
880b57cec5SDimitry Andric     category->Disable();
890b57cec5SDimitry Andric     return true;
900b57cec5SDimitry Andric   }
910b57cec5SDimitry Andric   return false;
920b57cec5SDimitry Andric }
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric void TypeCategoryMap::EnableAllCategories() {
950b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
960b57cec5SDimitry Andric   std::vector<ValueSP> sorted_categories(m_map.size(), ValueSP());
970b57cec5SDimitry Andric   MapType::iterator iter = m_map.begin(), end = m_map.end();
980b57cec5SDimitry Andric   for (; iter != end; ++iter) {
990b57cec5SDimitry Andric     if (iter->second->IsEnabled())
1000b57cec5SDimitry Andric       continue;
1010b57cec5SDimitry Andric     auto pos = iter->second->GetLastEnabledPosition();
1020b57cec5SDimitry Andric     if (pos >= sorted_categories.size()) {
1030b57cec5SDimitry Andric       auto iter = std::find_if(
1040b57cec5SDimitry Andric           sorted_categories.begin(), sorted_categories.end(),
1050b57cec5SDimitry Andric           [](const ValueSP &sp) -> bool { return sp.get() == nullptr; });
1060b57cec5SDimitry Andric       pos = std::distance(sorted_categories.begin(), iter);
1070b57cec5SDimitry Andric     }
1080b57cec5SDimitry Andric     sorted_categories.at(pos) = iter->second;
1090b57cec5SDimitry Andric   }
1100b57cec5SDimitry Andric   decltype(sorted_categories)::iterator viter = sorted_categories.begin(),
1110b57cec5SDimitry Andric                                         vend = sorted_categories.end();
1120b57cec5SDimitry Andric   for (; viter != vend; viter++)
1130b57cec5SDimitry Andric     if (*viter)
1140b57cec5SDimitry Andric       Enable(*viter, Last);
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric void TypeCategoryMap::DisableAllCategories() {
1180b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
1190b57cec5SDimitry Andric   for (Position p = First; !m_active_categories.empty(); p++) {
1200b57cec5SDimitry Andric     m_active_categories.front()->SetEnabledPosition(p);
1210b57cec5SDimitry Andric     Disable(m_active_categories.front());
1220b57cec5SDimitry Andric   }
1230b57cec5SDimitry Andric }
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric void TypeCategoryMap::Clear() {
1260b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
1270b57cec5SDimitry Andric   m_map.clear();
1280b57cec5SDimitry Andric   m_active_categories.clear();
1290b57cec5SDimitry Andric   if (listener)
1300b57cec5SDimitry Andric     listener->Changed();
1310b57cec5SDimitry Andric }
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric bool TypeCategoryMap::Get(KeyType name, ValueSP &entry) {
1340b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
1350b57cec5SDimitry Andric   MapIterator iter = m_map.find(name);
1360b57cec5SDimitry Andric   if (iter == m_map.end())
1370b57cec5SDimitry Andric     return false;
1380b57cec5SDimitry Andric   entry = iter->second;
1390b57cec5SDimitry Andric   return true;
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric bool TypeCategoryMap::Get(uint32_t pos, ValueSP &entry) {
1430b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
1440b57cec5SDimitry Andric   MapIterator iter = m_map.begin();
1450b57cec5SDimitry Andric   MapIterator end = m_map.end();
1460b57cec5SDimitry Andric   while (pos > 0) {
1470b57cec5SDimitry Andric     iter++;
1480b57cec5SDimitry Andric     pos--;
1490b57cec5SDimitry Andric     if (iter == end)
1500b57cec5SDimitry Andric       return false;
1510b57cec5SDimitry Andric   }
1520b57cec5SDimitry Andric   entry = iter->second;
1530b57cec5SDimitry Andric   return false;
1540b57cec5SDimitry Andric }
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric bool TypeCategoryMap::AnyMatches(
157bdd1243dSDimitry Andric     const FormattersMatchCandidate &candidate_type,
158bdd1243dSDimitry Andric     TypeCategoryImpl::FormatCategoryItems items, bool only_enabled,
159bdd1243dSDimitry Andric     const char **matching_category,
1600b57cec5SDimitry Andric     TypeCategoryImpl::FormatCategoryItems *matching_type) {
1610b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric   MapIterator pos, end = m_map.end();
1640b57cec5SDimitry Andric   for (pos = m_map.begin(); pos != end; pos++) {
165bdd1243dSDimitry Andric     if (pos->second->AnyMatches(candidate_type, items, only_enabled,
1660b57cec5SDimitry Andric                                 matching_category, matching_type))
1670b57cec5SDimitry Andric       return true;
1680b57cec5SDimitry Andric   }
1690b57cec5SDimitry Andric   return false;
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric 
172480093f4SDimitry Andric template <typename ImplSP>
173480093f4SDimitry Andric void TypeCategoryMap::Get(FormattersMatchData &match_data, ImplSP &retval) {
1740b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric   ActiveCategoriesIterator begin, end = m_active_categories.end();
1770b57cec5SDimitry Andric 
17881ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::DataFormatters);
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   if (log) {
1810b57cec5SDimitry Andric     for (auto match : match_data.GetMatchesVector()) {
1829dba64beSDimitry Andric       LLDB_LOGF(
1839dba64beSDimitry Andric           log,
1845ffd83dbSDimitry Andric           "[%s] candidate match = %s %s %s %s",
185480093f4SDimitry Andric           __FUNCTION__,
1860b57cec5SDimitry Andric           match.GetTypeName().GetCString(),
1870b57cec5SDimitry Andric           match.DidStripPointer() ? "strip-pointers" : "no-strip-pointers",
1880b57cec5SDimitry Andric           match.DidStripReference() ? "strip-reference" : "no-strip-reference",
1895ffd83dbSDimitry Andric           match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef");
1900b57cec5SDimitry Andric     }
1910b57cec5SDimitry Andric   }
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric   for (begin = m_active_categories.begin(); begin != end; begin++) {
1940b57cec5SDimitry Andric     lldb::TypeCategoryImplSP category_sp = *begin;
195480093f4SDimitry Andric     ImplSP current_format;
196480093f4SDimitry Andric     LLDB_LOGF(log, "[%s] Trying to use category %s", __FUNCTION__,
1970b57cec5SDimitry Andric               category_sp->GetName());
198480093f4SDimitry Andric     if (!category_sp->Get(
199480093f4SDimitry Andric             match_data.GetValueObject().GetObjectRuntimeLanguage(),
2005ffd83dbSDimitry Andric             match_data.GetMatchesVector(), current_format))
2010b57cec5SDimitry Andric       continue;
202480093f4SDimitry Andric 
203480093f4SDimitry Andric     retval = std::move(current_format);
204480093f4SDimitry Andric     return;
2050b57cec5SDimitry Andric   }
206480093f4SDimitry Andric   LLDB_LOGF(log, "[%s] nothing found - returning empty SP", __FUNCTION__);
2070b57cec5SDimitry Andric }
2080b57cec5SDimitry Andric 
209480093f4SDimitry Andric /// Explicit instantiations for the three types.
210480093f4SDimitry Andric /// \{
211480093f4SDimitry Andric template void
212480093f4SDimitry Andric TypeCategoryMap::Get<lldb::TypeFormatImplSP>(FormattersMatchData &match_data,
213480093f4SDimitry Andric                                              lldb::TypeFormatImplSP &retval);
214480093f4SDimitry Andric template void
215480093f4SDimitry Andric TypeCategoryMap::Get<lldb::TypeSummaryImplSP>(FormattersMatchData &match_data,
216480093f4SDimitry Andric                                               lldb::TypeSummaryImplSP &retval);
217480093f4SDimitry Andric template void TypeCategoryMap::Get<lldb::SyntheticChildrenSP>(
218480093f4SDimitry Andric     FormattersMatchData &match_data, lldb::SyntheticChildrenSP &retval);
219480093f4SDimitry Andric /// \}
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric void TypeCategoryMap::ForEach(ForEachCallback callback) {
2220b57cec5SDimitry Andric   if (callback) {
2230b57cec5SDimitry Andric     std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric     // loop through enabled categories in respective order
2260b57cec5SDimitry Andric     {
2270b57cec5SDimitry Andric       ActiveCategoriesIterator begin, end = m_active_categories.end();
2280b57cec5SDimitry Andric       for (begin = m_active_categories.begin(); begin != end; begin++) {
2290b57cec5SDimitry Andric         lldb::TypeCategoryImplSP category = *begin;
2300b57cec5SDimitry Andric         if (!callback(category))
2310b57cec5SDimitry Andric           break;
2320b57cec5SDimitry Andric       }
2330b57cec5SDimitry Andric     }
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric     // loop through disabled categories in just any order
2360b57cec5SDimitry Andric     {
2370b57cec5SDimitry Andric       MapIterator pos, end = m_map.end();
2380b57cec5SDimitry Andric       for (pos = m_map.begin(); pos != end; pos++) {
2390b57cec5SDimitry Andric         if (pos->second->IsEnabled())
2400b57cec5SDimitry Andric           continue;
2410b57cec5SDimitry Andric         if (!callback(pos->second))
2420b57cec5SDimitry Andric           break;
2430b57cec5SDimitry Andric       }
2440b57cec5SDimitry Andric     }
2450b57cec5SDimitry Andric   }
2460b57cec5SDimitry Andric }
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric TypeCategoryImplSP TypeCategoryMap::GetAtIndex(uint32_t index) {
2490b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric   if (index < m_map.size()) {
2520b57cec5SDimitry Andric     MapIterator pos, end = m_map.end();
2530b57cec5SDimitry Andric     for (pos = m_map.begin(); pos != end; pos++) {
2540b57cec5SDimitry Andric       if (index == 0)
2550b57cec5SDimitry Andric         return pos->second;
2560b57cec5SDimitry Andric       index--;
2570b57cec5SDimitry Andric     }
2580b57cec5SDimitry Andric   }
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric   return TypeCategoryImplSP();
2610b57cec5SDimitry Andric }
262