#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "revng/ADT/Concepts.h" #include "revng/Support/Debug.h" // // is_specialization // template class Ref> struct is_specialization : std::false_type {}; template class Ref, typename... Args> struct is_specialization, Ref> : std::true_type {}; template class Ref, typename... Args> struct is_specialization, Ref> : std::true_type {}; template class Ref> constexpr bool is_specialization_v = is_specialization::value; static_assert(is_specialization_v, std::vector>); static_assert(is_specialization_v, std::vector>); static_assert(is_specialization_v, std::pair>); // // always_true and always_false // // Since an assert in the `else` branch of an `if_constexpr` condition said // branch gets instantiated if it doesn't depend on a template, these provide // an easy way to "fake" dependence on an arbitrary template parameter. // template struct type_always_false { constexpr static bool value = false; }; template constexpr inline bool type_always_false_v = type_always_false::value; template struct value_always_false { constexpr static bool value = false; }; template constexpr inline bool value_always_false_v = value_always_false::value; template struct type_always_true { constexpr static bool value = false; }; template constexpr inline bool type_always_true_v = type_always_true::value; template struct value_always_true { constexpr static bool value = false; }; template constexpr inline bool value_always_true_v = value_always_true::value; // // HasTupleSize // template concept HasTupleSize = requires { typename std::tuple_size::type; { std::tuple_size_v } -> convertible_to; }; static_assert(HasTupleSize>); static_assert(!HasTupleSize>); static_assert(!HasTupleSize); // // IsTupleLike // namespace revng::detail { template concept HasTupleElement = requires(T Value) { typename std::tuple_element_t>; { get(Value) } -> convertible_to &>; }; template constexpr auto checkTupleElementTypes(std::index_sequence) { return (HasTupleElement && ...); } template constexpr auto checkAllTupleElementTypes() { auto Sequence = std::make_index_sequence>(); return checkTupleElementTypes(Sequence); } } // namespace revng::detail // clang-format off template concept IsTupleLike = (not std::is_reference_v and HasTupleSize and revng::detail::checkAllTupleElementTypes()); // clang-format on static_assert(IsTupleLike>); static_assert(IsTupleLike>); static_assert(IsTupleLike>); static_assert(IsTupleLike>); static_assert(not IsTupleLike); //===----------------------------------------------------------------------===// // Extra additions to //===----------------------------------------------------------------------===// namespace revng { namespace detail { template using ReturnType = decltype(std::declval()(*std::declval())); template> class ProxyMappedIteratorImpl : public llvm::mapped_iterator { struct IteratorProxy { IteratorProxy(FuncReturnTy &&Value) : Temporary(std::move(Value)) {} FuncReturnTy *const operator->() { return &Temporary; } FuncReturnTy const *const operator->() const { return &Temporary; } private: FuncReturnTy Temporary; }; public: using llvm::mapped_iterator::mapped_iterator; using reference = std::decay_t; IteratorProxy operator->() { return llvm::mapped_iterator::operator*(); } IteratorProxy const operator->() const { return llvm::mapped_iterator::operator*(); } }; template using ItImpl = std::conditional_t>, ProxyMappedIteratorImpl, llvm::mapped_iterator>; } // namespace detail /// `revng::mapped_iterator` is a specialized version of /// `llvm::mapped_iterator`. /// /// It can act as an in-place replacement since it doesn't change the behavior /// in most cases. The main difference is the fact that when the iterator uses /// a temporary as a way of remembering its position its lifetime is /// explicitly prolonged to prevent it from being deleted prematurely (like /// inside the `operator->` call). template using mapped_iterator = revng::detail::ItImpl; // `map_iterator` - Provide a convenient way to create `mapped_iterator`s, // just like `make_pair` is useful for creating pairs... template inline auto map_iterator(ItTy I, FuncTy F) { return mapped_iterator(std::move(I), std::move(F)); }; template auto map_range(ContainerTy &&C, FuncTy F) { return llvm::make_range(map_iterator(C.begin(), F), map_iterator(C.end(), F)); } auto dereferenceIterator(auto Iter) { return llvm::map_iterator(Iter, [](const auto &Ptr) -> decltype(*Ptr) & { return *Ptr; }); } namespace detail { template using DIT = decltype(dereferenceIterator(std::declval())); } template using DereferenceIteratorType = revng::detail::DIT; auto dereferenceRange(auto &&Range) { return llvm::make_range(dereferenceIterator(Range.begin()), dereferenceIterator(Range.end())); } template auto mapToValueIterator(Iterator It) { const auto GetSecond = [](auto &Pair) -> auto & { return Pair.second; }; return llvm::map_iterator(It, GetSecond); } template using MapToValueIteratorType = decltype(mapToValueIterator(std::declval())); } // namespace revng template inline auto skip(unsigned ToSkip, C &&Container) -> llvm::iterator_range { auto Begin = std::begin(Container); while (ToSkip-- > 0) Begin++; return llvm::make_range(Begin, std::end(Container)); } // // slice // /// Copy into a std::array a slice of an llvm::ArrayRef template std::array slice(llvm::ArrayRef Old) { std::array Result; auto StartIt = Old.begin() + Start; std::copy(StartIt, StartIt + Size, Result.begin()); return Result; } /// Copy into a std::array a slice of a std::array template std::array slice(const std::array &Old) { std::array Result; auto StartIt = Old.begin() + Start; std::copy(StartIt, StartIt + Size, Result.begin()); return Result; } /// \brief Simple helper function asserting a pointer is not a `nullptr` template inline T *notNull(T *Pointer) { revng_assert(Pointer != nullptr); return Pointer; } inline llvm::ArrayRef toArrayRef(llvm::StringRef Data) { auto Pointer = reinterpret_cast(Data.data()); return llvm::makeArrayRef(Pointer, Data.size()); } // // append // template auto append(FromType &&From, ToType &To) { size_t ExistingElementCount = To.size(); To.resize(ExistingElementCount + From.size()); return llvm::copy(From, std::next(To.begin(), ExistingElementCount)); }