// Take a list of things that can be pointers, and use them all in parallel. The iterators and // accessor operator[] for the class produce a tuple of the items. template<typename... Ts> class SkZip { using ReturnTuple = std::tuple<Ts&...>;
// Check to see if U can be used for const T or is the same as T template <typename U, typename T> using CanConvertToConst = typename std::integral_constant<bool,
std::is_convertible<U*, T*>::value && sizeof(U) == sizeof(T)>::type;
// Allow SkZip<const T> to be constructed from SkZip<T>. template<typename... Us, typename = std::enable_if<std::conjunction<CanConvertToConst<Us, Ts>...>::value>>
constexpr SkZip(const SkZip<Us...>& that) : fPointers(that.data()), fSize(that.size()) {}
class SkMakeZipDetail { template<typename T> struct DecayPointer{ using U = typename std::remove_cv<typename std::remove_reference<T>::type>::type; using type = typename std::conditional<std::is_pointer<U>::value, U, T>::type;
}; template<typename T> using DecayPointerT = typename DecayPointer<T>::type;
template<typename C> struct ContiguousMemory {}; template<typename T> struct ContiguousMemory<T*> { using value_type = T; static constexpr value_type* Data(T* t) { return t; } static constexpr size_t Size(T* s) { return SIZE_MAX; }
}; template<typename T, size_t N> struct ContiguousMemory<T(&)[N]> { using value_type = T; static constexpr value_type* Data(T(&t)[N]) { return t; } static constexpr size_t Size(T(&)[N]) { return N; }
}; // In general, we don't want r-value collections, but SkSpans are ok, because they are a view // onto an actual container. template<typename T> struct ContiguousMemory<SkSpan<T>> { using value_type = T; static constexpr value_type* Data(SkSpan<T> s) { return s.data(); } static constexpr size_t Size(SkSpan<T> s) { return s.size(); }
}; // Only accept l-value references to collections. template<typename C> struct ContiguousMemory<C&> { using value_type = typename std::remove_pointer<decltype(std::declval<C>().data())>::type; static constexpr value_type* Data(C& c) { return c.data(); } static constexpr size_t Size(C& c) { return c.size(); }
}; template<typename C> using Span = ContiguousMemory<DecayPointerT<C>>; template<typename C> using ValueType = typename Span<C>::value_type;
public: template<typename... Ts> static constexpr auto MakeZip(Ts&& ... ts) {
// Pick the first collection that has a size, and use that for the size.
size_t size = PickOneSize<DecayPointerT<Ts>...>::Size(std::forward<Ts>(ts)...);
#ifdef SK_DEBUG // Check that all sizes are the same.
size_t minSize = SIZE_MAX;
size_t maxSize = 0;
size_t sizes[sizeof...(Ts)] = {Span<Ts>::Size(std::forward<Ts>(ts))...}; for (size_t s : sizes) { if (s != SIZE_MAX) {
minSize = std::min(minSize, s);
maxSize = std::max(maxSize, s);
}
}
SkASSERT(minSize == maxSize); #endif
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.