//===-- FormattersContainer.h -----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef lldb_FormattersContainer_h_ #define lldb_FormattersContainer_h_ // C Includes // C++ Includes #include #include #include #include #include // Other libraries and framework includes // Project includes #include "lldb/lldb-public.h" #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/FormatClasses.h" #include "lldb/DataFormatters/TypeFormat.h" #include "lldb/DataFormatters/TypeSummary.h" #include "lldb/DataFormatters/TypeSynthetic.h" #include "lldb/DataFormatters/TypeValidator.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/StringLexer.h" namespace lldb_private { class IFormatChangeListener { public: virtual ~IFormatChangeListener() = default; virtual void Changed() = 0; virtual uint32_t GetCurrentRevision() = 0; }; // if the user tries to add formatters for, say, "struct Foo" // those will not match any type because of the way we strip qualifiers from // typenames // this method looks for the case where the user is adding a // "class","struct","enum" or "union" Foo // and strips the unnecessary qualifier static inline ConstString GetValidTypeName_Impl(const ConstString &type) { if (type.IsEmpty()) return type; std::string type_cstr(type.AsCString()); lldb_utility::StringLexer type_lexer(type_cstr); type_lexer.AdvanceIf("class "); type_lexer.AdvanceIf("enum "); type_lexer.AdvanceIf("struct "); type_lexer.AdvanceIf("union "); while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first) ; return ConstString(type_lexer.GetUnlexed()); } template class FormattersContainer; template class FormatMap { public: typedef typename ValueType::SharedPointer ValueSP; typedef std::map MapType; typedef typename MapType::iterator MapIterator; typedef std::function ForEachCallback; FormatMap(IFormatChangeListener *lst) : m_map(), m_map_mutex(), listener(lst) {} void Add(KeyType name, const ValueSP &entry) { if (listener) entry->GetRevision() = listener->GetCurrentRevision(); else entry->GetRevision() = 0; std::lock_guard guard(m_map_mutex); m_map[name] = entry; if (listener) listener->Changed(); } bool Delete(KeyType name) { std::lock_guard guard(m_map_mutex); MapIterator iter = m_map.find(name); if (iter == m_map.end()) return false; m_map.erase(name); if (listener) listener->Changed(); return true; } void Clear() { std::lock_guard guard(m_map_mutex); m_map.clear(); if (listener) listener->Changed(); } bool Get(KeyType name, ValueSP &entry) { std::lock_guard guard(m_map_mutex); MapIterator iter = m_map.find(name); if (iter == m_map.end()) return false; entry = iter->second; return true; } void ForEach(ForEachCallback callback) { if (callback) { std::lock_guard guard(m_map_mutex); MapIterator pos, end = m_map.end(); for (pos = m_map.begin(); pos != end; pos++) { KeyType type = pos->first; if (!callback(type, pos->second)) break; } } } uint32_t GetCount() { return m_map.size(); } ValueSP GetValueAtIndex(size_t index) { std::lock_guard guard(m_map_mutex); MapIterator iter = m_map.begin(); MapIterator end = m_map.end(); while (index > 0) { iter++; index--; if (end == iter) return ValueSP(); } return iter->second; } KeyType GetKeyAtIndex(size_t index) { std::lock_guard guard(m_map_mutex); MapIterator iter = m_map.begin(); MapIterator end = m_map.end(); while (index > 0) { iter++; index--; if (end == iter) return KeyType(); } return iter->first; } protected: MapType m_map; std::recursive_mutex m_map_mutex; IFormatChangeListener *listener; MapType &map() { return m_map; } std::recursive_mutex &mutex() { return m_map_mutex; } friend class FormattersContainer; friend class FormatManager; }; template class FormattersContainer { protected: typedef FormatMap BackEndType; public: typedef typename BackEndType::MapType MapType; typedef typename MapType::iterator MapIterator; typedef typename MapType::key_type MapKeyType; typedef typename MapType::mapped_type MapValueType; typedef typename BackEndType::ForEachCallback ForEachCallback; typedef typename std::shared_ptr> SharedPointer; friend class TypeCategoryImpl; FormattersContainer(std::string name, IFormatChangeListener *lst) : m_format_map(lst), m_name(name) {} void Add(const MapKeyType &type, const MapValueType &entry) { Add_Impl(type, entry, static_cast(nullptr)); } bool Delete(ConstString type) { return Delete_Impl(type, static_cast(nullptr)); } bool Get(ValueObject &valobj, MapValueType &entry, lldb::DynamicValueType use_dynamic, uint32_t *why = nullptr) { uint32_t value = lldb_private::eFormatterChoiceCriterionDirectChoice; CompilerType ast_type(valobj.GetCompilerType()); bool ret = Get(valobj, ast_type, entry, use_dynamic, value); if (ret) entry = MapValueType(entry); else entry = MapValueType(); if (why) *why = value; return ret; } bool Get(ConstString type, MapValueType &entry) { return Get_Impl(type, entry, static_cast(nullptr)); } bool GetExact(ConstString type, MapValueType &entry) { return GetExact_Impl(type, entry, static_cast(nullptr)); } MapValueType GetAtIndex(size_t index) { return m_format_map.GetValueAtIndex(index); } lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) { return GetTypeNameSpecifierAtIndex_Impl(index, static_cast(nullptr)); } void Clear() { m_format_map.Clear(); } void ForEach(ForEachCallback callback) { m_format_map.ForEach(callback); } uint32_t GetCount() { return m_format_map.GetCount(); } protected: BackEndType m_format_map; std::string m_name; DISALLOW_COPY_AND_ASSIGN(FormattersContainer); void Add_Impl(const MapKeyType &type, const MapValueType &entry, lldb::RegularExpressionSP *dummy) { m_format_map.Add(type, entry); } void Add_Impl(const ConstString &type, const MapValueType &entry, ConstString *dummy) { m_format_map.Add(GetValidTypeName_Impl(type), entry); } bool Delete_Impl(ConstString type, ConstString *dummy) { return m_format_map.Delete(type); } bool Delete_Impl(ConstString type, lldb::RegularExpressionSP *dummy) { std::lock_guard guard(m_format_map.mutex()); MapIterator pos, end = m_format_map.map().end(); for (pos = m_format_map.map().begin(); pos != end; pos++) { lldb::RegularExpressionSP regex = pos->first; if (type.GetStringRef() == regex->GetText()) { m_format_map.map().erase(pos); if (m_format_map.listener) m_format_map.listener->Changed(); return true; } } return false; } bool Get_Impl(ConstString type, MapValueType &entry, ConstString *dummy) { return m_format_map.Get(type, entry); } bool GetExact_Impl(ConstString type, MapValueType &entry, ConstString *dummy) { return Get_Impl(type, entry, static_cast(nullptr)); } lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex_Impl(size_t index, ConstString *dummy) { ConstString key = m_format_map.GetKeyAtIndex(index); if (key) return lldb::TypeNameSpecifierImplSP( new TypeNameSpecifierImpl(key.AsCString(), false)); else return lldb::TypeNameSpecifierImplSP(); } lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex_Impl(size_t index, lldb::RegularExpressionSP *dummy) { lldb::RegularExpressionSP regex = m_format_map.GetKeyAtIndex(index); if (regex.get() == nullptr) return lldb::TypeNameSpecifierImplSP(); return lldb::TypeNameSpecifierImplSP( new TypeNameSpecifierImpl(regex->GetText().str().c_str(), true)); } bool Get_Impl(ConstString key, MapValueType &value, lldb::RegularExpressionSP *dummy) { llvm::StringRef key_str = key.GetStringRef(); std::lock_guard guard(m_format_map.mutex()); MapIterator pos, end = m_format_map.map().end(); for (pos = m_format_map.map().begin(); pos != end; pos++) { lldb::RegularExpressionSP regex = pos->first; if (regex->Execute(key_str)) { value = pos->second; return true; } } return false; } bool GetExact_Impl(ConstString key, MapValueType &value, lldb::RegularExpressionSP *dummy) { std::lock_guard guard(m_format_map.mutex()); MapIterator pos, end = m_format_map.map().end(); for (pos = m_format_map.map().begin(); pos != end; pos++) { lldb::RegularExpressionSP regex = pos->first; if (regex->GetText() == key.GetStringRef()) { value = pos->second; return true; } } return false; } bool Get(const FormattersMatchVector &candidates, MapValueType &entry, uint32_t *reason) { for (const FormattersMatchCandidate &candidate : candidates) { if (Get(candidate.GetTypeName(), entry)) { if (candidate.IsMatch(entry) == false) { entry.reset(); continue; } else { if (reason) *reason = candidate.GetReason(); return true; } } } return false; } }; } // namespace lldb_private #endif // lldb_FormattersContainer_h_