Add support for overloaded entity references

This commit is contained in:
Jonathan Müller 2017-03-19 16:07:54 +01:00
commit 08717b2ae7
8 changed files with 197 additions and 47 deletions

View file

@ -101,8 +101,9 @@ namespace cppast
private:
cpp_base_class(const cpp_type_ref& base, cpp_access_specifier_kind access, bool is_virtual)
: cpp_entity(base.name()), base_id_(base.id()), access_(access), virtual_(is_virtual)
: cpp_entity(base.name()), base_id_(base.id()[0u]), access_(access), virtual_(is_virtual)
{
DEBUG_ASSERT(!base.is_overloaded(), detail::precondition_error_handler{});
}
cpp_entity_kind do_get_entity_kind() const noexcept override;

View file

@ -5,6 +5,10 @@
#ifndef CPPAST_CPP_ENTITY_REF_HPP_INCLUDED
#define CPPAST_CPP_ENTITY_REF_HPP_INCLUDED
#include <vector>
#include <type_safe/variant.hpp>
#include <cppast/cpp_entity_index.hpp>
namespace cppast
@ -12,6 +16,10 @@ namespace cppast
enum class cpp_entity_kind;
/// A basic reference to some kind of [cppast::cpp_entity]().
///
/// It can either refer to a single [cppast::cpp_entity]()
/// or multiple.
/// In the later case it is *overloaded*.
template <typename T, typename Predicate>
class basic_cpp_entity_ref
{
@ -22,32 +30,152 @@ namespace cppast
{
}
/// \effects Creates it giving it multiple target ids and name.
/// \notes This is to refer to an overloaded function.
basic_cpp_entity_ref(std::vector<cpp_entity_id> target_ids, std::string target_name)
: target_(std::move(target_ids)), name_(std::move(target_name))
{
}
/// \returns The name of the reference, as spelled in the source code.
const std::string& name() const noexcept
{
return name_;
}
/// \returns The [cppast::cpp_entity_id]() of the entity it refers to.
const cpp_entity_id& id() const noexcept
/// \returns Whether or not it refers to multiple entities.
bool is_overloaded() const noexcept
{
return target_;
return target_.has_value(type_safe::variant_type<std::vector<cpp_entity_id>>{});
}
/// \returns An optional reference to the [cppast::cpp_entity]() it refers to.
type_safe::optional_ref<const T> get(const cpp_entity_index& idx) const noexcept
/// \returns The number of entities it refers to.
type_safe::size_t no_overloaded() const noexcept
{
auto entity = idx.lookup(target_);
if (!entity)
return type_safe::nullopt;
DEBUG_ASSERT(Predicate{}(entity.value()), detail::precondition_error_handler{},
"predicate not fulfilled");
return static_cast<const T&>(entity.value());
return id().size();
}
/// \returns An array reference to the id or ids it refers to.
type_safe::array_ref<const cpp_entity_id> id() const noexcept
{
if (is_overloaded())
{
auto& vec = target_.value(type_safe::variant_type<std::vector<cpp_entity_id>>{});
return type_safe::ref(vec.data(), vec.size());
}
else
{
auto& id = target_.value(type_safe::variant_type<cpp_entity_id>{});
return type_safe::ref(&id, 1u);
}
}
private:
cpp_entity_id target_;
std::string name_;
class ref_impl
{
public:
ref_impl(type_safe::object_ref<const cpp_entity_index> idx,
type_safe::array_ref<const cpp_entity_id> ids)
: ids_(ids), index_(idx)
{
}
class iterator
{
public:
using value_type = type_safe::optional_ref<const T>;
using reference = value_type;
using pointer = value_type*;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
reference operator*() const noexcept
{
return (*ref_)[i_];
}
pointer operator->() const noexcept
{
return &(*ref_)[i_];
}
iterator& operator++() noexcept
{
++i_;
return *this;
}
iterator operator++(int)noexcept
{
auto tmp = *this;
++(*this);
return tmp;
}
friend bool operator==(const iterator& a, const iterator& b) noexcept
{
return a.ref_ == b.ref_ && a.i_ == b.i_;
}
friend bool operator!=(const iterator& a, const iterator& b) noexcept
{
return !(a == b);
}
private:
iterator(type_safe::object_ref<const ref_impl> ref, type_safe::index_t i)
: ref_(ref), i_(i)
{
}
type_safe::object_ref<const ref_impl> ref_;
type_safe::index_t i_;
friend ref_impl;
};
iterator begin() const noexcept
{
return iterator(type_safe::ref(*this), 0u);
}
iterator end() const noexcept
{
return iterator(type_safe::ref(*this), size());
}
type_safe::optional_ref<const T> operator[](type_safe::index_t i) const
{
return index_->lookup(ids_[i]).map([](const cpp_entity& e) -> const T& {
DEBUG_ASSERT(Predicate{}(e), detail::precondition_error_handler{},
"predicate not fulfilled");
return static_cast<const T&>(e);
});
}
type_safe::size_t size() const noexcept
{
return ids_.size();
}
private:
type_safe::array_ref<const cpp_entity_id> ids_;
type_safe::object_ref<const cpp_entity_index> index_;
};
public:
/// \returns An array reference to the entities it refers to.
/// The return type provides `operator[]` + `size()`,
/// as well as `begin()` and `end()` returning forward iterators.
/// \exclude return
ref_impl get(const cpp_entity_index& idx) const noexcept
{
return ref_impl(type_safe::ref(idx), id());
}
private:
type_safe::variant<cpp_entity_id, std::vector<cpp_entity_id>> target_;
std::string name_;
};
/// \exclude

View file

@ -101,8 +101,9 @@ namespace cppast
cpp_entity_kind do_get_entity_kind() const noexcept override;
cpp_include_directive(const cpp_file_ref& target, cpp_include_kind kind)
: cpp_entity(target.name()), target_(target.id()), kind_(kind)
: cpp_entity(target.name()), target_(target.id()[0u]), kind_(kind)
{
DEBUG_ASSERT(!target.is_overloaded(), detail::precondition_error_handler{});
}
cpp_entity_id target_;

View file

@ -183,10 +183,10 @@ namespace cppast
/// \effects Sets the entity that is being templated and the primary template.
cpp_template_specialization(std::unique_ptr<cpp_entity> entity,
const cpp_template_ref& templ)
: cpp_template(std::move(entity)), templ_(templ.id())
: cpp_template(std::move(entity)), templ_(templ.id()[0u])
{
DEBUG_ASSERT(templ.name() == entity->name(), detail::precondition_error_handler{},
"invalid name of template ref");
DEBUG_ASSERT(!templ.is_overloaded() && templ.name() == entity->name(),
detail::precondition_error_handler{}, "invalid name of template ref");
}
private: