#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include "revng/ADT/CompilationTime.h" #include "revng/ADT/Concepts.h" #include "revng/Model/DynamicFunction.h" #include "revng/Model/Function.h" #include "revng/Model/Segment.h" // // The following helpers are designed to help with handling metadata. // // Metadata are some common fields appearing in different (sometimes unrelated) // types within the model. These helpers allow to work with such fields in // a generic manner. namespace model { // Every supported metadata field should have an `EntityWithXXX` concept // declared for it. template concept EntityWithKey = requires(const Type &Value) { { Value.key() } -> std::convertible_to; }; template concept EntityWithName = requires(const Type &Value) { { Value.Name() } -> std::convertible_to; }; template concept EntityWithComment = requires(const Type &Value) { { Value.Comment() } -> std::convertible_to; }; template concept EntityWithReturnValueComment = requires(const Type &Value) { { Value.ReturnValueComment() } -> std::convertible_to; }; template void ensureCompatibility() { static_assert(EntityWithName || EntityWithComment || EntityWithReturnValueComment, "This would be a no-op."); } template LHS ©Metadata(LHS &To, const RHS &From) { ensureCompatibility(); ensureCompatibility(); if constexpr (EntityWithName && EntityWithName) To.Name() = From.Name(); if constexpr (EntityWithComment && EntityWithComment) To.Comment() = From.Comment(); if constexpr (EntityWithReturnValueComment && EntityWithReturnValueComment) { To.ReturnValueComment() = From.ReturnValueComment(); } return To; } template LHS &moveMetadata(LHS &To, const RHS &From) { ensureCompatibility(); ensureCompatibility(); if constexpr (EntityWithName && EntityWithName) To.Name() = std::move(From.Name()); if constexpr (EntityWithComment && EntityWithComment) To.Comment() = std::move(From.Comment()); if constexpr (EntityWithReturnValueComment && EntityWithReturnValueComment) { To.ReturnValueComment() = std::move(From.ReturnValueComment()); } return To; } template bool hasMetadata(const Type &Value) { ensureCompatibility(); if constexpr (EntityWithName) if (!Value.Name().empty()) return true; if constexpr (EntityWithComment) if (!Value.Comment().empty()) return true; if constexpr (EntityWithReturnValueComment) if (!Value.ReturnValueComment().empty()) return true; return false; } } // namespace model