Files
2024-11-06 15:20:37 +02:00

210 lines
6.4 KiB
C++

#pragma once
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include <any>
#include <memory>
#include <type_traits>
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "revng/Pipeline/GlobalTupleTreeDiff.h"
#include "revng/Pipeline/PathTargetBimap.h"
#include "revng/Storage/Path.h"
#include "revng/Support/Error.h"
#include "revng/Support/YAMLTraits.h"
#include "revng/TupleTree/Tracking.h"
#include "revng/TupleTree/TupleTreeDiff.h"
namespace pipeline {
class Global {
private:
const char *ID;
std::string Name;
public:
Global(const char *ID, llvm::StringRef Name) : ID(ID), Name(Name.str()) {}
virtual ~Global() {}
virtual Global &operator=(const Global &NewGlobal) = 0;
public:
Global(const Global &) = default;
Global(Global &&) = default;
Global &operator=(Global &&) = default;
public:
const char *getID() const { return ID; }
llvm::StringRef getName() const { return Name; }
public:
virtual GlobalTupleTreeDiff diff(const Global &Other) const = 0;
virtual llvm::Error applyDiff(const llvm::MemoryBuffer &Diff) = 0;
virtual llvm::Error applyDiff(const GlobalTupleTreeDiff &Diff) = 0;
virtual llvm::Error serialize(llvm::raw_ostream &OS) const = 0;
virtual llvm::Error fromString(llvm::StringRef String) = 0;
virtual llvm::Expected<GlobalTupleTreeDiff>
diffFromString(llvm::StringRef String) = 0;
virtual bool verify() const = 0;
virtual void clear() = 0;
virtual llvm::Expected<std::unique_ptr<Global>>
createNew(llvm::StringRef Name, const llvm::MemoryBuffer &Buffer) const = 0;
virtual std::unique_ptr<Global> clone() const = 0;
virtual llvm::Error store(const revng::FilePath &Path) const;
virtual llvm::Error load(const revng::FilePath &Path);
virtual std::optional<TupleTreePath>
deserializePath(llvm::StringRef Serialized) const = 0;
virtual std::optional<std::string>
serializePath(const TupleTreePath &Path) const = 0;
virtual void collectReadFields(const TargetInContainer &Target,
PathTargetBimap &Out) = 0;
virtual void clearAndResume() const = 0;
virtual void pushReadFields() const = 0;
virtual void popReadFields() const = 0;
virtual void stopTracking() const = 0;
};
template<TupleTreeCompatibleAndVerifiable Object>
class TupleTreeGlobal : public Global {
private:
TupleTree<Object> Value;
static const char &getID() {
static char ID;
return ID;
}
public:
explicit TupleTreeGlobal(llvm::StringRef Name, TupleTree<Object> Value) :
Global(&getID(), Name), Value(std::move(Value)) {}
explicit TupleTreeGlobal(llvm::StringRef Name) : Global(&getID(), Name) {}
TupleTreeGlobal(const TupleTreeGlobal &Other) = default;
TupleTreeGlobal(TupleTreeGlobal &&Other) = default;
TupleTreeGlobal &operator=(const TupleTreeGlobal &Other) = default;
TupleTreeGlobal &operator=(TupleTreeGlobal &&Other) = default;
virtual ~TupleTreeGlobal() override = default;
static bool classof(const Global *T) { return T->getID() == &getID(); }
public:
llvm::Expected<std::unique_ptr<Global>>
createNew(llvm::StringRef Name,
const llvm::MemoryBuffer &Buffer) const override {
auto MaybeTree = TupleTree<Object>::fromString(Buffer.getBuffer());
if (!MaybeTree)
return MaybeTree.takeError();
return std::make_unique<TupleTreeGlobal>(Name, MaybeTree.get());
}
std::unique_ptr<Global> clone() const override {
auto Ptr = new TupleTreeGlobal(*this);
return std::unique_ptr<Global>(Ptr);
}
void clear() override {
Value.evictCachedReferences();
*Value = Object();
}
llvm::Error serialize(llvm::raw_ostream &OS) const override {
Value.serialize(OS);
return llvm::Error::success();
}
llvm::Error fromString(llvm::StringRef String) override {
auto MaybeTupleTree = TupleTree<Object>::fromString(String);
if (!MaybeTupleTree)
return MaybeTupleTree.takeError();
if (not(*MaybeTupleTree)->verify()) {
return revng::createError("Verify failed on " + getName());
}
Value = *MaybeTupleTree;
return llvm::Error::success();
}
llvm::Expected<GlobalTupleTreeDiff>
diffFromString(llvm::StringRef String) override {
auto MaybeDiff = ::fromString<TupleTreeDiff<Object>>(String);
if (not MaybeDiff)
return MaybeDiff.takeError();
return GlobalTupleTreeDiff(std::move(*MaybeDiff), getName());
}
bool verify() const override { return Value->verify(); }
GlobalTupleTreeDiff diff(const Global &Other) const override {
const TupleTreeGlobal &Casted = llvm::cast<TupleTreeGlobal>(Other);
auto Diff = ::diff(*Value, *Casted.Value);
return GlobalTupleTreeDiff(std::move(Diff), getName());
}
llvm::Error applyDiff(const llvm::MemoryBuffer &Diff) override {
auto MaybeDiff = TupleTreeDiff<Object>::fromString(Diff.getBuffer());
if (not MaybeDiff) {
return MaybeDiff.takeError();
}
return MaybeDiff->apply(Value);
}
llvm::Error applyDiff(const TupleTreeDiff<Object> &Diff) {
return Diff.apply(Value);
}
llvm::Error applyDiff(const GlobalTupleTreeDiff &Diff) override {
return Diff.getAs<Object>()->apply(Value);
}
Global &operator=(const Global &Other) override {
const TupleTreeGlobal &Casted = llvm::cast<TupleTreeGlobal>(Other);
Value = Casted.Value;
return *this;
}
const TupleTree<Object> &get() const { return Value; }
TupleTree<Object> &get() { return Value; }
std::optional<TupleTreePath>
deserializePath(llvm::StringRef Serialized) const override {
return stringAsPath<Object>(Serialized);
}
std::optional<std::string>
serializePath(const TupleTreePath &Path) const override {
return pathAsString<Object>(Path);
}
void collectReadFields(const TargetInContainer &Target,
PathTargetBimap &Out) override {
const TupleTree<Object> &AsConst = Value;
ReadFields Results = revng::Tracking::collect(*AsConst);
for (const TupleTreePath &Result : Results.Read)
Out.insert(Target, Result);
for (const TupleTreePath &Result : Results.ExactVectors)
Out.insert(Target, Result);
}
void clearAndResume() const override {
revng::Tracking::clearAndResume(*Value);
}
void pushReadFields() const override { revng::Tracking::push(*Value); }
void popReadFields() const override { revng::Tracking::pop(*Value); }
void stopTracking() const override { revng::Tracking::stop(*Value); }
};
} // namespace pipeline