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