#ifndef BASE_CONTAINERS_CHECKED_ITERATORS_H_
#define BASE_CONTAINERS_CHECKED_ITERATORS_H_
#include <concepts>
#include <iterator>
#include <memory>
#include <type_traits>
#include "base/check.h"
#include "base/compiler_specific.h"
#include "base/containers/span_forward_internal.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "build/build_config.h"
namespace base {
template <typename T>
class CheckedContiguousIterator {
public:
using difference_type = std::ptrdiff_t;
using value_type = std::remove_cv_t<T>;
using pointer = T*;
using reference = T&;
using iterator_category = std::contiguous_iterator_tag;
using iterator_concept = std::contiguous_iterator_tag;
template <typename U>
friend class CheckedContiguousIterator;
template <typename Ptr>
friend struct std::pointer_traits;
constexpr CheckedContiguousIterator() = default;
UNSAFE_BUFFER_USAGE constexpr CheckedContiguousIterator(T* start,
const T* end)
: CheckedContiguousIterator(AssumeValid(start, start, end)) {
CHECK(start <= end);
}
UNSAFE_BUFFER_USAGE constexpr CheckedContiguousIterator(const T* start,
T* current,
const T* end)
: CheckedContiguousIterator(AssumeValid(start, current, end)) {
CHECK(start <= current);
CHECK(current <= end);
}
constexpr CheckedContiguousIterator(const CheckedContiguousIterator& other) =
default;
template <typename U>
constexpr CheckedContiguousIterator(const CheckedContiguousIterator<U>& other)
requires(std::convertible_to<U (*)[], T (*)[]>)
: start_(other.start_), current_(other.current_), end_(other.end_) {
DCHECK(other.start_ <= other.current_);
DCHECK(other.current_ <= other.end_);
}
~CheckedContiguousIterator() = default;
constexpr CheckedContiguousIterator& operator=(
const CheckedContiguousIterator& other) = default;
friend constexpr bool operator==(const CheckedContiguousIterator& lhs,
const CheckedContiguousIterator& rhs) {
lhs.CheckComparable(rhs);
return lhs.current_ == rhs.current_;
}
friend constexpr auto operator<=>(const CheckedContiguousIterator& lhs,
const CheckedContiguousIterator& rhs) {
lhs.CheckComparable(rhs);
return lhs.current_ <=> rhs.current_;
}
constexpr CheckedContiguousIterator& operator++() {
CHECK(current_ != end_);
UNSAFE_BUFFERS(++current_);
return *this;
}
constexpr CheckedContiguousIterator operator++(int) {
CheckedContiguousIterator old = *this;
++*this;
return old;
}
constexpr CheckedContiguousIterator& operator--() {
CHECK(current_ != start_);
UNSAFE_BUFFERS(--current_);
return *this;
}
constexpr CheckedContiguousIterator operator--(int) {
CheckedContiguousIterator old = *this;
--*this;
return old;
}
constexpr CheckedContiguousIterator& operator+=(difference_type rhs) {
CHECK(rhs <= end_ - current_);
CHECK(rhs >= start_ - current_);
UNSAFE_BUFFERS(current_ += rhs);
return *this;
}
constexpr CheckedContiguousIterator operator+(difference_type rhs) const {
CheckedContiguousIterator it = *this;
it += rhs;
return it;
}
constexpr friend CheckedContiguousIterator operator+(
difference_type lhs,
const CheckedContiguousIterator& rhs) {
return rhs + lhs;
}
constexpr CheckedContiguousIterator& operator-=(difference_type rhs) {
CHECK(rhs >= current_ - end_);
CHECK(rhs <= current_ - start_);
UNSAFE_BUFFERS(current_ -= rhs);
return *this;
}
constexpr CheckedContiguousIterator operator-(difference_type rhs) const {
CheckedContiguousIterator it = *this;
it -= rhs;
return it;
}
constexpr friend difference_type operator-(
const CheckedContiguousIterator& lhs,
const CheckedContiguousIterator& rhs) {
lhs.CheckComparable(rhs);
return lhs.current_ - rhs.current_;
}
constexpr reference operator*() const {
CHECK(current_ != end_);
return *current_;
}
constexpr pointer operator->() const {
CHECK(current_ != end_);
return current_;
}
constexpr reference operator[](difference_type rhs) const {
CHECK(rhs >= start_ - current_);
CHECK(rhs < end_ - current_);
return UNSAFE_BUFFERS(current_[rhs]);
}
private:
template <typename, size_t, typename>
friend class span;
struct AssumeValid {
RAW_PTR_EXCLUSION const T* start;
RAW_PTR_EXCLUSION T* current;
RAW_PTR_EXCLUSION const T* end;
};
constexpr explicit CheckedContiguousIterator(AssumeValid pointers)
: start_(pointers.start),
current_(pointers.current),
end_(pointers.end) {}
constexpr void CheckComparable(const CheckedContiguousIterator& other) const {
CHECK(start_ == other.start_);
CHECK(end_ == other.end_);
}
RAW_PTR_EXCLUSION const T* start_ = nullptr;
RAW_PTR_EXCLUSION T* current_ = nullptr;
RAW_PTR_EXCLUSION const T* end_ = nullptr;
};
template <typename T>
using CheckedContiguousConstIterator = CheckedContiguousIterator<const T>;
}
template <typename T>
struct std::pointer_traits<::base::CheckedContiguousIterator<T>> {
using pointer = ::base::CheckedContiguousIterator<T>;
using element_type = T;
using difference_type = ptrdiff_t;
template <typename U>
using rebind = ::base::CheckedContiguousIterator<U>;
static constexpr pointer pointer_to(element_type& r) noexcept {
return pointer(&r, &r);
}
static constexpr element_type* to_address(pointer p) noexcept {
return p.current_;
}
};
#endif