FormattersContainer.h revision 353358
1//===-- FormattersContainer.h -----------------------------------*- C++ -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8 9#ifndef lldb_FormattersContainer_h_ 10#define lldb_FormattersContainer_h_ 11 12#include <functional> 13#include <map> 14#include <memory> 15#include <mutex> 16#include <string> 17 18#include "lldb/lldb-public.h" 19 20#include "lldb/Core/ValueObject.h" 21#include "lldb/DataFormatters/FormatClasses.h" 22#include "lldb/DataFormatters/TypeFormat.h" 23#include "lldb/DataFormatters/TypeSummary.h" 24#include "lldb/DataFormatters/TypeSynthetic.h" 25#include "lldb/DataFormatters/TypeValidator.h" 26#include "lldb/Symbol/CompilerType.h" 27#include "lldb/Utility/RegularExpression.h" 28#include "lldb/Utility/StringLexer.h" 29 30namespace lldb_private { 31 32class IFormatChangeListener { 33public: 34 virtual ~IFormatChangeListener() = default; 35 36 virtual void Changed() = 0; 37 38 virtual uint32_t GetCurrentRevision() = 0; 39}; 40 41// if the user tries to add formatters for, say, "struct Foo" those will not 42// match any type because of the way we strip qualifiers from typenames this 43// method looks for the case where the user is adding a "class","struct","enum" 44// or "union" Foo and strips the unnecessary qualifier 45static inline ConstString GetValidTypeName_Impl(ConstString type) { 46 if (type.IsEmpty()) 47 return type; 48 49 std::string type_cstr(type.AsCString()); 50 lldb_utility::StringLexer type_lexer(type_cstr); 51 52 type_lexer.AdvanceIf("class "); 53 type_lexer.AdvanceIf("enum "); 54 type_lexer.AdvanceIf("struct "); 55 type_lexer.AdvanceIf("union "); 56 57 while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first) 58 ; 59 60 return ConstString(type_lexer.GetUnlexed()); 61} 62 63template <typename KeyType, typename ValueType> class FormattersContainer; 64 65template <typename KeyType, typename ValueType> class FormatMap { 66public: 67 typedef typename ValueType::SharedPointer ValueSP; 68 typedef std::map<KeyType, ValueSP> MapType; 69 typedef typename MapType::iterator MapIterator; 70 typedef std::function<bool(KeyType, const ValueSP &)> ForEachCallback; 71 72 FormatMap(IFormatChangeListener *lst) 73 : m_map(), m_map_mutex(), listener(lst) {} 74 75 void Add(KeyType name, const ValueSP &entry) { 76 if (listener) 77 entry->GetRevision() = listener->GetCurrentRevision(); 78 else 79 entry->GetRevision() = 0; 80 81 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 82 m_map[name] = entry; 83 if (listener) 84 listener->Changed(); 85 } 86 87 bool Delete(KeyType name) { 88 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 89 MapIterator iter = m_map.find(name); 90 if (iter == m_map.end()) 91 return false; 92 m_map.erase(name); 93 if (listener) 94 listener->Changed(); 95 return true; 96 } 97 98 void Clear() { 99 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 100 m_map.clear(); 101 if (listener) 102 listener->Changed(); 103 } 104 105 bool Get(KeyType name, ValueSP &entry) { 106 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 107 MapIterator iter = m_map.find(name); 108 if (iter == m_map.end()) 109 return false; 110 entry = iter->second; 111 return true; 112 } 113 114 void ForEach(ForEachCallback callback) { 115 if (callback) { 116 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 117 MapIterator pos, end = m_map.end(); 118 for (pos = m_map.begin(); pos != end; pos++) { 119 KeyType type = pos->first; 120 if (!callback(type, pos->second)) 121 break; 122 } 123 } 124 } 125 126 uint32_t GetCount() { return m_map.size(); } 127 128 ValueSP GetValueAtIndex(size_t index) { 129 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 130 MapIterator iter = m_map.begin(); 131 MapIterator end = m_map.end(); 132 while (index > 0) { 133 iter++; 134 index--; 135 if (end == iter) 136 return ValueSP(); 137 } 138 return iter->second; 139 } 140 141 KeyType GetKeyAtIndex(size_t index) { 142 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 143 MapIterator iter = m_map.begin(); 144 MapIterator end = m_map.end(); 145 while (index > 0) { 146 iter++; 147 index--; 148 if (end == iter) 149 return KeyType(); 150 } 151 return iter->first; 152 } 153 154protected: 155 MapType m_map; 156 std::recursive_mutex m_map_mutex; 157 IFormatChangeListener *listener; 158 159 MapType &map() { return m_map; } 160 161 std::recursive_mutex &mutex() { return m_map_mutex; } 162 163 friend class FormattersContainer<KeyType, ValueType>; 164 friend class FormatManager; 165}; 166 167template <typename KeyType, typename ValueType> class FormattersContainer { 168protected: 169 typedef FormatMap<KeyType, ValueType> BackEndType; 170 171public: 172 typedef typename BackEndType::MapType MapType; 173 typedef typename MapType::iterator MapIterator; 174 typedef typename MapType::key_type MapKeyType; 175 typedef typename MapType::mapped_type MapValueType; 176 typedef typename BackEndType::ForEachCallback ForEachCallback; 177 typedef typename std::shared_ptr<FormattersContainer<KeyType, ValueType>> 178 SharedPointer; 179 180 friend class TypeCategoryImpl; 181 182 FormattersContainer(std::string name, IFormatChangeListener *lst) 183 : m_format_map(lst), m_name(name) {} 184 185 void Add(const MapKeyType &type, const MapValueType &entry) { 186 Add_Impl(type, entry, static_cast<KeyType *>(nullptr)); 187 } 188 189 bool Delete(ConstString type) { 190 return Delete_Impl(type, static_cast<KeyType *>(nullptr)); 191 } 192 193 bool Get(ValueObject &valobj, MapValueType &entry, 194 lldb::DynamicValueType use_dynamic, uint32_t *why = nullptr) { 195 uint32_t value = lldb_private::eFormatterChoiceCriterionDirectChoice; 196 CompilerType ast_type(valobj.GetCompilerType()); 197 bool ret = Get(valobj, ast_type, entry, use_dynamic, value); 198 if (ret) 199 entry = MapValueType(entry); 200 else 201 entry = MapValueType(); 202 if (why) 203 *why = value; 204 return ret; 205 } 206 207 bool Get(ConstString type, MapValueType &entry) { 208 return Get_Impl(type, entry, static_cast<KeyType *>(nullptr)); 209 } 210 211 bool GetExact(ConstString type, MapValueType &entry) { 212 return GetExact_Impl(type, entry, static_cast<KeyType *>(nullptr)); 213 } 214 215 MapValueType GetAtIndex(size_t index) { 216 return m_format_map.GetValueAtIndex(index); 217 } 218 219 lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) { 220 return GetTypeNameSpecifierAtIndex_Impl(index, 221 static_cast<KeyType *>(nullptr)); 222 } 223 224 void Clear() { m_format_map.Clear(); } 225 226 void ForEach(ForEachCallback callback) { m_format_map.ForEach(callback); } 227 228 uint32_t GetCount() { return m_format_map.GetCount(); } 229 230protected: 231 BackEndType m_format_map; 232 std::string m_name; 233 234 DISALLOW_COPY_AND_ASSIGN(FormattersContainer); 235 236 void Add_Impl(const MapKeyType &type, const MapValueType &entry, 237 lldb::RegularExpressionSP *dummy) { 238 m_format_map.Add(type, entry); 239 } 240 241 void Add_Impl(ConstString type, const MapValueType &entry, 242 ConstString *dummy) { 243 m_format_map.Add(GetValidTypeName_Impl(type), entry); 244 } 245 246 bool Delete_Impl(ConstString type, ConstString *dummy) { 247 return m_format_map.Delete(type); 248 } 249 250 bool Delete_Impl(ConstString type, lldb::RegularExpressionSP *dummy) { 251 std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex()); 252 MapIterator pos, end = m_format_map.map().end(); 253 for (pos = m_format_map.map().begin(); pos != end; pos++) { 254 lldb::RegularExpressionSP regex = pos->first; 255 if (type.GetStringRef() == regex->GetText()) { 256 m_format_map.map().erase(pos); 257 if (m_format_map.listener) 258 m_format_map.listener->Changed(); 259 return true; 260 } 261 } 262 return false; 263 } 264 265 bool Get_Impl(ConstString type, MapValueType &entry, ConstString *dummy) { 266 return m_format_map.Get(type, entry); 267 } 268 269 bool GetExact_Impl(ConstString type, MapValueType &entry, 270 ConstString *dummy) { 271 return Get_Impl(type, entry, static_cast<KeyType *>(nullptr)); 272 } 273 274 lldb::TypeNameSpecifierImplSP 275 GetTypeNameSpecifierAtIndex_Impl(size_t index, ConstString *dummy) { 276 ConstString key = m_format_map.GetKeyAtIndex(index); 277 if (key) 278 return lldb::TypeNameSpecifierImplSP( 279 new TypeNameSpecifierImpl(key.AsCString(), false)); 280 else 281 return lldb::TypeNameSpecifierImplSP(); 282 } 283 284 lldb::TypeNameSpecifierImplSP 285 GetTypeNameSpecifierAtIndex_Impl(size_t index, 286 lldb::RegularExpressionSP *dummy) { 287 lldb::RegularExpressionSP regex = m_format_map.GetKeyAtIndex(index); 288 if (regex.get() == nullptr) 289 return lldb::TypeNameSpecifierImplSP(); 290 return lldb::TypeNameSpecifierImplSP( 291 new TypeNameSpecifierImpl(regex->GetText().str().c_str(), true)); 292 } 293 294 bool Get_Impl(ConstString key, MapValueType &value, 295 lldb::RegularExpressionSP *dummy) { 296 llvm::StringRef key_str = key.GetStringRef(); 297 std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex()); 298 MapIterator pos, end = m_format_map.map().end(); 299 for (pos = m_format_map.map().begin(); pos != end; pos++) { 300 lldb::RegularExpressionSP regex = pos->first; 301 if (regex->Execute(key_str)) { 302 value = pos->second; 303 return true; 304 } 305 } 306 return false; 307 } 308 309 bool GetExact_Impl(ConstString key, MapValueType &value, 310 lldb::RegularExpressionSP *dummy) { 311 std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex()); 312 MapIterator pos, end = m_format_map.map().end(); 313 for (pos = m_format_map.map().begin(); pos != end; pos++) { 314 lldb::RegularExpressionSP regex = pos->first; 315 if (regex->GetText() == key.GetStringRef()) { 316 value = pos->second; 317 return true; 318 } 319 } 320 return false; 321 } 322 323 bool Get(const FormattersMatchVector &candidates, MapValueType &entry, 324 uint32_t *reason) { 325 for (const FormattersMatchCandidate &candidate : candidates) { 326 if (Get(candidate.GetTypeName(), entry)) { 327 if (candidate.IsMatch(entry) == false) { 328 entry.reset(); 329 continue; 330 } else { 331 if (reason) 332 *reason = candidate.GetReason(); 333 return true; 334 } 335 } 336 } 337 return false; 338 } 339}; 340 341} // namespace lldb_private 342 343#endif // lldb_FormattersContainer_h_ 344