Initial refactor of namespace handling

This commit is contained in:
Bartek Kryza
2022-03-04 23:38:18 +01:00
parent bee20e7f26
commit a67b459437
40 changed files with 620 additions and 201 deletions

View File

@@ -26,12 +26,10 @@ namespace clanguml::common::model {
std::atomic_uint64_t element::m_nextId = 1;
element::element(const std::vector<std::string> &using_namespaces)
: using_namespace_{using_namespaces}
element::element(const namespace_ &using_namespace)
: using_namespace_{using_namespace}
, m_id{m_nextId++}
{
for (const auto &n : using_namespace_)
assert(!util::contains(n, "::"));
}
std::string element::alias() const { return fmt::format("C_{:010}", m_id); }
@@ -59,18 +57,12 @@ void element::add_relationship(relationship &&cr)
relationships_.emplace_back(std::move(cr));
}
void element::set_using_namespaces(const std::vector<std::string> &un)
void element::set_using_namespaces(const namespace_ &un)
{
for (const auto &n : un)
assert(!util::contains(n, "::"));
using_namespace_ = un;
}
const std::vector<std::string> &element::using_namespace() const
{
return using_namespace_;
}
const namespace_ &element::using_namespace() const { return ns_; }
std::vector<relationship> &element::relationships() { return relationships_; }
@@ -88,9 +80,8 @@ bool operator==(const element &l, const element &r)
std::ostream &operator<<(std::ostream &out, const element &rhs)
{
out << "(" << rhs.name() << ", ns=["
<< util::join(rhs.get_namespace(), "::") << "], full_name=["
<< rhs.full_name(true) << "])";
out << "(" << rhs.name() << ", ns=[" << rhs.get_namespace().to_string()
<< "], full_name=[" << rhs.full_name(true) << "])";
return out;
}

View File

@@ -18,6 +18,7 @@
#pragma once
#include "decorated_element.h"
#include "namespace.h"
#include "relationship.h"
#include "util/util.h"
@@ -30,7 +31,7 @@ namespace clanguml::common::model {
class element : public decorated_element {
public:
element(const std::vector<std::string> &using_namespaces);
element(const namespace_ &using_namespace);
virtual ~element() = default;
@@ -42,27 +43,24 @@ public:
std::string name_and_ns() const
{
auto ns = namespace_;
ns.push_back(name());
return util::join(ns, "::");
auto ns = ns_ | name();
return ns.to_string();
}
void set_namespace(const std::vector<std::string> &ns) { namespace_ = ns; }
void set_namespace(const namespace_ &ns) { ns_ = ns; }
std::vector<std::string> get_namespace() const { return namespace_; }
namespace_ get_namespace() const { return ns_; }
std::vector<std::string> get_relative_namespace() const
namespace_ get_relative_namespace() const
{
auto relative_ns = namespace_;
util::remove_prefix(relative_ns, using_namespace_);
return relative_ns;
return ns_.relative_to(using_namespace_);
}
virtual std::string full_name(bool relative) const { return name(); }
void set_using_namespaces(const std::vector<std::string> &un);
void set_using_namespaces(const namespace_ &un);
const std::vector<std::string> &using_namespace() const;
const namespace_ &using_namespace() const;
std::vector<relationship> &relationships();
@@ -81,8 +79,8 @@ protected:
private:
std::string name_;
std::vector<std::string> namespace_;
std::vector<std::string> using_namespace_;
namespace_ ns_;
namespace_ using_namespace_;
std::vector<relationship> relationships_;
static std::atomic_uint64_t m_nextId;

View File

@@ -0,0 +1,213 @@
/**
* src/common/model/namespace.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.
*/
#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(); }
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_);
}
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
{
/*
std::vector<std::string> namespaces_sorted{namespaces};
std::sort(namespaces_sorted.rbegin(), namespaces_sorted.rend());
auto res = name;
for (const auto &ns : namespaces_sorted) {
if (ns.empty())
continue;
if (name == ns)
return split(n, "::").back();
auto ns_prefix = ns + "::";
auto it = res.find(ns_prefix);
while (it != std::string::npos) {
res.erase(it, ns_prefix.size());
it = res.find(ns_prefix);
}
}
return res;
*/
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_;
}
std::string namespace_::name() const
{
assert(size() > 0);
return namespace_path_.back();
}
}

