diff options
author | Robert Phillips <robertphillips@google.com> | 2018-05-31 12:43:27 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-05-31 17:27:43 +0000 |
commit | 774168efac172d096cd7f09841bce51650cb6e84 (patch) | |
tree | 1433b93978baaf92439289fe5a0a3e648a73974f /include/private/SkTInternalLList.h | |
parent | e304a8a21b0bc40c3a7d85a96371a21180750076 (diff) |
Allow CCPR in DDL mode (take 2)
A lot of the changes to get this compiling on the
win_chromium_compile_dbg_ng bot (i.e., moving a lot of header files to
private) should be undone if that bot is ever "fixed".
Bug: skia:7988
Change-Id: I704ff793d80b18e7312048538874498824803580
Reviewed-on: https://skia-review.googlesource.com/130920
Reviewed-by: Chris Dalton <csmartdalton@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
Diffstat (limited to 'include/private/SkTInternalLList.h')
-rw-r--r-- | include/private/SkTInternalLList.h | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/include/private/SkTInternalLList.h b/include/private/SkTInternalLList.h new file mode 100644 index 0000000000..2f43f1c1eb --- /dev/null +++ b/include/private/SkTInternalLList.h @@ -0,0 +1,318 @@ +/* + * 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 SkTInternalLList_DEFINED +#define SkTInternalLList_DEFINED + +#include "SkTypes.h" + +/** + * Helper class to automatically initialize the doubly linked list created pointers. + */ +template <typename T> class SkPtrWrapper { + public: + SkPtrWrapper() : fPtr(nullptr) {} + SkPtrWrapper& operator =(T* ptr) { fPtr = ptr; return *this; } + operator T*() const { return fPtr; } + T* operator->() { return fPtr; } + private: + T* fPtr; +}; + + +/** + * 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. + */ +#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 + +/** + * This class implements a templated internal doubly linked list data structure. + */ +template <class T> class SkTInternalLList : SkNoncopyable { +public: + SkTInternalLList() + : fHead(nullptr) + , fTail(nullptr) { + } + + void reset() { + fHead = nullptr; + fTail = nullptr; + } + + void remove(T* entry) { + SkASSERT(fHead && fTail); + SkASSERT(this->isInList(entry)); + + T* prev = entry->fPrev; + T* next = entry->fNext; + + if (prev) { + prev->fNext = next; + } else { + fHead = next; + } + if (next) { + next->fPrev = prev; + } else { + fTail = prev; + } + + entry->fPrev = nullptr; + entry->fNext = nullptr; + +#ifdef SK_DEBUG + entry->fList = nullptr; +#endif + } + + void addToHead(T* entry) { + SkASSERT(nullptr == entry->fPrev && nullptr == entry->fNext); + SkASSERT(nullptr == entry->fList); + + entry->fPrev = nullptr; + entry->fNext = fHead; + if (fHead) { + fHead->fPrev = entry; + } + fHead = entry; + if (nullptr == fTail) { + fTail = entry; + } + +#ifdef SK_DEBUG + entry->fList = this; +#endif + } + + void addToTail(T* entry) { + SkASSERT(nullptr == entry->fPrev && nullptr == entry->fNext); + SkASSERT(nullptr == entry->fList); + + entry->fPrev = fTail; + entry->fNext = nullptr; + if (fTail) { + fTail->fNext = entry; + } + fTail = entry; + if (nullptr == fHead) { + fHead = entry; + } + +#ifdef SK_DEBUG + entry->fList = this; +#endif + } + + /** + * 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) { + SkASSERT(newEntry); + + if (nullptr == existingEntry) { + this->addToTail(newEntry); + return; + } + + SkASSERT(this->isInList(existingEntry)); + newEntry->fNext = existingEntry; + T* prev = existingEntry->fPrev; + existingEntry->fPrev = newEntry; + newEntry->fPrev = prev; + if (nullptr == prev) { + SkASSERT(fHead == existingEntry); + fHead = newEntry; + } else { + prev->fNext = newEntry; + } +#ifdef SK_DEBUG + 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) { + SkASSERT(newEntry); + + if (nullptr == existingEntry) { + this->addToHead(newEntry); + return; + } + + SkASSERT(this->isInList(existingEntry)); + newEntry->fPrev = existingEntry; + T* next = existingEntry->fNext; + existingEntry->fNext = newEntry; + newEntry->fNext = next; + if (nullptr == next) { + SkASSERT(fTail == existingEntry); + fTail = newEntry; + } else { + next->fPrev = newEntry; + } +#ifdef SK_DEBUG + newEntry->fList = this; +#endif + } + + void concat(SkTInternalLList&& list) { + if (list.isEmpty()) { + return; + } + + list.fHead->fPrev = fTail; + if (!fHead) { + SkASSERT(!list.fHead->fPrev); + fHead = list.fHead; + } else { + SkASSERT(fTail); + fTail->fNext = list.fHead; + } + fTail = list.fTail; + +#ifdef SK_DEBUG + for (T* node = list.fHead; node; node = node->fNext) { + SkASSERT(node->fList == &list); + node->fList = this; + } +#endif + + list.fHead = list.fTail = nullptr; + } + + bool isEmpty() const { + SkASSERT(SkToBool(fHead) == SkToBool(fTail)); + return !fHead; + } + + T* head() { return fHead; } + T* tail() { return fTail; } + + class Iter { + public: + enum IterStart { + kHead_IterStart, + kTail_IterStart + }; + + Iter() : fCurr(nullptr) {} + Iter(const Iter& iter) : fCurr(iter.fCurr) {} + Iter& operator= (const Iter& iter) { fCurr = iter.fCurr; return *this; } + + T* init(const SkTInternalLList& list, IterStart startLoc) { + if (kHead_IterStart == startLoc) { + fCurr = list.fHead; + } else { + SkASSERT(kTail_IterStart == startLoc); + fCurr = list.fTail; + } + + return fCurr; + } + + T* get() { return fCurr; } + + /** + * Return the next/previous element in the list or NULL if at the end. + */ + T* next() { + if (nullptr == fCurr) { + return nullptr; + } + + fCurr = fCurr->fNext; + return fCurr; + } + + T* prev() { + if (nullptr == fCurr) { + return nullptr; + } + + fCurr = fCurr->fPrev; + return fCurr; + } + + /** + * C++11 range-for interface. + */ + bool operator!=(const Iter& that) { return fCurr != that.fCurr; } + T* operator*() { return this->get(); } + void operator++() { this->next(); } + + private: + T* fCurr; + }; + + Iter begin() const { + Iter iter; + iter.init(*this, Iter::kHead_IterStart); + return iter; + } + + Iter end() const { return Iter(); } + +#ifdef SK_DEBUG + void validate() const { + SkASSERT(!fHead == !fTail); + Iter iter; + for (T* item = iter.init(*this, Iter::kHead_IterStart); item; item = iter.next()) { + SkASSERT(this->isInList(item)); + if (nullptr == item->fPrev) { + SkASSERT(fHead == item); + } else { + SkASSERT(item->fPrev->fNext == item); + } + if (nullptr == item->fNext) { + SkASSERT(fTail == item); + } else { + SkASSERT(item->fNext->fPrev == item); + } + } + } + + /** + * Debugging-only method that uses the list back pointer to check if 'entry' is indeed in 'this' + * list. + */ + 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; + for (T* entry = fHead; entry; entry = entry->fNext) { + ++count; + } + return count; + } +#endif // SK_DEBUG + +private: + T* fHead; + T* fTail; + + typedef SkNoncopyable INHERITED; +}; + +#endif |