// 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_MULTITHREADING_ASYNC_MAP_UTILS_HPP #define INCLUDED_SRC_BUILDTOOL_MULTITHREADING_ASYNC_MAP_UTILS_HPP #include #include #include #include #include "fmt/core.h" #include "src/buildtool/logging/log_level.hpp" #include "src/buildtool/logging/logger.hpp" #include "src/buildtool/multithreading/async_map_consumer.hpp" /// \brief Utility to detect and report cycles for an AsyncMap instance. /// \param name Human-readable string identifier related to the map or its use. /// \param map The AsyncMap instance. /// \param key_printer Callable returning key-specific identifier in string /// format. /// \returns The resulting cycle message as a string, or nullopt if no cycle /// detected. template [[nodiscard]] auto DetectAndReportCycle( std::string const& name, AsyncMapConsumer const& map, std::function key_printer) -> std::optional { using namespace std::string_literals; auto cycle = map.DetectCycle(); if (cycle) { bool found{false}; std::ostringstream oss{}; oss << fmt::format("Cycle detected in {}:", name) << std::endl; for (auto const& k : *cycle) { auto match = (k == cycle->back()); std::string prefix; if (match) { prefix = found ? "`-- "s : ".-> "s; } else { prefix = found ? "| "s : " "s; } oss << prefix << key_printer(k) << std::endl; found = found or match; } return oss.str(); } return std::nullopt; } /// \brief Utility to detect and report pending tasks for an AsyncMap instance. /// \param name Human-readable string identifier related to the map or its use. /// \param map The AsyncMap instance. /// \param key_printer Callable returning key-specific identifier in string /// format. /// \param logger Named logger, or nullptr to use global logger. template void DetectAndReportPending(std::string const& name, AsyncMapConsumer const& map, std::function key_printer, Logger const* logger = nullptr) { using namespace std::string_literals; auto keys = map.GetPendingKeys(); if (not keys.empty()) { std::ostringstream oss{}; oss << fmt::format("Internal error, failed to evaluate pending {}:", name) << std::endl; for (auto const& k : keys) { oss << " " << key_printer(k) << std::endl; } Logger::Log(logger, LogLevel::Error, "{}", oss.str()); } } #endif // INCLUDED_SRC_BUILDTOOL_MULTITHREADING_ASYNC_MAP_UTILS_HPP