// Copyright 2022 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_BUILD_ENGINE_EXPRESSION_EXPRESSION_HPP #define INCLUDED_SRC_BUILDTOOL_BUILD_ENGINE_EXPRESSION_EXPRESSION_HPP #include #include #include #include #include #include #include #include #include "fmt/core.h" #include "gsl/gsl" #include "src/buildtool/build_engine/base_maps/entity_name_data.hpp" #include "src/buildtool/build_engine/expression/expression_ptr.hpp" #include "src/buildtool/build_engine/expression/function_map.hpp" #include "src/buildtool/build_engine/expression/linked_map.hpp" #include "src/buildtool/build_engine/expression/target_node.hpp" #include "src/buildtool/build_engine/expression/target_result.hpp" #include "src/buildtool/common/artifact_description.hpp" #include "src/buildtool/crypto/hash_function.hpp" #include "src/buildtool/multithreading/atomic_value.hpp" #include "src/utils/cpp/hex_string.hpp" #include "src/utils/cpp/json.hpp" class Expression { friend auto operator+(Expression const& /*lhs*/, Expression const& /*rhs*/) -> Expression; public: using none_t = std::monostate; using number_t = double; using artifact_t = ArtifactDescription; using result_t = TargetResult; using node_t = TargetNode; using list_t = std::vector; using map_t = LinkedMap; using name_t = BuildMaps::Base::EntityName; template static consteval auto IsValidType() -> bool { if constexpr (kIndex < std::variant_size_v) { return std::is_same_v< T, std::variant_alternative_t> or IsValidType(); } return false; } class ExpressionTypeError : public std::exception { public: explicit ExpressionTypeError(std::string const& msg) noexcept : msg_{"ExpressionTypeError: " + msg} {} [[nodiscard]] auto what() const noexcept -> char const* final { return msg_.c_str(); } private: std::string msg_; }; Expression() noexcept = default; ~Expression() noexcept = default; Expression(Expression const& other) noexcept = delete; Expression(Expression&& other) noexcept = default; auto operator=(Expression const& other) noexcept = delete; auto operator=(Expression&& other) noexcept = delete; template requires(IsValidType>()) // NOLINTNEXTLINE(bugprone-forwarding-reference-overload) explicit Expression(T&& data) noexcept : data_{std::forward(data)} {} [[nodiscard]] auto IsNone() const noexcept -> bool { return IsA(); } [[nodiscard]] auto IsBool() const noexcept -> bool { return IsA(); } [[nodiscard]] auto IsNumber() const noexcept -> bool { return IsA(); } [[nodiscard]] auto IsString() const noexcept -> bool { return IsA(); } [[nodiscard]] auto IsName() const noexcept -> bool { return IsA(); } [[nodiscard]] auto IsArtifact() const noexcept -> bool { return IsA(); } [[nodiscard]] auto IsResult() const noexcept -> bool { return IsA(); } [[nodiscard]] auto IsNode() const noexcept -> bool { return IsA(); } [[nodiscard]] auto IsList() const noexcept -> bool { return IsA(); } [[nodiscard]] auto IsMap() const noexcept -> bool { return IsA(); } [[nodiscard]] auto Bool() const -> bool { return Cast(); } [[nodiscard]] auto Number() const -> number_t { return Cast(); } [[nodiscard]] auto Name() const -> name_t { return Cast(); } [[nodiscard]] auto String() const& -> std::string const& { return Cast(); } [[nodiscard]] auto String() && -> std::string { return std::move(*this).Cast(); } [[nodiscard]] auto Artifact() const& -> artifact_t const& { return Cast(); } [[nodiscard]] auto Artifact() && -> artifact_t { return std::move(*this).Cast(); } [[nodiscard]] auto Result() const& -> result_t const& { return Cast(); } [[nodiscard]] auto Result() && -> result_t { return std::move(*this).Cast(); } [[nodiscard]] auto Node() const& -> node_t const& { return Cast(); } [[nodiscard]] auto Node() && -> node_t { return std::move(*this).Cast(); } [[nodiscard]] auto List() const& -> list_t const& { return Cast(); } [[nodiscard]] auto List() && -> list_t { return std::move(*this).Cast(); } [[nodiscard]] auto Map() const& -> map_t const& { return Cast(); } [[nodiscard]] auto Map() && -> map_t { return std::move(*this).Cast(); } [[nodiscard]] auto At(std::string const& key) const& -> std::optional> { auto value = Map().Find(key); if (value) { return value; } return std::nullopt; } [[nodiscard]] auto At( std::string const& key) && -> std::optional { auto value = std::move(*this).Map().Find(key); if (value) { return std::move(*value); } return std::nullopt; } template requires(IsValidType>() or std::is_same_v, ExpressionPtr>) [[nodiscard]] auto Get(std::string const& key, T&& default_value) const -> ExpressionPtr { auto value = At(key); if (value) { return value->get(); } if constexpr (std::is_same_v, ExpressionPtr>) { return std::forward(default_value); } else { return ExpressionPtr{std::forward(default_value)}; } } template requires(IsValidType()) [[nodiscard]] auto Value() const& noexcept -> std::optional> { if (GetIndexOf() == data_.index()) { return std::make_optional(std::ref(std::get(data_))); } return std::nullopt; } template requires(IsValidType()) [[nodiscard]] auto Value() && noexcept -> std::optional { if (GetIndexOf() == data_.index()) { return std::make_optional(std::move(std::get(data_))); } return std::nullopt; } template [[nodiscard]] auto operator==(T const& other) const noexcept -> bool { if constexpr (std::is_same_v) { return (&data_ == &other.data_) or (ToHash() == other.ToHash()); } else { return IsValidType() and (GetIndexOf() == data_.index()) and ((static_cast(&data_) == static_cast(&other)) or (std::get(data_) == other)); } } template [[nodiscard]] auto operator!=(T const& other) const noexcept -> bool { return !(*this == other); } [[nodiscard]] auto operator[]( std::string const& key) const& -> ExpressionPtr const&; [[nodiscard]] auto operator[](std::string const& key) && -> ExpressionPtr; [[nodiscard]] auto operator[]( ExpressionPtr const& key) const& -> ExpressionPtr const&; [[nodiscard]] auto operator[](ExpressionPtr const& key) && -> ExpressionPtr; [[nodiscard]] auto operator[](size_t pos) const& -> ExpressionPtr const&; [[nodiscard]] auto operator[](size_t pos) && -> ExpressionPtr; enum class JsonMode { SerializeAll, SerializeAllButNodes, NullForNonJson }; [[nodiscard]] auto ToJson(JsonMode mode = JsonMode::SerializeAll) const -> nlohmann::json; [[nodiscard]] auto IsCacheable() const -> bool; [[nodiscard]] auto ToString() const -> std::string; [[nodiscard]] auto ToAbbrevString(size_t len) const -> std::string; [[nodiscard]] auto ToHash() const noexcept -> std::string; [[nodiscard]] auto ToIdentifier() const noexcept -> std::string { return ToHexString(ToHash()); } [[nodiscard]] static auto FromJson(nlohmann::json const& json) noexcept -> ExpressionPtr; inline static ExpressionPtr const kNone = Expression::FromJson("null"_json); inline static ExpressionPtr const kEmptyMap = Expression::FromJson("{}"_json); inline static ExpressionPtr const kEmptyList = Expression::FromJson("[]"_json); inline static ExpressionPtr const kEmptyMapExpr = Expression::FromJson(R"({"type": "empty_map"})"_json); private: std::variant data_{none_t{}}; AtomicValue hash_{}; AtomicValue is_cachable_{}; template requires(IsValidType()) [[nodiscard]] static consteval auto GetIndexOf() -> std::size_t { static_assert(kIndex < std::variant_size_v, "kIndex out of range"); if constexpr (std::is_same_v< T, std::variant_alternative_t>) { return kIndex; } else { return GetIndexOf(); } } template [[nodiscard]] auto IsA() const noexcept -> bool { return std::holds_alternative(data_); } template [[nodiscard]] auto Cast() const& -> T const& { if (GetIndexOf() == data_.index()) { return std::get(data_); } // throw descriptive ExpressionTypeError throw ExpressionTypeError{ fmt::format("Expression is not of type '{}' but '{}'.", TypeToString(), TypeString())}; } template [[nodiscard]] auto Cast() && -> T { if (GetIndexOf() == data_.index()) { return std::move(std::get(data_)); } // throw descriptive ExpressionTypeError throw ExpressionTypeError{ fmt::format("Expression is not of type '{}' but '{}'.", TypeToString(), TypeString())}; } template requires(Expression::IsValidType()) [[nodiscard]] static auto TypeToString() noexcept -> std::string { if constexpr (std::is_same_v) { return "bool"; } else if constexpr (std::is_same_v) { return "number"; } else if constexpr (std::is_same_v) { return "name"; } else if constexpr (std::is_same_v) { return "string"; } else if constexpr (std::is_same_v) { return "artifact"; } else if constexpr (std::is_same_v) { return "result"; } else if constexpr (std::is_same_v) { return "node"; } else if constexpr (std::is_same_v) { return "list"; } else if constexpr (std::is_same_v) { return "map"; } return "none"; } template [[nodiscard]] auto TypeStringForIndex() const noexcept -> std::string; [[nodiscard]] auto TypeString() const noexcept -> std::string; [[nodiscard]] auto ComputeHash() const noexcept -> std::string; [[nodiscard]] auto ComputeIsCacheable() const -> bool; }; namespace std { template <> struct hash { [[nodiscard]] auto operator()(Expression const& e) const noexcept -> std::size_t { auto hash = std::size_t{}; auto bytes = e.ToHash(); std::memcpy(&hash, bytes.data(), std::min(sizeof(hash), bytes.size())); return hash; } }; } // namespace std #endif // INCLUDED_SRC_BUILDTOOL_BUILD_ENGINE_EXPRESSION_EXPRESSION_HPP