26 using ReturnTuple = std::tuple<Ts&...>;
30 using value_type = ReturnTuple;
31 using difference_type = ptrdiff_t;
32 using pointer = value_type*;
33 using reference = value_type;
34 using iterator_category = std::input_iterator_tag;
35 constexpr Iterator(
const SkZip*
zip,
size_t index) : fZip{
zip}, fIndex{index} { }
36 constexpr Iterator(
const Iterator& that) : Iterator{ that.fZip, that.fIndex } { }
37 constexpr Iterator& operator++() { ++fIndex;
return *
this; }
38 constexpr Iterator operator++(
int) { Iterator tmp(*
this); operator++();
return tmp; }
39 constexpr bool operator==(
const Iterator& rhs)
const {
return fIndex == rhs.fIndex; }
40 constexpr bool operator!=(
const Iterator& rhs)
const {
return fIndex != rhs.fIndex; }
41 constexpr reference operator*() {
return (*fZip)[fIndex]; }
42 friend constexpr difference_type operator-(Iterator lhs, Iterator rhs) {
43 return lhs.fIndex - rhs.fIndex;
47 const SkZip*
const fZip =
nullptr;
52 inline static constexpr T* nullify =
nullptr;
55 constexpr SkZip() : fPointers{nullify<Ts>...}, fSize{0} {}
56 constexpr SkZip(
size_t) =
delete;
64 template <
typename U,
typename T>
66 std::is_convertible<U*, T*>::value &&
sizeof(U) ==
sizeof(
T)>
::type;
69 template<
typename... Us,
70 typename = std::enable_if<std::conjunction<CanConvertToConst<Us, Ts>...>::value>>
72 : fPointers(that.
data())
73 , fSize{that.
size()} { }
75 constexpr ReturnTuple
operator[](
size_t i)
const {
return this->index(i);}
76 constexpr size_t size()
const {
return fSize; }
77 constexpr bool empty()
const {
return this->
size() == 0; }
78 constexpr ReturnTuple
front()
const {
return this->index(0); }
79 constexpr ReturnTuple
back()
const {
return this->index(this->
size() - 1); }
80 constexpr Iterator
begin()
const {
return Iterator{
this, 0}; }
81 constexpr Iterator
end()
const {
return Iterator{
this, this->
size()}; }
82 template<
size_t I>
constexpr auto get()
const {
83 return SkSpan(std::get<I>(fPointers), fSize);
85 constexpr std::tuple<Ts*...>
data()
const {
return fPointers; }
88 if (n == 0) {
return SkZip(); }
89 return SkZip{n, fPointers};
93 if (n == 0) {
return SkZip(); }
94 return SkZip{n, this->pointersAt(fSize - n)};
104 constexpr SkZip(
size_t n,
const std::tuple<Ts*...>& pointers)
105 : fPointers{pointers}
108 constexpr ReturnTuple index(
size_t i)
const {
111 return indexDetail(i, std::make_index_sequence<
sizeof...(Ts)>{});
114 template<std::size_t... Is>
115 constexpr ReturnTuple indexDetail(
size_t i, std::index_sequence<Is...>)
const {
116 return ReturnTuple((std::get<Is>(fPointers))[i]...);
119 std::tuple<Ts*...> pointersAt(
size_t i)
const {
122 return pointersAtDetail(i, std::make_index_sequence<
sizeof...(Ts)>{});
125 template<std::size_t... Is>
126 constexpr std::tuple<Ts*...> pointersAtDetail(
size_t i, std::index_sequence<Is...>)
const {
127 return std::tuple<Ts*...>{&(std::get<Is>(fPointers))[i]...};
130 std::tuple<Ts*...> fPointers;
135 template<
typename T>
struct DecayPointer{
136 using U =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
137 using type =
typename std::conditional<std::is_pointer<U>::value, U,
T>::type;
139 template<
typename T>
using DecayPointerT =
typename DecayPointer<T>::type;
141 template<
typename C>
struct ContiguousMemory { };
142 template<
typename T>
struct ContiguousMemory<
T*> {
143 using value_type =
T;
144 static constexpr value_type* Data(
T* t) {
return t; }
145 static constexpr size_t Size(
T*
s) {
return SIZE_MAX; }
147 template<
typename T,
size_t N>
struct ContiguousMemory<
T(&)[
N]> {
148 using value_type =
T;
149 static constexpr value_type* Data(
T(&t)[
N]) {
return t; }
150 static constexpr size_t Size(
T(&)[
N]) {
return N; }
154 template<
typename T>
struct ContiguousMemory<
SkSpan<
T>> {
155 using value_type =
T;
156 static constexpr value_type* Data(
SkSpan<T> s) {
return s.data(); }
157 static constexpr size_t Size(
SkSpan<T> s) {
return s.size(); }
160 template<
typename C>
struct ContiguousMemory<
C&> {
161 using value_type =
typename std::remove_pointer<decltype(std::declval<C>().data())>
::type;
162 static constexpr value_type* Data(
C& c) {
return c.data(); }
163 static constexpr size_t Size(
C& c) {
return c.size(); }
165 template<
typename C>
using Span = ContiguousMemory<DecayPointerT<C>>;
166 template<
typename C>
using ValueType =
typename Span<C>::value_type;
168 template<
typename C,
typename... Ts>
struct PickOneSize { };
169 template <
typename T,
typename... Ts>
struct PickOneSize<
T*, Ts...> {
170 static constexpr size_t Size(
T* t, Ts... ts) {
171 return PickOneSize<Ts...>::Size(std::forward<Ts>(ts)...);
174 template <
typename T,
typename... Ts,
size_t N>
struct PickOneSize<
T(&)[
N], Ts...> {
175 static constexpr size_t Size(
T(&)[
N], Ts...) {
return N; }
177 template<
typename T,
typename... Ts>
struct PickOneSize<
SkSpan<
T>, Ts...> {
178 static constexpr size_t Size(
SkSpan<T> s, Ts...) {
return s.size(); }
180 template<
typename C,
typename... Ts>
struct PickOneSize<
C&, Ts...> {
181 static constexpr size_t Size(
C& c, Ts...) {
return c.size(); }
185 template<
typename... Ts>
189 size_t size = PickOneSize<DecayPointerT<Ts>...>::Size(std::forward<Ts>(ts)...);
193 size_t minSize = SIZE_MAX;
195 for (
size_t s : {Span<Ts>::Size(std::forward<Ts>(ts))...}) {
197 minSize = std::min(minSize,
s);
198 maxSize = std::max(maxSize,
s);