Type Graph: Replace MutationTracker with the more general ResultTracker

MutationTracker could only store Type nodes, while ResultTracker is
templated on the result type so can store anything.

Template the Visitor base class on the return type of visit() functions.

This sets us up for allowing visitors to return different results from
their visit() functions in the future.

This will be used in a future commit introducing DrgnExporter, where we
cache drgn_type* results while walking the type graph.
This commit is contained in:
Alastair Robertson 2023-12-13 08:23:47 -08:00 committed by Alastair Robertson
parent 8193d271a8
commit 8bf7dbae9f
6 changed files with 33 additions and 43 deletions

View File

@ -47,7 +47,7 @@ Type& IdentifyContainers::mutate(Type& type) {
return *mutated;
Type& mutated = type.accept(*this);
tracker_.set(type, mutated);
tracker_.set(type, &mutated);
return mutated;
}
@ -60,12 +60,12 @@ Type& IdentifyContainers::visit(Class& c) {
auto& container = typeGraph_.makeType<Container>(*containerInfo, c.size());
container.templateParams = c.templateParams;
tracker_.set(c, container);
tracker_.set(c, &container);
RecursiveMutator::visit(container);
return container;
}
tracker_.set(c, c);
tracker_.set(c, &c);
RecursiveMutator::visit(c);
return c;
}

View File

@ -50,7 +50,7 @@ class IdentifyContainers : public RecursiveMutator {
Type& visit(Class& c) override;
private:
MutationTracker tracker_;
ResultTracker<Type*> tracker_;
TypeGraph& typeGraph_;
const std::vector<std::unique_ptr<ContainerInfo>>& containers_;
};

View File

@ -109,23 +109,27 @@ class NodeTrackerHolder {
};
/*
* MutationTracker
* ResultTracker
*
* Helper class for mutators. Efficiently tracks visited and replaces nodes.
* Efficiently caches the results of visited nodes.
*/
class MutationTracker {
template <typename T>
class ResultTracker {
public:
MutationTracker(size_t size) : visited_(size) {
ResultTracker() = default;
ResultTracker(size_t size) : visited_(size) {
}
static_assert(std::is_pointer_v<T>);
/*
* get
*
* Returns a type pointer if the given node has been visited or replaced.
* Returns the cached result if the given node has been visited.
* Returns nullptr if this node has not yet been seen.
*/
Type* get(const Type& oldType) {
auto id = oldType.id();
T get(const Type& type) {
auto id = type.id();
if (id < 0)
return nullptr;
if (visited_.size() <= static_cast<size_t>(id))
@ -136,19 +140,19 @@ class MutationTracker {
/*
* set
*
* Sets newType as the replacement node for oldType.
* Caches the result of visiting the given node.
*/
void set(const Type& oldType, Type& newType) {
auto id = oldType.id();
void set(const Type& type, T result) {
auto id = type.id();
if (id < 0)
return;
if (visited_.size() <= static_cast<size_t>(id))
visited_.resize(id + 1);
visited_[id] = &newType;
visited_[id] = result;
}
private:
std::vector<Type*> visited_;
std::vector<T> visited_;
};
} // namespace oi::detail::type_graph

View File

@ -20,10 +20,10 @@
namespace oi::detail::type_graph {
#define X(OI_TYPE_NAME) \
void OI_TYPE_NAME::accept(Visitor& v) { \
void OI_TYPE_NAME::accept(Visitor<void>& v) { \
v.visit(*this); \
} \
Type& OI_TYPE_NAME::accept(Mutator& m) { \
Type& OI_TYPE_NAME::accept(Visitor<Type&>& m) { \
return m.visit(*this); \
} \
void OI_TYPE_NAME::accept(ConstVisitor& v) const { \

View File

@ -66,12 +66,12 @@ enum class Qualifier {
};
using QualifierSet = EnumBitset<Qualifier, static_cast<size_t>(Qualifier::Max)>;
template <typename T>
class Visitor;
class Mutator;
class ConstVisitor;
#define DECLARE_ACCEPT \
void accept(Visitor& v) override; \
Type& accept(Mutator& m) override; \
#define DECLARE_ACCEPT \
void accept(Visitor<void>& v) override; \
Type& accept(Visitor<Type&>& m) override; \
void accept(ConstVisitor& v) const override;
// TODO delete copy and move ctors
@ -84,8 +84,8 @@ class ConstVisitor;
class Type {
public:
virtual ~Type() = default;
virtual void accept(Visitor& v) = 0;
virtual Type& accept(Mutator& m) = 0;
virtual void accept(Visitor<void>& v) = 0;
virtual Type& accept(Visitor<Type&>& m) = 0;
virtual void accept(ConstVisitor& v) const = 0;
virtual const std::string& name() const = 0;

View File

@ -34,26 +34,12 @@ namespace oi::detail::type_graph {
* Abstract visitor base class.
* A visitor simply walks over nodes in a type graph.
*/
template <typename T>
class Visitor {
public:
virtual ~Visitor() = default;
#define X(OI_TYPE_NAME) virtual void visit(OI_TYPE_NAME&) = 0;
OI_TYPE_LIST
#undef X
};
/*
* Mutator
*
* Abstract mutator base class.
* A mutator replaces nodes in a type graph with the node returned by visit().
*/
class Mutator {
public:
virtual ~Mutator() = default;
#define X(OI_TYPE_NAME) virtual Type& visit(OI_TYPE_NAME&) = 0;
#define X(OI_TYPE_NAME) virtual T visit(OI_TYPE_NAME&) = 0;
OI_TYPE_LIST
#undef X
};
@ -63,7 +49,7 @@ class Mutator {
*
* Visitor base class which takes no action by default.
*/
class LazyVisitor : public Visitor {
class LazyVisitor : public Visitor<void> {
public:
virtual ~LazyVisitor() = default;
@ -79,7 +65,7 @@ class LazyVisitor : public Visitor {
*
* Visitor base class which recurses into types by default.
*/
class RecursiveVisitor : public Visitor {
class RecursiveVisitor : public Visitor<void> {
public:
virtual ~RecursiveVisitor() = default;
virtual void accept(Type&) = 0;
@ -136,7 +122,7 @@ class RecursiveVisitor : public Visitor {
*
* Mutator base class which recurses into types by default.
*/
class RecursiveMutator : public Mutator {
class RecursiveMutator : public Visitor<Type&> {
public:
virtual ~RecursiveMutator() = default;
virtual Type& mutate(Type&) = 0;