2 * Copyright (C) 2003 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #import "KWQListImpl.h"
30 #import <CoreFoundation/CFArray.h>
31 #import "KWQAssertions.h"
32 #import "misc/main_thread_malloc.h"
37 KWQListNode(void *d) : data(d), next(NULL), prev(NULL) { }
39 MAIN_THREAD_ALLOCATED;
47 static KWQListNode *copyList(KWQListNode *l, KWQListNode *&tail)
49 KWQListNode *node = l;
50 KWQListNode *copyHead = NULL;
51 KWQListNode *last = NULL;
53 while (node != NULL) {
54 KWQListNode *copy = new KWQListNode(node->data);
72 KWQListImpl::KWQListImpl(void (*deleteFunc)(void *)) :
77 deleteItem(deleteFunc),
82 KWQListImpl::KWQListImpl(const KWQListImpl &impl) :
84 nodeCount(impl.nodeCount),
85 deleteItem(impl.deleteItem),
88 head = copyList(impl.head, tail);
91 KWQListImpl::~KWQListImpl()
95 KWQListIteratorImpl *next;
96 for (KWQListIteratorImpl *it = iterators; it != NULL; it = next) {
99 ASSERT(it->node == NULL);
105 void KWQListImpl::clear(bool deleteItems)
109 for (KWQListNode *node = head; node != NULL; node = next) {
112 deleteItem(node->data);
122 for (KWQListIteratorImpl *it = iterators; it != NULL; it = it->next) {
127 void KWQListImpl::sort(int (*compareFunc)(void *a, void *b, void *data), void *data)
129 // no sorting for 0 or 1-element lists
130 if (nodeCount <= 1) {
134 // special case for 2-element lists
135 if (nodeCount == 2) {
136 void *a = head->data;
137 void *b = head->next->data;
138 if (compareFunc(a, b, data) <= 0) {
141 head->next->data = a;
146 // insertion sort for most common sizes
147 const uint cutoff = 32;
148 if (nodeCount <= cutoff) {
149 // Straight out of Sedgewick's Algorithms in C++.
151 // put all the elements into an array
154 for (KWQListNode *node = head; node != NULL; node = node->next) {
158 // move the smallest element to the start to serve as a sentinel
159 for (i = nodeCount - 1; i > 0; i--) {
160 if (compareFunc(a[i-1], a[i], data) > 0) {
167 // move other items to the right and put a[i] into position
168 for (i = 2; i < nodeCount; i++) {
171 while (compareFunc(v, a[j-1], data) < 0) {
178 // finally, put everything back into the list
180 for (KWQListNode *node = head; node != NULL; node = node->next) {
186 // CFArray sort for larger lists
188 CFMutableArrayRef array = CFArrayCreateMutable(NULL, nodeCount, NULL);
190 for (KWQListNode *node = head; node != NULL; node = node->next) {
191 CFArrayAppendValue(array, node->data);
194 CFArraySortValues(array, CFRangeMake(0, nodeCount), (CFComparatorFunction) compareFunc, data);
197 for (KWQListNode *node = head; node != NULL; node = node->next) {
198 node->data = const_cast<void *>(CFArrayGetValueAtIndex(array, i++));
204 void *KWQListImpl::at(uint n)
207 if (n >= nodeCount - 1) {
211 for (uint i = 0; i < n && node != NULL; i++) {
217 return node ? node->data : 0;
220 bool KWQListImpl::insert(uint n, const void *item)
226 KWQListNode *node = new KWQListNode((void *)item);
238 } else if (n == nodeCount) {
248 // iterate to one node before the insertion point, can't be null
249 // since we know n > 0 and n < nodeCount
250 KWQListNode *prevNode = head;
252 for (uint i = 0; i < n - 1; i++) {
253 prevNode = prevNode->next;
255 node->prev = prevNode;
256 node->next = prevNode->next;
257 if (node->next != NULL) {
258 node->next->prev = node;
260 prevNode->next = node;
268 bool KWQListImpl::remove(bool shouldDeleteItem)
270 KWQListNode *node = cur;
275 if (node->prev == NULL) {
278 node->prev->next = node->next;
281 if (node->next == NULL) {
284 node->next->prev = node->prev;
287 if (node->next != NULL) {
293 for (KWQListIteratorImpl *it = iterators; it != NULL; it = it->next) {
294 if (it->node == node) {
299 if (shouldDeleteItem) {
300 deleteItem(node->data);
309 bool KWQListImpl::remove(uint n, bool deleteItem)
311 if (n >= nodeCount) {
316 return remove(deleteItem);
319 bool KWQListImpl::removeFirst(bool deleteItem)
321 return remove(0, deleteItem);
324 bool KWQListImpl::removeLast(bool deleteItem)
326 return remove(nodeCount - 1, deleteItem);
329 bool KWQListImpl::remove(const void *item, bool deleteItem, int (*compareFunc)(void *a, void *b, void *data), void *data)
335 while (node != NULL && compareFunc((void *)item, node->data, data) != 0) {
345 return remove(deleteItem);
348 bool KWQListImpl::removeRef(const void *item, bool deleteItem)
354 while (node != NULL && item != node->data) {
364 return remove(deleteItem);
367 void *KWQListImpl::getFirst() const
369 return head ? head->data : 0;
372 void *KWQListImpl::getLast() const
374 return tail ? tail->data : 0;
377 void *KWQListImpl::current() const
386 void *KWQListImpl::first()
392 void *KWQListImpl::last()
398 void *KWQListImpl::next()
406 void *KWQListImpl::prev()
414 void *KWQListImpl::take(uint n)
416 void *retval = at(n);
421 void *KWQListImpl::take()
423 void *retval = current();
428 void KWQListImpl::append(const void *item)
430 insert(nodeCount, item);
433 void KWQListImpl::prepend(const void *item)
438 uint KWQListImpl::containsRef(const void *item) const
442 for (KWQListNode *node = head; node != NULL; node = node->next) {
443 if (item == node->data) {
451 // Only used for KDOM::NodeImpl::compareDocumentPosition(NodeImpl *other)
452 // remove when no longer needed.
453 int KWQListImpl::findRef(const void *item)
455 KWQListNode *node = head;
458 while (node != NULL && item != node->data) {
472 KWQListImpl &KWQListImpl::assign(const KWQListImpl &impl, bool deleteItems)
475 KWQListImpl(impl).swap(*this);
479 void KWQListImpl::addIterator(KWQListIteratorImpl *iter) const
481 iter->next = iterators;
484 if (iterators != NULL) {
485 iterators->prev = iter;
490 void KWQListImpl::removeIterator(KWQListIteratorImpl *iter) const
492 if (iter->prev == NULL) {
493 iterators = iter->next;
495 iter->prev->next = iter->next;
498 if (iter->next != NULL) {
499 iter->next->prev = iter->prev;
503 void KWQListImpl::swap(KWQListImpl &other)
507 ASSERT(iterators == NULL);
508 ASSERT(other.iterators == NULL);
510 swap(head, other.head);
511 swap(tail, other.tail);
512 swap(cur, other.cur);
513 swap(nodeCount, other.nodeCount);
514 swap(deleteItem, other.deleteItem);
518 KWQListIteratorImpl::KWQListIteratorImpl() :
524 KWQListIteratorImpl::KWQListIteratorImpl(const KWQListImpl &impl) :
528 impl.addIterator(this);
531 KWQListIteratorImpl::~KWQListIteratorImpl()
534 list->removeIterator(this);
538 KWQListIteratorImpl::KWQListIteratorImpl(const KWQListIteratorImpl &impl) :
543 list->addIterator(this);
547 uint KWQListIteratorImpl::count() const
549 return list == NULL ? 0 : list->count();
552 void *KWQListIteratorImpl::toFirst()
560 void *KWQListIteratorImpl::toLast()
568 void *KWQListIteratorImpl::current() const
570 return node == NULL ? NULL : node->data;
573 void *KWQListIteratorImpl::operator--()
581 void *KWQListIteratorImpl::operator++()
589 KWQListIteratorImpl &KWQListIteratorImpl::operator=(const KWQListIteratorImpl &impl)
592 list->removeIterator(this);
599 list->addIterator(this);