Reland "Remove SkTLList"
This reverts commit14b1d56a2b
. Reason for revert: fix emplace_back() usage Original change's description: > Revert "Remove SkTLList" > > This reverts commite1d523d70f
. > > Reason for revert: breaking old stdlib versions (< c17) > > Original change's description: > > Remove SkTLList > > > > Change-Id: I198678b5cb298cf51872fbb8d4fd5d705a6b684e > > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/437339 > > Reviewed-by: Brian Osman <brianosman@google.com> > > Commit-Queue: Michael Ludwig <michaelludwig@google.com> > > TBR=brianosman@google.com,michaelludwig@google.com,skcq-be@skia-corp.google.com.iam.gserviceaccount.com > > Change-Id: I8e02e4cd2f293e7530f842be783de10f69be2ef4 > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/438078 > Reviewed-by: Michael Ludwig <michaelludwig@google.com> > Commit-Queue: Michael Ludwig <michaelludwig@google.com> # Not skipping CQ checks because this is a reland. Change-Id: Ied33ce81a8312963ff0713c4660cdb8541a02180 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/438080 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
68556bc798
commit
b23630c509
@ -18,7 +18,6 @@
|
||||
#include "include/core/SkString.h"
|
||||
#include "include/private/GrTypesPriv.h"
|
||||
#include "src/core/SkCanvasPriv.h"
|
||||
#include "src/core/SkTLList.h"
|
||||
#include "src/gpu/GrFragmentProcessor.h"
|
||||
#include "src/gpu/GrPaint.h"
|
||||
#include "src/gpu/v1/SurfaceDrawContext_v1.h"
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "include/core/SkTypeface.h"
|
||||
#include "include/core/SkTypes.h"
|
||||
#include "include/effects/SkGradientShader.h"
|
||||
#include "src/core/SkTLList.h"
|
||||
#include "tools/ToolUtils.h"
|
||||
|
||||
static sk_sp<SkImage> make_img(int w, int h) {
|
||||
@ -112,7 +111,13 @@ protected:
|
||||
}
|
||||
|
||||
void onOnceBeforeDraw() override {
|
||||
fClips.addToTail()->setPath(SkPath::Polygon({
|
||||
// On < c++17, emplace_back() returns a void :(
|
||||
auto emplace_back = [](std::vector<Clip>& clips) -> Clip& {
|
||||
clips.emplace_back();
|
||||
return clips.back();
|
||||
};
|
||||
|
||||
emplace_back(fClips).setPath(SkPath::Polygon({
|
||||
{ 5.f, 5.f},
|
||||
{100.f, 20.f},
|
||||
{ 15.f, 100.f},
|
||||
@ -132,18 +137,18 @@ protected:
|
||||
hexagon.lineTo(point);
|
||||
}
|
||||
}
|
||||
fClips.addToTail()->setPath(hexagon.snapshot());
|
||||
emplace_back(fClips).setPath(hexagon.snapshot());
|
||||
|
||||
SkMatrix scaleM;
|
||||
scaleM.setScale(1.1f, 0.4f, kRadius, kRadius);
|
||||
fClips.addToTail()->setPath(hexagon.detach().makeTransform(scaleM));
|
||||
emplace_back(fClips).setPath(hexagon.detach().makeTransform(scaleM));
|
||||
|
||||
fClips.addToTail()->setRect(SkRect::MakeXYWH(8.3f, 11.6f, 78.2f, 72.6f));
|
||||
emplace_back(fClips).setRect(SkRect::MakeXYWH(8.3f, 11.6f, 78.2f, 72.6f));
|
||||
|
||||
SkRect rect = SkRect::MakeLTRB(10.f, 12.f, 80.f, 86.f);
|
||||
SkMatrix rotM;
|
||||
rotM.setRotate(23.f, rect.centerX(), rect.centerY());
|
||||
fClips.addToTail()->setPath(SkPath::Rect(rect).makeTransform(rotM));
|
||||
emplace_back(fClips).setPath(SkPath::Rect(rect).makeTransform(rotM));
|
||||
|
||||
fImg = make_img(100, 100);
|
||||
}
|
||||
@ -167,15 +172,12 @@ protected:
|
||||
SkScalar startX = 0;
|
||||
int testLayers = kBench_Mode != this->getMode();
|
||||
for (int doLayer = 0; doLayer <= testLayers; ++doLayer) {
|
||||
for (ClipList::Iter iter(fClips, ClipList::Iter::kHead_IterStart);
|
||||
iter.get();
|
||||
iter.next()) {
|
||||
const Clip* clip = iter.get();
|
||||
for (const Clip& clip : fClips) {
|
||||
SkScalar x = startX;
|
||||
for (int aa = 0; aa < 2; ++aa) {
|
||||
if (doLayer) {
|
||||
SkRect bounds;
|
||||
clip->getBounds(&bounds);
|
||||
clip.getBounds(&bounds);
|
||||
bounds.outset(2, 2);
|
||||
bounds.offset(x, y);
|
||||
canvas->saveLayer(&bounds, nullptr);
|
||||
@ -183,7 +185,7 @@ protected:
|
||||
canvas->save();
|
||||
}
|
||||
canvas->translate(x, y);
|
||||
clip->setOnCanvas(canvas, SkClipOp::kIntersect, SkToBool(aa));
|
||||
clip.setOnCanvas(canvas, SkClipOp::kIntersect, SkToBool(aa));
|
||||
canvas->drawImage(fImg, 0, 0);
|
||||
canvas->restore();
|
||||
x += fImg->width() + kMargin;
|
||||
@ -198,7 +200,7 @@ protected:
|
||||
|
||||
if (doLayer) {
|
||||
SkRect bounds;
|
||||
clip->getBounds(&bounds);
|
||||
clip.getBounds(&bounds);
|
||||
bounds.outset(2, 2);
|
||||
bounds.offset(x, y);
|
||||
canvas->saveLayer(&bounds, nullptr);
|
||||
@ -206,9 +208,9 @@ protected:
|
||||
canvas->save();
|
||||
}
|
||||
canvas->translate(x, y);
|
||||
SkPath closedClipPath = clip->asClosedPath();
|
||||
SkPath closedClipPath = clip.asClosedPath();
|
||||
canvas->drawPath(closedClipPath, clipOutlinePaint);
|
||||
clip->setOnCanvas(canvas, SkClipOp::kIntersect, SkToBool(aa));
|
||||
clip.setOnCanvas(canvas, SkClipOp::kIntersect, SkToBool(aa));
|
||||
canvas->scale(1.f, 1.8f);
|
||||
canvas->drawSimpleText(kTxt, SK_ARRAY_COUNT(kTxt)-1, SkTextEncoding::kUTF8,
|
||||
0, 1.5f * font.getSize(), font, txtPaint);
|
||||
@ -296,9 +298,8 @@ private:
|
||||
SkRect fRect;
|
||||
};
|
||||
|
||||
typedef SkTLList<Clip, 1> ClipList;
|
||||
ClipList fClips;
|
||||
sk_sp<SkImage> fImg;;
|
||||
std::vector<Clip> fClips;
|
||||
sk_sp<SkImage> fImg;;
|
||||
|
||||
using INHERITED = GM;
|
||||
};
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "include/core/SkString.h"
|
||||
#include "include/private/GrTypesPriv.h"
|
||||
#include "src/core/SkCanvasPriv.h"
|
||||
#include "src/core/SkTLList.h"
|
||||
#include "src/gpu/GrFragmentProcessor.h"
|
||||
#include "src/gpu/GrPaint.h"
|
||||
#include "src/gpu/effects/GrConvexPolyEffect.h"
|
||||
@ -56,11 +55,12 @@ protected:
|
||||
tri.lineTo(100.f, 20.f);
|
||||
tri.lineTo(15.f, 100.f);
|
||||
|
||||
fPaths.addToTail(tri);
|
||||
fPaths.addToTail(SkPath())->reverseAddPath(tri);
|
||||
fPaths.push_back(tri);
|
||||
fPaths.emplace_back();
|
||||
fPaths.back().reverseAddPath(tri);
|
||||
|
||||
tri.close();
|
||||
fPaths.addToTail(tri);
|
||||
fPaths.push_back(tri);
|
||||
|
||||
SkPath ngon;
|
||||
constexpr SkScalar kRadius = 50.f;
|
||||
@ -77,16 +77,16 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
fPaths.addToTail(ngon);
|
||||
fPaths.push_back(ngon);
|
||||
SkMatrix scaleM;
|
||||
scaleM.setScale(1.1f, 0.4f);
|
||||
ngon.transform(scaleM);
|
||||
fPaths.addToTail(ngon);
|
||||
fPaths.push_back(ngon);
|
||||
|
||||
SkPath linePath;
|
||||
linePath.moveTo(5.f, 5.f);
|
||||
linePath.lineTo(6.f, 6.f);
|
||||
fPaths.addToTail(linePath);
|
||||
fPaths.push_back(linePath);
|
||||
}
|
||||
|
||||
DrawResult onDraw(GrRecordingContext* rContext, SkCanvas* canvas, SkString* errorMsg) override {
|
||||
@ -100,16 +100,13 @@ protected:
|
||||
static constexpr SkScalar kDX = 12.f;
|
||||
static constexpr SkScalar kOutset = 5.f;
|
||||
|
||||
for (PathList::Iter iter(fPaths, PathList::Iter::kHead_IterStart);
|
||||
iter.get();
|
||||
iter.next()) {
|
||||
const SkPath* path = iter.get();
|
||||
for (const SkPath& path : fPaths) {
|
||||
SkScalar x = 0;
|
||||
|
||||
for (int et = 0; et < kGrClipEdgeTypeCnt; ++et) {
|
||||
const SkMatrix m = SkMatrix::Translate(x, y);
|
||||
SkPath p;
|
||||
path->transform(m, &p);
|
||||
path.transform(m, &p);
|
||||
|
||||
GrClipEdgeType edgeType = (GrClipEdgeType) et;
|
||||
auto [success, fp] = GrConvexPolyEffect::Make(/*inputFP=*/nullptr, edgeType, p);
|
||||
@ -125,28 +122,27 @@ protected:
|
||||
auto op = sk_gpu_test::test_ops::MakeRect(rContext, std::move(grPaint), rect);
|
||||
sdc->addDrawOp(std::move(op));
|
||||
|
||||
x += SkScalarCeilToScalar(path->getBounds().width() + kDX);
|
||||
x += SkScalarCeilToScalar(path.getBounds().width() + kDX);
|
||||
}
|
||||
|
||||
// Draw AA and non AA paths using normal API for reference.
|
||||
canvas->save();
|
||||
canvas->translate(x, y);
|
||||
SkPaint paint;
|
||||
canvas->drawPath(*path, paint);
|
||||
canvas->translate(path->getBounds().width() + 10.f, 0);
|
||||
canvas->drawPath(path, paint);
|
||||
canvas->translate(path.getBounds().width() + 10.f, 0);
|
||||
paint.setAntiAlias(true);
|
||||
canvas->drawPath(*path, paint);
|
||||
canvas->drawPath(path, paint);
|
||||
canvas->restore();
|
||||
|
||||
y += SkScalarCeilToScalar(path->getBounds().height() + 20.f);
|
||||
y += SkScalarCeilToScalar(path.getBounds().height() + 20.f);
|
||||
}
|
||||
|
||||
return DrawResult::kOk;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef SkTLList<SkPath, 1> PathList;
|
||||
PathList fPaths;
|
||||
std::vector<SkPath> fPaths;
|
||||
|
||||
using INHERITED = GM;
|
||||
};
|
||||
|
@ -377,7 +377,6 @@ skia_core_sources = [
|
||||
"$_src/core/SkTDPQueue.h",
|
||||
"$_src/core/SkTDynamicHash.h",
|
||||
"$_src/core/SkTInternalLList.h",
|
||||
"$_src/core/SkTLList.h",
|
||||
"$_src/core/SkTLazy.h",
|
||||
"$_src/core/SkTMultiMap.h",
|
||||
"$_src/core/SkTSearch.cpp",
|
||||
|
@ -1,350 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkTLList_DEFINED
|
||||
#define SkTLList_DEFINED
|
||||
|
||||
#include "include/core/SkTypes.h"
|
||||
#include "include/private/SkMalloc.h"
|
||||
#include "include/private/SkTemplates.h"
|
||||
#include "src/core/SkTInternalLList.h"
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
/** Doubly-linked list of objects. The objects' lifetimes are controlled by the list. I.e. the
|
||||
the list creates the objects and they are deleted upon removal. This class block-allocates
|
||||
space for entries based on a param passed to the constructor.
|
||||
|
||||
Elements of the list can be constructed in place using the following macros:
|
||||
SkNEW_INSERT_IN_LLIST_BEFORE(list, location, type_name, args)
|
||||
SkNEW_INSERT_IN_LLIST_AFTER(list, location, type_name, args)
|
||||
where list is a SkTLList<type_name>*, location is an iterator, and args is the paren-surrounded
|
||||
constructor arguments for type_name. These macros behave like addBefore() and addAfter().
|
||||
|
||||
allocCnt is the number of objects to allocate as a group. In the worst case fragmentation
|
||||
each object is using the space required for allocCnt unfragmented objects.
|
||||
*/
|
||||
template <typename T, unsigned int N> class SkTLList {
|
||||
private:
|
||||
struct Block;
|
||||
struct Node {
|
||||
SkAlignedSTStorage<1, T> fObj;
|
||||
SK_DECLARE_INTERNAL_LLIST_INTERFACE(Node);
|
||||
Block* fBlock; // owning block.
|
||||
};
|
||||
typedef SkTInternalLList<Node> NodeList;
|
||||
|
||||
public:
|
||||
class Iter;
|
||||
|
||||
// Having fCount initialized to -1 indicates that the first time we attempt to grab a free node
|
||||
// all the nodes in the pre-allocated first block need to be inserted into the free list. This
|
||||
// allows us to skip that loop in instances when the list is never populated.
|
||||
SkTLList() : fCount(-1) {}
|
||||
|
||||
~SkTLList() {
|
||||
this->validate();
|
||||
typename NodeList::Iter iter;
|
||||
Node* node = iter.init(fList, Iter::kHead_IterStart);
|
||||
while (node) {
|
||||
reinterpret_cast<T*>(node->fObj.get())->~T();
|
||||
Block* block = node->fBlock;
|
||||
node = iter.next();
|
||||
if (0 == --block->fNodesInUse) {
|
||||
for (unsigned int i = 0; i < N; ++i) {
|
||||
block->fNodes[i].~Node();
|
||||
}
|
||||
if (block != &fFirstBlock) {
|
||||
sk_free(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds a new element to the list at the head. */
|
||||
template <typename... Args> T* addToHead(Args&&... args) {
|
||||
this->validate();
|
||||
Node* node = this->createNode();
|
||||
fList.addToHead(node);
|
||||
this->validate();
|
||||
return new (node->fObj.get()) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/** Adds a new element to the list at the tail. */
|
||||
template <typename... Args> T* addToTail(Args&&... args) {
|
||||
this->validate();
|
||||
Node* node = this->createNode();
|
||||
fList.addToTail(node);
|
||||
this->validate();
|
||||
return new (node->fObj.get()) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/** Adds a new element to the list before the location indicated by the iterator. If the
|
||||
iterator refers to a nullptr location then the new element is added at the tail */
|
||||
template <typename... Args> T* addBefore(Iter location, Args&&... args) {
|
||||
this->validate();
|
||||
Node* node = this->createNode();
|
||||
fList.addBefore(node, location.getNode());
|
||||
this->validate();
|
||||
return new (node->fObj.get()) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/** Adds a new element to the list after the location indicated by the iterator. If the
|
||||
iterator refers to a nullptr location then the new element is added at the head */
|
||||
template <typename... Args> T* addAfter(Iter location, Args&&... args) {
|
||||
this->validate();
|
||||
Node* node = this->createNode();
|
||||
fList.addAfter(node, location.getNode());
|
||||
this->validate();
|
||||
return new (node->fObj.get()) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/** Convenience methods for getting an iterator initialized to the head/tail of the list. */
|
||||
Iter headIter() const { return Iter(*this, Iter::kHead_IterStart); }
|
||||
Iter tailIter() const { return Iter(*this, Iter::kTail_IterStart); }
|
||||
|
||||
T* head() { return Iter(*this, Iter::kHead_IterStart).get(); }
|
||||
T* tail() { return Iter(*this, Iter::kTail_IterStart).get(); }
|
||||
const T* head() const { return Iter(*this, Iter::kHead_IterStart).get(); }
|
||||
const T* tail() const { return Iter(*this, Iter::kTail_IterStart).get(); }
|
||||
|
||||
void popHead() {
|
||||
this->validate();
|
||||
Node* node = fList.head();
|
||||
if (node) {
|
||||
this->removeNode(node);
|
||||
}
|
||||
this->validate();
|
||||
}
|
||||
|
||||
void popTail() {
|
||||
this->validate();
|
||||
Node* node = fList.tail();
|
||||
if (node) {
|
||||
this->removeNode(node);
|
||||
}
|
||||
this->validate();
|
||||
}
|
||||
|
||||
void remove(T* t) {
|
||||
this->validate();
|
||||
Node* node = reinterpret_cast<Node*>(t);
|
||||
SkASSERT(reinterpret_cast<T*>(node->fObj.get()) == t);
|
||||
this->removeNode(node);
|
||||
this->validate();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
this->validate();
|
||||
Iter iter(*this, Iter::kHead_IterStart);
|
||||
while (iter.get()) {
|
||||
Iter next = iter;
|
||||
next.next();
|
||||
this->remove(iter.get());
|
||||
iter = next;
|
||||
}
|
||||
SkASSERT(0 == fCount || -1 == fCount);
|
||||
this->validate();
|
||||
}
|
||||
|
||||
int count() const { return std::max(fCount ,0); }
|
||||
bool isEmpty() const { this->validate(); return 0 == fCount || -1 == fCount; }
|
||||
|
||||
bool operator== (const SkTLList& list) const {
|
||||
if (this == &list) {
|
||||
return true;
|
||||
}
|
||||
// Call count() rather than use fCount because an empty list may have fCount = 0 or -1.
|
||||
if (this->count() != list.count()) {
|
||||
return false;
|
||||
}
|
||||
for (Iter a(*this, Iter::kHead_IterStart), b(list, Iter::kHead_IterStart);
|
||||
a.get();
|
||||
a.next(), b.next()) {
|
||||
SkASSERT(b.get()); // already checked that counts match.
|
||||
if (!(*a.get() == *b.get())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool operator!= (const SkTLList& list) const { return !(*this == list); }
|
||||
|
||||
/** The iterator becomes invalid if the element it refers to is removed from the list. */
|
||||
class Iter : private NodeList::Iter {
|
||||
private:
|
||||
using INHERITED = typename NodeList::Iter;
|
||||
|
||||
public:
|
||||
typedef typename INHERITED::IterStart IterStart;
|
||||
//!< Start the iterator at the head of the list.
|
||||
static const IterStart kHead_IterStart = INHERITED::kHead_IterStart;
|
||||
//!< Start the iterator at the tail of the list.
|
||||
static const IterStart kTail_IterStart = INHERITED::kTail_IterStart;
|
||||
|
||||
Iter() {}
|
||||
Iter(const Iter& that) : INHERITED(that) {}
|
||||
Iter& operator=(const Iter& that) { INHERITED::operator=(that); return *this; }
|
||||
|
||||
Iter(const SkTLList& list, IterStart start = kHead_IterStart) {
|
||||
INHERITED::init(list.fList, start);
|
||||
}
|
||||
|
||||
T* init(const SkTLList& list, IterStart start = kHead_IterStart) {
|
||||
return this->nodeToObj(INHERITED::init(list.fList, start));
|
||||
}
|
||||
|
||||
T* get() { return this->nodeToObj(INHERITED::get()); }
|
||||
|
||||
T* next() { return this->nodeToObj(INHERITED::next()); }
|
||||
|
||||
T* prev() { return this->nodeToObj(INHERITED::prev()); }
|
||||
|
||||
private:
|
||||
friend class SkTLList;
|
||||
Node* getNode() { return INHERITED::get(); }
|
||||
|
||||
T* nodeToObj(Node* node) {
|
||||
if (node) {
|
||||
return reinterpret_cast<T*>(node->fObj.get());
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
struct Block {
|
||||
int fNodesInUse;
|
||||
Node fNodes[N];
|
||||
};
|
||||
|
||||
void delayedInit() {
|
||||
SkASSERT(-1 == fCount);
|
||||
fFirstBlock.fNodesInUse = 0;
|
||||
for (unsigned int i = 0; i < N; ++i) {
|
||||
fFreeList.addToHead(fFirstBlock.fNodes + i);
|
||||
fFirstBlock.fNodes[i].fBlock = &fFirstBlock;
|
||||
}
|
||||
fCount = 0;
|
||||
this->validate();
|
||||
}
|
||||
|
||||
Node* createNode() {
|
||||
if (-1 == fCount) {
|
||||
this->delayedInit();
|
||||
}
|
||||
Node* node = fFreeList.head();
|
||||
if (node) {
|
||||
fFreeList.remove(node);
|
||||
++node->fBlock->fNodesInUse;
|
||||
} else {
|
||||
// Should not get here when count == 0 because we always have the preallocated first
|
||||
// block.
|
||||
SkASSERT(fCount > 0);
|
||||
Block* block = reinterpret_cast<Block*>(sk_malloc_throw(sizeof(Block)));
|
||||
node = &block->fNodes[0];
|
||||
new (node) Node;
|
||||
node->fBlock = block;
|
||||
block->fNodesInUse = 1;
|
||||
for (unsigned int i = 1; i < N; ++i) {
|
||||
new (block->fNodes + i) Node;
|
||||
fFreeList.addToHead(block->fNodes + i);
|
||||
block->fNodes[i].fBlock = block;
|
||||
}
|
||||
}
|
||||
++fCount;
|
||||
return node;
|
||||
}
|
||||
|
||||
void removeNode(Node* node) {
|
||||
SkASSERT(node);
|
||||
fList.remove(node);
|
||||
reinterpret_cast<T*>(node->fObj.get())->~T();
|
||||
Block* block = node->fBlock;
|
||||
// Don't ever elease the first block, just add its nodes to the free list
|
||||
if (0 == --block->fNodesInUse && block != &fFirstBlock) {
|
||||
for (unsigned int i = 0; i < N; ++i) {
|
||||
if (block->fNodes + i != node) {
|
||||
fFreeList.remove(block->fNodes + i);
|
||||
}
|
||||
block->fNodes[i].~Node();
|
||||
}
|
||||
sk_free(block);
|
||||
} else {
|
||||
fFreeList.addToHead(node);
|
||||
}
|
||||
--fCount;
|
||||
this->validate();
|
||||
}
|
||||
|
||||
void validate() const {
|
||||
#ifdef SK_DEBUG
|
||||
bool isEmpty = false;
|
||||
if (-1 == fCount) {
|
||||
// We should not yet have initialized the free list.
|
||||
SkASSERT(fFreeList.isEmpty());
|
||||
isEmpty = true;
|
||||
} else if (0 == fCount) {
|
||||
// Should only have the nodes from the first block in the free list.
|
||||
SkASSERT(fFreeList.countEntries() == N);
|
||||
isEmpty = true;
|
||||
}
|
||||
SkASSERT(isEmpty == fList.isEmpty());
|
||||
fList.validate();
|
||||
fFreeList.validate();
|
||||
typename NodeList::Iter iter;
|
||||
Node* freeNode = iter.init(fFreeList, Iter::kHead_IterStart);
|
||||
while (freeNode) {
|
||||
SkASSERT(fFreeList.isInList(freeNode));
|
||||
Block* block = freeNode->fBlock;
|
||||
// Only the first block is allowed to have all its nodes in the free list.
|
||||
SkASSERT(block->fNodesInUse > 0 || block == &fFirstBlock);
|
||||
SkASSERT((unsigned)block->fNodesInUse < N);
|
||||
SkDEBUGCODE(int activeCnt = 0;)
|
||||
for (unsigned int i = 0; i < N; ++i) {
|
||||
bool free = fFreeList.isInList(block->fNodes + i);
|
||||
bool active = fList.isInList(block->fNodes + i);
|
||||
SkASSERT(free != active);
|
||||
SkDEBUGCODE(activeCnt += active;)
|
||||
}
|
||||
SkASSERT(activeCnt == block->fNodesInUse);
|
||||
freeNode = iter.next();
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
Node* activeNode = iter.init(fList, Iter::kHead_IterStart);
|
||||
while (activeNode) {
|
||||
++count;
|
||||
SkASSERT(fList.isInList(activeNode));
|
||||
Block* block = activeNode->fBlock;
|
||||
SkASSERT(block->fNodesInUse > 0 && (unsigned)block->fNodesInUse <= N);
|
||||
|
||||
SkDEBUGCODE(int activeCnt = 0;)
|
||||
for (unsigned int i = 0; i < N; ++i) {
|
||||
bool free = fFreeList.isInList(block->fNodes + i);
|
||||
bool active = fList.isInList(block->fNodes + i);
|
||||
SkASSERT(free != active);
|
||||
SkDEBUGCODE(activeCnt += active;)
|
||||
}
|
||||
SkASSERT(activeCnt == block->fNodesInUse);
|
||||
activeNode = iter.next();
|
||||
}
|
||||
SkASSERT(count == fCount || (0 == count && -1 == fCount));
|
||||
#endif
|
||||
}
|
||||
|
||||
NodeList fList;
|
||||
NodeList fFreeList;
|
||||
Block fFirstBlock;
|
||||
int fCount;
|
||||
|
||||
SkTLList(const SkTLList&) = delete;
|
||||
SkTLList& operator=(const SkTLList&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
@ -19,7 +19,7 @@
|
||||
#include "src/core/SkOpts.h"
|
||||
#include "src/core/SkRectPriv.h"
|
||||
#include "src/core/SkStrikeSpec.h"
|
||||
#include "src/core/SkTLList.h"
|
||||
#include "src/core/SkTInternalLList.h"
|
||||
#include "src/core/SkTLazy.h"
|
||||
#include "src/gpu/GrColor.h"
|
||||
#include "src/gpu/GrSubRunAllocator.h"
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "include/gpu/GrRecordingContext.h"
|
||||
#include "include/gpu/GrYUVABackendTextures.h"
|
||||
#include "src/core/SkBitmapCache.h"
|
||||
#include "src/core/SkTLList.h"
|
||||
#include "src/gpu/GrDirectContextPriv.h"
|
||||
#include "src/gpu/GrImageContextPriv.h"
|
||||
#include "src/gpu/GrImageInfo.h"
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
#include "include/utils/SkRandom.h"
|
||||
#include "src/core/SkTInternalLList.h"
|
||||
#include "src/core/SkTLList.h"
|
||||
#include "tests/Test.h"
|
||||
|
||||
class ListElement {
|
||||
@ -41,7 +40,7 @@ static void check_list(const SkTInternalLList<ListElement>& list,
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_tinternallist(skiatest::Reporter* reporter) {
|
||||
DEF_TEST(InternalLList, reporter) {
|
||||
SkTInternalLList<ListElement> list;
|
||||
ListElement elements[4] = {
|
||||
ListElement(0),
|
||||
@ -152,191 +151,3 @@ static void test_tinternallist(skiatest::Reporter* reporter) {
|
||||
REPORTER_ASSERT(reporter, cur->fID == i);
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned int N> static void test_tllist(skiatest::Reporter* reporter) {
|
||||
typedef SkTLList<ListElement, N> ElList;
|
||||
typedef typename ElList::Iter Iter;
|
||||
SkRandom random;
|
||||
|
||||
ElList list1;
|
||||
ElList list2;
|
||||
Iter iter1;
|
||||
Iter iter2;
|
||||
Iter iter3;
|
||||
Iter iter4;
|
||||
|
||||
REPORTER_ASSERT(reporter, list1.isEmpty());
|
||||
REPORTER_ASSERT(reporter, nullptr == iter1.init(list1, Iter::kHead_IterStart));
|
||||
REPORTER_ASSERT(reporter, nullptr == iter1.init(list1, Iter::kTail_IterStart));
|
||||
// Try popping an empty list
|
||||
list1.popHead();
|
||||
list1.popTail();
|
||||
REPORTER_ASSERT(reporter, list1.isEmpty());
|
||||
REPORTER_ASSERT(reporter, list1 == list2);
|
||||
|
||||
// Create two identical lists, one by appending to head and the other to the tail.
|
||||
list1.addToHead(ListElement(1));
|
||||
list2.addToTail(ListElement(1));
|
||||
iter1.init(list1, Iter::kHead_IterStart);
|
||||
iter2.init(list1, Iter::kTail_IterStart);
|
||||
REPORTER_ASSERT(reporter, iter1.get()->fID == iter2.get()->fID);
|
||||
iter3.init(list2, Iter::kHead_IterStart);
|
||||
iter4.init(list2, Iter::kTail_IterStart);
|
||||
REPORTER_ASSERT(reporter, iter3.get()->fID == iter1.get()->fID);
|
||||
REPORTER_ASSERT(reporter, iter4.get()->fID == iter1.get()->fID);
|
||||
REPORTER_ASSERT(reporter, list1 == list2);
|
||||
|
||||
list2.reset();
|
||||
|
||||
// use both before/after in-place construction on an empty list
|
||||
list2.addBefore(list2.headIter(), 1);
|
||||
REPORTER_ASSERT(reporter, list2 == list1);
|
||||
list2.reset();
|
||||
|
||||
list2.addAfter(list2.tailIter(), 1);
|
||||
REPORTER_ASSERT(reporter, list2 == list1);
|
||||
|
||||
// add an element to the second list, check that iters are still valid
|
||||
iter3.init(list2, Iter::kHead_IterStart);
|
||||
iter4.init(list2, Iter::kTail_IterStart);
|
||||
list2.addToHead(ListElement(2));
|
||||
|
||||
REPORTER_ASSERT(reporter, iter3.get()->fID == iter1.get()->fID);
|
||||
REPORTER_ASSERT(reporter, iter4.get()->fID == iter1.get()->fID);
|
||||
REPORTER_ASSERT(reporter, 1 == Iter(list2, Iter::kTail_IterStart).get()->fID);
|
||||
REPORTER_ASSERT(reporter, 2 == Iter(list2, Iter::kHead_IterStart).get()->fID);
|
||||
REPORTER_ASSERT(reporter, list1 != list2);
|
||||
list1.addToHead(ListElement(2));
|
||||
REPORTER_ASSERT(reporter, list1 == list2);
|
||||
REPORTER_ASSERT(reporter, !list1.isEmpty());
|
||||
|
||||
list1.reset();
|
||||
list2.reset();
|
||||
REPORTER_ASSERT(reporter, list1.isEmpty() && list2.isEmpty());
|
||||
|
||||
list1.addToTail(ListElement(1));
|
||||
list1.addToTail(ListElement(2));
|
||||
list1.addToTail(ListElement(4));
|
||||
list1.addToTail(ListElement(8));
|
||||
list1.popHead();
|
||||
REPORTER_ASSERT(reporter, list1.count() == 3);
|
||||
REPORTER_ASSERT(reporter, *list1.head() == ListElement(2));
|
||||
REPORTER_ASSERT(reporter, *list1.tail() == ListElement(8));
|
||||
list1.popTail();
|
||||
REPORTER_ASSERT(reporter, list1.count() == 2);
|
||||
REPORTER_ASSERT(reporter, *list1.head() == ListElement(2));
|
||||
REPORTER_ASSERT(reporter, *list1.tail() == ListElement(4));
|
||||
|
||||
list1.reset();
|
||||
|
||||
// randomly perform insertions and deletions on a list and perform tests
|
||||
int count = 0;
|
||||
for (int j = 0; j < 100; ++j) {
|
||||
if (list1.isEmpty() || random.nextBiasedBool(3 * SK_Scalar1 / 4)) {
|
||||
int id = j;
|
||||
// Choose one of three ways to insert a new element: at the head, at the tail,
|
||||
// before a random element, after a random element
|
||||
int numValidMethods = 0 == count ? 2 : 4;
|
||||
int insertionMethod = random.nextULessThan(numValidMethods);
|
||||
switch (insertionMethod) {
|
||||
case 0:
|
||||
list1.addToHead(ListElement(id));
|
||||
break;
|
||||
case 1:
|
||||
list1.addToTail(ListElement(id));
|
||||
break;
|
||||
case 2: // fallthru to share code that picks random element.
|
||||
case 3: {
|
||||
int n = random.nextULessThan(list1.count());
|
||||
Iter iter = list1.headIter();
|
||||
// remember the elements before/after the insertion point.
|
||||
while (n--) {
|
||||
iter.next();
|
||||
}
|
||||
Iter prev(iter);
|
||||
Iter next(iter);
|
||||
next.next();
|
||||
prev.prev();
|
||||
|
||||
SkASSERT(iter.get());
|
||||
// insert either before or after the iterator, then check that the
|
||||
// surrounding sequence is correct.
|
||||
if (2 == insertionMethod) {
|
||||
list1.addBefore(iter, id);
|
||||
Iter newItem(iter);
|
||||
newItem.prev();
|
||||
REPORTER_ASSERT(reporter, newItem.get()->fID == id);
|
||||
|
||||
if (next.get()) {
|
||||
REPORTER_ASSERT(reporter, next.prev()->fID == iter.get()->fID);
|
||||
}
|
||||
if (prev.get()) {
|
||||
REPORTER_ASSERT(reporter, prev.next()->fID == id);
|
||||
}
|
||||
} else {
|
||||
list1.addAfter(iter, id);
|
||||
Iter newItem(iter);
|
||||
newItem.next();
|
||||
REPORTER_ASSERT(reporter, newItem.get()->fID == id);
|
||||
|
||||
if (next.get()) {
|
||||
REPORTER_ASSERT(reporter, next.prev()->fID == id);
|
||||
}
|
||||
if (prev.get()) {
|
||||
REPORTER_ASSERT(reporter, prev.next()->fID == iter.get()->fID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
++count;
|
||||
} else {
|
||||
// walk to a random place either forward or backwards and remove.
|
||||
int n = random.nextULessThan(list1.count());
|
||||
typename Iter::IterStart start;
|
||||
ListElement* (Iter::*incrFunc)();
|
||||
|
||||
if (random.nextBool()) {
|
||||
start = Iter::kHead_IterStart;
|
||||
incrFunc = &Iter::next;
|
||||
} else {
|
||||
start = Iter::kTail_IterStart;
|
||||
incrFunc = &Iter::prev;
|
||||
}
|
||||
|
||||
// find the element
|
||||
Iter iter(list1, start);
|
||||
while (n--) {
|
||||
REPORTER_ASSERT(reporter, iter.get());
|
||||
(iter.*incrFunc)();
|
||||
}
|
||||
REPORTER_ASSERT(reporter, iter.get());
|
||||
|
||||
// remember the prev and next elements from the element to be removed
|
||||
Iter prev = iter;
|
||||
Iter next = iter;
|
||||
prev.prev();
|
||||
next.next();
|
||||
list1.remove(iter.get());
|
||||
|
||||
// make sure the remembered next/prev iters still work
|
||||
Iter pn = prev; pn.next();
|
||||
Iter np = next; np.prev();
|
||||
// pn should match next unless the target node was the head, in which case prev
|
||||
// walked off the list.
|
||||
REPORTER_ASSERT(reporter, pn.get() == next.get() || nullptr == prev.get());
|
||||
// Similarly, np should match prev unless next originally walked off the tail.
|
||||
REPORTER_ASSERT(reporter, np.get() == prev.get() || nullptr == next.get());
|
||||
--count;
|
||||
}
|
||||
REPORTER_ASSERT(reporter, count == list1.count());
|
||||
}
|
||||
}
|
||||
|
||||
DEF_TEST(LList, reporter) {
|
||||
test_tinternallist(reporter);
|
||||
test_tllist<1>(reporter);
|
||||
test_tllist<3>(reporter);
|
||||
test_tllist<8>(reporter);
|
||||
test_tllist<10>(reporter);
|
||||
test_tllist<16>(reporter);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user