blob: 9d7d37343ac252166f8fc40e109eb1b850c53cc6 [file] [log] [blame]
//===-- FormattersContainer.h -----------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef lldb_FormattersContainer_h_
#define lldb_FormattersContainer_h_
#include <functional>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include "lldb/lldb-public.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/FormatClasses.h"
#include "lldb/DataFormatters/TypeFormat.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/DataFormatters/TypeValidator.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/StringLexer.h"
namespace lldb_private {
class IFormatChangeListener {
public:
virtual ~IFormatChangeListener() = default;
virtual void Changed() = 0;
virtual uint32_t GetCurrentRevision() = 0;
};
// if the user tries to add formatters for, say, "struct Foo" those will not
// match any type because of the way we strip qualifiers from typenames this
// method looks for the case where the user is adding a "class","struct","enum"
// or "union" Foo and strips the unnecessary qualifier
static inline ConstString GetValidTypeName_Impl(ConstString type) {
if (type.IsEmpty())
return type;
std::string type_cstr(type.AsCString());
lldb_utility::StringLexer type_lexer(type_cstr);
type_lexer.AdvanceIf("class ");
type_lexer.AdvanceIf("enum ");
type_lexer.AdvanceIf("struct ");
type_lexer.AdvanceIf("union ");
while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first)
;
return ConstString(type_lexer.GetUnlexed());
}
template <typename KeyType, typename ValueType> class FormattersContainer;
template <typename KeyType, typename ValueType> class FormatMap {
public:
typedef typename ValueType::SharedPointer ValueSP;
typedef std::map<KeyType, ValueSP> MapType;
typedef typename MapType::iterator MapIterator;
typedef std::function<bool(KeyType, const ValueSP &)> ForEachCallback;
FormatMap(IFormatChangeListener *lst)
: m_map(), m_map_mutex(), listener(lst) {}
void Add(KeyType name, const ValueSP &entry) {
if (listener)
entry->GetRevision() = listener->GetCurrentRevision();
else
entry->GetRevision() = 0;
std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
m_map[name] = entry;
if (listener)
listener->Changed();
}
bool Delete(KeyType name) {
std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
MapIterator iter = m_map.find(name);
if (iter == m_map.end())
return false;
m_map.erase(name);
if (listener)
listener->Changed();
return true;
}
void Clear() {
std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
m_map.clear();
if (listener)
listener->Changed();
}
bool Get(KeyType name, ValueSP &entry) {
std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
MapIterator iter = m_map.find(name);
if (iter == m_map.end())
return false;
entry = iter->second;
return true;
}
void ForEach(ForEachCallback callback) {
if (callback) {
std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
MapIterator pos, end = m_map.end();
for (pos = m_map.begin(); pos != end; pos++) {
KeyType type = pos->first;
if (!callback(type, pos->second))
break;
}
}
}
uint32_t GetCount() { return m_map.size(); }
ValueSP GetValueAtIndex(size_t index) {
std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
MapIterator iter = m_map.begin();
MapIterator end = m_map.end();
while (index > 0) {
iter++;
index--;
if (end == iter)
return ValueSP();
}
return iter->second;
}
KeyType GetKeyAtIndex(size_t index) {
std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
MapIterator iter = m_map.begin();
MapIterator end = m_map.end();
while (index > 0) {
iter++;
index--;
if (end == iter)
return KeyType();
}
return iter->first;
}
protected:
MapType m_map;
std::recursive_mutex m_map_mutex;
IFormatChangeListener *listener;
MapType &map() { return m_map; }
std::recursive_mutex &mutex() { return m_map_mutex; }
friend class FormattersContainer<KeyType, ValueType>;
friend class FormatManager;
};
template <typename KeyType, typename ValueType> class FormattersContainer {
protected:
typedef FormatMap<KeyType, ValueType> BackEndType;
public:
typedef typename BackEndType::MapType MapType;
typedef typename MapType::iterator MapIterator;
typedef typename MapType::key_type MapKeyType;
typedef typename MapType::mapped_type MapValueType;
typedef typename BackEndType::ForEachCallback ForEachCallback;
typedef typename std::shared_ptr<FormattersContainer<KeyType, ValueType>>
SharedPointer;
friend class TypeCategoryImpl;
FormattersContainer(std::string name, IFormatChangeListener *lst)
: m_format_map(lst), m_name(name) {}
void Add(const MapKeyType &type, const MapValueType &entry) {
Add_Impl(type, entry, static_cast<KeyType *>(nullptr));
}
bool Delete(ConstString type) {
return Delete_Impl(type, static_cast<KeyType *>(nullptr));
}
bool Get(ValueObject &valobj, MapValueType &entry,
lldb::DynamicValueType use_dynamic, uint32_t *why = nullptr) {
uint32_t value = lldb_private::eFormatterChoiceCriterionDirectChoice;
CompilerType ast_type(valobj.GetCompilerType());
bool ret = Get(valobj, ast_type, entry, use_dynamic, value);
if (ret)
entry = MapValueType(entry);
else
entry = MapValueType();
if (why)
*why = value;
return ret;
}
bool Get(ConstString type, MapValueType &entry) {
return Get_Impl(type, entry, static_cast<KeyType *>(nullptr));
}
bool GetExact(ConstString type, MapValueType &entry) {
return GetExact_Impl(type, entry, static_cast<KeyType *>(nullptr));
}
MapValueType GetAtIndex(size_t index) {
return m_format_map.GetValueAtIndex(index);
}
lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) {
return GetTypeNameSpecifierAtIndex_Impl(index,
static_cast<KeyType *>(nullptr));
}
void Clear() { m_format_map.Clear(); }
void ForEach(ForEachCallback callback) { m_format_map.ForEach(callback); }
uint32_t GetCount() { return m_format_map.GetCount(); }
protected:
BackEndType m_format_map;
std::string m_name;
DISALLOW_COPY_AND_ASSIGN(FormattersContainer);
void Add_Impl(const MapKeyType &type, const MapValueType &entry,
lldb::RegularExpressionSP *dummy) {
m_format_map.Add(type, entry);
}
void Add_Impl(ConstString type, const MapValueType &entry,
ConstString *dummy) {
m_format_map.Add(GetValidTypeName_Impl(type), entry);
}
bool Delete_Impl(ConstString type, ConstString *dummy) {
return m_format_map.Delete(type);
}
bool Delete_Impl(ConstString type, lldb::RegularExpressionSP *dummy) {
std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());
MapIterator pos, end = m_format_map.map().end();
for (pos = m_format_map.map().begin(); pos != end; pos++) {
lldb::RegularExpressionSP regex = pos->first;
if (type.GetStringRef() == regex->GetText()) {
m_format_map.map().erase(pos);
if (m_format_map.listener)
m_format_map.listener->Changed();
return true;
}
}
return false;
}
bool Get_Impl(ConstString type, MapValueType &entry, ConstString *dummy) {
return m_format_map.Get(type, entry);
}
bool GetExact_Impl(ConstString type, MapValueType &entry,
ConstString *dummy) {
return Get_Impl(type, entry, static_cast<KeyType *>(nullptr));
}
lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierAtIndex_Impl(size_t index, ConstString *dummy) {
ConstString key = m_format_map.GetKeyAtIndex(index);
if (key)
return lldb::TypeNameSpecifierImplSP(
new TypeNameSpecifierImpl(key.AsCString(), false));
else
return lldb::TypeNameSpecifierImplSP();
}
lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierAtIndex_Impl(size_t index,
lldb::RegularExpressionSP *dummy) {
lldb::RegularExpressionSP regex = m_format_map.GetKeyAtIndex(index);
if (regex.get() == nullptr)
return lldb::TypeNameSpecifierImplSP();
return lldb::TypeNameSpecifierImplSP(
new TypeNameSpecifierImpl(regex->GetText().str().c_str(), true));
}
bool Get_Impl(ConstString key, MapValueType &value,
lldb::RegularExpressionSP *dummy) {
llvm::StringRef key_str = key.GetStringRef();
std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());
MapIterator pos, end = m_format_map.map().end();
for (pos = m_format_map.map().begin(); pos != end; pos++) {
lldb::RegularExpressionSP regex = pos->first;
if (regex->Execute(key_str)) {
value = pos->second;
return true;
}
}
return false;
}
bool GetExact_Impl(ConstString key, MapValueType &value,
lldb::RegularExpressionSP *dummy) {
std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());
MapIterator pos, end = m_format_map.map().end();
for (pos = m_format_map.map().begin(); pos != end; pos++) {
lldb::RegularExpressionSP regex = pos->first;
if (regex->GetText() == key.GetStringRef()) {
value = pos->second;
return true;
}
}
return false;
}
bool Get(const FormattersMatchVector &candidates, MapValueType &entry,
uint32_t *reason) {
for (const FormattersMatchCandidate &candidate : candidates) {
if (Get(candidate.GetTypeName(), entry)) {
if (candidate.IsMatch(entry) == false) {
entry.reset();
continue;
} else {
if (reason)
*reason = candidate.GetReason();
return true;
}
}
}
return false;
}
};
} // namespace lldb_private
#endif // lldb_FormattersContainer_h_