blob: 2f0cb6c78472f1c5c338a3ac44c2d2519f4d7f55 [file] [log] [blame]
//===-- TypeCategory.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_DATAFORMATTERS_TYPECATEGORY_H
#define LLDB_DATAFORMATTERS_TYPECATEGORY_H
#include <array>
#include <initializer_list>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-public.h"
#include "lldb/DataFormatters/FormatClasses.h"
#include "lldb/DataFormatters/FormattersContainer.h"
namespace lldb_private {
// A formatter container with sub-containers for different priority tiers, that
// also exposes a flat view of all formatters in it.
//
// Formatters have different priority during matching, depending on the type of
// matching specified at registration. Exact matchers are processed first, then
// regex, and finally callback matchers. However, the scripting API presents a
// flat view of formatters in a category, with methods like `GetNumFormats()`
// and `GetFormatAtIndex(i)`. So we need something that can behave like both
// representations.
template <typename FormatterImpl> class TieredFormatterContainer {
public:
using Subcontainer = FormattersContainer<FormatterImpl>;
using SubcontainerSP = std::shared_ptr<Subcontainer>;
using ForEachCallback = typename Subcontainer::ForEachCallback;
using MapValueType = typename Subcontainer::ValueSP;
TieredFormatterContainer(IFormatChangeListener *change_listener) {
for (auto& sc : m_subcontainers)
sc = std::make_shared<Subcontainer>(change_listener);
}
/// Returns the subcontainer containing formatters for exact matching.
std::shared_ptr<Subcontainer> GetExactMatch() const {
return m_subcontainers[lldb::eFormatterMatchExact];
}
/// Returns the subcontainer containing formatters for regex matching.
std::shared_ptr<Subcontainer> GetRegexMatch() const {
return m_subcontainers[lldb::eFormatterMatchRegex];
}
/// Adds a formatter to the right subcontainer depending on the matching type
/// specified by `type_sp`.
void Add(lldb::TypeNameSpecifierImplSP type_sp,
std::shared_ptr<FormatterImpl> format_sp) {
m_subcontainers[type_sp->GetMatchType()]->Add(TypeMatcher(type_sp),
format_sp);
}
/// Deletes the formatter specified by `type_sp`.
bool Delete(lldb::TypeNameSpecifierImplSP type_sp) {
return m_subcontainers[type_sp->GetMatchType()]->Delete(
TypeMatcher(type_sp));
}
/// Returns the total count of elements across all subcontainers.
uint32_t GetCount() {
uint32_t result = 0;
for (auto sc : m_subcontainers)
result += sc->GetCount();
return result;
}
/// Returns the formatter at `index`, simulating a flattened view of all
/// subcontainers in priority order.
MapValueType GetAtIndex(size_t index) {
for (auto sc : m_subcontainers) {
if (index < sc->GetCount())
return sc->GetAtIndex(index);
index -= sc->GetCount();
}
return MapValueType();
}
/// Looks for a matching candidate across all priority tiers, in priority
/// order. If a match is found, returns `true` and puts the matching entry in
/// `entry`.
bool Get(const FormattersMatchVector &candidates,
std::shared_ptr<FormatterImpl> &entry) {
for (auto sc : m_subcontainers) {
if (sc->Get(candidates, entry))
return true;
}
return false;
}
/// Returns a formatter that is an exact match for `type_specifier_sp`. It
/// looks for a formatter with the same matching type that was created from
/// the same string. This is useful so we can refer to a formatter using the
/// same string used to register it.
///
/// For example, `type_specifier_sp` can be something like
/// {"std::vector<.*>", eFormatterMatchRegex}, and we'd look for a regex
/// matcher with that exact regex string, NOT try to match that string using
/// regex.
MapValueType
GetForTypeNameSpecifier(lldb::TypeNameSpecifierImplSP type_specifier_sp) {
MapValueType retval;
if (type_specifier_sp) {
m_subcontainers[type_specifier_sp->GetMatchType()]->GetExact(
ConstString(type_specifier_sp->GetName()), retval);
}
return retval;
}
/// Returns the type name specifier at `index`, simulating a flattened view of
/// all subcontainers in priority order.
lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) {
for (auto sc : m_subcontainers) {
if (index < sc->GetCount())
return sc->GetTypeNameSpecifierAtIndex(index);
index -= sc->GetCount();
}
return lldb::TypeNameSpecifierImplSP();
}
private:
std::array<std::shared_ptr<Subcontainer>, lldb::eLastFormatterMatchType + 1>
m_subcontainers;
};
class TypeCategoryImpl {
private:
typedef TieredFormatterContainer<TypeFormatImpl> FormatContainer;
typedef TieredFormatterContainer<TypeSummaryImpl> SummaryContainer;
typedef TieredFormatterContainer<TypeFilterImpl> FilterContainer;
typedef TieredFormatterContainer<SyntheticChildren> SynthContainer;
public:
typedef uint16_t FormatCategoryItems;
static const uint16_t ALL_ITEM_TYPES = UINT16_MAX;
template <typename T> class ForEachCallbacks {
public:
ForEachCallbacks() = default;
~ForEachCallbacks() = default;
template <typename U = TypeFormatImpl>
typename std::enable_if<std::is_same<U, T>::value, ForEachCallbacks &>::type
SetExact(FormatContainer::ForEachCallback callback) {
m_format_exact = std::move(callback);
return *this;
}
template <typename U = TypeFormatImpl>
typename std::enable_if<std::is_same<U, T>::value, ForEachCallbacks &>::type
SetWithRegex(FormatContainer::ForEachCallback callback) {
m_format_regex = std::move(callback);
return *this;
}
template <typename U = TypeSummaryImpl>
typename std::enable_if<std::is_same<U, T>::value, ForEachCallbacks &>::type
SetExact(SummaryContainer::ForEachCallback callback) {
m_summary_exact = std::move(callback);
return *this;
}
template <typename U = TypeSummaryImpl>
typename std::enable_if<std::is_same<U, T>::value, ForEachCallbacks &>::type
SetWithRegex(SummaryContainer::ForEachCallback callback) {
m_summary_regex = std::move(callback);
return *this;
}
template <typename U = TypeFilterImpl>
typename std::enable_if<std::is_same<U, T>::value, ForEachCallbacks &>::type
SetExact(FilterContainer::ForEachCallback callback) {
m_filter_exact = std::move(callback);
return *this;
}
template <typename U = TypeFilterImpl>
typename std::enable_if<std::is_same<U, T>::value, ForEachCallbacks &>::type
SetWithRegex(FilterContainer::ForEachCallback callback) {
m_filter_regex = std::move(callback);
return *this;
}
template <typename U = SyntheticChildren>
typename std::enable_if<std::is_same<U, T>::value, ForEachCallbacks &>::type
SetExact(SynthContainer::ForEachCallback callback) {
m_synth_exact = std::move(callback);
return *this;
}
template <typename U = SyntheticChildren>
typename std::enable_if<std::is_same<U, T>::value, ForEachCallbacks &>::type
SetWithRegex(SynthContainer::ForEachCallback callback) {
m_synth_regex = std::move(callback);
return *this;
}
FormatContainer::ForEachCallback GetFormatExactCallback() const {
return m_format_exact;
}
FormatContainer::ForEachCallback GetFormatRegexCallback() const {
return m_format_regex;
}
SummaryContainer::ForEachCallback GetSummaryExactCallback() const {
return m_summary_exact;
}
SummaryContainer::ForEachCallback GetSummaryRegexCallback() const {
return m_summary_regex;
}
FilterContainer::ForEachCallback GetFilterExactCallback() const {
return m_filter_exact;
}
FilterContainer::ForEachCallback GetFilterRegexCallback() const {
return m_filter_regex;
}
SynthContainer::ForEachCallback GetSynthExactCallback() const {
return m_synth_exact;
}
SynthContainer::ForEachCallback GetSynthRegexCallback() const {
return m_synth_regex;
}
private:
FormatContainer::ForEachCallback m_format_exact;
FormatContainer::ForEachCallback m_format_regex;
SummaryContainer::ForEachCallback m_summary_exact;
SummaryContainer::ForEachCallback m_summary_regex;
FilterContainer::ForEachCallback m_filter_exact;
FilterContainer::ForEachCallback m_filter_regex;
SynthContainer::ForEachCallback m_synth_exact;
SynthContainer::ForEachCallback m_synth_regex;
};
TypeCategoryImpl(IFormatChangeListener *clist, ConstString name);
template <typename T> void ForEach(const ForEachCallbacks<T> &foreach) {
GetTypeFormatsContainer()->ForEach(foreach.GetFormatExactCallback());
GetRegexTypeFormatsContainer()->ForEach(foreach.GetFormatRegexCallback());
GetTypeSummariesContainer()->ForEach(foreach.GetSummaryExactCallback());
GetRegexTypeSummariesContainer()->ForEach(
foreach.GetSummaryRegexCallback());
GetTypeFiltersContainer()->ForEach(foreach.GetFilterExactCallback());
GetRegexTypeFiltersContainer()->ForEach(foreach.GetFilterRegexCallback());
GetTypeSyntheticsContainer()->ForEach(foreach.GetSynthExactCallback());
GetRegexTypeSyntheticsContainer()->ForEach(foreach.GetSynthRegexCallback());
}
FormatContainer::SubcontainerSP GetTypeFormatsContainer() {
return m_format_cont.GetExactMatch();
}
FormatContainer::SubcontainerSP GetRegexTypeFormatsContainer() {
return m_format_cont.GetRegexMatch();
}
FormatContainer &GetFormatContainer() { return m_format_cont; }
SummaryContainer::SubcontainerSP GetTypeSummariesContainer() {
return m_summary_cont.GetExactMatch();
}
SummaryContainer::SubcontainerSP GetRegexTypeSummariesContainer() {
return m_summary_cont.GetRegexMatch();
}
SummaryContainer &GetSummaryContainer() { return m_summary_cont; }
FilterContainer::SubcontainerSP GetTypeFiltersContainer() {
return m_filter_cont.GetExactMatch();
}
FilterContainer::SubcontainerSP GetRegexTypeFiltersContainer() {
return m_filter_cont.GetRegexMatch();
}
FilterContainer &GetFilterContainer() { return m_filter_cont; }
FormatContainer::MapValueType
GetFormatForType(lldb::TypeNameSpecifierImplSP type_sp);
SummaryContainer::MapValueType
GetSummaryForType(lldb::TypeNameSpecifierImplSP type_sp);
FilterContainer::MapValueType
GetFilterForType(lldb::TypeNameSpecifierImplSP type_sp);
SynthContainer::MapValueType
GetSyntheticForType(lldb::TypeNameSpecifierImplSP type_sp);
void AddTypeFormat(lldb::TypeNameSpecifierImplSP type_sp,
lldb::TypeFormatImplSP format_sp) {
m_format_cont.Add(type_sp, format_sp);
}
void AddTypeSummary(lldb::TypeNameSpecifierImplSP type_sp,
lldb::TypeSummaryImplSP summary_sp) {
m_summary_cont.Add(type_sp, summary_sp);
}
void AddTypeFilter(lldb::TypeNameSpecifierImplSP type_sp,
lldb::TypeFilterImplSP filter_sp) {
m_filter_cont.Add(type_sp, filter_sp);
}
void AddTypeSynthetic(lldb::TypeNameSpecifierImplSP type_sp,
lldb::SyntheticChildrenSP synth_sp) {
m_synth_cont.Add(type_sp, synth_sp);
}
bool DeleteTypeFormat(lldb::TypeNameSpecifierImplSP type_sp) {
return m_format_cont.Delete(type_sp);
}
bool DeleteTypeSummary(lldb::TypeNameSpecifierImplSP type_sp) {
return m_summary_cont.Delete(type_sp);
}
bool DeleteTypeFilter(lldb::TypeNameSpecifierImplSP type_sp) {
return m_filter_cont.Delete(type_sp);
}
bool DeleteTypeSynthetic(lldb::TypeNameSpecifierImplSP type_sp) {
return m_synth_cont.Delete(type_sp);
}
uint32_t GetNumFormats() { return m_format_cont.GetCount(); }
uint32_t GetNumSummaries() { return m_summary_cont.GetCount(); }
uint32_t GetNumFilters() { return m_filter_cont.GetCount(); }
uint32_t GetNumSynthetics() { return m_synth_cont.GetCount(); }
lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierForFormatAtIndex(size_t index);
lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierForSummaryAtIndex(size_t index);
lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierForFilterAtIndex(size_t index);
lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierForSyntheticAtIndex(size_t index);
FormatContainer::MapValueType GetFormatAtIndex(size_t index);
SummaryContainer::MapValueType GetSummaryAtIndex(size_t index);
FilterContainer::MapValueType GetFilterAtIndex(size_t index);
SynthContainer::MapValueType GetSyntheticAtIndex(size_t index);
SynthContainer::SubcontainerSP GetTypeSyntheticsContainer() {
return m_synth_cont.GetExactMatch();
}
SynthContainer::SubcontainerSP GetRegexTypeSyntheticsContainer() {
return m_synth_cont.GetRegexMatch();
}
SynthContainer &GetSyntheticsContainer() { return m_synth_cont; }
bool IsEnabled() const { return m_enabled; }
uint32_t GetEnabledPosition() {
if (!m_enabled)
return UINT32_MAX;
else
return m_enabled_position;
}
bool Get(lldb::LanguageType lang, const FormattersMatchVector &candidates,
lldb::TypeFormatImplSP &entry);
bool Get(lldb::LanguageType lang, const FormattersMatchVector &candidates,
lldb::TypeSummaryImplSP &entry);
bool Get(lldb::LanguageType lang, const FormattersMatchVector &candidates,
lldb::SyntheticChildrenSP &entry);
void Clear(FormatCategoryItems items = ALL_ITEM_TYPES);
bool Delete(ConstString name, FormatCategoryItems items = ALL_ITEM_TYPES);
uint32_t GetCount(FormatCategoryItems items = ALL_ITEM_TYPES);
const char *GetName() { return m_name.GetCString(); }
size_t GetNumLanguages();
lldb::LanguageType GetLanguageAtIndex(size_t idx);
void AddLanguage(lldb::LanguageType lang);
std::string GetDescription();
bool AnyMatches(ConstString type_name,
FormatCategoryItems items = ALL_ITEM_TYPES,
bool only_enabled = true,
const char **matching_category = nullptr,
FormatCategoryItems *matching_type = nullptr);
typedef std::shared_ptr<TypeCategoryImpl> SharedPointer;
private:
FormatContainer m_format_cont;
SummaryContainer m_summary_cont;
FilterContainer m_filter_cont;
SynthContainer m_synth_cont;
bool m_enabled;
IFormatChangeListener *m_change_listener;
std::recursive_mutex m_mutex;
ConstString m_name;
std::vector<lldb::LanguageType> m_languages;
uint32_t m_enabled_position = 0;
void Enable(bool value, uint32_t position);
void Disable() { Enable(false, UINT32_MAX); }
bool IsApplicable(lldb::LanguageType lang);
uint32_t GetLastEnabledPosition() { return m_enabled_position; }
void SetEnabledPosition(uint32_t p) { m_enabled_position = p; }
friend class FormatManager;
friend class LanguageCategory;
friend class TypeCategoryMap;
friend class FormattersContainer<TypeFormatImpl>;
friend class FormattersContainer<TypeSummaryImpl>;
friend class FormattersContainer<TypeFilterImpl>;
friend class FormattersContainer<ScriptedSyntheticChildren>;
};
} // namespace lldb_private
#endif // LLDB_DATAFORMATTERS_TYPECATEGORY_H