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