View File

@@ -0,0 +1,87 @@
/**
* src/common/model/namespace.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 <string>
#include <vector>
namespace clanguml::common::model {
class namespace_ {
using container_type = std::vector<std::string>;
public:
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);
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();
bool starts_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_;
};
}

View File

@@ -52,58 +52,59 @@ public:
}
template <typename V = T>
void add_element(std::vector<std::string> path, std::unique_ptr<V> p)
void add_element(namespace_ ns, std::unique_ptr<V> p)
{
assert(p);
LOG_DBG("Adding nested element {} at path {}", p->name(),
fmt::join(path, "::"));
LOG_DBG(
"Adding nested element {} at path {}", p->name(), ns.to_string());
if (path.empty()) {
if (ns.is_empty()) {
add_element(std::move(p));
return;
}
auto parent = get_element(path);
auto parent = get_element(ns);
if (parent && dynamic_cast<nested_trait<T> *>(&parent.value()))
dynamic_cast<nested_trait<T> &>(parent.value())
.template add_element<V>(std::move(p));
else {
spdlog::error(
"No parent element found at: {}", fmt::join(path, "::"));
throw std::runtime_error("No parent element found");
spdlog::error("No parent element found at: {}", ns.to_string());
throw std::runtime_error(
"No parent element found for " + ns.to_string());
}
}
template <typename V = T>
auto get_element(std::vector<std::string> path) const
template <typename V = T> auto get_element(const namespace_ &path) const
{
LOG_DBG("Getting nested element at path: {}", fmt::join(path, "::"));
LOG_DBG("Getting nested element at path: {}", path.to_string());
if (path.empty() || !has_element(path.at(0))) {
LOG_WARN("Nested element {} not found in element",
fmt::join(path, "::"));
if (path.is_empty() || !has_element(path[0])) {
LOG_WARN(
"Nested element {} not found in element", path.to_string());
return type_safe::optional_ref<V>{};
}
if (path.size() == 1)
return get_element<V>(path.at(0));
return get_element<V>(path[0]);
auto p = get_element<T>(path.at(0));
auto p = get_element<T>(path[0]);
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>(
std::vector<std::string>(path.begin() + 1, path.end()));
namespace_{path.begin() + 1, path.end()});
return type_safe::optional_ref<V>{};
}
template <typename V = T> auto get_element(const std::string &name) const
{
assert(!util::contains(name, "::"));
auto it = std::find_if(elements_.cbegin(), elements_.cend(),
[&](const auto &p) { return name == p->name(); });

View File

@@ -23,24 +23,33 @@
#include <sstream>
namespace clanguml::common::model {
package::package(const std::vector<std::string> &using_namespaces)
: element{using_namespaces}
package::package(const common::model::namespace_ &using_namespace)
: element{using_namespace}
{
}
std::string package::full_name(bool relative) const
{
auto fn = get_namespace();
auto ns = using_namespace();
if (relative && (fn.size() >= ns.size())) {
if (util::starts_with(fn, ns))
fn = std::vector<std::string>(fn.begin() + ns.size(), fn.end());
if (relative) {
auto res = get_namespace().relative_to(using_namespace()) | name();
return res.to_string();
}
fn.push_back(name());
return (get_namespace().relative_to(using_namespace()) | name())
.to_string();
return fmt::format("{}", fmt::join(fn, "::"));
// auto fn = get_namespace();
// auto ns = using_namespace();
//
// if (relative && (fn.size() >= ns.size())) {
// if (fn.starts_with(using_namespace())
// fn = std::vector<std::string>(fn.begin() + ns.size(),
// fn.end());
// }
//
// fn.push_back(name());
//
// return fmt::format("{}", fmt::join(fn, "::"));
}
bool package::is_deprecated() const { return is_deprecated_; }

View File

@@ -35,7 +35,7 @@ class package : public element,
public stylable_element,
public nested_trait<element> {
public:
package(const std::vector<std::string> &using_namespaces);
package(const common::model::namespace_ &using_namespace);
package(const package &) = delete;
package(package &&) = default;