mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
246 lines
7.8 KiB
C++
246 lines
7.8 KiB
C++
#pragma once
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <iterator>
|
|
#include <set>
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/iterator.h"
|
|
|
|
#include "revng/ADT/KeyedObjectContainer.h"
|
|
#include "revng/Support/Assert.h"
|
|
|
|
template<typename T>
|
|
concept HasKeyType = requires { typename T::key_type; };
|
|
|
|
template<typename T>
|
|
concept HasMappedType = requires { typename T::mapped_type; };
|
|
|
|
template<typename T>
|
|
concept MapLike = HasKeyType<T> and HasMappedType<T>
|
|
and std::is_same_v<const typename T::value_type::first_type,
|
|
const typename T::key_type>
|
|
and std::is_same_v<typename T::value_type::second_type,
|
|
typename T::mapped_type>;
|
|
|
|
template<typename T>
|
|
concept SetLike = HasKeyType<T> and not HasMappedType<T>
|
|
and std::is_same_v<typename T::key_type,
|
|
typename T::value_type>;
|
|
|
|
template<typename T>
|
|
concept VectorOfPairs = std::is_same_v<std::vector<std::pair<
|
|
typename T::value_type::first_type,
|
|
typename T::value_type::second_type>>,
|
|
std::remove_const_t<T>>
|
|
and std::is_const_v<typename T::value_type::first_type>;
|
|
|
|
namespace {
|
|
|
|
using namespace std;
|
|
|
|
static_assert(VectorOfPairs<const vector<pair<const int, long>>>, "");
|
|
static_assert(VectorOfPairs<vector<pair<const int, long>>>, "");
|
|
static_assert(not VectorOfPairs<const vector<pair<int, long>>>, "");
|
|
static_assert(not VectorOfPairs<vector<pair<int, long>>>, "");
|
|
|
|
} // namespace
|
|
|
|
//
|
|
// element_pointer_t
|
|
//
|
|
template<typename T>
|
|
using element_pointer_t = decltype(&*std::declval<T>().begin());
|
|
|
|
template<SetLike T>
|
|
const typename T::key_type &keyFromValue(const typename T::value_type &Value) {
|
|
return Value;
|
|
}
|
|
|
|
template<KeyedObjectContainer T>
|
|
typename T::key_type keyFromValue(const typename T::value_type &Value) {
|
|
return KeyedObjectTraits<typename T::value_type>::key(Value);
|
|
}
|
|
|
|
template<VectorOfPairs T>
|
|
const typename T::value_type::first_type &
|
|
keyFromValue(const typename T::value_type &Value) {
|
|
return Value.first;
|
|
}
|
|
|
|
template<MapLike T>
|
|
const typename T::value_type::first_type &
|
|
keyFromValue(const typename T::value_type &Value) {
|
|
return Value.first;
|
|
}
|
|
|
|
template<typename T>
|
|
concept HasFirstMethod = requires(const T::value_type &V) {
|
|
{ V.first() };
|
|
};
|
|
|
|
template<HasFirstMethod T>
|
|
auto keyFromValue(const typename T::value_type &Value) {
|
|
return Value.first();
|
|
}
|
|
|
|
template<typename LeftMap, typename RightMap>
|
|
struct DefaultComparator {
|
|
template<typename T, typename Q>
|
|
static int compare(const T &LHS, const Q &RHS) {
|
|
auto LHSKey = keyFromValue<LeftMap>(LHS);
|
|
auto RHSKey = keyFromValue<RightMap>(RHS);
|
|
static_assert(std::is_same_v<decltype(LHSKey), decltype(RHSKey)>);
|
|
auto Less = std::less<decltype(LHSKey)>();
|
|
if (Less(LHSKey, RHSKey))
|
|
return -1;
|
|
else if (Less(RHSKey, LHSKey))
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
template<typename LeftMap, typename RightMap>
|
|
using zipmap_pair = std::pair<element_pointer_t<LeftMap>,
|
|
element_pointer_t<RightMap>>;
|
|
|
|
namespace revng::detail {
|
|
template<typename A, typename B>
|
|
using fifc = llvm::iterator_facade_base<A, std::forward_iterator_tag, B>;
|
|
}
|
|
|
|
template<typename LeftMap,
|
|
typename RightMap,
|
|
typename Comparator = DefaultComparator<LeftMap, RightMap>>
|
|
class ZipMapIterator
|
|
: public revng::detail::fifc<ZipMapIterator<LeftMap, RightMap, Comparator>,
|
|
const zipmap_pair<LeftMap, RightMap>> {
|
|
public:
|
|
template<bool C, typename A, typename B>
|
|
using conditional_t = typename std::conditional<C, A, B>::type;
|
|
using left_inner_iterator = conditional_t<std::is_const_v<LeftMap>,
|
|
typename LeftMap::const_iterator,
|
|
typename LeftMap::iterator>;
|
|
using right_inner_iterator = conditional_t<std::is_const_v<RightMap>,
|
|
typename RightMap::const_iterator,
|
|
typename RightMap::iterator>;
|
|
using left_inner_range = llvm::iterator_range<left_inner_iterator>;
|
|
using right_inner_range = llvm::iterator_range<right_inner_iterator>;
|
|
using value_type = zipmap_pair<LeftMap, RightMap>;
|
|
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<typename LeftMap,
|
|
typename RightMap,
|
|
typename Comparator = DefaultComparator<LeftMap, RightMap>>
|
|
inline ZipMapIterator<LeftMap, RightMap, Comparator>
|
|
zipmap_begin(LeftMap &Left, RightMap &Right) {
|
|
return ZipMapIterator<LeftMap,
|
|
RightMap,
|
|
Comparator>(llvm::make_range(Left.begin(), Left.end()),
|
|
llvm::make_range(Right.begin(),
|
|
Right.end()));
|
|
}
|
|
|
|
template<typename LeftMap,
|
|
typename RightMap,
|
|
typename Comparator = DefaultComparator<LeftMap, RightMap>>
|
|
inline ZipMapIterator<LeftMap, RightMap, Comparator>
|
|
zipmap_end(LeftMap &Left, RightMap &Right) {
|
|
return ZipMapIterator<LeftMap,
|
|
RightMap,
|
|
Comparator>(llvm::make_range(Left.end(), Left.end()),
|
|
llvm::make_range(Right.end(), Right.end()));
|
|
}
|
|
|
|
template<typename LeftMap,
|
|
typename RightMap,
|
|
typename Comparator = DefaultComparator<LeftMap, RightMap>>
|
|
inline llvm::iterator_range<ZipMapIterator<LeftMap, RightMap, Comparator>>
|
|
zipmap_range(LeftMap &Left, RightMap &Right) {
|
|
return llvm::make_range(zipmap_begin<LeftMap, RightMap, Comparator>(Left,
|
|
Right),
|
|
zipmap_end<LeftMap, RightMap, Comparator>(Left,
|
|
Right));
|
|
}
|