Reland "SkZip - synchronized indexing of several pointers"
This is a reland of f3c4a829c6
Original change's description:
> SkZip - synchronized indexing of several pointers
>
> This is the mechanism for syncing a bunch of things with
> contiguous memory like vector<>, array<> and SkSpan<>.
>
> In a following CL, a convenience function SkMakeZip will
> easily convert most containers into a zip.
>
> Change-Id: Icda5b1774ae21c4c163a663f6d2b0f119f63ccba
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/240200
> Commit-Queue: Herb Derby <herb@google.com>
> Reviewed-by: Ben Wagner <bungeman@google.com>
Change-Id: I7d1a91a9c35dde721147bb3c1f23c9b3a8d59d04
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/242476
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
parent
1ba169135a
commit
c44ee1a263
@ -405,6 +405,7 @@ skia_core_sources = [
|
||||
"$_src/core/SkYUVPlanesCache.h",
|
||||
"$_src/core/SkYUVASizeInfo.cpp",
|
||||
"$_src/core/SkYUVMath.cpp",
|
||||
"$_src/core/SkZip.h",
|
||||
|
||||
"$_src/image/SkImage.cpp",
|
||||
|
||||
|
@ -9,9 +9,6 @@
|
||||
#define SkSpan_DEFINED
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "include/private/SkTo.h"
|
||||
|
||||
template <typename T>
|
||||
|
79
src/core/SkZip.h
Normal file
79
src/core/SkZip.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkZip_DEFINED
|
||||
#define SkZip_DEFINED
|
||||
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#include "include/private/SkTLogic.h"
|
||||
#include "include/private/SkTemplates.h"
|
||||
#include "include/private/SkTo.h"
|
||||
#include "src/core/SkSpan.h"
|
||||
|
||||
// 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&...>;
|
||||
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator(const SkZip* zip, size_t index) : fZip{zip}, fIndex{index} { }
|
||||
Iterator(const Iterator& that) : Iterator{ that.fZip, that.fIndex } { }
|
||||
Iterator& operator++() { ++fIndex; return *this; }
|
||||
Iterator operator++(int) { Iterator tmp(*this); operator++(); return tmp; }
|
||||
bool operator==(const Iterator& rhs) const { return fIndex == rhs.fIndex; }
|
||||
bool operator!=(const Iterator& rhs) const { return fIndex != rhs.fIndex; }
|
||||
ReturnTuple operator*() { return (*fZip)[fIndex]; }
|
||||
|
||||
private:
|
||||
const SkZip* const fZip = nullptr;
|
||||
size_t fIndex = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
SkZip(size_t) = delete;
|
||||
explicit SkZip(size_t size, Ts*... ts)
|
||||
: fPointers{ts...}
|
||||
, fSize{size} {}
|
||||
|
||||
template<typename... Us>
|
||||
SkZip(const SkZip<Us...>& that)
|
||||
: fPointers{that.fPointers}
|
||||
, fSize{that.fSize} {}
|
||||
|
||||
ReturnTuple operator[](size_t i) const {
|
||||
return this->index(i);
|
||||
}
|
||||
|
||||
size_t size() const { return fSize; }
|
||||
bool empty() const { return this->size() == 0; }
|
||||
ReturnTuple front() const { return this->index(0); }
|
||||
ReturnTuple back() const { return this->index(this->size() - 1); }
|
||||
Iterator begin() const { return Iterator{this, 0}; }
|
||||
Iterator end() const { return Iterator{this, this->size()}; }
|
||||
template<size_t I> auto get() const { return SkMakeSpan(std::get<I>(fPointers), fSize); }
|
||||
|
||||
private:
|
||||
ReturnTuple index(size_t i) const {
|
||||
SkASSERT(this->size() > 0);
|
||||
SkASSERT(i < this->size());
|
||||
return indexDetail(i, skstd::make_index_sequence<sizeof...(Ts)>{});
|
||||
}
|
||||
|
||||
template<std::size_t... Is>
|
||||
ReturnTuple indexDetail(size_t i, skstd::index_sequence<Is...>) const {
|
||||
return ReturnTuple((std::get<Is>(fPointers))[i]...);
|
||||
}
|
||||
|
||||
std::tuple<Ts*...> fPointers;
|
||||
size_t fSize;
|
||||
};
|
||||
#endif //SkZip_DEFINED
|
@ -10,9 +10,12 @@
|
||||
#include "src/core/SkSpan.h"
|
||||
#include "src/core/SkTSearch.h"
|
||||
#include "src/core/SkTSort.h"
|
||||
#include "src/core/SkZip.h"
|
||||
#include "tests/Test.h"
|
||||
|
||||
#include <array>
|
||||
#include <initializer_list>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
class RefClass : public SkRefCnt {
|
||||
@ -211,3 +214,108 @@ DEF_TEST(SkMakeSpan, reporter) {
|
||||
REPORTER_ASSERT(reporter, s[3] == 100);
|
||||
}
|
||||
}
|
||||
|
||||
DEF_TEST(SkZip, reporter) {
|
||||
uint16_t A[] = {1, 2, 3, 4};
|
||||
const float B[] = {10.f, 20.f, 30.f, 40.f};
|
||||
std::vector<int> C = {{20, 30, 40, 50}};
|
||||
std::array<int, 4> D = {{100, 200, 300, 400}};
|
||||
SkSpan<int> S = SkMakeSpan(C);
|
||||
|
||||
// Check SkZip calls
|
||||
SkZip<uint16_t, const float, int, int, int>
|
||||
z{4, &A[0], &B[0], C.data(), D.data(), S.data()};
|
||||
|
||||
REPORTER_ASSERT(reporter, z.size() == 4);
|
||||
REPORTER_ASSERT(reporter, !z.empty());
|
||||
|
||||
{
|
||||
// Check front
|
||||
auto t = z.front();
|
||||
REPORTER_ASSERT(reporter, std::get<0>(t) == 1);
|
||||
REPORTER_ASSERT(reporter, std::get<1>(t) == 10.f);
|
||||
REPORTER_ASSERT(reporter, std::get<2>(t) == 20);
|
||||
REPORTER_ASSERT(reporter, std::get<3>(t) == 100);
|
||||
REPORTER_ASSERT(reporter, std::get<4>(t) == 20);
|
||||
}
|
||||
|
||||
{
|
||||
// Check back
|
||||
auto t = z.back();
|
||||
REPORTER_ASSERT(reporter, std::get<0>(t) == 4);
|
||||
REPORTER_ASSERT(reporter, std::get<1>(t) == 40.f);
|
||||
}
|
||||
|
||||
{
|
||||
// Check ranged-for
|
||||
int i = 0;
|
||||
for (auto t : z) {
|
||||
uint16_t a; float b; int c; int d; int s;
|
||||
std::tie(a, b, c, d, s) = t;
|
||||
REPORTER_ASSERT(reporter, a == A[i]);
|
||||
REPORTER_ASSERT(reporter, b == B[i]);
|
||||
REPORTER_ASSERT(reporter, c == C[i]);
|
||||
REPORTER_ASSERT(reporter, d == D[i]);
|
||||
REPORTER_ASSERT(reporter, s == S[i]);
|
||||
|
||||
i++;
|
||||
}
|
||||
REPORTER_ASSERT(reporter, i = 4);
|
||||
}
|
||||
|
||||
// Check copy.
|
||||
auto zz{z};
|
||||
{
|
||||
int i = 0;
|
||||
for (auto t : zz) {
|
||||
uint16_t a; float b; int c; int d; int s;
|
||||
std::tie(a, b, c, d, s) = t;
|
||||
REPORTER_ASSERT(reporter, a == A[i]);
|
||||
REPORTER_ASSERT(reporter, b == B[i]);
|
||||
REPORTER_ASSERT(reporter, c == C[i]);
|
||||
REPORTER_ASSERT(reporter, d == D[i]);
|
||||
REPORTER_ASSERT(reporter, s == S[i]);
|
||||
|
||||
i++;
|
||||
}
|
||||
REPORTER_ASSERT(reporter, i = 4);
|
||||
}
|
||||
|
||||
// Check index getter
|
||||
{
|
||||
auto span = z.get<1>();
|
||||
REPORTER_ASSERT(reporter, span[1] == 20.f);
|
||||
}
|
||||
|
||||
// The following mutates the data.
|
||||
{
|
||||
// Check indexing
|
||||
auto t = z[1];
|
||||
REPORTER_ASSERT(reporter, std::get<0>(t) == 2);
|
||||
REPORTER_ASSERT(reporter, std::get<1>(t) == 20.f);
|
||||
REPORTER_ASSERT(reporter, std::get<2>(t) == 30);
|
||||
REPORTER_ASSERT(reporter, std::get<3>(t) == 200);
|
||||
REPORTER_ASSERT(reporter, std::get<4>(t) == 30);
|
||||
|
||||
// Check correct refs returned.
|
||||
REPORTER_ASSERT(reporter, &std::get<0>(t) == &A[1]);
|
||||
REPORTER_ASSERT(reporter, &std::get<1>(t) == &B[1]);
|
||||
REPORTER_ASSERT(reporter, &std::get<2>(t) == &C[1]);
|
||||
REPORTER_ASSERT(reporter, &std::get<3>(t) == &D[1]);
|
||||
REPORTER_ASSERT(reporter, &std::get<4>(t) == &S[1]);
|
||||
|
||||
// Check assignment
|
||||
std::get<0>(t) = 20;
|
||||
// std::get<1>(t) = 300.f; // is const
|
||||
std::get<2>(t) = 300;
|
||||
std::get<3>(t) = 2000;
|
||||
std::get<4>(t) = 300;
|
||||
|
||||
auto t1 = z[1];
|
||||
REPORTER_ASSERT(reporter, std::get<0>(t1) == 20);
|
||||
REPORTER_ASSERT(reporter, std::get<1>(t1) == 20.f);
|
||||
REPORTER_ASSERT(reporter, std::get<2>(t1) == 300);
|
||||
REPORTER_ASSERT(reporter, std::get<3>(t1) == 2000);
|
||||
REPORTER_ASSERT(reporter, std::get<4>(t1) == 300);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user