Files
revng-revng/include/revng/ADT/ZipMapIterator.h
2024-09-27 12:07:16 +02:00

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));
}