#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include #include #include #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/iterator.h" #include "revng/ADT/KeyedObjectContainer.h" #include "revng/Support/Assert.h" // clang-format off template concept HasKeyType = requires { typename T::key_type; }; template concept HasMappedType = requires { typename T::mapped_type; }; template concept MapLike = HasKeyType and HasMappedType and std::is_same_v and std::is_same_v; template concept SetLike = HasKeyType and not HasMappedType and std::is_same_v; template concept VectorOfPairs = std::is_same_v>, std::remove_const_t> and std::is_const_v; namespace { using namespace std; static_assert(VectorOfPairs>>, ""); static_assert(VectorOfPairs>>, ""); static_assert(not VectorOfPairs>>, ""); static_assert(not VectorOfPairs>>, ""); } // namespace // clang-format on // // element_pointer_t // template using element_pointer_t = decltype(&*std::declval().begin()); template const typename T::key_type &keyFromValue(const typename T::value_type &Value) { return Value; } template typename T::key_type keyFromValue(const typename T::value_type &Value) { return KeyedObjectTraits::key(Value); } template const typename T::value_type::first_type & keyFromValue(const typename T::value_type &Value) { return Value.first; } template const typename T::value_type::first_type & keyFromValue(const typename T::value_type &Value) { return Value.first; } template struct DefaultComparator { template static int compare(const T &LHS, const Q &RHS) { auto LHSKey = keyFromValue(LHS); auto RHSKey = keyFromValue(RHS); static_assert(std::is_same_v); auto Less = std::less(); if (Less(LHSKey, RHSKey)) return -1; else if (Less(RHSKey, LHSKey)) return 1; else return 0; } }; template using zipmap_pair = std::pair, element_pointer_t>; namespace revng::detail { template using fifc = llvm::iterator_facade_base; } template> class ZipMapIterator : public revng::detail::fifc, const zipmap_pair> { public: template using conditional_t = typename std::conditional::type; using left_inner_iterator = conditional_t, typename LeftMap::const_iterator, typename LeftMap::iterator>; using right_inner_iterator = conditional_t, typename RightMap::const_iterator, typename RightMap::iterator>; using left_inner_range = llvm::iterator_range; using right_inner_range = llvm::iterator_range; using value_type = zipmap_pair; using reference = typename ZipMapIterator::reference; private: value_type Current; left_inner_iterator LeftIt; const left_inner_iterator EndLeftIt; right_inner_iterator RightIt; const right_inner_iterator EndRightIt; public: ZipMapIterator(left_inner_range LeftRange, right_inner_range RightRange) : LeftIt(LeftRange.begin()), EndLeftIt(LeftRange.end()), RightIt(RightRange.begin()), EndRightIt(RightRange.end()) { next(); } ZipMapIterator(left_inner_iterator LeftIt, right_inner_iterator RightIt) : ZipMapIterator(llvm::make_range(LeftIt, LeftIt), llvm::make_range(RightIt, RightIt)) {} bool operator==(const ZipMapIterator &Other) const { revng_assert(EndLeftIt == Other.EndLeftIt); revng_assert(EndRightIt == Other.EndRightIt); auto ThisTie = std::tie(LeftIt, RightIt, Current); auto OtherTie = std::tie(Other.LeftIt, Other.RightIt, Other.Current); return ThisTie == OtherTie; } ZipMapIterator &operator++() { next(); return *this; } reference operator*() const { return Current; } private: bool leftIsValid() const { return LeftIt != EndLeftIt; } bool rightIsValid() const { return RightIt != EndRightIt; } void next() { if (leftIsValid() and rightIsValid()) { switch (Comparator::compare(*LeftIt, *RightIt)) { case 0: Current = decltype(Current)(&*LeftIt, &*RightIt); LeftIt++; RightIt++; break; case -1: Current = std::make_pair(&*LeftIt, nullptr); LeftIt++; break; case 1: Current = std::make_pair(nullptr, &*RightIt); RightIt++; break; default: revng_abort(); } } else if (leftIsValid()) { Current = std::make_pair(&*LeftIt, nullptr); LeftIt++; } else if (rightIsValid()) { Current = std::make_pair(nullptr, &*RightIt); RightIt++; } else { Current = std::make_pair(nullptr, nullptr); } } }; template> inline ZipMapIterator zipmap_begin(LeftMap &Left, RightMap &Right) { return ZipMapIterator(llvm::make_range(Left.begin(), Left.end()), llvm::make_range(Right.begin(), Right.end())); } template> inline ZipMapIterator zipmap_end(LeftMap &Left, RightMap &Right) { return ZipMapIterator(llvm::make_range(Left.end(), Left.end()), llvm::make_range(Right.end(), Right.end())); } template> inline llvm::iterator_range> zipmap_range(LeftMap &Left, RightMap &Right) { return llvm::make_range(zipmap_begin(Left, Right), zipmap_end(Left, Right)); }