#pragma once
#include "ZXAlgorithms.h"
#include <cstdint>
#include <iterator>
namespace ZXing {
template <typename Iterator>
struct StrideIter
{
Iterator pos;
int stride;
using iterator_category = std::random_access_iterator_tag;
using difference_type = typename std::iterator_traits<Iterator>::difference_type;
using value_type = typename std::iterator_traits<Iterator>::value_type;
using pointer = Iterator;
using reference = typename std::iterator_traits<Iterator>::reference;
auto operator*() const { return *pos; }
auto operator[](int i) const { return *(pos + i * stride); }
StrideIter<Iterator>& operator++() { return pos += stride, *this; }
StrideIter<Iterator> operator++(int) { auto temp = *this; ++*this; return temp; }
bool operator==(const StrideIter<Iterator>& rhs) const { return pos == rhs.pos; }
bool operator!=(const StrideIter<Iterator>& rhs) const { return pos != rhs.pos; }
StrideIter<Iterator> operator+(int i) const { return {pos + i * stride, stride}; }
StrideIter<Iterator> operator-(int i) const { return {pos - i * stride, stride}; }
int operator-(const StrideIter<Iterator>& rhs) const { return narrow_cast<int>((pos - rhs.pos) / stride); }
};
template <typename Iterator>
StrideIter(const Iterator&, int) -> StrideIter<Iterator>;
template <typename Iterator>
struct Range
{
Iterator _begin, _end;
Range(Iterator b, Iterator e) : _begin(b), _end(e) {}
template <typename C>
Range(const C& c) : _begin(std::begin(c)), _end(std::end(c)) {}
Iterator begin() const noexcept { return _begin; }
Iterator end() const noexcept { return _end; }
explicit operator bool() const { return begin() < end(); }
int size() const { return narrow_cast<int>(end() - begin()); }
};
template <typename C>
Range(const C&) -> Range<typename C::const_iterator>;
template <typename T>
class ArrayView
{
const T* _data = nullptr;
std::size_t _size = 0;
public:
using value_type = T;
using pointer = const value_type*;
using const_pointer = const value_type*;
using reference = const value_type&;
using const_reference = const value_type&;
using size_type = std::size_t;
constexpr ArrayView() noexcept = default;
constexpr ArrayView(pointer data, size_type size) noexcept : _data(data), _size(size) {}
template <typename P, typename U = T,
typename = std::enable_if_t<
sizeof(U) == 1 && std::is_same_v<void, std::remove_cv_t<std::remove_reference_t<std::remove_pointer_t<P>>>>>>
constexpr ArrayView(P data, size_type size) noexcept : _data(reinterpret_cast<pointer>(data)), _size(size)
{}
template <typename Container,
typename = std::enable_if_t<std::is_convertible_v<decltype(std::data(std::declval<Container&>())), const_pointer>>>
constexpr ArrayView(const Container& c) noexcept : _data(std::data(c)), _size(std::size(c))
{}
constexpr pointer data() const noexcept { return _data; }
constexpr size_type size() const noexcept { return _size; }
constexpr bool empty() const noexcept { return _size == 0; }
constexpr const_reference operator[](size_type index) const noexcept { return _data[index]; }
constexpr pointer begin() const noexcept { return _data; }
constexpr pointer end() const noexcept { return _data + _size; }
constexpr ArrayView<T> subview(size_type pos, size_type len = size_type(-1)) const noexcept
{
if (pos > _size)
return {};
return {_data + pos, std::min(len, _size - pos)};
}
};
using ByteView = ArrayView<uint8_t>;
}