Added initial structure for include diagram generation
This commit is contained in:
@@ -17,7 +17,9 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "diagram_element.h"
|
||||
#include "enums.h"
|
||||
#include "namespace.h"
|
||||
|
||||
#include <type_safe/optional_ref.hpp>
|
||||
|
||||
@@ -27,7 +29,6 @@
|
||||
namespace clanguml::common::model {
|
||||
|
||||
class diagram_filter;
|
||||
class namespace_;
|
||||
class element;
|
||||
class relationship;
|
||||
|
||||
@@ -38,7 +39,7 @@ public:
|
||||
|
||||
virtual diagram_t type() const = 0;
|
||||
|
||||
virtual type_safe::optional_ref<const element> get(
|
||||
virtual type_safe::optional_ref<const diagram_element> get(
|
||||
const std::string &full_name) const = 0;
|
||||
|
||||
diagram(const diagram &) = delete;
|
||||
|
||||
99
src/common/model/diagram_element.cc
Normal file
99
src/common/model/diagram_element.cc
Normal file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* src/common/model/diagram_element.cc
|
||||
*
|
||||
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "diagram_element.h"
|
||||
|
||||
#include "util/util.h"
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace clanguml::common::model {
|
||||
|
||||
std::atomic_uint64_t diagram_element::m_nextId = 1;
|
||||
|
||||
diagram_element::diagram_element()
|
||||
: m_id{m_nextId++}
|
||||
{
|
||||
}
|
||||
|
||||
std::string diagram_element::alias() const
|
||||
{
|
||||
return fmt::format("C_{:010}", m_id);
|
||||
}
|
||||
|
||||
void diagram_element::add_relationship(relationship &&cr)
|
||||
{
|
||||
if (cr.destination().empty()) {
|
||||
LOG_DBG("Skipping relationship '{}' - {} - '{}' due empty "
|
||||
"destination",
|
||||
cr.destination(), to_string(cr.type()), full_name(true));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((cr.type() == relationship_t::kInstantiation) &&
|
||||
(cr.destination() == full_name(true))) {
|
||||
LOG_DBG("Skipping self instantiation relationship for {}",
|
||||
cr.destination());
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DBG("Adding relationship: '{}' - {} - '{}'", cr.destination(),
|
||||
to_string(cr.type()), full_name(true));
|
||||
|
||||
if (!util::contains(relationships_, cr))
|
||||
relationships_.emplace_back(std::move(cr));
|
||||
}
|
||||
|
||||
std::vector<relationship> &diagram_element::relationships()
|
||||
{
|
||||
return relationships_;
|
||||
}
|
||||
|
||||
const std::vector<relationship> &diagram_element::relationships() const
|
||||
{
|
||||
return relationships_;
|
||||
}
|
||||
|
||||
void diagram_element::append(const decorated_element &e)
|
||||
{
|
||||
decorated_element::append(e);
|
||||
}
|
||||
|
||||
inja::json diagram_element::context() const
|
||||
{
|
||||
inja::json ctx;
|
||||
ctx["name"] = name();
|
||||
ctx["alias"] = alias();
|
||||
ctx["full_name"] = full_name(false);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
bool operator==(const diagram_element &l, const diagram_element &r)
|
||||
{
|
||||
return l.full_name(false) == r.full_name(false);
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const diagram_element &rhs)
|
||||
{
|
||||
out << "(" << rhs.name() << ", full_name=[" << rhs.full_name(false) << "])";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
71
src/common/model/diagram_element.h
Normal file
71
src/common/model/diagram_element.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* src/common/model/diagram_element.h
|
||||
*
|
||||
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "decorated_element.h"
|
||||
#include "relationship.h"
|
||||
#include "util/util.h"
|
||||
|
||||
#include <inja/inja.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace clanguml::common::model {
|
||||
|
||||
class diagram_element : public decorated_element {
|
||||
public:
|
||||
diagram_element();
|
||||
|
||||
virtual ~diagram_element() = default;
|
||||
|
||||
std::string alias() const;
|
||||
|
||||
void set_name(const std::string &name) { name_ = name; }
|
||||
|
||||
std::string name() const { return name_; }
|
||||
|
||||
virtual std::string full_name(bool relative) const { return name(); }
|
||||
|
||||
std::vector<relationship> &relationships();
|
||||
|
||||
const std::vector<relationship> &relationships() const;
|
||||
|
||||
void add_relationship(relationship &&cr);
|
||||
|
||||
void append(const decorated_element &e);
|
||||
|
||||
friend bool operator==(const diagram_element &l, const diagram_element &r);
|
||||
|
||||
friend std::ostream &operator<<(
|
||||
std::ostream &out, const diagram_element &rhs);
|
||||
|
||||
virtual inja::json context() const;
|
||||
|
||||
protected:
|
||||
const uint64_t m_id{0};
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::vector<relationship> relationships_;
|
||||
|
||||
static std::atomic_uint64_t m_nextId;
|
||||
};
|
||||
}
|
||||
@@ -24,39 +24,11 @@
|
||||
|
||||
namespace clanguml::common::model {
|
||||
|
||||
std::atomic_uint64_t element::m_nextId = 1;
|
||||
|
||||
element::element(const namespace_ &using_namespace)
|
||||
: using_namespace_{using_namespace}
|
||||
, m_id{m_nextId++}
|
||||
{
|
||||
}
|
||||
|
||||
std::string element::alias() const { return fmt::format("C_{:010}", m_id); }
|
||||
|
||||
void element::add_relationship(relationship &&cr)
|
||||
{
|
||||
if (cr.destination().empty()) {
|
||||
LOG_DBG("Skipping relationship '{}' - {} - '{}' due empty "
|
||||
"destination",
|
||||
cr.destination(), to_string(cr.type()), full_name(true));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((cr.type() == relationship_t::kInstantiation) &&
|
||||
(cr.destination() == full_name(true))) {
|
||||
LOG_DBG("Skipping self instantiation relationship for {}",
|
||||
cr.destination());
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DBG("Adding relationship: '{}' - {} - '{}'", cr.destination(),
|
||||
to_string(cr.type()), full_name(true));
|
||||
|
||||
if (!util::contains(relationships_, cr))
|
||||
relationships_.emplace_back(std::move(cr));
|
||||
}
|
||||
|
||||
void element::set_using_namespaces(const namespace_ &un)
|
||||
{
|
||||
using_namespace_ = un;
|
||||
@@ -64,15 +36,6 @@ void element::set_using_namespaces(const namespace_ &un)
|
||||
|
||||
const namespace_ &element::using_namespace() const { return using_namespace_; }
|
||||
|
||||
std::vector<relationship> &element::relationships() { return relationships_; }
|
||||
|
||||
const std::vector<relationship> &element::relationships() const
|
||||
{
|
||||
return relationships_;
|
||||
}
|
||||
|
||||
void element::append(const element &e) { decorated_element::append(e); }
|
||||
|
||||
inja::json element::context() const
|
||||
{
|
||||
inja::json ctx;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "decorated_element.h"
|
||||
#include "diagram_element.h"
|
||||
#include "namespace.h"
|
||||
#include "relationship.h"
|
||||
#include "source_location.h"
|
||||
@@ -32,18 +32,12 @@
|
||||
|
||||
namespace clanguml::common::model {
|
||||
|
||||
class element : public decorated_element, public source_location {
|
||||
class element : public diagram_element, public source_location {
|
||||
public:
|
||||
element(const namespace_ &using_namespace);
|
||||
|
||||
virtual ~element() = default;
|
||||
|
||||
std::string alias() const;
|
||||
|
||||
void set_name(const std::string &name) { name_ = name; }
|
||||
|
||||
std::string name() const { return name_; }
|
||||
|
||||
std::string name_and_ns() const
|
||||
{
|
||||
auto ns = ns_ | name();
|
||||
@@ -59,36 +53,26 @@ public:
|
||||
return ns_.relative_to(using_namespace_);
|
||||
}
|
||||
|
||||
virtual std::string full_name(bool relative) const { return name_and_ns(); }
|
||||
const namespace_ &path() const { return ns_; }
|
||||
|
||||
std::string full_name(bool relative) const override
|
||||
{
|
||||
return name_and_ns();
|
||||
}
|
||||
|
||||
void set_using_namespaces(const namespace_ &un);
|
||||
|
||||
const namespace_ &using_namespace() const;
|
||||
|
||||
std::vector<relationship> &relationships();
|
||||
|
||||
const std::vector<relationship> &relationships() const;
|
||||
|
||||
void add_relationship(relationship &&cr);
|
||||
|
||||
void append(const element &e);
|
||||
|
||||
friend bool operator==(const element &l, const element &r);
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &out, const element &rhs);
|
||||
|
||||
virtual inja::json context() const;
|
||||
|
||||
protected:
|
||||
const uint64_t m_id{0};
|
||||
inja::json context() const override;
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
namespace_ ns_;
|
||||
namespace_ using_namespace_;
|
||||
std::vector<relationship> relationships_;
|
||||
type_safe::optional<source_location> location_;
|
||||
|
||||
static std::atomic_uint64_t m_nextId;
|
||||
// type_safe::optional<source_location> location_;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -35,7 +35,8 @@ enum class relationship_t {
|
||||
kAssociation,
|
||||
kInstantiation,
|
||||
kFriendship,
|
||||
kDependency
|
||||
kDependency,
|
||||
kInclusion
|
||||
};
|
||||
|
||||
enum class message_t { kCall, kReturn };
|
||||
|
||||
@@ -17,194 +17,3 @@
|
||||
*/
|
||||
|
||||
#include "namespace.h"
|
||||
|
||||
#include "util/util.h"
|
||||
|
||||
namespace clanguml::common::model {
|
||||
|
||||
namespace_::namespace_(std::initializer_list<std::string> ns)
|
||||
{
|
||||
if ((ns.size() == 1) && util::contains(*ns.begin(), "::"))
|
||||
namespace_path_ = util::split(*ns.begin(), "::");
|
||||
else
|
||||
namespace_path_ = ns;
|
||||
}
|
||||
|
||||
namespace_::namespace_(const std::vector<std::string> &ns)
|
||||
{
|
||||
if ((ns.size() == 1) && util::contains(*ns.begin(), "::"))
|
||||
namespace_path_ = util::split(*ns.begin(), "::");
|
||||
else
|
||||
namespace_path_ = ns;
|
||||
}
|
||||
|
||||
namespace_::namespace_(const std::string &ns)
|
||||
{
|
||||
namespace_path_ = util::split(ns, "::");
|
||||
}
|
||||
|
||||
namespace_::namespace_(
|
||||
container_type::const_iterator begin, container_type::const_iterator end)
|
||||
{
|
||||
std::copy(begin, end, std::back_inserter(namespace_path_));
|
||||
}
|
||||
|
||||
std::string namespace_::to_string() const
|
||||
{
|
||||
return fmt::format("{}", fmt::join(namespace_path_, "::"));
|
||||
}
|
||||
|
||||
size_t namespace_::size() const { return namespace_path_.size(); }
|
||||
|
||||
bool namespace_::is_empty() const { return namespace_path_.empty(); }
|
||||
|
||||
namespace_::container_type::iterator namespace_::begin()
|
||||
{
|
||||
return namespace_path_.begin();
|
||||
}
|
||||
namespace_::container_type::iterator namespace_::end()
|
||||
{
|
||||
return namespace_path_.end();
|
||||
}
|
||||
|
||||
namespace_::container_type::const_iterator namespace_::cbegin() const
|
||||
{
|
||||
return namespace_path_.cbegin();
|
||||
}
|
||||
namespace_::container_type::const_iterator namespace_::cend() const
|
||||
{
|
||||
return namespace_path_.cend();
|
||||
}
|
||||
|
||||
namespace_::container_type::const_iterator namespace_::begin() const
|
||||
{
|
||||
return namespace_path_.begin();
|
||||
}
|
||||
namespace_::container_type::const_iterator namespace_::end() const
|
||||
{
|
||||
return namespace_path_.end();
|
||||
}
|
||||
|
||||
void namespace_::append(const std::string &ns)
|
||||
{
|
||||
namespace_path_.push_back(ns);
|
||||
}
|
||||
|
||||
void namespace_::append(const namespace_ &ns)
|
||||
{
|
||||
for (const auto &n : ns) {
|
||||
append(n);
|
||||
}
|
||||
}
|
||||
|
||||
void namespace_::pop_back() { namespace_path_.pop_back(); }
|
||||
|
||||
type_safe::optional<namespace_> namespace_::parent() const
|
||||
{
|
||||
if (size() <= 1) {
|
||||
return {};
|
||||
}
|
||||
|
||||
namespace_ res{*this};
|
||||
res.pop_back();
|
||||
return {std::move(res)};
|
||||
}
|
||||
|
||||
namespace_ namespace_::operator|(const namespace_ &right) const
|
||||
{
|
||||
namespace_ res{*this};
|
||||
res.append(right);
|
||||
return res;
|
||||
}
|
||||
|
||||
void namespace_::operator|=(const namespace_ &right) { append(right); }
|
||||
|
||||
namespace_ namespace_::operator|(const std::string &right) const
|
||||
{
|
||||
namespace_ res{*this};
|
||||
res.append(right);
|
||||
return res;
|
||||
}
|
||||
|
||||
void namespace_::operator|=(const std::string &right) { append(right); }
|
||||
|
||||
std::string &namespace_::operator[](const int index)
|
||||
{
|
||||
return namespace_path_[index];
|
||||
}
|
||||
|
||||
const std::string &namespace_::operator[](const int index) const
|
||||
{
|
||||
return namespace_path_[index];
|
||||
}
|
||||
|
||||
bool namespace_::starts_with(const namespace_ &right) const
|
||||
{
|
||||
return util::starts_with(namespace_path_, right.namespace_path_);
|
||||
}
|
||||
|
||||
bool namespace_::ends_with(const namespace_ &right) const
|
||||
{
|
||||
return util::ends_with(namespace_path_, right.namespace_path_);
|
||||
}
|
||||
|
||||
namespace_ namespace_::common_path(const namespace_ &right) const
|
||||
{
|
||||
namespace_ res{};
|
||||
for (auto i = 0U; i < std::min(size(), right.size()); i++) {
|
||||
if (namespace_path_[i] == right[i])
|
||||
res |= namespace_path_[i];
|
||||
else
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
namespace_ namespace_::relative_to(const namespace_ &right) const
|
||||
{
|
||||
namespace_ res{*this};
|
||||
|
||||
if (res.starts_with(right))
|
||||
util::remove_prefix(res.namespace_path_, right.namespace_path_);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string namespace_::relative(const std::string &name) const
|
||||
{
|
||||
if (is_empty())
|
||||
return name;
|
||||
|
||||
if (name == to_string())
|
||||
return name;
|
||||
|
||||
auto res = name;
|
||||
auto ns_prefix = to_string() + "::";
|
||||
|
||||
auto it = res.find(ns_prefix);
|
||||
while (it != std::string::npos) {
|
||||
res.erase(it, ns_prefix.size());
|
||||
it = res.find(ns_prefix);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool operator==(const namespace_ &left, const namespace_ &right)
|
||||
{
|
||||
return left.namespace_path_ == right.namespace_path_;
|
||||
}
|
||||
|
||||
bool operator<(const namespace_ &left, const namespace_ &right)
|
||||
{
|
||||
return std::hash<namespace_>{}(left) < std::hash<namespace_>{}(right);
|
||||
}
|
||||
|
||||
std::string namespace_::name() const
|
||||
{
|
||||
assert(size() > 0);
|
||||
|
||||
return namespace_path_.back();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,78 +17,20 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "path.h"
|
||||
|
||||
#include <string>
|
||||
#include <type_safe/optional.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace clanguml::common::model {
|
||||
|
||||
class namespace_ {
|
||||
public:
|
||||
using container_type = std::vector<std::string>;
|
||||
|
||||
namespace_() = default;
|
||||
|
||||
namespace_(const std::string &ns);
|
||||
|
||||
namespace_(container_type::const_iterator begin,
|
||||
container_type::const_iterator end);
|
||||
|
||||
namespace_(const namespace_ &right) noexcept = default;
|
||||
|
||||
namespace_ &operator=(const namespace_ &right) noexcept = default;
|
||||
|
||||
namespace_(namespace_ &&right) noexcept = default;
|
||||
|
||||
namespace_ &operator=(namespace_ &&right) noexcept = default;
|
||||
|
||||
friend bool operator==(const namespace_ &left, const namespace_ &right);
|
||||
friend bool operator<(const namespace_ &left, const namespace_ &right);
|
||||
|
||||
namespace_(std::initializer_list<std::string> ns);
|
||||
|
||||
explicit namespace_(const std::vector<std::string> &ns);
|
||||
|
||||
std::string to_string() const;
|
||||
|
||||
bool is_empty() const;
|
||||
|
||||
size_t size() const;
|
||||
|
||||
namespace_ operator|(const namespace_ &right) const;
|
||||
void operator|=(const namespace_ &right);
|
||||
namespace_ operator|(const std::string &right) const;
|
||||
void operator|=(const std::string &right);
|
||||
|
||||
std::string &operator[](const int index);
|
||||
const std::string &operator[](const int index) const;
|
||||
|
||||
void append(const std::string &ns);
|
||||
|
||||
void append(const namespace_ &ns);
|
||||
|
||||
void pop_back();
|
||||
|
||||
type_safe::optional<namespace_> parent() const;
|
||||
|
||||
bool starts_with(const namespace_ &right) const;
|
||||
bool ends_with(const namespace_ &right) const;
|
||||
namespace_ common_path(const namespace_ &right) const;
|
||||
namespace_ relative_to(const namespace_ &right) const;
|
||||
std::string relative(const std::string &name) const;
|
||||
std::string name() const;
|
||||
|
||||
container_type::iterator begin();
|
||||
container_type::iterator end();
|
||||
container_type::const_iterator begin() const;
|
||||
container_type::const_iterator end() const;
|
||||
container_type::const_iterator cbegin() const;
|
||||
container_type::const_iterator cend() const;
|
||||
|
||||
private:
|
||||
container_type namespace_path_;
|
||||
struct ns_path_separator {
|
||||
static constexpr std::string_view value = "::";
|
||||
};
|
||||
|
||||
using namespace_ = path<ns_path_separator>;
|
||||
|
||||
}
|
||||
|
||||
namespace std {
|
||||
@@ -96,7 +38,7 @@ namespace std {
|
||||
template <> struct hash<clanguml::common::model::namespace_> {
|
||||
std::size_t operator()(const clanguml::common::model::namespace_ &key) const
|
||||
{
|
||||
using clanguml::common::model::namespace_;
|
||||
using clanguml::common::model::path;
|
||||
|
||||
std::size_t seed = key.size();
|
||||
for (const auto &ns : key) {
|
||||
@@ -108,4 +50,4 @@ template <> struct hash<clanguml::common::model::namespace_> {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* src/common/model/element.h
|
||||
* src/common/model/nested_trait.h
|
||||
*
|
||||
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
|
||||
*
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <vector>
|
||||
|
||||
namespace clanguml::common::model {
|
||||
template <typename T> class nested_trait {
|
||||
template <typename T, typename Path> class nested_trait {
|
||||
public:
|
||||
nested_trait() = default;
|
||||
|
||||
@@ -52,31 +52,31 @@ public:
|
||||
}
|
||||
|
||||
template <typename V = T>
|
||||
void add_element(namespace_ ns, std::unique_ptr<V> p)
|
||||
void add_element(const Path &path, std::unique_ptr<V> p)
|
||||
{
|
||||
assert(p);
|
||||
|
||||
LOG_DBG(
|
||||
"Adding nested element {} at path {}", p->name(), ns.to_string());
|
||||
"Adding nested element {} at path {}", p->name(), path.to_string());
|
||||
|
||||
if (ns.is_empty()) {
|
||||
if (path.is_empty()) {
|
||||
add_element(std::move(p));
|
||||
return;
|
||||
}
|
||||
|
||||
auto parent = get_element(ns);
|
||||
auto parent = get_element(path);
|
||||
|
||||
if (parent && dynamic_cast<nested_trait<T> *>(&parent.value()))
|
||||
dynamic_cast<nested_trait<T> &>(parent.value())
|
||||
if (parent && dynamic_cast<nested_trait<T, Path> *>(&parent.value()))
|
||||
dynamic_cast<nested_trait<T, Path> &>(parent.value())
|
||||
.template add_element<V>(std::move(p));
|
||||
else {
|
||||
spdlog::error("No parent element found at: {}", ns.to_string());
|
||||
spdlog::error("No parent element found at: {}", path.to_string());
|
||||
throw std::runtime_error(
|
||||
"No parent element found for " + ns.to_string());
|
||||
"No parent element found for " + path.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename V = T> auto get_element(const namespace_ &path) const
|
||||
template <typename V = T> auto get_element(const Path &path) const
|
||||
{
|
||||
LOG_DBG("Getting nested element at path: {}", path.to_string());
|
||||
|
||||
@@ -93,9 +93,9 @@ public:
|
||||
if (!p)
|
||||
return type_safe::optional_ref<V>{};
|
||||
|
||||
if (dynamic_cast<nested_trait<T> *>(&p.value()))
|
||||
return dynamic_cast<nested_trait<T> &>(p.value()).get_element<V>(
|
||||
namespace_{path.begin() + 1, path.end()});
|
||||
if (dynamic_cast<nested_trait<T, Path> *>(&p.value()))
|
||||
return dynamic_cast<nested_trait<T, Path> &>(p.value())
|
||||
.get_element<V>(Path{path.begin() + 1, path.end()});
|
||||
|
||||
return type_safe::optional_ref<V>{};
|
||||
}
|
||||
@@ -145,9 +145,10 @@ public:
|
||||
std::cout << "--- Printing tree:\n";
|
||||
}
|
||||
for (const auto &e : d) {
|
||||
if (dynamic_cast<nested_trait<T> *>(e.get())) {
|
||||
if (dynamic_cast<nested_trait<T, Path> *>(e.get())) {
|
||||
std::cout << std::string(level, ' ') << "[" << *e << "]\n";
|
||||
dynamic_cast<nested_trait<T> *>(e.get())->print_tree(level + 1);
|
||||
dynamic_cast<nested_trait<T, Path> *>(e.get())->print_tree(
|
||||
level + 1);
|
||||
}
|
||||
else {
|
||||
std::cout << std::string(level, ' ') << "- " << *e << "]\n";
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace clanguml::common::model {
|
||||
|
||||
class package : public element,
|
||||
public stylable_element,
|
||||
public nested_trait<element> {
|
||||
public nested_trait<element, namespace_> {
|
||||
public:
|
||||
package(const common::model::namespace_ &using_namespace);
|
||||
|
||||
|
||||
207
src/common/model/path.h
Normal file
207
src/common/model/path.h
Normal file
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
* src/common/model/path.h
|
||||
*
|
||||
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "util/util.h"
|
||||
|
||||
#include <string>
|
||||
#include <type_safe/optional.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace clanguml::common::model {
|
||||
|
||||
template <typename Sep> class path {
|
||||
public:
|
||||
using container_type = std::vector<std::string>;
|
||||
|
||||
path() = default;
|
||||
|
||||
path(const std::string &ns) { path_ = util::split(ns, Sep::value); }
|
||||
|
||||
path(container_type::const_iterator begin,
|
||||
container_type::const_iterator end)
|
||||
{
|
||||
std::copy(begin, end, std::back_inserter(path_));
|
||||
}
|
||||
|
||||
path(const path &right) noexcept = default;
|
||||
|
||||
path &operator=(const path &right) noexcept = default;
|
||||
|
||||
path(path &&right) noexcept = default;
|
||||
|
||||
path &operator=(path &&right) noexcept = default;
|
||||
|
||||
path(std::initializer_list<std::string> ns)
|
||||
{
|
||||
if ((ns.size() == 1) && util::contains(*ns.begin(), Sep::value))
|
||||
path_ = util::split(*ns.begin(), Sep::value);
|
||||
else
|
||||
path_ = ns;
|
||||
}
|
||||
|
||||
explicit path(const std::vector<std::string> &ns)
|
||||
{
|
||||
if ((ns.size() == 1) && util::contains(*ns.begin(), Sep::value))
|
||||
path_ = util::split(*ns.begin(), Sep::value);
|
||||
else
|
||||
path_ = ns;
|
||||
}
|
||||
|
||||
friend bool operator==(const path<Sep> &left, const path<Sep> &right)
|
||||
{
|
||||
return left.path_ == right.path_;
|
||||
}
|
||||
|
||||
friend bool operator<(const path<Sep> &left, const path<Sep> &right)
|
||||
{
|
||||
return std::hash<path<Sep>>{}(left) < std::hash<path<Sep>>{}(right);
|
||||
}
|
||||
|
||||
std::string to_string() const
|
||||
{
|
||||
return fmt::format("{}", fmt::join(path_, Sep::value));
|
||||
}
|
||||
|
||||
bool is_empty() const { return path_.empty(); }
|
||||
|
||||
size_t size() const { return path_.size(); }
|
||||
|
||||
path operator|(const path &right) const
|
||||
{
|
||||
path res{*this};
|
||||
res.append(right);
|
||||
return res;
|
||||
}
|
||||
|
||||
void operator|=(const path &right) { append(right); }
|
||||
|
||||
path operator|(const std::string &right) const
|
||||
{
|
||||
path res{*this};
|
||||
res.append(right);
|
||||
return res;
|
||||
}
|
||||
|
||||
void operator|=(const std::string &right) { append(right); }
|
||||
|
||||
std::string &operator[](const int index) { return path_[index]; }
|
||||
|
||||
const std::string &operator[](const int index) const
|
||||
{
|
||||
return path_[index];
|
||||
}
|
||||
|
||||
void append(const std::string &ns) { path_.push_back(ns); }
|
||||
|
||||
void append(const path &ns)
|
||||
{
|
||||
for (const auto &n : ns) {
|
||||
append(n);
|
||||
}
|
||||
}
|
||||
|
||||
void pop_back() { path_.pop_back(); }
|
||||
|
||||
type_safe::optional<path> parent() const
|
||||
{
|
||||
if (size() <= 1) {
|
||||
return {};
|
||||
}
|
||||
|
||||
path res{*this};
|
||||
res.pop_back();
|
||||
return {std::move(res)};
|
||||
}
|
||||
|
||||
bool starts_with(const path &right) const
|
||||
{
|
||||
return util::starts_with(path_, right.path_);
|
||||
}
|
||||
|
||||
bool ends_with(const path &right) const
|
||||
{
|
||||
return util::ends_with(path_, right.path_);
|
||||
}
|
||||
|
||||
path common_path(const path &right) const
|
||||
{
|
||||
path res{};
|
||||
for (auto i = 0U; i < std::min(size(), right.size()); i++) {
|
||||
if (path_[i] == right[i])
|
||||
res |= path_[i];
|
||||
else
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
path relative_to(const path &right) const
|
||||
{
|
||||
path res{*this};
|
||||
|
||||
if (res.starts_with(right))
|
||||
util::remove_prefix(res.path_, right.path_);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string relative(const std::string &name) const
|
||||
{
|
||||
if (is_empty())
|
||||
return name;
|
||||
|
||||
if (name == to_string())
|
||||
return name;
|
||||
|
||||
auto res = name;
|
||||
auto ns_prefix = to_string() + std::string{Sep::value};
|
||||
|
||||
auto it = res.find(ns_prefix);
|
||||
while (it != std::string::npos) {
|
||||
res.erase(it, ns_prefix.size());
|
||||
it = res.find(ns_prefix);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string name() const
|
||||
{
|
||||
assert(size() > 0);
|
||||
|
||||
return path_.back();
|
||||
}
|
||||
|
||||
path::container_type::iterator begin() { return path_.begin(); }
|
||||
path::container_type::iterator end() { return path_.end(); }
|
||||
|
||||
path::container_type::const_iterator cbegin() const
|
||||
{
|
||||
return path_.cbegin();
|
||||
}
|
||||
path::container_type::const_iterator cend() const { return path_.cend(); }
|
||||
|
||||
path::container_type::const_iterator begin() const { return path_.begin(); }
|
||||
path::container_type::const_iterator end() const { return path_.end(); }
|
||||
|
||||
private:
|
||||
container_type path_;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user