summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/buildtool/build_engine/base_maps/source_map.cpp2
-rw-r--r--src/buildtool/file_system/file_root.hpp200
-rw-r--r--src/buildtool/file_system/object_type.hpp3
-rw-r--r--src/utils/cpp/concepts.hpp6
4 files changed, 192 insertions, 19 deletions
diff --git a/src/buildtool/build_engine/base_maps/source_map.cpp b/src/buildtool/build_engine/base_maps/source_map.cpp
index 39976016..5e18a3e5 100644
--- a/src/buildtool/build_engine/base_maps/source_map.cpp
+++ b/src/buildtool/build_engine/base_maps/source_map.cpp
@@ -72,7 +72,7 @@ auto CreateSourceTargetMap(const gsl::not_null<DirectoryEntriesMap*>& dirs,
ts,
{ModuleName{target.repository, dir.string()}},
[key, src_file_reader](auto values) {
- src_file_reader(values[0]->Contains(
+ src_file_reader(values[0]->ContainsFile(
path(key.GetNamedTarget().name).filename().string()));
},
[logger, dir](auto msg, auto fatal) {
diff --git a/src/buildtool/file_system/file_root.hpp b/src/buildtool/file_system/file_root.hpp
index 1df40588..58f521cd 100644
--- a/src/buildtool/file_system/file_root.hpp
+++ b/src/buildtool/file_system/file_root.hpp
@@ -2,15 +2,75 @@
#define INCLUDED_SRC_BUILDTOOL_FILE_SYSTEM_FILE_ROOT_HPP
#include <filesystem>
+#include <iterator>
#include <memory>
#include <string>
+#include <unordered_map>
#include <unordered_set>
+#include <utility>
#include <variant>
#include "gsl-lite/gsl-lite.hpp"
#include "src/buildtool/common/artifact_description.hpp"
#include "src/buildtool/file_system/file_system_manager.hpp"
#include "src/buildtool/file_system/git_tree.hpp"
+#include "src/utils/cpp/concepts.hpp"
+
+/// FilteredIterator is an helper class to allow for iteration over
+/// directory-only or file-only entries stored inside the class
+/// DirectoryEntries. Internally, DirectoryEntries holds a
+/// map<string,ObjectType> or map<string, GitTree*>. While iterating, we are
+/// just interested in the name of the entry (i.e., the string).
+/// To decide which entries retain, the FilteredIterator requires a predicate.
+template <StrMapConstForwardIterator I>
+// I is a forward iterator
+// I::value_type is a std::pair<const std::string, *>
+class FilteredIterator {
+ public:
+ using value_type = std::string const;
+ using pointer = value_type*;
+ using reference = value_type&;
+ using difference_type = std::ptrdiff_t;
+ using iteratori_category = std::forward_iterator_tag;
+ using predicate_t = std::function<bool(typename I::reference)>;
+
+ FilteredIterator() noexcept = default;
+ // [first, last) is a valid sequence
+ FilteredIterator(I first, I last, predicate_t p) noexcept
+ : iterator_{std::find_if(first, last, p)},
+ end_{std::move(last)},
+ p{std::move(p)} {}
+
+ auto operator*() const noexcept -> reference { return iterator_->first; }
+
+ auto operator++() noexcept -> FilteredIterator& {
+ ++iterator_;
+ iterator_ = std::find_if(iterator_, end_, p);
+ return *this;
+ }
+
+ [[nodiscard]] auto begin() noexcept -> FilteredIterator& { return *this; }
+ [[nodiscard]] auto end() const noexcept -> FilteredIterator {
+ return FilteredIterator{end_, end_, p};
+ }
+
+ [[nodiscard]] friend auto operator==(FilteredIterator const& x,
+ FilteredIterator const& y) noexcept
+ -> bool {
+ return x.iterator_ == y.iterator_;
+ }
+
+ [[nodiscard]] friend auto operator!=(FilteredIterator const& x,
+ FilteredIterator const& y) noexcept
+ -> bool {
+ return not(x == y);
+ }
+
+ private:
+ I iterator_{};
+ const I end_{};
+ predicate_t p{};
+};
class FileRoot {
using fs_root_t = std::filesystem::path;
@@ -22,27 +82,100 @@ class FileRoot {
public:
class DirectoryEntries {
- using names_t = std::unordered_set<std::string>;
+ friend class FileRoot;
+ using pairs_t = std::unordered_map<std::string, ObjectType>;
using tree_t = gsl::not_null<GitTree const*>;
- using entries_t = std::variant<std::monostate, names_t, tree_t>;
+ using entries_t = std::variant<std::monostate, tree_t, pairs_t>;
+
+ using fs_iterator_type = typename pairs_t::const_iterator;
+ using fs_iterator = FilteredIterator<fs_iterator_type>;
+
+ using git_iterator_type = GitTree::entries_t::const_iterator;
+ using git_iterator = FilteredIterator<git_iterator_type>;
+
+ /// Iterator has two FilteredIterators, one for iterating over pairs_t
+ /// and one for tree_t. Each FilteredIterator is constructed with a
+ /// proper predicate, allowing for iteration on file-only or
+ /// directory-only entries
+ class Iterator {
+ public:
+ using value_type = std::string const;
+ using pointer = value_type*;
+ using reference = value_type&;
+ using difference_type = std::ptrdiff_t;
+ using iteratori_category = std::forward_iterator_tag;
+ explicit Iterator(fs_iterator fs_it) : it_{std::move(fs_it)} {}
+ explicit Iterator(git_iterator git_it) : it_{std::move(git_it)} {}
+
+ auto operator*() const noexcept -> reference {
+ if (std::holds_alternative<fs_iterator>(it_)) {
+ return *std::get<fs_iterator>(it_);
+ }
+ return *std::get<git_iterator>(it_);
+ }
+
+ [[nodiscard]] auto begin() noexcept -> Iterator& { return *this; }
+ [[nodiscard]] auto end() const noexcept -> Iterator {
+ if (std::holds_alternative<fs_iterator>(it_)) {
+ return Iterator{std::get<fs_iterator>(it_).end()};
+ }
+ return Iterator{std::get<git_iterator>(it_).end()};
+ }
+ auto operator++() noexcept -> Iterator& {
+ if (std::holds_alternative<fs_iterator>(it_)) {
+ ++(std::get<fs_iterator>(it_));
+ }
+ else {
+ ++(std::get<git_iterator>(it_));
+ }
+ return *this;
+ }
+
+ friend auto operator==(Iterator const& x,
+ Iterator const& y) noexcept -> bool {
+ return x.it_ == y.it_;
+ }
+ friend auto operator!=(Iterator const& x,
+ Iterator const& y) noexcept -> bool {
+ return not(x == y);
+ }
+
+ private:
+ std::variant<fs_iterator, git_iterator> it_;
+ };
public:
DirectoryEntries() noexcept = default;
- explicit DirectoryEntries(names_t names) noexcept
- : data_{std::move(names)} {}
+
+ explicit DirectoryEntries(pairs_t pairs) noexcept
+ : data_{std::move(pairs)} {}
+
explicit DirectoryEntries(tree_t git_tree) noexcept
: data_{std::move(git_tree)} {}
- [[nodiscard]] auto Contains(std::string const& name) const noexcept
+
+ [[nodiscard]] auto ContainsFile(std::string const& name) const noexcept
-> bool {
- if (std::holds_alternative<tree_t>(data_)) {
- return static_cast<bool>(
- std::get<tree_t>(data_)->LookupEntryByName(name));
- }
- if (std::holds_alternative<names_t>(data_)) {
- return std::get<names_t>(data_).contains(name);
+ try {
+ if (std::holds_alternative<tree_t>(data_)) {
+ auto const& data = std::get<tree_t>(data_);
+ auto ptr = data->LookupEntryByName(name);
+ if (static_cast<bool>(ptr)) {
+ return ptr->IsBlob();
+ }
+ return false;
+ }
+ if (std::holds_alternative<pairs_t>(data_)) {
+ auto const& data = std::get<pairs_t>(data_);
+ auto it = data.find(name);
+ return (it != data.end() and
+ it->second == ObjectType::File);
+ }
+ } catch (...) {
}
+
return false;
}
+
[[nodiscard]] auto Empty() const noexcept -> bool {
if (std::holds_alternative<tree_t>(data_)) {
try {
@@ -52,12 +185,45 @@ class FileRoot {
return false;
}
}
- if (std::holds_alternative<names_t>(data_)) {
- return std::get<names_t>(data_).empty();
+ if (std::holds_alternative<pairs_t>(data_)) {
+ return std::get<pairs_t>(data_).empty();
}
return true;
}
+ [[nodiscard]] auto FilesIterator() const -> Iterator {
+ if (std::holds_alternative<pairs_t>(data_)) {
+ auto const& data = std::get<pairs_t>(data_);
+ return Iterator{FilteredIterator{
+ data.begin(), data.end(), [](auto const& x) {
+ return x.second == ObjectType::File;
+ }}};
+ }
+ // std::holds_alternative<tree_t>(data_) == true
+ auto const& data = std::get<tree_t>(data_);
+ return Iterator{FilteredIterator{
+ data->begin(), data->end(), [](auto const& x) noexcept -> bool {
+ return x.second->IsBlob();
+ }}};
+ }
+
+ [[nodiscard]] auto DirectoriesIterator() const -> Iterator {
+ if (std::holds_alternative<pairs_t>(data_)) {
+ auto const& data = std::get<pairs_t>(data_);
+ return Iterator{FilteredIterator{
+ data.begin(), data.end(), [](auto const& x) {
+ return x.second == ObjectType::Tree;
+ }}};
+ }
+
+ // std::holds_alternative<tree_t>(data_) == true
+ auto const& data = std::get<tree_t>(data_);
+ return Iterator{FilteredIterator{
+ data->begin(), data->end(), [](auto const& x) noexcept -> bool {
+ return x.second->IsTree();
+ }}};
+ }
+
private:
entries_t data_{};
};
@@ -163,14 +329,14 @@ class FileRoot {
}
}
else {
- std::unordered_set<std::string> names{};
+ DirectoryEntries::pairs_t map{};
if (FileSystemManager::ReadDirectory(
std::get<fs_root_t>(root_) / dir_path,
- [&names](auto name, auto /*type*/) {
- names.emplace(name.string());
+ [&map](const auto& name, auto type) {
+ map.emplace(name.string(), type);
return true;
})) {
- return DirectoryEntries{std::move(names)};
+ return DirectoryEntries{std::move(map)};
}
}
} catch (std::exception const& ex) {
diff --git a/src/buildtool/file_system/object_type.hpp b/src/buildtool/file_system/object_type.hpp
index 6209f05d..79aaa96b 100644
--- a/src/buildtool/file_system/object_type.hpp
+++ b/src/buildtool/file_system/object_type.hpp
@@ -1,7 +1,8 @@
#ifndef INCLUDED_SRC_BUILDTOOL_FILE_SYSTEM_OBJECT_TYPE_HPP
#define INCLUDED_SRC_BUILDTOOL_FILE_SYSTEM_OBJECT_TYPE_HPP
+#include <cstdint>
-enum class ObjectType {
+enum class ObjectType : std::int8_t {
File,
Executable,
Tree,
diff --git a/src/utils/cpp/concepts.hpp b/src/utils/cpp/concepts.hpp
index 597179e1..04b2bfcc 100644
--- a/src/utils/cpp/concepts.hpp
+++ b/src/utils/cpp/concepts.hpp
@@ -66,4 +66,10 @@ concept ClockHasFromTime = requires(std::time_t const t) {
T::from_time_t(t);
};
+template <typename T>
+concept StrMapConstForwardIterator = requires(T const c) {
+ { (*c).first }
+ ->same_as<std::string const>;
+};
+
#endif // INCLUDED_SRC_UTILS_CPP_CONCEPTS_HPP