1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2019 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#ifndef SkZip_DEFINED 9cb93a386Sopenharmony_ci#define SkZip_DEFINED 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ci#include <iterator> 12cb93a386Sopenharmony_ci#include <tuple> 13cb93a386Sopenharmony_ci#include <type_traits> 14cb93a386Sopenharmony_ci#include <utility> 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_ci#include "include/core/SkSpan.h" 17cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 18cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 19cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ci// Take a list of things that can be pointers, and use them all in parallel. The iterators and 22cb93a386Sopenharmony_ci// accessor operator[] for the class produce a tuple of the items. 23cb93a386Sopenharmony_citemplate<typename... Ts> 24cb93a386Sopenharmony_ciclass SkZip { 25cb93a386Sopenharmony_ci using ReturnTuple = std::tuple<Ts&...>; 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci class Iterator { 28cb93a386Sopenharmony_ci public: 29cb93a386Sopenharmony_ci using value_type = ReturnTuple; 30cb93a386Sopenharmony_ci using difference_type = ptrdiff_t; 31cb93a386Sopenharmony_ci using pointer = value_type*; 32cb93a386Sopenharmony_ci using reference = value_type; 33cb93a386Sopenharmony_ci using iterator_category = std::input_iterator_tag; 34cb93a386Sopenharmony_ci constexpr Iterator(const SkZip* zip, size_t index) : fZip{zip}, fIndex{index} { } 35cb93a386Sopenharmony_ci constexpr Iterator(const Iterator& that) : Iterator{ that.fZip, that.fIndex } { } 36cb93a386Sopenharmony_ci constexpr Iterator& operator++() { ++fIndex; return *this; } 37cb93a386Sopenharmony_ci constexpr Iterator operator++(int) { Iterator tmp(*this); operator++(); return tmp; } 38cb93a386Sopenharmony_ci constexpr bool operator==(const Iterator& rhs) const { return fIndex == rhs.fIndex; } 39cb93a386Sopenharmony_ci constexpr bool operator!=(const Iterator& rhs) const { return fIndex != rhs.fIndex; } 40cb93a386Sopenharmony_ci constexpr reference operator*() { return (*fZip)[fIndex]; } 41cb93a386Sopenharmony_ci friend constexpr difference_type operator-(Iterator lhs, Iterator rhs) { 42cb93a386Sopenharmony_ci return lhs.fIndex - rhs.fIndex; 43cb93a386Sopenharmony_ci } 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci private: 46cb93a386Sopenharmony_ci const SkZip* const fZip = nullptr; 47cb93a386Sopenharmony_ci size_t fIndex = 0; 48cb93a386Sopenharmony_ci }; 49cb93a386Sopenharmony_ci 50cb93a386Sopenharmony_ci template<typename T> 51cb93a386Sopenharmony_ci inline static constexpr T* nullify = nullptr; 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_cipublic: 54cb93a386Sopenharmony_ci constexpr SkZip() : fPointers{nullify<Ts>...}, fSize{0} {} 55cb93a386Sopenharmony_ci constexpr SkZip(size_t) = delete; 56cb93a386Sopenharmony_ci constexpr SkZip(size_t size, Ts*... ts) 57cb93a386Sopenharmony_ci : fPointers{ts...} 58cb93a386Sopenharmony_ci , fSize{size} {} 59cb93a386Sopenharmony_ci constexpr SkZip(const SkZip& that) = default; 60cb93a386Sopenharmony_ci constexpr SkZip& operator=(const SkZip &that) = default; 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_ci // Check to see if U can be used for const T or is the same as T 63cb93a386Sopenharmony_ci template <typename U, typename T> 64cb93a386Sopenharmony_ci using CanConvertToConst = typename std::integral_constant<bool, 65cb93a386Sopenharmony_ci std::is_convertible<U*, T*>::value && sizeof(U) == sizeof(T)>::type; 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_ci // Allow SkZip<const T> to be constructed from SkZip<T>. 68cb93a386Sopenharmony_ci template<typename... Us, 69cb93a386Sopenharmony_ci typename = std::enable_if<skstd::conjunction<CanConvertToConst<Us, Ts>...>::value>> 70cb93a386Sopenharmony_ci constexpr SkZip(const SkZip<Us...>& that) 71cb93a386Sopenharmony_ci : fPointers(that.data()) 72cb93a386Sopenharmony_ci , fSize{that.size()} { } 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ci constexpr ReturnTuple operator[](size_t i) const { return this->index(i);} 75cb93a386Sopenharmony_ci constexpr size_t size() const { return fSize; } 76cb93a386Sopenharmony_ci constexpr bool empty() const { return this->size() == 0; } 77cb93a386Sopenharmony_ci constexpr ReturnTuple front() const { return this->index(0); } 78cb93a386Sopenharmony_ci constexpr ReturnTuple back() const { return this->index(this->size() - 1); } 79cb93a386Sopenharmony_ci constexpr Iterator begin() const { return Iterator{this, 0}; } 80cb93a386Sopenharmony_ci constexpr Iterator end() const { return Iterator{this, this->size()}; } 81cb93a386Sopenharmony_ci template<size_t I> constexpr auto get() const { 82cb93a386Sopenharmony_ci return SkMakeSpan(std::get<I>(fPointers), fSize); 83cb93a386Sopenharmony_ci } 84cb93a386Sopenharmony_ci constexpr std::tuple<Ts*...> data() const { return fPointers; } 85cb93a386Sopenharmony_ci constexpr SkZip first(size_t n) const { 86cb93a386Sopenharmony_ci SkASSERT(n <= this->size()); 87cb93a386Sopenharmony_ci if (n == 0) { return SkZip(); } 88cb93a386Sopenharmony_ci return SkZip{n, fPointers}; 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci constexpr SkZip last(size_t n) const { 91cb93a386Sopenharmony_ci SkASSERT(n <= this->size()); 92cb93a386Sopenharmony_ci if (n == 0) { return SkZip(); } 93cb93a386Sopenharmony_ci return SkZip{n, this->pointersAt(fSize - n)}; 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci constexpr SkZip subspan(size_t offset, size_t count) const { 96cb93a386Sopenharmony_ci SkASSERT(offset < this->size()); 97cb93a386Sopenharmony_ci SkASSERT(count <= this->size() - offset); 98cb93a386Sopenharmony_ci if (count == 0) { return SkZip(); } 99cb93a386Sopenharmony_ci return SkZip(count, pointersAt(offset)); 100cb93a386Sopenharmony_ci } 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ciprivate: 103cb93a386Sopenharmony_ci constexpr SkZip(size_t n, const std::tuple<Ts*...>& pointers) 104cb93a386Sopenharmony_ci : fPointers{pointers} 105cb93a386Sopenharmony_ci , fSize{n} {} 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci constexpr ReturnTuple index(size_t i) const { 108cb93a386Sopenharmony_ci SkASSERT(this->size() > 0); 109cb93a386Sopenharmony_ci SkASSERT(i < this->size()); 110cb93a386Sopenharmony_ci return indexDetail(i, std::make_index_sequence<sizeof...(Ts)>{}); 111cb93a386Sopenharmony_ci } 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_ci template<std::size_t... Is> 114cb93a386Sopenharmony_ci constexpr ReturnTuple indexDetail(size_t i, std::index_sequence<Is...>) const { 115cb93a386Sopenharmony_ci return ReturnTuple((std::get<Is>(fPointers))[i]...); 116cb93a386Sopenharmony_ci } 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_ci std::tuple<Ts*...> pointersAt(size_t i) const { 119cb93a386Sopenharmony_ci SkASSERT(this->size() > 0); 120cb93a386Sopenharmony_ci SkASSERT(i < this->size()); 121cb93a386Sopenharmony_ci return pointersAtDetail(i, std::make_index_sequence<sizeof...(Ts)>{}); 122cb93a386Sopenharmony_ci } 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_ci template<std::size_t... Is> 125cb93a386Sopenharmony_ci constexpr std::tuple<Ts*...> pointersAtDetail(size_t i, std::index_sequence<Is...>) const { 126cb93a386Sopenharmony_ci return std::tuple<Ts*...>{&(std::get<Is>(fPointers))[i]...}; 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_ci std::tuple<Ts*...> fPointers; 130cb93a386Sopenharmony_ci size_t fSize; 131cb93a386Sopenharmony_ci}; 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ciclass SkMakeZipDetail { 134cb93a386Sopenharmony_ci template<typename T> struct DecayPointer{ 135cb93a386Sopenharmony_ci using U = typename std::remove_cv<typename std::remove_reference<T>::type>::type; 136cb93a386Sopenharmony_ci using type = typename std::conditional<std::is_pointer<U>::value, U, T>::type; 137cb93a386Sopenharmony_ci }; 138cb93a386Sopenharmony_ci template<typename T> using DecayPointerT = typename DecayPointer<T>::type; 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_ci template<typename C> struct ContiguousMemory { }; 141cb93a386Sopenharmony_ci template<typename T> struct ContiguousMemory<T*> { 142cb93a386Sopenharmony_ci using value_type = T; 143cb93a386Sopenharmony_ci static constexpr value_type* Data(T* t) { return t; } 144cb93a386Sopenharmony_ci static constexpr size_t Size(T* s) { return SIZE_MAX; } 145cb93a386Sopenharmony_ci }; 146cb93a386Sopenharmony_ci template<typename T, size_t N> struct ContiguousMemory<T(&)[N]> { 147cb93a386Sopenharmony_ci using value_type = T; 148cb93a386Sopenharmony_ci static constexpr value_type* Data(T(&t)[N]) { return t; } 149cb93a386Sopenharmony_ci static constexpr size_t Size(T(&)[N]) { return N; } 150cb93a386Sopenharmony_ci }; 151cb93a386Sopenharmony_ci // In general, we don't want r-value collections, but SkSpans are ok, because they are a view 152cb93a386Sopenharmony_ci // onto an actual container. 153cb93a386Sopenharmony_ci template<typename T> struct ContiguousMemory<SkSpan<T>> { 154cb93a386Sopenharmony_ci using value_type = T; 155cb93a386Sopenharmony_ci static constexpr value_type* Data(SkSpan<T> s) { return s.data(); } 156cb93a386Sopenharmony_ci static constexpr size_t Size(SkSpan<T> s) { return s.size(); } 157cb93a386Sopenharmony_ci }; 158cb93a386Sopenharmony_ci // Only accept l-value references to collections. 159cb93a386Sopenharmony_ci template<typename C> struct ContiguousMemory<C&> { 160cb93a386Sopenharmony_ci using value_type = typename std::remove_pointer<decltype(std::declval<C>().data())>::type; 161cb93a386Sopenharmony_ci static constexpr value_type* Data(C& c) { return c.data(); } 162cb93a386Sopenharmony_ci static constexpr size_t Size(C& c) { return c.size(); } 163cb93a386Sopenharmony_ci }; 164cb93a386Sopenharmony_ci template<typename C> using Span = ContiguousMemory<DecayPointerT<C>>; 165cb93a386Sopenharmony_ci template<typename C> using ValueType = typename Span<C>::value_type; 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_ci template<typename C, typename... Ts> struct PickOneSize { }; 168cb93a386Sopenharmony_ci template <typename T, typename... Ts> struct PickOneSize<T*, Ts...> { 169cb93a386Sopenharmony_ci static constexpr size_t Size(T* t, Ts... ts) { 170cb93a386Sopenharmony_ci return PickOneSize<Ts...>::Size(std::forward<Ts>(ts)...); 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci }; 173cb93a386Sopenharmony_ci template <typename T, typename... Ts, size_t N> struct PickOneSize<T(&)[N], Ts...> { 174cb93a386Sopenharmony_ci static constexpr size_t Size(T(&)[N], Ts...) { return N; } 175cb93a386Sopenharmony_ci }; 176cb93a386Sopenharmony_ci template<typename T, typename... Ts> struct PickOneSize<SkSpan<T>, Ts...> { 177cb93a386Sopenharmony_ci static constexpr size_t Size(SkSpan<T> s, Ts...) { return s.size(); } 178cb93a386Sopenharmony_ci }; 179cb93a386Sopenharmony_ci template<typename C, typename... Ts> struct PickOneSize<C&, Ts...> { 180cb93a386Sopenharmony_ci static constexpr size_t Size(C& c, Ts...) { return c.size(); } 181cb93a386Sopenharmony_ci }; 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_cipublic: 184cb93a386Sopenharmony_ci template<typename... Ts> 185cb93a386Sopenharmony_ci static constexpr auto MakeZip(Ts&& ... ts) { 186cb93a386Sopenharmony_ci 187cb93a386Sopenharmony_ci // Pick the first collection that has a size, and use that for the size. 188cb93a386Sopenharmony_ci size_t size = PickOneSize<DecayPointerT<Ts>...>::Size(std::forward<Ts>(ts)...); 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci#ifdef SK_DEBUG 191cb93a386Sopenharmony_ci // Check that all sizes are the same. 192cb93a386Sopenharmony_ci size_t minSize = SIZE_MAX; 193cb93a386Sopenharmony_ci size_t maxSize = 0; 194cb93a386Sopenharmony_ci for (size_t s : {Span<Ts>::Size(std::forward<Ts>(ts))...}) { 195cb93a386Sopenharmony_ci if (s != SIZE_MAX) { 196cb93a386Sopenharmony_ci minSize = std::min(minSize, s); 197cb93a386Sopenharmony_ci maxSize = std::max(maxSize, s); 198cb93a386Sopenharmony_ci } 199cb93a386Sopenharmony_ci } 200cb93a386Sopenharmony_ci SkASSERT(minSize == maxSize); 201cb93a386Sopenharmony_ci#endif 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ci return SkZip<ValueType<Ts>...>{size, Span<Ts>::Data(std::forward<Ts>(ts))...}; 204cb93a386Sopenharmony_ci } 205cb93a386Sopenharmony_ci}; 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_citemplate<typename... Ts> 208cb93a386Sopenharmony_ciinline constexpr auto SkMakeZip(Ts&& ... ts) { 209cb93a386Sopenharmony_ci return SkMakeZipDetail::MakeZip(std::forward<Ts>(ts)...); 210cb93a386Sopenharmony_ci} 211cb93a386Sopenharmony_ci#endif //SkZip_DEFINED 212