2012-08-23 11:13:48 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2012 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
2012-12-03 14:54:59 +00:00
|
|
|
#ifndef SkTInternalLList_DEFINED
|
|
|
|
#define SkTInternalLList_DEFINED
|
2012-08-23 11:13:48 +00:00
|
|
|
|
|
|
|
#include "SkTypes.h"
|
|
|
|
|
2012-08-23 18:09:54 +00:00
|
|
|
/**
|
2012-12-03 14:54:59 +00:00
|
|
|
* Helper class to automatically initialize the doubly linked list created pointers.
|
2012-08-23 11:13:48 +00:00
|
|
|
*/
|
|
|
|
template <typename T> class SkPtrWrapper {
|
|
|
|
public:
|
|
|
|
SkPtrWrapper() : fPtr(NULL) {}
|
|
|
|
SkPtrWrapper& operator =(T* ptr) { fPtr = ptr; return *this; }
|
|
|
|
operator T*() const { return fPtr; }
|
|
|
|
T* operator->() { return fPtr; }
|
|
|
|
private:
|
|
|
|
T* fPtr;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2012-12-03 14:54:59 +00:00
|
|
|
* This macro creates the member variables required by the SkTInternalLList class. It should be
|
|
|
|
* placed in the private section of any class that will be stored in a double linked list.
|
2012-08-23 11:13:48 +00:00
|
|
|
*/
|
2012-12-03 14:54:59 +00:00
|
|
|
#define SK_DECLARE_INTERNAL_LLIST_INTERFACE(ClassName) \
|
|
|
|
friend class SkTInternalLList<ClassName>; \
|
|
|
|
/* back pointer to the owning list - for debugging */ \
|
|
|
|
SkDEBUGCODE(SkPtrWrapper<SkTInternalLList<ClassName> > fList;) \
|
|
|
|
SkPtrWrapper<ClassName> fPrev; \
|
|
|
|
SkPtrWrapper<ClassName> fNext
|
2012-08-23 11:13:48 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This class implements a templated internal doubly linked list data structure.
|
|
|
|
*/
|
2014-04-07 19:34:38 +00:00
|
|
|
template <class T> class SkTInternalLList : SkNoncopyable {
|
2012-08-23 11:13:48 +00:00
|
|
|
public:
|
2012-12-03 14:54:59 +00:00
|
|
|
SkTInternalLList()
|
2012-08-23 11:13:48 +00:00
|
|
|
: fHead(NULL)
|
|
|
|
, fTail(NULL) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void remove(T* entry) {
|
2014-09-05 20:34:00 +00:00
|
|
|
SkASSERT(fHead && fTail);
|
2012-08-23 11:13:48 +00:00
|
|
|
SkASSERT(this->isInList(entry));
|
|
|
|
|
|
|
|
T* prev = entry->fPrev;
|
|
|
|
T* next = entry->fNext;
|
|
|
|
|
2014-09-05 20:34:00 +00:00
|
|
|
if (prev) {
|
2012-08-23 11:13:48 +00:00
|
|
|
prev->fNext = next;
|
|
|
|
} else {
|
|
|
|
fHead = next;
|
|
|
|
}
|
2014-09-05 20:34:00 +00:00
|
|
|
if (next) {
|
2012-08-23 11:13:48 +00:00
|
|
|
next->fPrev = prev;
|
|
|
|
} else {
|
|
|
|
fTail = prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry->fPrev = NULL;
|
|
|
|
entry->fNext = NULL;
|
|
|
|
|
2012-08-23 13:24:31 +00:00
|
|
|
#ifdef SK_DEBUG
|
2012-08-23 11:13:48 +00:00
|
|
|
entry->fList = NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void addToHead(T* entry) {
|
|
|
|
SkASSERT(NULL == entry->fPrev && NULL == entry->fNext);
|
|
|
|
SkASSERT(NULL == entry->fList);
|
|
|
|
|
|
|
|
entry->fPrev = NULL;
|
|
|
|
entry->fNext = fHead;
|
2014-09-05 20:34:00 +00:00
|
|
|
if (fHead) {
|
2012-08-23 11:13:48 +00:00
|
|
|
fHead->fPrev = entry;
|
|
|
|
}
|
|
|
|
fHead = entry;
|
|
|
|
if (NULL == fTail) {
|
|
|
|
fTail = entry;
|
|
|
|
}
|
|
|
|
|
2012-12-03 14:54:59 +00:00
|
|
|
#ifdef SK_DEBUG
|
|
|
|
entry->fList = this;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void addToTail(T* entry) {
|
|
|
|
SkASSERT(NULL == entry->fPrev && NULL == entry->fNext);
|
|
|
|
SkASSERT(NULL == entry->fList);
|
|
|
|
|
|
|
|
entry->fPrev = fTail;
|
|
|
|
entry->fNext = NULL;
|
2014-09-05 20:34:00 +00:00
|
|
|
if (fTail) {
|
2012-12-03 14:54:59 +00:00
|
|
|
fTail->fNext = entry;
|
|
|
|
}
|
|
|
|
fTail = entry;
|
|
|
|
if (NULL == fHead) {
|
|
|
|
fHead = entry;
|
|
|
|
}
|
|
|
|
|
2012-08-23 13:24:31 +00:00
|
|
|
#ifdef SK_DEBUG
|
2012-08-23 11:13:48 +00:00
|
|
|
entry->fList = this;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-12-03 19:47:41 +00:00
|
|
|
/**
|
|
|
|
* Inserts a new list entry before an existing list entry. The new entry must not already be
|
|
|
|
* a member of this or any other list. If existingEntry is NULL then the new entry is added
|
|
|
|
* at the tail.
|
|
|
|
*/
|
|
|
|
void addBefore(T* newEntry, T* existingEntry) {
|
2014-09-05 20:34:00 +00:00
|
|
|
SkASSERT(newEntry);
|
2012-12-03 19:47:41 +00:00
|
|
|
|
|
|
|
if (NULL == existingEntry) {
|
|
|
|
this->addToTail(newEntry);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkASSERT(this->isInList(existingEntry));
|
|
|
|
newEntry->fNext = existingEntry;
|
|
|
|
T* prev = existingEntry->fPrev;
|
|
|
|
existingEntry->fPrev = newEntry;
|
|
|
|
newEntry->fPrev = prev;
|
|
|
|
if (NULL == prev) {
|
|
|
|
SkASSERT(fHead == existingEntry);
|
|
|
|
fHead = newEntry;
|
|
|
|
} else {
|
|
|
|
prev->fNext = newEntry;
|
|
|
|
}
|
2012-12-03 23:34:32 +00:00
|
|
|
#ifdef SK_DEBUG
|
2012-12-03 19:47:41 +00:00
|
|
|
newEntry->fList = this;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Inserts a new list entry after an existing list entry. The new entry must not already be
|
|
|
|
* a member of this or any other list. If existingEntry is NULL then the new entry is added
|
|
|
|
* at the head.
|
|
|
|
*/
|
|
|
|
void addAfter(T* newEntry, T* existingEntry) {
|
2014-09-05 20:34:00 +00:00
|
|
|
SkASSERT(newEntry);
|
2012-12-03 19:47:41 +00:00
|
|
|
|
|
|
|
if (NULL == existingEntry) {
|
|
|
|
this->addToHead(newEntry);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkASSERT(this->isInList(existingEntry));
|
|
|
|
newEntry->fPrev = existingEntry;
|
|
|
|
T* next = existingEntry->fNext;
|
|
|
|
existingEntry->fNext = newEntry;
|
|
|
|
newEntry->fNext = next;
|
|
|
|
if (NULL == next) {
|
|
|
|
SkASSERT(fTail == existingEntry);
|
|
|
|
fTail = newEntry;
|
|
|
|
} else {
|
|
|
|
next->fPrev = newEntry;
|
|
|
|
}
|
2012-12-03 23:34:32 +00:00
|
|
|
#ifdef SK_DEBUG
|
2012-12-03 19:47:41 +00:00
|
|
|
newEntry->fList = this;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-08-23 18:09:54 +00:00
|
|
|
bool isEmpty() const {
|
|
|
|
return NULL == fHead && NULL == fTail;
|
2012-08-23 11:13:48 +00:00
|
|
|
}
|
|
|
|
|
2012-08-28 12:34:17 +00:00
|
|
|
T* head() { return fHead; }
|
|
|
|
T* tail() { return fTail; }
|
|
|
|
|
2012-08-23 11:13:48 +00:00
|
|
|
class Iter {
|
|
|
|
public:
|
|
|
|
enum IterStart {
|
|
|
|
kHead_IterStart,
|
|
|
|
kTail_IterStart
|
|
|
|
};
|
|
|
|
|
2012-12-03 14:54:59 +00:00
|
|
|
Iter() : fCurr(NULL) {}
|
|
|
|
Iter(const Iter& iter) : fCurr(iter.fCurr) {}
|
|
|
|
Iter& operator= (const Iter& iter) { fCurr = iter.fCurr; return *this; }
|
2012-08-23 11:13:48 +00:00
|
|
|
|
2012-12-03 14:54:59 +00:00
|
|
|
T* init(const SkTInternalLList& list, IterStart startLoc) {
|
2012-08-23 11:13:48 +00:00
|
|
|
if (kHead_IterStart == startLoc) {
|
2012-12-03 14:54:59 +00:00
|
|
|
fCurr = list.fHead;
|
2012-08-23 11:13:48 +00:00
|
|
|
} else {
|
|
|
|
SkASSERT(kTail_IterStart == startLoc);
|
2012-12-03 14:54:59 +00:00
|
|
|
fCurr = list.fTail;
|
2012-08-23 11:13:48 +00:00
|
|
|
}
|
|
|
|
|
2012-12-03 14:54:59 +00:00
|
|
|
return fCurr;
|
2012-08-23 11:13:48 +00:00
|
|
|
}
|
|
|
|
|
2012-12-03 14:54:59 +00:00
|
|
|
T* get() { return fCurr; }
|
|
|
|
|
2012-08-23 11:13:48 +00:00
|
|
|
/**
|
|
|
|
* Return the next/previous element in the list or NULL if at the end.
|
|
|
|
*/
|
|
|
|
T* next() {
|
2012-12-03 14:54:59 +00:00
|
|
|
if (NULL == fCurr) {
|
2012-08-23 11:13:48 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-12-03 14:54:59 +00:00
|
|
|
fCurr = fCurr->fNext;
|
|
|
|
return fCurr;
|
2012-08-23 11:13:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
T* prev() {
|
2012-12-03 14:54:59 +00:00
|
|
|
if (NULL == fCurr) {
|
2012-08-23 11:13:48 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-12-03 14:54:59 +00:00
|
|
|
fCurr = fCurr->fPrev;
|
|
|
|
return fCurr;
|
2012-08-23 11:13:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2012-12-03 14:54:59 +00:00
|
|
|
T* fCurr;
|
2012-08-23 11:13:48 +00:00
|
|
|
};
|
|
|
|
|
2012-08-23 13:24:31 +00:00
|
|
|
#ifdef SK_DEBUG
|
2012-08-23 11:13:48 +00:00
|
|
|
void validate() const {
|
2012-12-03 14:54:59 +00:00
|
|
|
SkASSERT(!fHead == !fTail);
|
2012-12-03 19:47:41 +00:00
|
|
|
Iter iter;
|
2014-09-05 20:34:00 +00:00
|
|
|
for (T* item = iter.init(*this, Iter::kHead_IterStart); item; item = iter.next()) {
|
2012-12-03 19:47:41 +00:00
|
|
|
SkASSERT(this->isInList(item));
|
|
|
|
if (NULL == item->fPrev) {
|
|
|
|
SkASSERT(fHead == item);
|
|
|
|
} else {
|
|
|
|
SkASSERT(item->fPrev->fNext == item);
|
|
|
|
}
|
|
|
|
if (NULL == item->fNext) {
|
|
|
|
SkASSERT(fTail == item);
|
|
|
|
} else {
|
|
|
|
SkASSERT(item->fNext->fPrev == item);
|
|
|
|
}
|
|
|
|
}
|
2012-08-23 11:13:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2012-12-03 14:54:59 +00:00
|
|
|
* Debugging-only method that uses the list back pointer to check if 'entry' is indeed in 'this'
|
|
|
|
* list.
|
2012-08-23 11:13:48 +00:00
|
|
|
*/
|
|
|
|
bool isInList(const T* entry) const {
|
|
|
|
return entry->fList == this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Debugging-only method that laboriously counts the list entries.
|
|
|
|
*/
|
|
|
|
int countEntries() const {
|
|
|
|
int count = 0;
|
2014-09-05 20:34:00 +00:00
|
|
|
for (T* entry = fHead; entry; entry = entry->fNext) {
|
2012-08-23 11:13:48 +00:00
|
|
|
++count;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
#endif // SK_DEBUG
|
|
|
|
|
|
|
|
private:
|
|
|
|
T* fHead;
|
|
|
|
T* fTail;
|
|
|
|
|
|
|
|
typedef SkNoncopyable INHERITED;
|
|
|
|
};
|
|
|
|
|
2012-12-03 14:54:59 +00:00
|
|
|
#endif
|