diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/buildtool/file_system/TARGETS | 13 | ||||
-rw-r--r-- | src/buildtool/file_system/precomputed_root.cpp | 163 | ||||
-rw-r--r-- | src/buildtool/file_system/precomputed_root.hpp | 108 |
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 |