Initial refactor of namespace handling
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
213
src/common/model/namespace.cc
Normal file
213
src/common/model/namespace.cc
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
87
src/common/model/namespace.h
Normal file
87
src/common/model/namespace.h
Normal 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_;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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(); });
|
||||
|
||||
|
||||
@@ -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_; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user