1296417Sdim//===-- FormattersContainer.h -----------------------------------*- C++ -*-===//
2262182Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6262182Semaste//
7262182Semaste//===----------------------------------------------------------------------===//
8262182Semaste
9262182Semaste#ifndef lldb_FormattersContainer_h_
10262182Semaste#define lldb_FormattersContainer_h_
11262182Semaste
12296417Sdim#include <functional>
13296417Sdim#include <map>
14296417Sdim#include <memory>
15309124Sdim#include <mutex>
16296417Sdim#include <string>
17262182Semaste
18262182Semaste#include "lldb/lldb-public.h"
19262182Semaste
20262182Semaste#include "lldb/Core/ValueObject.h"
21262182Semaste#include "lldb/DataFormatters/FormatClasses.h"
22262182Semaste#include "lldb/DataFormatters/TypeFormat.h"
23262182Semaste#include "lldb/DataFormatters/TypeSummary.h"
24262182Semaste#include "lldb/DataFormatters/TypeSynthetic.h"
25296417Sdim#include "lldb/Symbol/CompilerType.h"
26321369Sdim#include "lldb/Utility/RegularExpression.h"
27280031Sdim#include "lldb/Utility/StringLexer.h"
28280031Sdim
29262182Semastenamespace lldb_private {
30314564Sdim
31314564Sdimclass IFormatChangeListener {
32262182Semastepublic:
33314564Sdim  virtual ~IFormatChangeListener() = default;
34296417Sdim
35314564Sdim  virtual void Changed() = 0;
36296417Sdim
37314564Sdim  virtual uint32_t GetCurrentRevision() = 0;
38262182Semaste};
39314564Sdim
40341825Sdim// if the user tries to add formatters for, say, "struct Foo" those will not
41341825Sdim// match any type because of the way we strip qualifiers from typenames this
42341825Sdim// method looks for the case where the user is adding a "class","struct","enum"
43341825Sdim// or "union" Foo and strips the unnecessary qualifier
44353358Sdimstatic inline ConstString GetValidTypeName_Impl(ConstString type) {
45314564Sdim  if (type.IsEmpty())
46314564Sdim    return type;
47314564Sdim
48314564Sdim  std::string type_cstr(type.AsCString());
49360784Sdim  StringLexer type_lexer(type_cstr);
50314564Sdim
51314564Sdim  type_lexer.AdvanceIf("class ");
52314564Sdim  type_lexer.AdvanceIf("enum ");
53314564Sdim  type_lexer.AdvanceIf("struct ");
54314564Sdim  type_lexer.AdvanceIf("union ");
55314564Sdim
56314564Sdim  while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first)
57314564Sdim    ;
58314564Sdim
59314564Sdim  return ConstString(type_lexer.GetUnlexed());
60262182Semaste}
61280031Sdim
62314564Sdimtemplate <typename KeyType, typename ValueType> class FormattersContainer;
63262182Semaste
64314564Sdimtemplate <typename KeyType, typename ValueType> class FormatMap {
65262182Semastepublic:
66314564Sdim  typedef typename ValueType::SharedPointer ValueSP;
67360784Sdim  typedef std::vector<std::pair<KeyType, ValueSP>> MapType;
68314564Sdim  typedef typename MapType::iterator MapIterator;
69360784Sdim  typedef std::function<bool(const KeyType &, const ValueSP &)> ForEachCallback;
70309124Sdim
71314564Sdim  FormatMap(IFormatChangeListener *lst)
72314564Sdim      : m_map(), m_map_mutex(), listener(lst) {}
73309124Sdim
74314564Sdim  void Add(KeyType name, const ValueSP &entry) {
75314564Sdim    if (listener)
76314564Sdim      entry->GetRevision() = listener->GetCurrentRevision();
77314564Sdim    else
78314564Sdim      entry->GetRevision() = 0;
79262182Semaste
80314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
81360784Sdim    Delete(name);
82360784Sdim    m_map.emplace_back(std::move(name), std::move(entry));
83314564Sdim    if (listener)
84314564Sdim      listener->Changed();
85314564Sdim  }
86309124Sdim
87360784Sdim  bool Delete(const KeyType &name) {
88314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
89360784Sdim    for (MapIterator iter = m_map.begin(); iter != m_map.end(); ++iter)
90360784Sdim      if (iter->first == name) {
91360784Sdim        m_map.erase(iter);
92360784Sdim        if (listener)
93360784Sdim          listener->Changed();
94360784Sdim        return true;
95360784Sdim      }
96360784Sdim    return false;
97314564Sdim  }
98309124Sdim
99314564Sdim  void Clear() {
100314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
101314564Sdim    m_map.clear();
102314564Sdim    if (listener)
103314564Sdim      listener->Changed();
104314564Sdim  }
105309124Sdim
106360784Sdim  bool Get(const KeyType &name, ValueSP &entry) {
107314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
108360784Sdim    for (const auto &pos : m_map)
109360784Sdim      if (pos.first == name) {
110360784Sdim        entry = pos.second;
111360784Sdim        return true;
112360784Sdim      }
113360784Sdim    return false;
114314564Sdim  }
115309124Sdim
116314564Sdim  void ForEach(ForEachCallback callback) {
117314564Sdim    if (callback) {
118314564Sdim      std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
119360784Sdim      for (const auto &pos : m_map) {
120360784Sdim        const KeyType &type = pos.first;
121360784Sdim        if (!callback(type, pos.second))
122314564Sdim          break;
123314564Sdim      }
124262182Semaste    }
125314564Sdim  }
126309124Sdim
127314564Sdim  uint32_t GetCount() { return m_map.size(); }
128309124Sdim
129314564Sdim  ValueSP GetValueAtIndex(size_t index) {
130314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
131360784Sdim    if (index >= m_map.size())
132360784Sdim      return ValueSP();
133360784Sdim    return m_map[index].second;
134314564Sdim  }
135309124Sdim
136360784Sdim  // If caller holds the mutex we could return a reference without copy ctor.
137314564Sdim  KeyType GetKeyAtIndex(size_t index) {
138314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
139360784Sdim    if (index >= m_map.size())
140360784Sdim      return {};
141360784Sdim    return m_map[index].first;
142314564Sdim  }
143309124Sdim
144262182Semasteprotected:
145314564Sdim  MapType m_map;
146314564Sdim  std::recursive_mutex m_map_mutex;
147314564Sdim  IFormatChangeListener *listener;
148309124Sdim
149314564Sdim  MapType &map() { return m_map; }
150309124Sdim
151314564Sdim  std::recursive_mutex &mutex() { return m_map_mutex; }
152309124Sdim
153314564Sdim  friend class FormattersContainer<KeyType, ValueType>;
154314564Sdim  friend class FormatManager;
155262182Semaste};
156314564Sdim
157314564Sdimtemplate <typename KeyType, typename ValueType> class FormattersContainer {
158262182Semasteprotected:
159314564Sdim  typedef FormatMap<KeyType, ValueType> BackEndType;
160314564Sdim
161262182Semastepublic:
162314564Sdim  typedef typename BackEndType::MapType MapType;
163314564Sdim  typedef typename MapType::iterator MapIterator;
164360784Sdim  typedef KeyType MapKeyType;
165360784Sdim  typedef std::shared_ptr<ValueType> MapValueType;
166314564Sdim  typedef typename BackEndType::ForEachCallback ForEachCallback;
167314564Sdim  typedef typename std::shared_ptr<FormattersContainer<KeyType, ValueType>>
168314564Sdim      SharedPointer;
169262182Semaste
170314564Sdim  friend class TypeCategoryImpl;
171314564Sdim
172314564Sdim  FormattersContainer(std::string name, IFormatChangeListener *lst)
173314564Sdim      : m_format_map(lst), m_name(name) {}
174314564Sdim
175360784Sdim  void Add(MapKeyType type, const MapValueType &entry) {
176360784Sdim    Add_Impl(std::move(type), entry, static_cast<KeyType *>(nullptr));
177314564Sdim  }
178314564Sdim
179314564Sdim  bool Delete(ConstString type) {
180314564Sdim    return Delete_Impl(type, static_cast<KeyType *>(nullptr));
181314564Sdim  }
182314564Sdim
183314564Sdim  bool Get(ValueObject &valobj, MapValueType &entry,
184314564Sdim           lldb::DynamicValueType use_dynamic, uint32_t *why = nullptr) {
185314564Sdim    uint32_t value = lldb_private::eFormatterChoiceCriterionDirectChoice;
186314564Sdim    CompilerType ast_type(valobj.GetCompilerType());
187314564Sdim    bool ret = Get(valobj, ast_type, entry, use_dynamic, value);
188314564Sdim    if (ret)
189314564Sdim      entry = MapValueType(entry);
190314564Sdim    else
191314564Sdim      entry = MapValueType();
192314564Sdim    if (why)
193314564Sdim      *why = value;
194314564Sdim    return ret;
195314564Sdim  }
196314564Sdim
197314564Sdim  bool Get(ConstString type, MapValueType &entry) {
198314564Sdim    return Get_Impl(type, entry, static_cast<KeyType *>(nullptr));
199314564Sdim  }
200314564Sdim
201314564Sdim  bool GetExact(ConstString type, MapValueType &entry) {
202314564Sdim    return GetExact_Impl(type, entry, static_cast<KeyType *>(nullptr));
203314564Sdim  }
204314564Sdim
205314564Sdim  MapValueType GetAtIndex(size_t index) {
206314564Sdim    return m_format_map.GetValueAtIndex(index);
207314564Sdim  }
208314564Sdim
209314564Sdim  lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) {
210314564Sdim    return GetTypeNameSpecifierAtIndex_Impl(index,
211314564Sdim                                            static_cast<KeyType *>(nullptr));
212314564Sdim  }
213314564Sdim
214314564Sdim  void Clear() { m_format_map.Clear(); }
215314564Sdim
216314564Sdim  void ForEach(ForEachCallback callback) { m_format_map.ForEach(callback); }
217314564Sdim
218314564Sdim  uint32_t GetCount() { return m_format_map.GetCount(); }
219314564Sdim
220262182Semasteprotected:
221314564Sdim  BackEndType m_format_map;
222314564Sdim  std::string m_name;
223262182Semaste
224314564Sdim  DISALLOW_COPY_AND_ASSIGN(FormattersContainer);
225262182Semaste
226360784Sdim  void Add_Impl(MapKeyType type, const MapValueType &entry,
227360784Sdim                RegularExpression *dummy) {
228360784Sdim    m_format_map.Add(std::move(type), entry);
229314564Sdim  }
230262182Semaste
231353358Sdim  void Add_Impl(ConstString type, const MapValueType &entry,
232314564Sdim                ConstString *dummy) {
233314564Sdim    m_format_map.Add(GetValidTypeName_Impl(type), entry);
234314564Sdim  }
235262182Semaste
236314564Sdim  bool Delete_Impl(ConstString type, ConstString *dummy) {
237314564Sdim    return m_format_map.Delete(type);
238314564Sdim  }
239262182Semaste
240360784Sdim  bool Delete_Impl(ConstString type, RegularExpression *dummy) {
241314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());
242314564Sdim    MapIterator pos, end = m_format_map.map().end();
243314564Sdim    for (pos = m_format_map.map().begin(); pos != end; pos++) {
244360784Sdim      const RegularExpression &regex = pos->first;
245360784Sdim      if (type.GetStringRef() == regex.GetText()) {
246314564Sdim        m_format_map.map().erase(pos);
247314564Sdim        if (m_format_map.listener)
248314564Sdim          m_format_map.listener->Changed();
249314564Sdim        return true;
250314564Sdim      }
251262182Semaste    }
252314564Sdim    return false;
253314564Sdim  }
254262182Semaste
255314564Sdim  bool Get_Impl(ConstString type, MapValueType &entry, ConstString *dummy) {
256314564Sdim    return m_format_map.Get(type, entry);
257314564Sdim  }
258314564Sdim
259314564Sdim  bool GetExact_Impl(ConstString type, MapValueType &entry,
260314564Sdim                     ConstString *dummy) {
261314564Sdim    return Get_Impl(type, entry, static_cast<KeyType *>(nullptr));
262314564Sdim  }
263314564Sdim
264314564Sdim  lldb::TypeNameSpecifierImplSP
265314564Sdim  GetTypeNameSpecifierAtIndex_Impl(size_t index, ConstString *dummy) {
266314564Sdim    ConstString key = m_format_map.GetKeyAtIndex(index);
267314564Sdim    if (key)
268314564Sdim      return lldb::TypeNameSpecifierImplSP(
269314564Sdim          new TypeNameSpecifierImpl(key.AsCString(), false));
270314564Sdim    else
271314564Sdim      return lldb::TypeNameSpecifierImplSP();
272314564Sdim  }
273314564Sdim
274314564Sdim  lldb::TypeNameSpecifierImplSP
275360784Sdim  GetTypeNameSpecifierAtIndex_Impl(size_t index, RegularExpression *dummy) {
276360784Sdim    RegularExpression regex = m_format_map.GetKeyAtIndex(index);
277360784Sdim    if (regex == RegularExpression())
278314564Sdim      return lldb::TypeNameSpecifierImplSP();
279314564Sdim    return lldb::TypeNameSpecifierImplSP(
280360784Sdim        new TypeNameSpecifierImpl(regex.GetText().str().c_str(), true));
281314564Sdim  }
282314564Sdim
283314564Sdim  bool Get_Impl(ConstString key, MapValueType &value,
284360784Sdim                RegularExpression *dummy) {
285314564Sdim    llvm::StringRef key_str = key.GetStringRef();
286314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());
287360784Sdim    // Patterns are matched in reverse-chronological order.
288360784Sdim    for (const auto &pos : llvm::reverse(m_format_map.map())) {
289360784Sdim      const RegularExpression &regex = pos.first;
290360784Sdim      if (regex.Execute(key_str)) {
291360784Sdim        value = pos.second;
292314564Sdim        return true;
293314564Sdim      }
294262182Semaste    }
295314564Sdim    return false;
296314564Sdim  }
297309124Sdim
298314564Sdim  bool GetExact_Impl(ConstString key, MapValueType &value,
299360784Sdim                     RegularExpression *dummy) {
300314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());
301360784Sdim    for (const auto &pos : m_format_map.map()) {
302360784Sdim      const RegularExpression &regex = pos.first;
303360784Sdim      if (regex.GetText() == key.GetStringRef()) {
304360784Sdim        value = pos.second;
305314564Sdim        return true;
306314564Sdim      }
307262182Semaste    }
308314564Sdim    return false;
309314564Sdim  }
310262182Semaste
311314564Sdim  bool Get(const FormattersMatchVector &candidates, MapValueType &entry,
312314564Sdim           uint32_t *reason) {
313314564Sdim    for (const FormattersMatchCandidate &candidate : candidates) {
314314564Sdim      if (Get(candidate.GetTypeName(), entry)) {
315314564Sdim        if (candidate.IsMatch(entry) == false) {
316314564Sdim          entry.reset();
317314564Sdim          continue;
318314564Sdim        } else {
319314564Sdim          if (reason)
320314564Sdim            *reason = candidate.GetReason();
321314564Sdim          return true;
322262182Semaste        }
323314564Sdim      }
324262182Semaste    }
325314564Sdim    return false;
326314564Sdim  }
327262182Semaste};
328262182Semaste
329262182Semaste} // namespace lldb_private
330262182Semaste
331296417Sdim#endif // lldb_FormattersContainer_h_
332