aboutsummaryrefslogtreecommitdiffhomepage
path: root/include/core/SkTDLinkedList.h
blob: 92478121bbc7aaad7575c04368d60d651df7ffc9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/*
 * 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 SkTDLinkedList_DEFINED
#define SkTDLinkedList_DEFINED

#include "SkTypes.h"

/**
 * Helper class to automatically initialize the doubly linked list
 * created pointers.
 */
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;
};


/**
 * This macro creates the member variables required by
 * the SkTDLinkedList class. It should be placed in the private section
 * of any class that will be stored in a double linked list.
 */
#define SK_DEFINE_DLINKEDLIST_INTERFACE(ClassName)              \
    friend class SkTDLinkedList<ClassName>;                     \
    /* back pointer to the owning list - for debugging */       \
    SkDEBUGCODE(SkPtrWrapper<SkTDLinkedList<ClassName> > fList;)\
    SkPtrWrapper<ClassName> fPrev;                              \
    SkPtrWrapper<ClassName> fNext;

/**
 * This class implements a templated internal doubly linked list data structure.
 */
template <class T> class SkTDLinkedList : public SkNoncopyable {
public:
    SkTDLinkedList()
        : fHead(NULL)
        , fTail(NULL) {
    }

    void remove(T* entry) {
        SkASSERT(NULL != fHead && NULL != fTail);
        SkASSERT(this->isInList(entry));

        T* prev = entry->fPrev;
        T* next = entry->fNext;

        if (NULL != prev) {
            prev->fNext = next;
        } else {
            fHead = next;
        }
        if (NULL != next) {
            next->fPrev = prev;
        } else {
            fTail = prev;
        }

        entry->fPrev = NULL;
        entry->fNext = NULL;

#ifdef SK_DEBUG
        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;
        if (NULL != fHead) {
            fHead->fPrev = entry;
        }
        fHead = entry;
        if (NULL == fTail) {
            fTail = entry;
        }

#ifdef SK_DEBUG
        entry->fList = this;
#endif
    }

    bool isEmpty() const {
        return NULL == fHead && NULL == fTail;
    }

    T* head() { return fHead; }
    T* tail() { return fTail; }

    class Iter {
    public:
        enum IterStart {
            kHead_IterStart,
            kTail_IterStart
        };

        Iter() : fCur(NULL) {}

        T* init(SkTDLinkedList& list, IterStart startLoc) {
            if (kHead_IterStart == startLoc) {
                fCur = list.fHead;
            } else {
                SkASSERT(kTail_IterStart == startLoc);
                fCur = list.fTail;
            }

            return fCur;
        }

        /**
         * Return the next/previous element in the list or NULL if at the end.
         */
        T* next() {
            if (NULL == fCur) {
                return NULL;
            }

            fCur = fCur->fNext;
            return fCur;
        }

        T* prev() {
            if (NULL == fCur) {
                return NULL;
            }

            fCur = fCur->fPrev;
            return fCur;
        }

    private:
        T* fCur;
    };

#ifdef SK_DEBUG
    void validate() const {
        GrAssert(!fHead == !fTail);
    }

    /**
     * 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; NULL != entry; entry = entry->fNext) {
            ++count;
        }
        return count;
    }
#endif // SK_DEBUG

private:
    T* fHead;
    T* fTail;

    typedef SkNoncopyable INHERITED;
};

#endif // SkTDLinkedList_DEFINED