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