1 //===-- FormattersContainer.h -----------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef lldb_FormattersContainer_h_
10 #define lldb_FormattersContainer_h_
18 #include "lldb/lldb-public.h"
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"
30 namespace lldb_private {
32 class IFormatChangeListener {
34 virtual ~IFormatChangeListener() = default;
36 virtual void Changed() = 0;
38 virtual uint32_t GetCurrentRevision() = 0;
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
45 static inline ConstString GetValidTypeName_Impl(ConstString type) {
49 std::string type_cstr(type.AsCString());
50 lldb_utility::StringLexer type_lexer(type_cstr);
52 type_lexer.AdvanceIf("class ");
53 type_lexer.AdvanceIf("enum ");
54 type_lexer.AdvanceIf("struct ");
55 type_lexer.AdvanceIf("union ");
57 while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first)
60 return ConstString(type_lexer.GetUnlexed());
63 template <typename KeyType, typename ValueType> class FormattersContainer;
65 template <typename KeyType, typename ValueType> class FormatMap {
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;
72 FormatMap(IFormatChangeListener *lst)
73 : m_map(), m_map_mutex(), listener(lst) {}
75 void Add(KeyType name, const ValueSP &entry) {
77 entry->GetRevision() = listener->GetCurrentRevision();
79 entry->GetRevision() = 0;
81 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
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())
99 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
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())
110 entry = iter->second;
114 void ForEach(ForEachCallback 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))
126 uint32_t GetCount() { return m_map.size(); }
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();
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();
156 std::recursive_mutex m_map_mutex;
157 IFormatChangeListener *listener;
159 MapType &map() { return m_map; }
161 std::recursive_mutex &mutex() { return m_map_mutex; }
163 friend class FormattersContainer<KeyType, ValueType>;
164 friend class FormatManager;
167 template <typename KeyType, typename ValueType> class FormattersContainer {
169 typedef FormatMap<KeyType, ValueType> BackEndType;
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>>
180 friend class TypeCategoryImpl;
182 FormattersContainer(std::string name, IFormatChangeListener *lst)
183 : m_format_map(lst), m_name(name) {}
185 void Add(const MapKeyType &type, const MapValueType &entry) {
186 Add_Impl(type, entry, static_cast<KeyType *>(nullptr));
189 bool Delete(ConstString type) {
190 return Delete_Impl(type, static_cast<KeyType *>(nullptr));
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);
199 entry = MapValueType(entry);
201 entry = MapValueType();
207 bool Get(ConstString type, MapValueType &entry) {
208 return Get_Impl(type, entry, static_cast<KeyType *>(nullptr));
211 bool GetExact(ConstString type, MapValueType &entry) {
212 return GetExact_Impl(type, entry, static_cast<KeyType *>(nullptr));
215 MapValueType GetAtIndex(size_t index) {
216 return m_format_map.GetValueAtIndex(index);
219 lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) {
220 return GetTypeNameSpecifierAtIndex_Impl(index,
221 static_cast<KeyType *>(nullptr));
224 void Clear() { m_format_map.Clear(); }
226 void ForEach(ForEachCallback callback) { m_format_map.ForEach(callback); }
228 uint32_t GetCount() { return m_format_map.GetCount(); }
231 BackEndType m_format_map;
234 DISALLOW_COPY_AND_ASSIGN(FormattersContainer);
236 void Add_Impl(const MapKeyType &type, const MapValueType &entry,
237 lldb::RegularExpressionSP *dummy) {
238 m_format_map.Add(type, entry);
241 void Add_Impl(ConstString type, const MapValueType &entry,
242 ConstString *dummy) {
243 m_format_map.Add(GetValidTypeName_Impl(type), entry);
246 bool Delete_Impl(ConstString type, ConstString *dummy) {
247 return m_format_map.Delete(type);
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();
265 bool Get_Impl(ConstString type, MapValueType &entry, ConstString *dummy) {
266 return m_format_map.Get(type, entry);
269 bool GetExact_Impl(ConstString type, MapValueType &entry,
270 ConstString *dummy) {
271 return Get_Impl(type, entry, static_cast<KeyType *>(nullptr));
274 lldb::TypeNameSpecifierImplSP
275 GetTypeNameSpecifierAtIndex_Impl(size_t index, ConstString *dummy) {
276 ConstString key = m_format_map.GetKeyAtIndex(index);
278 return lldb::TypeNameSpecifierImplSP(
279 new TypeNameSpecifierImpl(key.AsCString(), false));
281 return lldb::TypeNameSpecifierImplSP();
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));
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)) {
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()) {
323 bool Get(const FormattersMatchVector &candidates, MapValueType &entry,
325 for (const FormattersMatchCandidate &candidate : candidates) {
326 if (Get(candidate.GetTypeName(), entry)) {
327 if (candidate.IsMatch(entry) == false) {
332 *reason = candidate.GetReason();
341 } // namespace lldb_private
343 #endif // lldb_FormattersContainer_h_