blob: 4ff6a7d7e6c97ba4ecc414bc827a7b12870ba4d1 [file]
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <compare>
#include <iterator>
#include <utility>
namespace android {
namespace detail {
// A few useful aliases to not repeat them everywhere
template <class It1, class It2>
using Value = std::pair<typename std::iterator_traits<It1>::value_type,
typename std::iterator_traits<It2>::value_type>;
template <class It1, class It2>
using BaseRefPair = std::pair<typename std::iterator_traits<It1>::reference,
typename std::iterator_traits<It2>::reference>;
template <class It1, class It2>
struct RefPair : BaseRefPair<It1, It2> {
using Base = BaseRefPair<It1, It2>;
using Value = detail::Value<It1, It2>;
RefPair(It1 it1, It2 it2) : Base(*it1, *it2) {
}
RefPair& operator=(const Value& v) {
this->first = v.first;
this->second = v.second;
return *this;
}
operator Value() const {
return Value(this->first, this->second);
}
bool operator==(const RefPair& other) {
return this->first == other.first;
}
bool operator==(const Value& other) {
return this->first == other.first;
}
std::strong_ordering operator<=>(const RefPair& other) const {
return this->first <=> other.first;
}
std::strong_ordering operator<=>(const Value& other) const {
return this->first <=> other.first;
}
friend void swap(RefPair& l, RefPair& r) {
using std::swap;
swap(l.first, r.first);
swap(l.second, r.second);
}
};
template <class It1, class It2>
struct RefPairPtr {
RefPair<It1, It2> value;
RefPair<It1, It2>* operator->() const {
return &value;
}
};
} // namespace detail
//
// CombinedIterator - a class to combine two iterators to process them as a single iterator to a
// pair of values. Useful for processing a data structure of "struct of arrays", replacing
// array of structs for cache locality.
//
// The value type is a pair of copies of the values of each iterator, and the reference is a
// pair of references to the corresponding values. Comparison only compares the first element,
// making it most useful for using on data like (vector<Key>, vector<Value>) for binary searching,
// sorting both together and so on.
//
// The class is designed for handling arrays, so it requires random access iterators as an input.
//
template <class It1, class It2>
requires std::random_access_iterator<It1> && std::random_access_iterator<It2>
struct CombinedIterator {
typedef detail::Value<It1, It2> value_type;
typedef detail::RefPair<It1, It2> reference;
typedef std::ptrdiff_t difference_type;
typedef detail::RefPairPtr<It1, It2> pointer;
typedef std::random_access_iterator_tag iterator_category;
CombinedIterator(It1 it1 = {}, It2 it2 = {}) : it1(it1), it2(it2) {
}
bool operator<(const CombinedIterator& other) const {
return it1 < other.it1;
}
bool operator<=(const CombinedIterator& other) const {
return it1 <= other.it1;
}
bool operator>(const CombinedIterator& other) const {
return it1 > other.it1;
}
bool operator>=(const CombinedIterator& other) const {
return it1 >= other.it1;
}
bool operator==(const CombinedIterator& other) const {
return it1 == other.it1;
}
pointer operator->() const {
return pointer{{it1, it2}};
}
reference operator*() const {
return {it1, it2};
}
reference operator[](difference_type n) const {
return {it1 + n, it2 + n};
}
CombinedIterator& operator++() {
++it1;
++it2;
return *this;
}
CombinedIterator operator++(int) {
const auto res = *this;
++*this;
return res;
}
CombinedIterator& operator--() {
--it1;
--it2;
return *this;
}
CombinedIterator operator--(int) {
const auto res = *this;
--*this;
return res;
}
CombinedIterator& operator+=(difference_type n) {
it1 += n;
it2 += n;
return *this;
}
CombinedIterator operator+(difference_type n) const {
CombinedIterator res = *this;
return res += n;
}
CombinedIterator& operator-=(difference_type n) {
it1 -= n;
it2 -= n;
return *this;
}
CombinedIterator operator-(difference_type n) const {
CombinedIterator res = *this;
return res -= n;
}
difference_type operator-(const CombinedIterator& other) {
return it1 - other.it1;
}
It1 it1;
It2 it2;
};
} // namespace android