1df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin/*
2df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin * Copyright 2012 Google Inc.
3df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin *
4df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin * Use of this source code is governed by a BSD-style license that can be
5df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin * found in the LICENSE file.
6df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin */
7df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin
8df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin#ifndef SkTInternalLList_DEFINED
9df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin#define SkTInternalLList_DEFINED
10df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin
11df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin#include "SkTypes.h"
12df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin
13df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin/**
14df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin * Helper class to automatically initialize the doubly linked list created pointers.
15df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin */
16df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jintemplate <typename T> class SkPtrWrapper {
17df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin  public:
18df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin      SkPtrWrapper() : fPtr(NULL) {}
19df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin      SkPtrWrapper& operator =(T* ptr) { fPtr = ptr; return *this; }
20df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin      operator T*() const { return fPtr; }
21df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin      T* operator->() { return fPtr; }
22df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin  private:
23df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin      T* fPtr;
24df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin};
25df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin
26df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin
27df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin/**
28df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin * This macro creates the member variables required by the SkTInternalLList class. It should be
29df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin * placed in the private section of any class that will be stored in a double linked list.
30df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin */
31df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin#define SK_DECLARE_INTERNAL_LLIST_INTERFACE(ClassName)              \
32df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin    friend class SkTInternalLList<ClassName>;                       \
33df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin    /* back pointer to the owning list - for debugging */           \
34df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin    SkDEBUGCODE(SkPtrWrapper<SkTInternalLList<ClassName> > fList;)  \
35df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin    SkPtrWrapper<ClassName> fPrev;                                  \
36df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin    SkPtrWrapper<ClassName> fNext
37df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin
38df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin/**
39df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin * This class implements a templated internal doubly linked list data structure.
40df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jin */
41df778b5b087c324e1078c6ba692d0aff4f940ac9Kevin Jintemplate <class T> class SkTInternalLList : SkNoncopyable {
42public:
43    SkTInternalLList()
44        : fHead(NULL)
45        , fTail(NULL) {
46    }
47
48    void remove(T* entry) {
49        SkASSERT(fHead && fTail);
50        SkASSERT(this->isInList(entry));
51
52        T* prev = entry->fPrev;
53        T* next = entry->fNext;
54
55        if (prev) {
56            prev->fNext = next;
57        } else {
58            fHead = next;
59        }
60        if (next) {
61            next->fPrev = prev;
62        } else {
63            fTail = prev;
64        }
65
66        entry->fPrev = NULL;
67        entry->fNext = NULL;
68
69#ifdef SK_DEBUG
70        entry->fList = NULL;
71#endif
72    }
73
74    void addToHead(T* entry) {
75        SkASSERT(NULL == entry->fPrev && NULL == entry->fNext);
76        SkASSERT(NULL == entry->fList);
77
78        entry->fPrev = NULL;
79        entry->fNext = fHead;
80        if (fHead) {
81            fHead->fPrev = entry;
82        }
83        fHead = entry;
84        if (NULL == fTail) {
85            fTail = entry;
86        }
87
88#ifdef SK_DEBUG
89        entry->fList = this;
90#endif
91    }
92
93    void addToTail(T* entry) {
94        SkASSERT(NULL == entry->fPrev && NULL == entry->fNext);
95        SkASSERT(NULL == entry->fList);
96
97        entry->fPrev = fTail;
98        entry->fNext = NULL;
99        if (fTail) {
100            fTail->fNext = entry;
101        }
102        fTail = entry;
103        if (NULL == fHead) {
104            fHead = entry;
105        }
106
107#ifdef SK_DEBUG
108        entry->fList = this;
109#endif
110    }
111
112    /**
113     * Inserts a new list entry before an existing list entry. The new entry must not already be
114     * a member of this or any other list. If existingEntry is NULL then the new entry is added
115     * at the tail.
116     */
117    void addBefore(T* newEntry, T* existingEntry) {
118        SkASSERT(newEntry);
119
120        if (NULL == existingEntry) {
121            this->addToTail(newEntry);
122            return;
123        }
124
125        SkASSERT(this->isInList(existingEntry));
126        newEntry->fNext = existingEntry;
127        T* prev = existingEntry->fPrev;
128        existingEntry->fPrev = newEntry;
129        newEntry->fPrev = prev;
130        if (NULL == prev) {
131            SkASSERT(fHead == existingEntry);
132            fHead = newEntry;
133        } else {
134            prev->fNext = newEntry;
135        }
136#ifdef SK_DEBUG
137        newEntry->fList = this;
138#endif
139    }
140
141    /**
142     * Inserts a new list entry after an existing list entry. The new entry must not already be
143     * a member of this or any other list. If existingEntry is NULL then the new entry is added
144     * at the head.
145     */
146    void addAfter(T* newEntry, T* existingEntry) {
147        SkASSERT(newEntry);
148
149        if (NULL == existingEntry) {
150            this->addToHead(newEntry);
151            return;
152        }
153
154        SkASSERT(this->isInList(existingEntry));
155        newEntry->fPrev = existingEntry;
156        T* next = existingEntry->fNext;
157        existingEntry->fNext = newEntry;
158        newEntry->fNext = next;
159        if (NULL == next) {
160            SkASSERT(fTail == existingEntry);
161            fTail = newEntry;
162        } else {
163            next->fPrev = newEntry;
164        }
165#ifdef SK_DEBUG
166        newEntry->fList = this;
167#endif
168    }
169
170    bool isEmpty() const {
171        return NULL == fHead && NULL == fTail;
172    }
173
174    T* head() { return fHead; }
175    T* tail() { return fTail; }
176
177    class Iter {
178    public:
179        enum IterStart {
180            kHead_IterStart,
181            kTail_IterStart
182        };
183
184        Iter() : fCurr(NULL) {}
185        Iter(const Iter& iter) : fCurr(iter.fCurr) {}
186        Iter& operator= (const Iter& iter) { fCurr = iter.fCurr; return *this; }
187
188        T* init(const SkTInternalLList& list, IterStart startLoc) {
189            if (kHead_IterStart == startLoc) {
190                fCurr = list.fHead;
191            } else {
192                SkASSERT(kTail_IterStart == startLoc);
193                fCurr = list.fTail;
194            }
195
196            return fCurr;
197        }
198
199        T* get() { return fCurr; }
200
201        /**
202         * Return the next/previous element in the list or NULL if at the end.
203         */
204        T* next() {
205            if (NULL == fCurr) {
206                return NULL;
207            }
208
209            fCurr = fCurr->fNext;
210            return fCurr;
211        }
212
213        T* prev() {
214            if (NULL == fCurr) {
215                return NULL;
216            }
217
218            fCurr = fCurr->fPrev;
219            return fCurr;
220        }
221
222    private:
223        T* fCurr;
224    };
225
226#ifdef SK_DEBUG
227    void validate() const {
228        SkASSERT(!fHead == !fTail);
229        Iter iter;
230        for (T* item = iter.init(*this, Iter::kHead_IterStart); item; item = iter.next()) {
231            SkASSERT(this->isInList(item));
232            if (NULL == item->fPrev) {
233                SkASSERT(fHead == item);
234            } else {
235                SkASSERT(item->fPrev->fNext == item);
236            }
237            if (NULL == item->fNext) {
238                SkASSERT(fTail == item);
239            } else {
240                SkASSERT(item->fNext->fPrev == item);
241            }
242        }
243    }
244
245    /**
246     * Debugging-only method that uses the list back pointer to check if 'entry' is indeed in 'this'
247     * list.
248     */
249    bool isInList(const T* entry) const {
250        return entry->fList == this;
251    }
252
253    /**
254     * Debugging-only method that laboriously counts the list entries.
255     */
256    int countEntries() const {
257        int count = 0;
258        for (T* entry = fHead; entry; entry = entry->fNext) {
259            ++count;
260        }
261        return count;
262    }
263#endif // SK_DEBUG
264
265private:
266    T* fHead;
267    T* fTail;
268
269    typedef SkNoncopyable INHERITED;
270};
271
272#endif
273