List.h revision b7286aa02e1e554a1ef21a957fabe593f05c1260
1/*
2 * Copyright (C) 2005 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//
18// Templated list class.  Normally we'd use STL, but we don't have that.
19// This class mimics STL's interfaces.
20//
21// Objects are copied into the list with the '=' operator or with copy-
22// construction, so if the compiler's auto-generated versions won't work for
23// you, define your own.
24//
25// The only class you want to use from here is "List".
26//
27#ifndef _SYSUTILS_LIST_H
28#define _SYSUTILS_LIST_H
29
30#include <stddef.h>
31#include <stdint.h>
32
33namespace android {
34namespace sysutils {
35
36/*
37 * Doubly-linked list.  Instantiate with "List<MyClass> myList".
38 *
39 * Objects added to the list are copied using the assignment operator,
40 * so this must be defined.
41 */
42template<typename T>
43class List
44{
45protected:
46    /*
47     * One element in the list.
48     */
49    class _Node {
50    public:
51        explicit _Node(const T& val) : mVal(val) {}
52        ~_Node() {}
53        inline T& getRef() { return mVal; }
54        inline const T& getRef() const { return mVal; }
55        inline _Node* getPrev() const { return mpPrev; }
56        inline _Node* getNext() const { return mpNext; }
57        inline void setVal(const T& val) { mVal = val; }
58        inline void setPrev(_Node* ptr) { mpPrev = ptr; }
59        inline void setNext(_Node* ptr) { mpNext = ptr; }
60    private:
61        friend class List;
62        friend class _ListIterator;
63        T           mVal;
64        _Node*      mpPrev;
65        _Node*      mpNext;
66    };
67
68    /*
69     * Iterator for walking through the list.
70     */
71
72    template <typename TYPE>
73    struct CONST_ITERATOR {
74        typedef _Node const * NodePtr;
75        typedef const TYPE Type;
76    };
77
78    template <typename TYPE>
79    struct NON_CONST_ITERATOR {
80        typedef _Node* NodePtr;
81        typedef TYPE Type;
82    };
83
84    template<
85        typename U,
86        template <class> class Constness
87    >
88    class _ListIterator {
89        typedef _ListIterator<U, Constness>     _Iter;
90        typedef typename Constness<U>::NodePtr  _NodePtr;
91        typedef typename Constness<U>::Type     _Type;
92
93        explicit _ListIterator(_NodePtr ptr) : mpNode(ptr) {}
94
95    public:
96        _ListIterator() {}
97        _ListIterator(const _Iter& rhs) : mpNode(rhs.mpNode) {}
98        ~_ListIterator() {}
99
100        // this will handle conversions from iterator to const_iterator
101        // (and also all convertible iterators)
102        // Here, in this implementation, the iterators can be converted
103        // if the nodes can be converted
104        template<typename V> explicit
105        _ListIterator(const V& rhs) : mpNode(rhs.mpNode) {}
106
107
108        /*
109         * Dereference operator.  Used to get at the juicy insides.
110         */
111        _Type& operator*() const { return mpNode->getRef(); }
112        _Type* operator->() const { return &(mpNode->getRef()); }
113
114        /*
115         * Iterator comparison.
116         */
117        inline bool operator==(const _Iter& right) const {
118            return mpNode == right.mpNode; }
119
120        inline bool operator!=(const _Iter& right) const {
121            return mpNode != right.mpNode; }
122
123        /*
124         * handle comparisons between iterator and const_iterator
125         */
126        template<typename OTHER>
127        inline bool operator==(const OTHER& right) const {
128            return mpNode == right.mpNode; }
129
130        template<typename OTHER>
131        inline bool operator!=(const OTHER& right) const {
132            return mpNode != right.mpNode; }
133
134        /*
135         * Incr/decr, used to move through the list.
136         */
137        inline _Iter& operator++() {     // pre-increment
138            mpNode = mpNode->getNext();
139            return *this;
140        }
141        const _Iter operator++(int) {    // post-increment
142            _Iter tmp(*this);
143            mpNode = mpNode->getNext();
144            return tmp;
145        }
146        inline _Iter& operator--() {     // pre-increment
147            mpNode = mpNode->getPrev();
148            return *this;
149        }
150        const _Iter operator--(int) {   // post-increment
151            _Iter tmp(*this);
152            mpNode = mpNode->getPrev();
153            return tmp;
154        }
155
156        inline _NodePtr getNode() const { return mpNode; }
157
158        _NodePtr mpNode;    /* should be private, but older gcc fails */
159    private:
160        friend class List;
161    };
162
163public:
164    List() {
165        prep();
166    }
167    List(const List<T>& src) {      // copy-constructor
168        prep();
169        insert(begin(), src.begin(), src.end());
170    }
171    virtual ~List() {
172        clear();
173        delete[] (unsigned char*) mpMiddle;
174    }
175
176    typedef _ListIterator<T, NON_CONST_ITERATOR> iterator;
177    typedef _ListIterator<T, CONST_ITERATOR> const_iterator;
178
179    List<T>& operator=(const List<T>& right);
180
181    /* returns true if the list is empty */
182    inline bool empty() const { return mpMiddle->getNext() == mpMiddle; }
183
184    /* return #of elements in list */
185    size_t size() const {
186        return size_t(distance(begin(), end()));
187    }
188
189    /*
190     * Return the first element or one past the last element.  The
191     * _Node* we're returning is converted to an "iterator" by a
192     * constructor in _ListIterator.
193     */
194    inline iterator begin() {
195        return iterator(mpMiddle->getNext());
196    }
197    inline const_iterator begin() const {
198        return const_iterator(const_cast<_Node const*>(mpMiddle->getNext()));
199    }
200    inline iterator end() {
201        return iterator(mpMiddle);
202    }
203    inline const_iterator end() const {
204        return const_iterator(const_cast<_Node const*>(mpMiddle));
205    }
206
207    /* add the object to the head or tail of the list */
208    void push_front(const T& val) { insert(begin(), val); }
209    void push_back(const T& val) { insert(end(), val); }
210
211    /* insert before the current node; returns iterator at new node */
212    iterator insert(iterator posn, const T& val)
213    {
214        _Node* newNode = new _Node(val);        // alloc & copy-construct
215        newNode->setNext(posn.getNode());
216        newNode->setPrev(posn.getNode()->getPrev());
217        posn.getNode()->getPrev()->setNext(newNode);
218        posn.getNode()->setPrev(newNode);
219        return iterator(newNode);
220    }
221
222    /* insert a range of elements before the current node */
223    void insert(iterator posn, const_iterator first, const_iterator last) {
224        for ( ; first != last; ++first)
225            insert(posn, *first);
226    }
227
228    /* remove one entry; returns iterator at next node */
229    iterator erase(iterator posn) {
230        _Node* pNext = posn.getNode()->getNext();
231        _Node* pPrev = posn.getNode()->getPrev();
232        pPrev->setNext(pNext);
233        pNext->setPrev(pPrev);
234        delete posn.getNode();
235        return iterator(pNext);
236    }
237
238    /* remove a range of elements */
239    iterator erase(iterator first, iterator last) {
240        while (first != last)
241            erase(first++);     // don't erase than incr later!
242        return iterator(last);
243    }
244
245    /* remove all contents of the list */
246    void clear() {
247        _Node* pCurrent = mpMiddle->getNext();
248        _Node* pNext;
249
250        while (pCurrent != mpMiddle) {
251            pNext = pCurrent->getNext();
252            delete pCurrent;
253            pCurrent = pNext;
254        }
255        mpMiddle->setPrev(mpMiddle);
256        mpMiddle->setNext(mpMiddle);
257    }
258
259    /*
260     * Measure the distance between two iterators.  On exist, "first"
261     * will be equal to "last".  The iterators must refer to the same
262     * list.
263     *
264     * FIXME: This is actually a generic iterator function. It should be a
265     * template function at the top-level with specializations for things like
266     * vector<>, which can just do pointer math). Here we limit it to
267     * _ListIterator of the same type but different constness.
268     */
269    template<
270        typename U,
271        template <class> class CL,
272        template <class> class CR
273    >
274    ptrdiff_t distance(
275            _ListIterator<U, CL> first, _ListIterator<U, CR> last) const
276    {
277        ptrdiff_t count = 0;
278        while (first != last) {
279            ++first;
280            ++count;
281        }
282        return count;
283    }
284
285private:
286    /*
287     * I want a _Node but don't need it to hold valid data.  More
288     * to the point, I don't want T's constructor to fire, since it
289     * might have side-effects or require arguments.  So, we do this
290     * slightly uncouth storage alloc.
291     */
292    void prep() {
293        mpMiddle = (_Node*) new unsigned char[sizeof(_Node)];
294        mpMiddle->setPrev(mpMiddle);
295        mpMiddle->setNext(mpMiddle);
296    }
297
298    /*
299     * This node plays the role of "pointer to head" and "pointer to tail".
300     * It sits in the middle of a circular list of nodes.  The iterator
301     * runs around the circle until it encounters this one.
302     */
303    _Node*      mpMiddle;
304};
305
306/*
307 * Assignment operator.
308 *
309 * The simplest way to do this would be to clear out the target list and
310 * fill it with the source.  However, we can speed things along by
311 * re-using existing elements.
312 */
313template<class T>
314List<T>& List<T>::operator=(const List<T>& right)
315{
316    if (this == &right)
317        return *this;       // self-assignment
318    iterator firstDst = begin();
319    iterator lastDst = end();
320    const_iterator firstSrc = right.begin();
321    const_iterator lastSrc = right.end();
322    while (firstSrc != lastSrc && firstDst != lastDst)
323        *firstDst++ = *firstSrc++;
324    if (firstSrc == lastSrc)        // ran out of elements in source?
325        erase(firstDst, lastDst);   // yes, erase any extras
326    else
327        insert(lastDst, firstSrc, lastSrc);     // copy remaining over
328    return *this;
329}
330
331}; // namespace sysutils
332}; // namespace android
333
334#endif // _SYSUTILS_LIST_H
335