1296417Sdim//===-- FormattersContainer.h -----------------------------------*- C++ -*-===// 2262182Semaste// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6262182Semaste// 7262182Semaste//===----------------------------------------------------------------------===// 8262182Semaste 9262182Semaste#ifndef lldb_FormattersContainer_h_ 10262182Semaste#define lldb_FormattersContainer_h_ 11262182Semaste 12296417Sdim#include <functional> 13296417Sdim#include <map> 14296417Sdim#include <memory> 15309124Sdim#include <mutex> 16296417Sdim#include <string> 17262182Semaste 18262182Semaste#include "lldb/lldb-public.h" 19262182Semaste 20262182Semaste#include "lldb/Core/ValueObject.h" 21262182Semaste#include "lldb/DataFormatters/FormatClasses.h" 22262182Semaste#include "lldb/DataFormatters/TypeFormat.h" 23262182Semaste#include "lldb/DataFormatters/TypeSummary.h" 24262182Semaste#include "lldb/DataFormatters/TypeSynthetic.h" 25296417Sdim#include "lldb/Symbol/CompilerType.h" 26321369Sdim#include "lldb/Utility/RegularExpression.h" 27280031Sdim#include "lldb/Utility/StringLexer.h" 28280031Sdim 29262182Semastenamespace lldb_private { 30314564Sdim 31314564Sdimclass IFormatChangeListener { 32262182Semastepublic: 33314564Sdim virtual ~IFormatChangeListener() = default; 34296417Sdim 35314564Sdim virtual void Changed() = 0; 36296417Sdim 37314564Sdim virtual uint32_t GetCurrentRevision() = 0; 38262182Semaste}; 39314564Sdim 40341825Sdim// if the user tries to add formatters for, say, "struct Foo" those will not 41341825Sdim// match any type because of the way we strip qualifiers from typenames this 42341825Sdim// method looks for the case where the user is adding a "class","struct","enum" 43341825Sdim// or "union" Foo and strips the unnecessary qualifier 44353358Sdimstatic inline ConstString GetValidTypeName_Impl(ConstString type) { 45314564Sdim if (type.IsEmpty()) 46314564Sdim return type; 47314564Sdim 48314564Sdim std::string type_cstr(type.AsCString()); 49360784Sdim StringLexer type_lexer(type_cstr); 50314564Sdim 51314564Sdim type_lexer.AdvanceIf("class "); 52314564Sdim type_lexer.AdvanceIf("enum "); 53314564Sdim type_lexer.AdvanceIf("struct "); 54314564Sdim type_lexer.AdvanceIf("union "); 55314564Sdim 56314564Sdim while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first) 57314564Sdim ; 58314564Sdim 59314564Sdim return ConstString(type_lexer.GetUnlexed()); 60262182Semaste} 61280031Sdim 62314564Sdimtemplate <typename KeyType, typename ValueType> class FormattersContainer; 63262182Semaste 64314564Sdimtemplate <typename KeyType, typename ValueType> class FormatMap { 65262182Semastepublic: 66314564Sdim typedef typename ValueType::SharedPointer ValueSP; 67360784Sdim typedef std::vector<std::pair<KeyType, ValueSP>> MapType; 68314564Sdim typedef typename MapType::iterator MapIterator; 69360784Sdim typedef std::function<bool(const KeyType &, const ValueSP &)> ForEachCallback; 70309124Sdim 71314564Sdim FormatMap(IFormatChangeListener *lst) 72314564Sdim : m_map(), m_map_mutex(), listener(lst) {} 73309124Sdim 74314564Sdim void Add(KeyType name, const ValueSP &entry) { 75314564Sdim if (listener) 76314564Sdim entry->GetRevision() = listener->GetCurrentRevision(); 77314564Sdim else 78314564Sdim entry->GetRevision() = 0; 79262182Semaste 80314564Sdim std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 81360784Sdim Delete(name); 82360784Sdim m_map.emplace_back(std::move(name), std::move(entry)); 83314564Sdim if (listener) 84314564Sdim listener->Changed(); 85314564Sdim } 86309124Sdim 87360784Sdim bool Delete(const KeyType &name) { 88314564Sdim std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 89360784Sdim for (MapIterator iter = m_map.begin(); iter != m_map.end(); ++iter) 90360784Sdim if (iter->first == name) { 91360784Sdim m_map.erase(iter); 92360784Sdim if (listener) 93360784Sdim listener->Changed(); 94360784Sdim return true; 95360784Sdim } 96360784Sdim return false; 97314564Sdim } 98309124Sdim 99314564Sdim void Clear() { 100314564Sdim std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 101314564Sdim m_map.clear(); 102314564Sdim if (listener) 103314564Sdim listener->Changed(); 104314564Sdim } 105309124Sdim 106360784Sdim bool Get(const KeyType &name, ValueSP &entry) { 107314564Sdim std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 108360784Sdim for (const auto &pos : m_map) 109360784Sdim if (pos.first == name) { 110360784Sdim entry = pos.second; 111360784Sdim return true; 112360784Sdim } 113360784Sdim return false; 114314564Sdim } 115309124Sdim 116314564Sdim void ForEach(ForEachCallback callback) { 117314564Sdim if (callback) { 118314564Sdim std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 119360784Sdim for (const auto &pos : m_map) { 120360784Sdim const KeyType &type = pos.first; 121360784Sdim if (!callback(type, pos.second)) 122314564Sdim break; 123314564Sdim } 124262182Semaste } 125314564Sdim } 126309124Sdim 127314564Sdim uint32_t GetCount() { return m_map.size(); } 128309124Sdim 129314564Sdim ValueSP GetValueAtIndex(size_t index) { 130314564Sdim std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 131360784Sdim if (index >= m_map.size()) 132360784Sdim return ValueSP(); 133360784Sdim return m_map[index].second; 134314564Sdim } 135309124Sdim 136360784Sdim // If caller holds the mutex we could return a reference without copy ctor. 137314564Sdim KeyType GetKeyAtIndex(size_t index) { 138314564Sdim std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 139360784Sdim if (index >= m_map.size()) 140360784Sdim return {}; 141360784Sdim return m_map[index].first; 142314564Sdim } 143309124Sdim 144262182Semasteprotected: 145314564Sdim MapType m_map; 146314564Sdim std::recursive_mutex m_map_mutex; 147314564Sdim IFormatChangeListener *listener; 148309124Sdim 149314564Sdim MapType &map() { return m_map; } 150309124Sdim 151314564Sdim std::recursive_mutex &mutex() { return m_map_mutex; } 152309124Sdim 153314564Sdim friend class FormattersContainer<KeyType, ValueType>; 154314564Sdim friend class FormatManager; 155262182Semaste}; 156314564Sdim 157314564Sdimtemplate <typename KeyType, typename ValueType> class FormattersContainer { 158262182Semasteprotected: 159314564Sdim typedef FormatMap<KeyType, ValueType> BackEndType; 160314564Sdim 161262182Semastepublic: 162314564Sdim typedef typename BackEndType::MapType MapType; 163314564Sdim typedef typename MapType::iterator MapIterator; 164360784Sdim typedef KeyType MapKeyType; 165360784Sdim typedef std::shared_ptr<ValueType> MapValueType; 166314564Sdim typedef typename BackEndType::ForEachCallback ForEachCallback; 167314564Sdim typedef typename std::shared_ptr<FormattersContainer<KeyType, ValueType>> 168314564Sdim SharedPointer; 169262182Semaste 170314564Sdim friend class TypeCategoryImpl; 171314564Sdim 172314564Sdim FormattersContainer(std::string name, IFormatChangeListener *lst) 173314564Sdim : m_format_map(lst), m_name(name) {} 174314564Sdim 175360784Sdim void Add(MapKeyType type, const MapValueType &entry) { 176360784Sdim Add_Impl(std::move(type), entry, static_cast<KeyType *>(nullptr)); 177314564Sdim } 178314564Sdim 179314564Sdim bool Delete(ConstString type) { 180314564Sdim return Delete_Impl(type, static_cast<KeyType *>(nullptr)); 181314564Sdim } 182314564Sdim 183314564Sdim bool Get(ValueObject &valobj, MapValueType &entry, 184314564Sdim lldb::DynamicValueType use_dynamic, uint32_t *why = nullptr) { 185314564Sdim uint32_t value = lldb_private::eFormatterChoiceCriterionDirectChoice; 186314564Sdim CompilerType ast_type(valobj.GetCompilerType()); 187314564Sdim bool ret = Get(valobj, ast_type, entry, use_dynamic, value); 188314564Sdim if (ret) 189314564Sdim entry = MapValueType(entry); 190314564Sdim else 191314564Sdim entry = MapValueType(); 192314564Sdim if (why) 193314564Sdim *why = value; 194314564Sdim return ret; 195314564Sdim } 196314564Sdim 197314564Sdim bool Get(ConstString type, MapValueType &entry) { 198314564Sdim return Get_Impl(type, entry, static_cast<KeyType *>(nullptr)); 199314564Sdim } 200314564Sdim 201314564Sdim bool GetExact(ConstString type, MapValueType &entry) { 202314564Sdim return GetExact_Impl(type, entry, static_cast<KeyType *>(nullptr)); 203314564Sdim } 204314564Sdim 205314564Sdim MapValueType GetAtIndex(size_t index) { 206314564Sdim return m_format_map.GetValueAtIndex(index); 207314564Sdim } 208314564Sdim 209314564Sdim lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) { 210314564Sdim return GetTypeNameSpecifierAtIndex_Impl(index, 211314564Sdim static_cast<KeyType *>(nullptr)); 212314564Sdim } 213314564Sdim 214314564Sdim void Clear() { m_format_map.Clear(); } 215314564Sdim 216314564Sdim void ForEach(ForEachCallback callback) { m_format_map.ForEach(callback); } 217314564Sdim 218314564Sdim uint32_t GetCount() { return m_format_map.GetCount(); } 219314564Sdim 220262182Semasteprotected: 221314564Sdim BackEndType m_format_map; 222314564Sdim std::string m_name; 223262182Semaste 224314564Sdim DISALLOW_COPY_AND_ASSIGN(FormattersContainer); 225262182Semaste 226360784Sdim void Add_Impl(MapKeyType type, const MapValueType &entry, 227360784Sdim RegularExpression *dummy) { 228360784Sdim m_format_map.Add(std::move(type), entry); 229314564Sdim } 230262182Semaste 231353358Sdim void Add_Impl(ConstString type, const MapValueType &entry, 232314564Sdim ConstString *dummy) { 233314564Sdim m_format_map.Add(GetValidTypeName_Impl(type), entry); 234314564Sdim } 235262182Semaste 236314564Sdim bool Delete_Impl(ConstString type, ConstString *dummy) { 237314564Sdim return m_format_map.Delete(type); 238314564Sdim } 239262182Semaste 240360784Sdim bool Delete_Impl(ConstString type, RegularExpression *dummy) { 241314564Sdim std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex()); 242314564Sdim MapIterator pos, end = m_format_map.map().end(); 243314564Sdim for (pos = m_format_map.map().begin(); pos != end; pos++) { 244360784Sdim const RegularExpression ®ex = pos->first; 245360784Sdim if (type.GetStringRef() == regex.GetText()) { 246314564Sdim m_format_map.map().erase(pos); 247314564Sdim if (m_format_map.listener) 248314564Sdim m_format_map.listener->Changed(); 249314564Sdim return true; 250314564Sdim } 251262182Semaste } 252314564Sdim return false; 253314564Sdim } 254262182Semaste 255314564Sdim bool Get_Impl(ConstString type, MapValueType &entry, ConstString *dummy) { 256314564Sdim return m_format_map.Get(type, entry); 257314564Sdim } 258314564Sdim 259314564Sdim bool GetExact_Impl(ConstString type, MapValueType &entry, 260314564Sdim ConstString *dummy) { 261314564Sdim return Get_Impl(type, entry, static_cast<KeyType *>(nullptr)); 262314564Sdim } 263314564Sdim 264314564Sdim lldb::TypeNameSpecifierImplSP 265314564Sdim GetTypeNameSpecifierAtIndex_Impl(size_t index, ConstString *dummy) { 266314564Sdim ConstString key = m_format_map.GetKeyAtIndex(index); 267314564Sdim if (key) 268314564Sdim return lldb::TypeNameSpecifierImplSP( 269314564Sdim new TypeNameSpecifierImpl(key.AsCString(), false)); 270314564Sdim else 271314564Sdim return lldb::TypeNameSpecifierImplSP(); 272314564Sdim } 273314564Sdim 274314564Sdim lldb::TypeNameSpecifierImplSP 275360784Sdim GetTypeNameSpecifierAtIndex_Impl(size_t index, RegularExpression *dummy) { 276360784Sdim RegularExpression regex = m_format_map.GetKeyAtIndex(index); 277360784Sdim if (regex == RegularExpression()) 278314564Sdim return lldb::TypeNameSpecifierImplSP(); 279314564Sdim return lldb::TypeNameSpecifierImplSP( 280360784Sdim new TypeNameSpecifierImpl(regex.GetText().str().c_str(), true)); 281314564Sdim } 282314564Sdim 283314564Sdim bool Get_Impl(ConstString key, MapValueType &value, 284360784Sdim RegularExpression *dummy) { 285314564Sdim llvm::StringRef key_str = key.GetStringRef(); 286314564Sdim std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex()); 287360784Sdim // Patterns are matched in reverse-chronological order. 288360784Sdim for (const auto &pos : llvm::reverse(m_format_map.map())) { 289360784Sdim const RegularExpression ®ex = pos.first; 290360784Sdim if (regex.Execute(key_str)) { 291360784Sdim value = pos.second; 292314564Sdim return true; 293314564Sdim } 294262182Semaste } 295314564Sdim return false; 296314564Sdim } 297309124Sdim 298314564Sdim bool GetExact_Impl(ConstString key, MapValueType &value, 299360784Sdim RegularExpression *dummy) { 300314564Sdim std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex()); 301360784Sdim for (const auto &pos : m_format_map.map()) { 302360784Sdim const RegularExpression ®ex = pos.first; 303360784Sdim if (regex.GetText() == key.GetStringRef()) { 304360784Sdim value = pos.second; 305314564Sdim return true; 306314564Sdim } 307262182Semaste } 308314564Sdim return false; 309314564Sdim } 310262182Semaste 311314564Sdim bool Get(const FormattersMatchVector &candidates, MapValueType &entry, 312314564Sdim uint32_t *reason) { 313314564Sdim for (const FormattersMatchCandidate &candidate : candidates) { 314314564Sdim if (Get(candidate.GetTypeName(), entry)) { 315314564Sdim if (candidate.IsMatch(entry) == false) { 316314564Sdim entry.reset(); 317314564Sdim continue; 318314564Sdim } else { 319314564Sdim if (reason) 320314564Sdim *reason = candidate.GetReason(); 321314564Sdim return true; 322262182Semaste } 323314564Sdim } 324262182Semaste } 325314564Sdim return false; 326314564Sdim } 327262182Semaste}; 328262182Semaste 329262182Semaste} // namespace lldb_private 330262182Semaste 331296417Sdim#endif // lldb_FormattersContainer_h_ 332