Extended context filter config schema to accept optional radius parameter
This commit is contained in:
@@ -534,39 +534,35 @@ tvl::value_t access_filter::match(
|
|||||||
[&a](const auto &access) { return a == access; });
|
[&a](const auto &access) { return a == access; });
|
||||||
}
|
}
|
||||||
|
|
||||||
context_filter::context_filter(filter_t type,
|
context_filter::context_filter(
|
||||||
std::vector<common::string_or_regex> context, unsigned radius)
|
filter_t type, std::vector<config::context_config> context, unsigned radius)
|
||||||
: filter_visitor{type}
|
: filter_visitor{type}
|
||||||
, radius_{radius}
|
|
||||||
, context_{std::move(context)}
|
, context_{std::move(context)}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void context_filter::initialize(const diagram &d) const
|
void context_filter::initialize_effective_context(
|
||||||
|
const diagram &d, unsigned idx) const
|
||||||
{
|
{
|
||||||
if (initialized_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
initialized_ = true;
|
|
||||||
|
|
||||||
bool effective_context_extended{true};
|
bool effective_context_extended{true};
|
||||||
|
|
||||||
|
auto &effective_context = effective_contexts_[idx];
|
||||||
|
|
||||||
// First add to effective context all elements matching context_
|
// First add to effective context all elements matching context_
|
||||||
for (const auto &c : context_) {
|
const auto &context = context_.at(idx);
|
||||||
const auto &context_matches =
|
const auto &context_matches =
|
||||||
static_cast<const class_diagram::model::diagram &>(d)
|
static_cast<const class_diagram::model::diagram &>(d)
|
||||||
.find<class_diagram::model::class_>(c);
|
.find<class_diagram::model::class_>(context.pattern);
|
||||||
|
|
||||||
for (const auto &maybe_match : context_matches) {
|
for (const auto &maybe_match : context_matches) {
|
||||||
if (maybe_match)
|
if (maybe_match)
|
||||||
effective_context_.emplace(maybe_match.value().id());
|
effective_context.emplace(maybe_match.value().id());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now repeat radius times - extend the effective context with elements
|
// Now repeat radius times - extend the effective context with elements
|
||||||
// matching in direct relationship to what is in context
|
// matching in direct relationship to what is in context
|
||||||
auto radius_counter = radius_;
|
auto radius_counter = context.radius;
|
||||||
decltype(effective_context_) current_iteration_context;
|
std::set<clanguml::common::id_t> current_iteration_context;
|
||||||
|
|
||||||
while (radius_counter > 0 && effective_context_extended) {
|
while (radius_counter > 0 && effective_context_extended) {
|
||||||
// If at any iteration the effective context was not extended - we
|
// If at any iteration the effective context was not extended - we
|
||||||
@@ -581,13 +577,13 @@ void context_filter::initialize(const diagram &d) const
|
|||||||
// Return a positive match if the element e is in a direct
|
// Return a positive match if the element e is in a direct
|
||||||
// relationship with any of the effective context elements ...
|
// relationship with any of the effective context elements ...
|
||||||
for (const relationship &rel : c.get().relationships()) {
|
for (const relationship &rel : c.get().relationships()) {
|
||||||
for (const auto &ec : effective_context_) {
|
for (const auto &ec : effective_context) {
|
||||||
if (d.should_include(rel.type()) && rel.destination() == ec)
|
if (d.should_include(rel.type()) && rel.destination() == ec)
|
||||||
current_iteration_context.emplace(c.get().id());
|
current_iteration_context.emplace(c.get().id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ... or vice-versa
|
// ... or vice-versa
|
||||||
for (const auto &ec : effective_context_) {
|
for (const auto &ec : effective_context) {
|
||||||
const auto &maybe_class =
|
const auto &maybe_class =
|
||||||
static_cast<const class_diagram::model::diagram &>(d)
|
static_cast<const class_diagram::model::diagram &>(d)
|
||||||
.find<class_diagram::model::class_>(ec);
|
.find<class_diagram::model::class_>(ec);
|
||||||
@@ -608,7 +604,7 @@ void context_filter::initialize(const diagram &d) const
|
|||||||
// effective context...
|
// effective context...
|
||||||
for (const class_diagram::model::class_parent &p :
|
for (const class_diagram::model::class_parent &p :
|
||||||
c.get().parents()) {
|
c.get().parents()) {
|
||||||
for (const auto &ec : effective_context_) {
|
for (const auto &ec : effective_context) {
|
||||||
const auto &maybe_parent =
|
const auto &maybe_parent =
|
||||||
static_cast<const class_diagram::model::diagram &>(d)
|
static_cast<const class_diagram::model::diagram &>(d)
|
||||||
.find<class_diagram::model::class_>(ec);
|
.find<class_diagram::model::class_>(ec);
|
||||||
@@ -622,7 +618,7 @@ void context_filter::initialize(const diagram &d) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// .. or vice-versa
|
// .. or vice-versa
|
||||||
for (const auto &ec : effective_context_) {
|
for (const auto &ec : effective_context) {
|
||||||
const auto &maybe_child =
|
const auto &maybe_child =
|
||||||
static_cast<const class_diagram::model::diagram &>(d)
|
static_cast<const class_diagram::model::diagram &>(d)
|
||||||
.find<class_diagram::model::class_>(ec);
|
.find<class_diagram::model::class_>(ec);
|
||||||
@@ -637,15 +633,29 @@ void context_filter::initialize(const diagram &d) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (auto id : current_iteration_context) {
|
for (auto id : current_iteration_context) {
|
||||||
if (effective_context_.count(id) == 0) {
|
if (effective_context.count(id) == 0) {
|
||||||
// Found new element to add to context
|
// Found new element to add to context
|
||||||
effective_context_.emplace(id);
|
effective_context.emplace(id);
|
||||||
effective_context_extended = true;
|
effective_context_extended = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void context_filter::initialize(const diagram &d) const
|
||||||
|
{
|
||||||
|
if (initialized_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
initialized_ = true;
|
||||||
|
|
||||||
|
// Prepare effective_contexts_
|
||||||
|
for (auto i = 0U; i < context_.size(); i++) {
|
||||||
|
effective_contexts_.push_back({});
|
||||||
|
initialize_effective_context(d, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tvl::value_t context_filter::match(const diagram &d, const element &e) const
|
tvl::value_t context_filter::match(const diagram &d, const element &e) const
|
||||||
{
|
{
|
||||||
if (d.type() != diagram_t::kClass)
|
if (d.type() != diagram_t::kClass)
|
||||||
@@ -658,11 +668,14 @@ tvl::value_t context_filter::match(const diagram &d, const element &e) const
|
|||||||
|
|
||||||
initialize(d);
|
initialize(d);
|
||||||
|
|
||||||
if (effective_context_.empty())
|
if (std::all_of(effective_contexts_.begin(), effective_contexts_.end(),
|
||||||
|
[](const auto &ec) { return ec.empty(); }))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (effective_context_.count(e.id()) > 0)
|
for (const auto &ec : effective_contexts_) {
|
||||||
|
if (ec.count(e.id()) > 0)
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -447,7 +447,7 @@ private:
|
|||||||
* to any of the elements specified in context.
|
* to any of the elements specified in context.
|
||||||
*/
|
*/
|
||||||
struct context_filter : public filter_visitor {
|
struct context_filter : public filter_visitor {
|
||||||
context_filter(filter_t type, std::vector<common::string_or_regex> context,
|
context_filter(filter_t type, std::vector<config::context_config> context,
|
||||||
unsigned radius = 1);
|
unsigned radius = 1);
|
||||||
|
|
||||||
~context_filter() override = default;
|
~context_filter() override = default;
|
||||||
@@ -457,15 +457,15 @@ struct context_filter : public filter_visitor {
|
|||||||
private:
|
private:
|
||||||
void initialize(const diagram &d) const;
|
void initialize(const diagram &d) const;
|
||||||
|
|
||||||
const unsigned radius_;
|
void initialize_effective_context(const diagram &d, unsigned idx) const;
|
||||||
|
|
||||||
std::vector<common::string_or_regex> context_;
|
std::vector<config::context_config> context_;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Represents all elements which should belong to the diagram based
|
* Represents all elements which should belong to the diagram based
|
||||||
* on this filter. It is populated by the initialize() method.
|
* on this filter. It is populated by the initialize() method.
|
||||||
*/
|
*/
|
||||||
mutable std::set<clanguml::common::id_t> effective_context_;
|
mutable std::vector<std::set<clanguml::common::id_t>> effective_contexts_;
|
||||||
|
|
||||||
/*! Flag to mark whether the filter context has been computed */
|
/*! Flag to mark whether the filter context has been computed */
|
||||||
mutable bool initialized_{false};
|
mutable bool initialized_{false};
|
||||||
|
|||||||
@@ -141,6 +141,11 @@ struct mermaid {
|
|||||||
void append(const mermaid &r);
|
void append(const mermaid &r);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct context_config {
|
||||||
|
common::string_or_regex pattern;
|
||||||
|
unsigned radius{0};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Definition of diagram template
|
* @brief Definition of diagram template
|
||||||
*/
|
*/
|
||||||
@@ -316,9 +321,13 @@ struct filter {
|
|||||||
* include:
|
* include:
|
||||||
* context:
|
* context:
|
||||||
* - ns1::ns2::ClassA
|
* - ns1::ns2::ClassA
|
||||||
|
* - r: ns1::ns2::ClassB<.*>
|
||||||
|
* - match:
|
||||||
|
* pattern: ns1::ns2::ClassA
|
||||||
|
* radius: 3
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
std::vector<common::string_or_regex> context;
|
std::vector<context_config> context;
|
||||||
|
|
||||||
/*! @brief Paths filter
|
/*! @brief Paths filter
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -112,6 +112,13 @@ types:
|
|||||||
- function
|
- function
|
||||||
- function_template
|
- function_template
|
||||||
- lambda
|
- lambda
|
||||||
|
context_filter_match_t:
|
||||||
|
match:
|
||||||
|
radius: int
|
||||||
|
pattern: regex_or_string_t
|
||||||
|
context_filter_t:
|
||||||
|
- regex_or_string_t
|
||||||
|
- context_filter_match_t
|
||||||
filter_t:
|
filter_t:
|
||||||
namespaces: !optional [regex_or_string_t]
|
namespaces: !optional [regex_or_string_t]
|
||||||
elements: !optional [regex_or_string_t]
|
elements: !optional [regex_or_string_t]
|
||||||
@@ -123,7 +130,7 @@ types:
|
|||||||
specializations: !optional [regex_or_string_t]
|
specializations: !optional [regex_or_string_t]
|
||||||
dependants: !optional [regex_or_string_t]
|
dependants: !optional [regex_or_string_t]
|
||||||
dependencies: !optional [regex_or_string_t]
|
dependencies: !optional [regex_or_string_t]
|
||||||
context: !optional [regex_or_string_t]
|
context: !optional [context_filter_t]
|
||||||
paths: !optional [string]
|
paths: !optional [string]
|
||||||
method_types: !optional [method_type_filter_t]
|
method_types: !optional [method_type_filter_t]
|
||||||
callee_types: !optional [callee_type_filter_t]
|
callee_types: !optional [callee_type_filter_t]
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ using clanguml::common::model::relationship_t;
|
|||||||
using clanguml::config::callee_type;
|
using clanguml::config::callee_type;
|
||||||
using clanguml::config::class_diagram;
|
using clanguml::config::class_diagram;
|
||||||
using clanguml::config::config;
|
using clanguml::config::config;
|
||||||
|
using clanguml::config::context_config;
|
||||||
using clanguml::config::diagram_template;
|
using clanguml::config::diagram_template;
|
||||||
using clanguml::config::filter;
|
using clanguml::config::filter;
|
||||||
using clanguml::config::generate_links_config;
|
using clanguml::config::generate_links_config;
|
||||||
@@ -419,6 +420,23 @@ template <> struct convert<string_or_regex> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <> struct convert<context_config> {
|
||||||
|
static bool decode(const Node &node, context_config &rhs)
|
||||||
|
{
|
||||||
|
using namespace std::string_literals;
|
||||||
|
if (node.IsMap() && has_key(node, "match")) {
|
||||||
|
rhs.radius = node["match"]["radius"].as<unsigned>();
|
||||||
|
rhs.pattern = node["match"]["radius"].as<string_or_regex>();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rhs.radius = 1;
|
||||||
|
rhs.pattern = node.as<string_or_regex>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <> struct convert<namespace_or_regex> {
|
template <> struct convert<namespace_or_regex> {
|
||||||
static bool decode(const Node &node, namespace_or_regex &rhs)
|
static bool decode(const Node &node, namespace_or_regex &rhs)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -104,6 +104,19 @@ YAML::Emitter &operator<<(YAML::Emitter &out, const package_type_t &r)
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
YAML::Emitter &operator<<(YAML::Emitter &out, const context_config &c)
|
||||||
|
{
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "match";
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "radius" << YAML::Value << c.radius;
|
||||||
|
out << YAML::Key << "pattern" << YAML::Value << c.pattern;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
YAML::Emitter &operator<<(YAML::Emitter &out, const filter &f)
|
YAML::Emitter &operator<<(YAML::Emitter &out, const filter &f)
|
||||||
{
|
{
|
||||||
out << YAML::BeginMap;
|
out << YAML::BeginMap;
|
||||||
|
|||||||
Reference in New Issue
Block a user