Files
2024-09-27 12:07:16 +02:00

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