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 
TypeCategoryMap(IFormatChangeListener * lst)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 
Add(KeyType name,const TypeCategoryImplSP & entry)275f757f3fSDimitry Andric void TypeCategoryMap::Add(KeyType name, const TypeCategoryImplSP &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 
Delete(KeyType name)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 
Enable(KeyType category_name,Position pos)460b57cec5SDimitry Andric bool TypeCategoryMap::Enable(KeyType category_name, Position pos) {
470b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
485f757f3fSDimitry Andric   TypeCategoryImplSP category;
490b57cec5SDimitry Andric   if (!Get(category_name, category))
500b57cec5SDimitry Andric     return false;
510b57cec5SDimitry Andric   return Enable(category, pos);
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric 
Disable(KeyType category_name)540b57cec5SDimitry Andric bool TypeCategoryMap::Disable(KeyType category_name) {
550b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
565f757f3fSDimitry Andric   TypeCategoryImplSP category;
570b57cec5SDimitry Andric   if (!Get(category_name, category))
580b57cec5SDimitry Andric     return false;
590b57cec5SDimitry Andric   return Disable(category);
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric 
Enable(TypeCategoryImplSP category,Position pos)625f757f3fSDimitry Andric bool TypeCategoryMap::Enable(TypeCategoryImplSP 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 
Disable(TypeCategoryImplSP category)845f757f3fSDimitry Andric bool TypeCategoryMap::Disable(TypeCategoryImplSP 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 
EnableAllCategories()940b57cec5SDimitry Andric void TypeCategoryMap::EnableAllCategories() {
950b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
965f757f3fSDimitry Andric   std::vector<TypeCategoryImplSP> sorted_categories(m_map.size(), TypeCategoryImplSP());
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(),
1055f757f3fSDimitry Andric           [](const TypeCategoryImplSP &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 
DisableAllCategories()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 
Clear()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 
Get(KeyType name,TypeCategoryImplSP & entry)1335f757f3fSDimitry Andric bool TypeCategoryMap::Get(KeyType name, TypeCategoryImplSP &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 
AnyMatches(const FormattersMatchCandidate & candidate_type,TypeCategoryImpl::FormatCategoryItems items,bool only_enabled,const char ** matching_category,TypeCategoryImpl::FormatCategoryItems * matching_type)1420b57cec5SDimitry Andric bool TypeCategoryMap::AnyMatches(
143bdd1243dSDimitry Andric     const FormattersMatchCandidate &candidate_type,
144bdd1243dSDimitry Andric     TypeCategoryImpl::FormatCategoryItems items, bool only_enabled,
145bdd1243dSDimitry Andric     const char **matching_category,
1460b57cec5SDimitry Andric     TypeCategoryImpl::FormatCategoryItems *matching_type) {
1470b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric   MapIterator pos, end = m_map.end();
1500b57cec5SDimitry Andric   for (pos = m_map.begin(); pos != end; pos++) {
151bdd1243dSDimitry Andric     if (pos->second->AnyMatches(candidate_type, items, only_enabled,
1520b57cec5SDimitry Andric                                 matching_category, matching_type))
1530b57cec5SDimitry Andric       return true;
1540b57cec5SDimitry Andric   }
1550b57cec5SDimitry Andric   return false;
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric 
158480093f4SDimitry Andric template <typename ImplSP>
Get(FormattersMatchData & match_data,ImplSP & retval)159480093f4SDimitry Andric void TypeCategoryMap::Get(FormattersMatchData &match_data, ImplSP &retval) {
1600b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric   ActiveCategoriesIterator begin, end = m_active_categories.end();
1630b57cec5SDimitry Andric 
16481ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::DataFormatters);
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   if (log) {
1670b57cec5SDimitry Andric     for (auto match : match_data.GetMatchesVector()) {
1689dba64beSDimitry Andric       LLDB_LOGF(
1699dba64beSDimitry Andric           log,
1705ffd83dbSDimitry Andric           "[%s] candidate match = %s %s %s %s",
171480093f4SDimitry Andric           __FUNCTION__,
1720b57cec5SDimitry Andric           match.GetTypeName().GetCString(),
1730b57cec5SDimitry Andric           match.DidStripPointer() ? "strip-pointers" : "no-strip-pointers",
1740b57cec5SDimitry Andric           match.DidStripReference() ? "strip-reference" : "no-strip-reference",
1755ffd83dbSDimitry Andric           match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef");
1760b57cec5SDimitry Andric     }
1770b57cec5SDimitry Andric   }
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric   for (begin = m_active_categories.begin(); begin != end; begin++) {
1800b57cec5SDimitry Andric     lldb::TypeCategoryImplSP category_sp = *begin;
181480093f4SDimitry Andric     ImplSP current_format;
182480093f4SDimitry Andric     LLDB_LOGF(log, "[%s] Trying to use category %s", __FUNCTION__,
1830b57cec5SDimitry Andric               category_sp->GetName());
184480093f4SDimitry Andric     if (!category_sp->Get(
185480093f4SDimitry Andric             match_data.GetValueObject().GetObjectRuntimeLanguage(),
1865ffd83dbSDimitry Andric             match_data.GetMatchesVector(), current_format))
1870b57cec5SDimitry Andric       continue;
188480093f4SDimitry Andric 
189480093f4SDimitry Andric     retval = std::move(current_format);
190480093f4SDimitry Andric     return;
1910b57cec5SDimitry Andric   }
192480093f4SDimitry Andric   LLDB_LOGF(log, "[%s] nothing found - returning empty SP", __FUNCTION__);
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric 
195480093f4SDimitry Andric /// Explicit instantiations for the three types.
196480093f4SDimitry Andric /// \{
197480093f4SDimitry Andric template void
198480093f4SDimitry Andric TypeCategoryMap::Get<lldb::TypeFormatImplSP>(FormattersMatchData &match_data,
199480093f4SDimitry Andric                                              lldb::TypeFormatImplSP &retval);
200480093f4SDimitry Andric template void
201480093f4SDimitry Andric TypeCategoryMap::Get<lldb::TypeSummaryImplSP>(FormattersMatchData &match_data,
202480093f4SDimitry Andric                                               lldb::TypeSummaryImplSP &retval);
203480093f4SDimitry Andric template void TypeCategoryMap::Get<lldb::SyntheticChildrenSP>(
204480093f4SDimitry Andric     FormattersMatchData &match_data, lldb::SyntheticChildrenSP &retval);
205480093f4SDimitry Andric /// \}
2060b57cec5SDimitry Andric 
ForEach(ForEachCallback callback)2070b57cec5SDimitry Andric void TypeCategoryMap::ForEach(ForEachCallback callback) {
2080b57cec5SDimitry Andric   if (callback) {
2090b57cec5SDimitry Andric     std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric     // loop through enabled categories in respective order
2120b57cec5SDimitry Andric     {
2130b57cec5SDimitry Andric       ActiveCategoriesIterator begin, end = m_active_categories.end();
2140b57cec5SDimitry Andric       for (begin = m_active_categories.begin(); begin != end; begin++) {
2150b57cec5SDimitry Andric         lldb::TypeCategoryImplSP category = *begin;
2160b57cec5SDimitry Andric         if (!callback(category))
2170b57cec5SDimitry Andric           break;
2180b57cec5SDimitry Andric       }
2190b57cec5SDimitry Andric     }
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric     // loop through disabled categories in just any order
2220b57cec5SDimitry Andric     {
2230b57cec5SDimitry Andric       MapIterator pos, end = m_map.end();
2240b57cec5SDimitry Andric       for (pos = m_map.begin(); pos != end; pos++) {
2250b57cec5SDimitry Andric         if (pos->second->IsEnabled())
2260b57cec5SDimitry Andric           continue;
2270b57cec5SDimitry Andric         if (!callback(pos->second))
2280b57cec5SDimitry Andric           break;
2290b57cec5SDimitry Andric       }
2300b57cec5SDimitry Andric     }
2310b57cec5SDimitry Andric   }
2320b57cec5SDimitry Andric }
2330b57cec5SDimitry Andric 
GetAtIndex(uint32_t index)2340b57cec5SDimitry Andric TypeCategoryImplSP TypeCategoryMap::GetAtIndex(uint32_t index) {
2350b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric   if (index < m_map.size()) {
2380b57cec5SDimitry Andric     MapIterator pos, end = m_map.end();
2390b57cec5SDimitry Andric     for (pos = m_map.begin(); pos != end; pos++) {
2400b57cec5SDimitry Andric       if (index == 0)
2410b57cec5SDimitry Andric         return pos->second;
2420b57cec5SDimitry Andric       index--;
2430b57cec5SDimitry Andric     }
2440b57cec5SDimitry Andric   }
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric   return TypeCategoryImplSP();
2470b57cec5SDimitry Andric }
248