mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
181 lines
4.9 KiB
C++
181 lines
4.9 KiB
C++
#pragma once
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <cstddef>
|
|
#include <fstream>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <set>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
#include "llvm/ADT/StringMap.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#include "revng/Pipeline/Container.h"
|
|
#include "revng/Pipeline/ContainerFactory.h"
|
|
#include "revng/Pipeline/Kind.h"
|
|
#include "revng/Pipeline/Target.h"
|
|
#include "revng/Support/Assert.h"
|
|
|
|
namespace pipeline {
|
|
|
|
/// A map from containerName to the container itself, which is initially empty.
|
|
///
|
|
/// This class is used mostly in two points, as the backing containers of each
|
|
/// step, as well as the containers containing the target extracted from each
|
|
/// step to perform the computation.
|
|
///
|
|
/// This class contains both the containers and a pointer to a factory that is
|
|
/// used to create that container when it does not exists.
|
|
class ContainerSet {
|
|
private:
|
|
using Map = llvm::StringMap<std::unique_ptr<ContainerBase>>;
|
|
|
|
public:
|
|
using const_iterator = Map::const_iterator;
|
|
using iterator = Map::iterator;
|
|
using value_type = Map::value_type;
|
|
|
|
private:
|
|
Map Content;
|
|
llvm::StringMap<const ContainerFactory *> Factories;
|
|
|
|
public:
|
|
ContainerSet() = default;
|
|
|
|
ContainerSet(Map Content) : Content(std::move(Content)) {}
|
|
|
|
ContainerSet(ContainerSet &&) = default;
|
|
ContainerSet &operator=(ContainerSet &&) = default;
|
|
|
|
ContainerSet(const ContainerSet &) = delete;
|
|
ContainerSet &operator=(const ContainerSet &) = delete;
|
|
|
|
~ContainerSet() = default;
|
|
|
|
public:
|
|
const_iterator begin() const { return Content.begin(); }
|
|
const_iterator end() const { return Content.end(); }
|
|
|
|
iterator begin() { return Content.begin(); }
|
|
iterator end() { return Content.end(); }
|
|
|
|
iterator find(llvm::StringRef Name) { return Content.find(Name); }
|
|
|
|
size_t size() const { return Factories.size(); }
|
|
|
|
public:
|
|
ContainerSet cloneFiltered(const ContainerToTargetsMap &Targets);
|
|
|
|
void mergeBack(ContainerSet &&Other) {
|
|
for (auto &Entry : Other.Content) {
|
|
revng_assert(containsOrCanCreate(Entry.first()));
|
|
|
|
auto &LContainer = Content.find(Entry.first())->second;
|
|
auto &RContainer = Entry.second;
|
|
if (RContainer == nullptr)
|
|
continue;
|
|
|
|
if (LContainer == nullptr)
|
|
LContainer = std::move(RContainer);
|
|
else
|
|
LContainer->mergeBack(std::move(*RContainer));
|
|
}
|
|
}
|
|
|
|
ContainerBase &operator[](llvm::StringRef Name) {
|
|
revng_assert(containsOrCanCreate(Name));
|
|
if (Content[Name] == nullptr)
|
|
Content[Name] = (*Factories[Name])(Name);
|
|
auto &Pointer = Content.find(Name)->second;
|
|
revng_assert(Pointer != nullptr);
|
|
return *Pointer;
|
|
}
|
|
|
|
ContainerBase &at(llvm::StringRef Name) {
|
|
revng_assert(contains(Name));
|
|
return *Content.find(Name)->second;
|
|
}
|
|
|
|
const ContainerBase &at(llvm::StringRef Name) const {
|
|
revng_assert(contains(Name));
|
|
return *Content.find(Name)->second;
|
|
}
|
|
|
|
bool isContainerRegistered(llvm::StringRef Name) const {
|
|
return Factories.find(Name) != Factories.end();
|
|
}
|
|
|
|
bool contains(llvm::StringRef Name) const {
|
|
auto Iterator = Content.find(Name);
|
|
return Iterator != Content.end() and Iterator->second != nullptr;
|
|
}
|
|
|
|
bool containsOrCanCreate(llvm::StringRef Name) const {
|
|
return Content.find(Name) != Content.end();
|
|
}
|
|
|
|
template<typename T>
|
|
const T &get(llvm::StringRef Name) const {
|
|
return llvm::cast<T>(*Content.find(Name)->second);
|
|
}
|
|
|
|
template<typename T>
|
|
T &get(llvm::StringRef Name) {
|
|
return llvm::cast<T>(*Content.find(Name)->second);
|
|
}
|
|
|
|
template<typename T>
|
|
T &getOrCreate(llvm::StringRef Name) {
|
|
return llvm::cast<T>(operator[](Name));
|
|
}
|
|
|
|
bool contains(const Target &Target) const;
|
|
|
|
ContainerToTargetsMap enumerate() const;
|
|
|
|
llvm::Error verify() const;
|
|
|
|
public:
|
|
void add(llvm::StringRef Name,
|
|
const ContainerFactory &Factory,
|
|
std::unique_ptr<ContainerBase> Container = nullptr) {
|
|
Content.try_emplace(Name, std::move(Container));
|
|
Factories.try_emplace(Name, &Factory);
|
|
}
|
|
|
|
llvm::Error remove(const ContainerToTargetsMap &ToRemove);
|
|
void intersect(ContainerToTargetsMap &ToIntersect) const;
|
|
|
|
public:
|
|
llvm::Error store(const revng::DirectoryPath &DirectoryPath) const;
|
|
llvm::Error load(const revng::DirectoryPath &DirectoryPath);
|
|
|
|
std::vector<revng::FilePath>
|
|
getWrittenFiles(const revng::DirectoryPath &DirectoryPath) const;
|
|
|
|
public:
|
|
template<typename OStream>
|
|
void dump(OStream &OS, size_t Indentation = 0) const {
|
|
for (const auto &Entry : Content) {
|
|
indent(OS, Indentation);
|
|
OS << Entry.first().str() << "\n";
|
|
if (Entry.second != nullptr)
|
|
Entry.second->enumerate().dump(OS, Indentation + 1);
|
|
}
|
|
}
|
|
|
|
void dump() const debug_function { dump(dbg); }
|
|
};
|
|
|
|
} // namespace pipeline
|