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