From b6390d91063025d9b8f3a02b731b2a998baf4e1c Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sun, 24 Apr 2022 13:36:07 +0200 Subject: [PATCH] Refactored edge traversal diagram filter --- src/common/model/diagram_filter.cc | 52 +++++---- src/common/model/diagram_filter.h | 181 ++++++++++++----------------- src/common/model/nested_trait.h | 15 ++- 3 files changed, 119 insertions(+), 129 deletions(-) diff --git a/src/common/model/diagram_filter.cc b/src/common/model/diagram_filter.cc index 57809b59..8969abd4 100644 --- a/src/common/model/diagram_filter.cc +++ b/src/common/model/diagram_filter.cc @@ -76,6 +76,12 @@ const type_safe::optional_ref get( return d.get_file(full_name); } +template <> +std::string destination_comparator( + const common::model::source_file &f) +{ + return f.alias(); +} } // namespace detail filter_visitor::filter_visitor(filter_t type) @@ -416,27 +422,27 @@ void diagram_filter::init_filters(const config::diagram &c) filter_t::kInclusive, c.include().subclasses)); element_filters.emplace_back(std::make_unique< - tree_element_filter>(filter_t::kInclusive, relationship_t::kInstantiation, c.include().specializations)); element_filters.emplace_back(std::make_unique< - tree_element_filter>(filter_t::kInclusive, relationship_t::kDependency, c.include().dependants)); element_filters.emplace_back(std::make_unique< - tree_element_filter>(filter_t::kInclusive, relationship_t::kDependency, c.include().dependencies, true)); } else if (c.type() == diagram_t::kPackage) { - element_filters.emplace_back(std::make_unique>( filter_t::kInclusive, relationship_t::kDependency, c.include().dependants)); - element_filters.emplace_back(std::make_unique>( filter_t::kInclusive, relationship_t::kDependency, c.include().dependencies, true)); @@ -466,13 +472,13 @@ void diagram_filter::init_filters(const config::diagram &c) } element_filters.emplace_back(std::make_unique< - tree_element_filter>( filter_t::kInclusive, relationship_t::kAssociation, dependants)); element_filters.emplace_back(std::make_unique< - tree_element_filter>( filter_t::kInclusive, relationship_t::kAssociation, dependencies, true)); @@ -505,27 +511,27 @@ void diagram_filter::init_filters(const config::diagram &c) add_exclusive_filter(std::make_unique( filter_t::kExclusive, c.exclude().subclasses)); - add_exclusive_filter( - std::make_unique>(filter_t::kExclusive, - relationship_t::kInstantiation, c.exclude().specializations)); + add_exclusive_filter(std::make_unique>( + filter_t::kExclusive, relationship_t::kInstantiation, + c.exclude().specializations)); - add_exclusive_filter( - std::make_unique>(filter_t::kExclusive, - relationship_t::kDependency, c.exclude().dependants)); + add_exclusive_filter(std::make_unique>( + filter_t::kExclusive, relationship_t::kDependency, + c.exclude().dependants)); - add_exclusive_filter(std::make_unique>( filter_t::kExclusive, relationship_t::kDependency, c.exclude().dependants)); - add_exclusive_filter( - std::make_unique>(filter_t::kExclusive, - relationship_t::kDependency, c.exclude().dependencies, true)); + add_exclusive_filter(std::make_unique>( + filter_t::kExclusive, relationship_t::kDependency, + c.exclude().dependencies, true)); - add_exclusive_filter(std::make_unique>( filter_t::kExclusive, relationship_t::kDependency, c.exclude().dependencies, true)); @@ -555,12 +561,12 @@ void diagram_filter::init_filters(const config::diagram &c) } add_exclusive_filter(std::make_unique< - tree_element_filter>(filter_t::kExclusive, relationship_t::kAssociation, dependencies, true)); add_exclusive_filter(std::make_unique< - tree_element_filter>(filter_t::kExclusive, relationship_t::kAssociation, dependants)); } diff --git a/src/common/model/diagram_filter.h b/src/common/model/diagram_filter.h index 3b90d059..a6beaf7d 100644 --- a/src/common/model/diagram_filter.h +++ b/src/common/model/diagram_filter.h @@ -43,6 +43,15 @@ const std::vector> &view( template const type_safe::optional_ref get( const DiagramT &d, const std::string &full_name); + +template +std::string destination_comparator(const ElementT &e) +{ + return e.full_name(false); +} + +template <> +std::string destination_comparator(const common::model::source_file &f); } // namespace detail class filter_visitor { @@ -118,8 +127,8 @@ private: template -struct tree_element_filter : public filter_visitor { - tree_element_filter(filter_t type, relationship_t relationship, +struct edge_traversal_filter : public filter_visitor { + edge_traversal_filter(filter_t type, relationship_t relationship, std::vector roots, bool forward = false) : filter_visitor{type} , relationship_{relationship} @@ -161,126 +170,88 @@ struct tree_element_filter : public filter_visitor { } private: + template + bool add_adjacent(const C &from, const D &to, + const std::vector &relationships) const + { + bool added_new_element{false}; + + for (const auto &from_el : from) { + // Check if any of its relationships of type relationship_ + // points to an element already in the matching_elements_ + // set + for (const auto &rel : from_el->relationships()) { + // Consider only if connected by one of specified relationships + if (util::contains(relationships, rel.type())) { + for (const auto &to_el : to) { + if (rel.destination() == + detail::destination_comparator(*to_el)) { + const auto &to_add = forward_ ? to_el : from_el; + if (matching_elements_.insert(to_add).second) + added_new_element = true; + } + } + } + } + } + + return added_new_element; + } + + void add_parents(const DiagramT &cd) const + { + decltype(matching_elements_) parents; + + util::for_each( + matching_elements_, [this, &cd, &parents](const auto &element) { + auto parent = detail::get( + cd, element.get().path().to_string()); + + while (parent.has_value()) { + parents.emplace(type_safe::ref(parent.value())); + parent = detail::get( + cd, parent.value().path().to_string()); + } + }); + + matching_elements_.insert(std::begin(parents), std::end(parents)); + } + void init(const DiagramT &cd) const { if (initialized_) return; // First get all elements specified in the filter configuration + // which will serve as starting points for the search + // of matching elements for (const auto &template_root : roots_) { auto template_ref = detail::get(cd, template_root); if (template_ref.has_value()) matching_elements_.emplace(template_ref.value()); } - assert(!matching_elements_.empty()); + assert(roots_.empty() == matching_elements_.empty()); - if constexpr (std::is_same_v) { - auto match_tree_rel = [&, this](const auto &from, const auto &to) { - bool added_new_element{false}; - - for (const auto &from_el : from) { - // Check if any of its relationships of type relationship_ - // points to an element already in the matching_elements_ - // set - for (const auto &rel : from_el->relationships()) { - if (rel.type() == relationship_) { - for (const auto &to_el : to) { - auto dest = rel.destination(); - auto alias = to_el->alias(); - if (dest == alias) { - const auto &to_add = - forward_ ? to_el : from_el; - if (matching_elements_.insert(to_add) - .second) - added_new_element = true; - } - } - } - } - } - - return added_new_element; - }; - - bool keep_looking{true}; - while (keep_looking) { - keep_looking = false; - if (forward_) { - if (match_tree_rel( - matching_elements_, detail::view(cd))) - keep_looking = true; - } - else { - if (match_tree_rel( - detail::view(cd), matching_elements_)) - keep_looking = true; - } + bool keep_looking{true}; + while (keep_looking) { + keep_looking = false; + if (forward_) { + if (add_adjacent(matching_elements_, detail::view(cd), + {relationship_})) + keep_looking = true; } - } - else { - auto match_tree_rel = [&, this](const auto &from, const auto &to) { - bool added_new_element{false}; - - for (const auto &from_el : from) { - // Check if any of its relationships of type relationship_ - // points to an element already in the matching_elements_ - // set - for (const auto &rel : from_el->relationships()) { - if (rel.type() == relationship_) { - for (const auto &to_el : to) { - auto dest = rel.destination(); - auto to_el_fn = to_el->full_name(false); - if (dest == to_el_fn) { - const auto &to_add = - forward_ ? to_el : from_el; - if (matching_elements_.insert(to_add) - .second) - added_new_element = true; - } - } - } - } - } - - return added_new_element; - }; - - bool keep_looking{true}; - while (keep_looking) { - keep_looking = false; - if (forward_) { - if (match_tree_rel( - matching_elements_, detail::view(cd))) - keep_looking = true; - } - else { - if (match_tree_rel( - detail::view(cd), matching_elements_)) - keep_looking = true; - } + else { + if (add_adjacent(detail::view(cd), matching_elements_, + {relationship_})) + keep_looking = true; } } - if constexpr (std::is_same_v) { - if (type() == filter_t::kInclusive) { - // For package diagrams, add also all parents of matching - // packages - decltype(matching_elements_) parents; - util::for_each(matching_elements_, - [this, &cd, &parents](const auto &package) { - auto parent_path = package.get().path(); - auto parent = cd.get_package(parent_path.to_string()); - while (parent.has_value()) { - parents.emplace(type_safe::ref(parent.value())); - parent = cd.get_package( - parent.value().path().to_string()); - } - }); - - matching_elements_.insert( - std::begin(parents), std::end(parents)); - } + // For nested diagrams, include also parent elements + if ((type() == filter_t::kInclusive) && + (cd.type() == common::model::diagram_t::kPackage)) { + add_parents(cd); } initialized_ = true; diff --git a/src/common/model/nested_trait.h b/src/common/model/nested_trait.h index d79d04b3..8894d4e1 100644 --- a/src/common/model/nested_trait.h +++ b/src/common/model/nested_trait.h @@ -85,8 +85,9 @@ public: return type_safe::optional_ref{}; } - if (path.size() == 1) + if (path.size() == 1) { return get_element(path[0]); + } auto p = get_element(path[0]); @@ -100,6 +101,18 @@ public: return type_safe::optional_ref{}; } + template auto get_element_parent(const T &element) const + { + auto path = element.path(); + auto parent = get_element(path); + + if (parent.has_value()) + return type_safe::optional_ref{ + type_safe::ref(dynamic_cast(parent.value()))}; + + return type_safe::optional_ref{}; + } + template auto get_element(const std::string &name) const { assert(!util::contains(name, "::"));