From 619def44c1cca9f3cdf63544d5f24f2c7a7d9b77 Mon Sep 17 00:00:00 2001 From: Klaus Aehlig Date: Tue, 22 Feb 2022 17:03:21 +0100 Subject: Initial self-hosting commit This is the initial version of our tool that is able to build itself. In can be bootstrapped by ./bin/bootstrap.py Co-authored-by: Oliver Reiche Co-authored-by: Victor Moreno --- .../build_engine/expression/expression.hpp | 380 +++++++++++++++++++++ 1 file changed, 380 insertions(+) create mode 100644 src/buildtool/build_engine/expression/expression.hpp (limited to 'src/buildtool/build_engine/expression/expression.hpp') diff --git a/src/buildtool/build_engine/expression/expression.hpp b/src/buildtool/build_engine/expression/expression.hpp new file mode 100644 index 00000000..ffcd01c8 --- /dev/null +++ b/src/buildtool/build_engine/expression/expression.hpp @@ -0,0 +1,380 @@ +#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-lite/gsl-lite.hpp" +#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_generator.hpp" +#include "src/utils/cpp/atomic.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 + : data_{other.data_}, hash_{other.hash_.load()} {} + Expression(Expression&& other) noexcept + : data_{std::move(other.data_)}, hash_{other.hash_.load()} {} + auto operator=(Expression const& other) noexcept -> Expression& { + if (this != &other) { + data_ = other.data_; + } + hash_ = other.hash_.load(); + return *this; + } + auto operator=(Expression&& other) noexcept -> Expression& { + data_ = std::move(other.data_); + hash_ = other.hash_.load(); + return *this; + } + + 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 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: + inline static HashGenerator const hash_gen_{ + HashGenerator::HashType::SHA256}; + + std::variant + data_{none_t{}}; + + mutable atomic_shared_ptr hash_{}; + mutable std::atomic hash_loading_{}; + + 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]] inline auto operator+(Expression const& lhs, + Expression const& rhs) -> Expression { + if (lhs.data_.index() != rhs.data_.index()) { + throw Expression::ExpressionTypeError{ + fmt::format("Cannot add expressions of different type: {} != {}", + lhs.TypeString(), + rhs.TypeString())}; + } + if (not lhs.IsList()) { + throw Expression::ExpressionTypeError{fmt::format( + "Cannot add expressions of type '{}'.", lhs.TypeString())}; + } + auto list = Expression::list_t{}; + auto const& llist = lhs.List(); + auto const& rlist = rhs.List(); + list.reserve(llist.size() + rlist.size()); + list.insert(list.begin(), llist.begin(), llist.end()); + list.insert(list.end(), rlist.begin(), rlist.end()); + return Expression{list}; +} + +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 -- cgit v1.2.3