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