• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
33 namespace android {
34 namespace 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  */
42 template<typename T>
43 class List
44 {
45 protected:
46     /*
47      * One element in the list.
48      */
49     class _Node {
50     public:
_Node(const T & val)51         explicit _Node(const T& val) : mVal(val) {}
~_Node()52         ~_Node() {}
getRef()53         inline T& getRef() { return mVal; }
getRef()54         inline const T& getRef() const { return mVal; }
getPrev()55         inline _Node* getPrev() const { return mpPrev; }
getNext()56         inline _Node* getNext() const { return mpNext; }
setVal(const T & val)57         inline void setVal(const T& val) { mVal = val; }
setPrev(_Node * ptr)58         inline void setPrev(_Node* ptr) { mpPrev = ptr; }
setNext(_Node * 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 
_ListIterator(_NodePtr ptr)93         explicit _ListIterator(_NodePtr ptr) : mpNode(ptr) {}
94 
95     public:
_ListIterator()96         _ListIterator() {}
_ListIterator(const _Iter & rhs)97         _ListIterator(const _Iter& rhs) : mpNode(rhs.mpNode) {}
~_ListIterator()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
_ListIterator(const V & rhs)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 
getNode()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 
163 public:
List()164     List() {
165         prep();
166     }
List(const List<T> & src)167     List(const List<T>& src) {      // copy-constructor
168         prep();
169         insert(begin(), src.begin(), src.end());
170     }
~List()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 */
empty()182     inline bool empty() const { return mpMiddle->getNext() == mpMiddle; }
183 
184     /* return #of elements in list */
size()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      */
begin()194     inline iterator begin() {
195         return iterator(mpMiddle->getNext());
196     }
begin()197     inline const_iterator begin() const {
198         return const_iterator(const_cast<_Node const*>(mpMiddle->getNext()));
199     }
end()200     inline iterator end() {
201         return iterator(mpMiddle);
202     }
end()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 */
push_front(const T & val)208     void push_front(const T& val) { insert(begin(), val); }
push_back(const T & val)209     void push_back(const T& val) { insert(end(), val); }
210 
211     /* insert before the current node; returns iterator at new node */
insert(iterator posn,const T & val)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 */
insert(iterator posn,const_iterator first,const_iterator last)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 */
erase(iterator posn)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 */
erase(iterator first,iterator last)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 */
clear()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     >
distance(_ListIterator<U,CL> first,_ListIterator<U,CR> last)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 
285 private:
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      */
prep()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  */
313 template<class T>
314 List<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