summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/buildtool/file_system/TARGETS13
-rw-r--r--src/buildtool/file_system/precomputed_root.cpp163
-rw-r--r--src/buildtool/file_system/precomputed_root.hpp108
3 files changed, 284 insertions, 0 deletions
diff --git a/src/buildtool/file_system/TARGETS b/src/buildtool/file_system/TARGETS
index c8c26458..3f604393 100644
--- a/src/buildtool/file_system/TARGETS
+++ b/src/buildtool/file_system/TARGETS
@@ -198,4 +198,17 @@
]
, "stage": ["src", "buildtool", "file_system"]
}
+, "precomputed_root":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["precomputed_root"]
+ , "hdrs": ["precomputed_root.hpp"]
+ , "srcs": ["precomputed_root.cpp"]
+ , "deps": [["@", "json", "", "json"], ["src/utils/cpp", "expected"]]
+ , "private-deps":
+ [ ["@", "fmt", "", "fmt"]
+ , ["@", "gsl", "", "gsl"]
+ , ["src/utils/cpp", "hash_combine"]
+ ]
+ , "stage": ["src", "buildtool", "file_system"]
+ }
}
diff --git a/src/buildtool/file_system/precomputed_root.cpp b/src/buildtool/file_system/precomputed_root.cpp
new file mode 100644
index 00000000..8e20f2f0
--- /dev/null
+++ b/src/buildtool/file_system/precomputed_root.cpp
@@ -0,0 +1,163 @@
+// Copyright 2024 Huawei Cloud Computing Technology Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/buildtool/file_system/precomputed_root.hpp"
+
+#include <compare>
+#include <exception>
+
+#include "fmt/core.h"
+#include "gsl/gsl"
+#include "src/utils/cpp/hash_combine.hpp"
+
+namespace {
+template <typename T>
+[[nodiscard]] auto ParseImpl(nlohmann::json const& /*root*/)
+ -> expected<T, std::string> {
+ Ensures(false);
+}
+
+template <typename T>
+[[nodiscard]] auto ParsePrecomputed(nlohmann::json const& root) noexcept
+ -> expected<PrecomputedRoot, std::string> {
+ try {
+ auto parsed_root = ParseImpl<T>(root);
+ if (not parsed_root) {
+ return unexpected{fmt::format("While parsing {} root {}:\n{}",
+ T::kMarker,
+ root.dump(),
+ std::move(parsed_root).error())};
+ }
+ return PrecomputedRoot{*std::move(parsed_root)};
+ } catch (const std::exception& e) {
+ return unexpected{fmt::format("While parsing {} root {}:\n{}",
+ T::kMarker,
+ root.dump(),
+ e.what())};
+ }
+}
+
+template <>
+[[nodiscard]] auto ParseImpl<ComputedRoot>(nlohmann::json const& root)
+ -> expected<ComputedRoot, std::string> {
+ if (root.size() != ComputedRoot::kSchemeLength) {
+ return unexpected{fmt::format(
+ "The root has a wrong number of arguments: {}\nThe scheme requires "
+ "[<scheme>, <root>, <module>, <name>, <config>]",
+ root.dump())};
+ }
+
+ if (not root[1].is_string()) {
+ return unexpected{fmt::format(
+ "The root has a wrong type of <root>. Expected a string, got {}",
+ root[1].dump())};
+ }
+
+ if (not root[2].is_string()) {
+ return unexpected{fmt::format(
+ "The root has a wrong type of <module>. Expected a string, got {}",
+ root[2].dump())};
+ }
+ if (not root[3].is_string()) {
+ return unexpected{fmt::format(
+ "The root has a wrong type of <name>. Expected a string, got {}",
+ root[3].dump())};
+ }
+ if (not root[4].is_object()) {
+ return unexpected{
+ fmt::format("The root has a wrong type of <config>. Expected a "
+ "plain json, got {}",
+ root[4].dump())};
+ }
+
+ return ComputedRoot{.repository = std::string{root[1]},
+ .target_module = std::string{root[2]},
+ .target_name = std::string{root[3]},
+ .config = root[4]};
+}
+} // namespace
+
+auto ComputedRoot::operator==(ComputedRoot const& other) const noexcept
+ -> bool {
+ return repository == other.repository and
+ target_module == other.target_module and
+ target_name == other.target_name and config == other.config;
+}
+
+auto ComputedRoot::operator<(ComputedRoot const& other) const noexcept -> bool {
+ if (auto const res = repository <=> other.repository; res != 0) {
+ return res < 0;
+ }
+ if (auto const res = target_module <=> other.target_module; res != 0) {
+ return res < 0;
+ }
+ if (auto const res = target_name <=> other.target_name; res != 0) {
+ return res < 0;
+ }
+ return config < other.config;
+}
+
+auto ComputedRoot::ToString() const -> std::string {
+ return fmt::format("([\"@\", {}, {}, {}], {})",
+ nlohmann::json(repository).dump(),
+ nlohmann::json(target_module).dump(),
+ nlohmann::json(target_name).dump(),
+ config.dump());
+}
+
+auto ComputedRoot::ComputeHash() const -> std::size_t {
+ size_t seed{};
+ hash_combine<std::string>(&seed, kMarker);
+ hash_combine<std::string>(&seed, repository);
+ hash_combine<std::string>(&seed, target_module);
+ hash_combine<std::string>(&seed, target_name);
+ hash_combine<nlohmann::json>(&seed, config);
+ return seed;
+}
+
+auto PrecomputedRoot::Parse(nlohmann::json const& root) noexcept
+ -> expected<PrecomputedRoot, std::string> {
+ if ((not root.is_array()) or root.empty()) {
+ return unexpected{
+ fmt::format("The root is empty or has unsupported format: \"{}\"",
+ root.dump())};
+ }
+
+ if (root[0] == ComputedRoot::kMarker) {
+ return ParsePrecomputed<ComputedRoot>(root);
+ }
+
+ return unexpected{
+ fmt::format("Unknown precomputed type of the root {}", root.dump())};
+}
+
+auto PrecomputedRoot::ToString() const noexcept -> std::string {
+ try {
+ return std::visit([](auto const& r) { return r.ToString(); }, root_);
+ } catch (...) {
+ Ensures(false);
+ }
+}
+
+auto PrecomputedRoot::GetReferencedRepository() const noexcept -> std::string {
+ try {
+ return std::visit([](auto const& r) { return r.repository; }, root_);
+ } catch (...) {
+ Ensures(false);
+ }
+}
+
+auto PrecomputedRoot::ComputeHash(root_t const& root) -> std::size_t {
+ return std::visit([](auto const& r) { return r.ComputeHash(); }, root);
+}
diff --git a/src/buildtool/file_system/precomputed_root.hpp b/src/buildtool/file_system/precomputed_root.hpp
new file mode 100644
index 00000000..8261b94c
--- /dev/null
+++ b/src/buildtool/file_system/precomputed_root.hpp
@@ -0,0 +1,108 @@
+// Copyright 2024 Huawei Cloud Computing Technology Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef INCLUDED_SRC_BUILDTOOL_FILE_SYSTEM_PRECOMPUTED_ROOT_HPP
+#define INCLUDED_SRC_BUILDTOOL_FILE_SYSTEM_PRECOMPUTED_ROOT_HPP
+
+#include <cstddef>
+#include <functional>
+#include <optional>
+#include <string>
+#include <utility>
+#include <variant>
+
+#include "nlohmann/json.hpp"
+#include "src/utils/cpp/expected.hpp"
+
+struct ComputedRoot final {
+ static constexpr auto kMarker = "computed";
+ static constexpr std::size_t kSchemeLength = 5;
+
+ std::string repository;
+ std::string target_module;
+ std::string target_name;
+ nlohmann::json config;
+
+ [[nodiscard]] auto operator==(ComputedRoot const& other) const noexcept
+ -> bool;
+ [[nodiscard]] auto operator<(ComputedRoot const& other) const noexcept
+ -> bool;
+ [[nodiscard]] auto ToString() const -> std::string;
+ [[nodiscard]] auto ComputeHash() const -> std::size_t;
+};
+
+namespace std {
+template <typename>
+struct hash;
+}
+
+/// \brief Generalized representation of roots that must be evaluated before the
+/// real build starts.
+class PrecomputedRoot final {
+ public:
+ using root_t = std::variant<ComputedRoot>;
+ explicit PrecomputedRoot() : PrecomputedRoot(ComputedRoot{}) {}
+ explicit PrecomputedRoot(root_t root)
+ : root_{std::move(root)}, hash_{ComputeHash(root_)} {}
+
+ [[nodiscard]] static auto Parse(nlohmann::json const& root) noexcept
+ -> expected<PrecomputedRoot, std::string>;
+
+ [[nodiscard]] static auto IsPrecomputedMarker(
+ std::string const& marker) noexcept -> bool {
+ return marker == ComputedRoot::kMarker;
+ }
+
+ [[nodiscard]] auto operator==(PrecomputedRoot const& other) const noexcept
+ -> bool {
+ return root_ == other.root_;
+ }
+ [[nodiscard]] auto operator<(PrecomputedRoot const& other) const noexcept
+ -> bool {
+ return root_ < other.root_;
+ }
+
+ [[nodiscard]] auto ToString() const noexcept -> std::string;
+ [[nodiscard]] auto GetReferencedRepository() const noexcept -> std::string;
+
+ [[nodiscard]] auto IsComputed() const noexcept -> bool {
+ return std::holds_alternative<ComputedRoot>(root_);
+ }
+ [[nodiscard]] auto AsComputed() const -> std::optional<ComputedRoot> {
+ if (auto const* computed = std::get_if<ComputedRoot>(&root_)) {
+ return *computed;
+ }
+ return std::nullopt;
+ }
+
+ private:
+ root_t root_;
+ std::size_t hash_;
+
+ [[nodiscard]] static auto ComputeHash(root_t const& root) -> std::size_t;
+
+ friend struct std::hash<PrecomputedRoot>;
+};
+
+namespace std {
+template <>
+struct hash<PrecomputedRoot> {
+ [[nodiscard]] auto operator()(PrecomputedRoot const& root) const
+ -> std::size_t {
+ return root.hash_;
+ }
+};
+} // namespace std
+
+#endif // INCLUDED_SRC_BUILDTOOL_FILE_SYSTEM_PRECOMPUTED_ROOT_HPP