📄 kwqlistimpl.cpp
字号:
/* * Copyright (C) 2001, 2002 Apple Computer, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "KWQListImpl.h"#include <cstddef>#include <algorithm>#if !KWIQ#include <CoreFoundation/CFArray.h>#endif#include "KWQAssertions.h"class KWQListNode{public: KWQListNode(void *d) : data(d), next(NULL), prev(NULL) { } void *data; KWQListNode *next; KWQListNode *prev;};static KWQListNode *copyList(KWQListNode *l, KWQListNode *&tail){ KWQListNode *node = l; KWQListNode *copyHead = NULL; KWQListNode *last = NULL; while (node != NULL) { KWQListNode *copy = new KWQListNode(node->data); if (last != NULL) { last->next = copy; } else { copyHead = copy; } copy->prev = last; last = copy; node = node->next; } tail = last; return copyHead;}KWQListImpl::KWQListImpl(void (*deleteFunc)(void *)) : head(NULL), tail(NULL), cur(NULL), nodeCount(0), deleteItem(deleteFunc), iterators(NULL){}KWQListImpl::KWQListImpl(const KWQListImpl &impl) : cur(NULL), nodeCount(impl.nodeCount), deleteItem(impl.deleteItem), iterators(NULL){ head = copyList(impl.head, tail);}KWQListImpl::~KWQListImpl(){ clear(false); KWQListIteratorImpl *next; for (KWQListIteratorImpl *it = iterators; it != NULL; it = next) { next = it->next; it->list = NULL; ASSERT(it->node == NULL); it->next = NULL; it->prev = NULL; }} void KWQListImpl::clear(bool deleteItems){ KWQListNode *next; for (KWQListNode *node = head; node != NULL; node = next) { next = node->next; if (deleteItems) { deleteItem(node->data); } delete node; } head = NULL; tail = NULL; cur = NULL; nodeCount = 0; for (KWQListIteratorImpl *it = iterators; it != NULL; it = it->next) { it->node = NULL; }}/* FIXME: not re-entrant */static void *_data = 0;static int (*_cmpfunc)(void *a, void *b, void *data);extern "C" {static int _qsortCmpFunc(const void*a, const void*b){ return _cmpfunc(const_cast<void*>(a), const_cast<void*>(b), _data);}}void KWQListImpl::sort(int (*compareFunc)(void *a, void *b, void *data), void *data){ // no sorting for 0 or 1-element lists if (nodeCount <= 1) { return; } // special case for 2-element lists if (nodeCount == 2) { void *a = head->data; void *b = head->next->data; if (compareFunc(a, b, data) <= 0) { return; } head->next->data = a; head->data = b; return; } // insertion sort for most common sizes const uint cutoff = 2000; if (nodeCount <= cutoff) { // Straight out of Sedgewick's Algorithms in C++. // put all the elements into an array void *a[cutoff]; uint i = 0; KWQListNode *node; for (node = head; node != NULL; node = node->next) { a[i++] = node->data; } // move the smallest element to the start to serve as a sentinel for (i = nodeCount - 1; i > 0; i--) { if (compareFunc(a[i-1], a[i], data) > 0) { void *t = a[i-1]; a[i-1] = a[i]; a[i] = t; } } // move other items to the right and put a[i] into position for (i = 2; i < nodeCount; i++) { void *v = a[i]; uint j = i; while (compareFunc(v, a[j-1], data) < 0) { a[j] = a[j-1]; j--; } a[j] = v; } // finally, put everything back into the list i = 0; for (node = head; node != NULL; node = node->next) { node->data = a[i++]; } return; } /* use standard c lib qsort */ void **arr = new void*[nodeCount]; if (arr) { void *olddata = _data; int (*oldcmpfunc)(void *a, void *b, void *data) = _cmpfunc; _data = data; _cmpfunc = compareFunc; int i = 0; for (KWQListNode *node = head; node != NULL; node = node->next) { arr[i++] = node->data; } qsort(arr, nodeCount, sizeof(void*), _qsortCmpFunc); i = 0; for (KWQListNode *node = head; node != NULL; node = node->next) { node->data = const_cast<void *>(arr[i++]); } _data = olddata; _cmpfunc = oldcmpfunc; delete [] arr; }}void *KWQListImpl::at(uint n){ KWQListNode *node; if (n >= nodeCount - 1) { node = tail; } else { node = head; for (uint i = 0; i < n && node != NULL; i++) { node = node->next; } } cur = node; return node ? node->data : 0;}bool KWQListImpl::insert(uint n, const void *item){ if (n > nodeCount) { return false; } KWQListNode *node = new KWQListNode((void *)item); if (n == 0) { // inserting at head node->next = head; if (head != NULL) { head->prev = node; } head = node; if (tail == NULL) { tail = node; } } else if (n == nodeCount) { // inserting at tail node->prev = tail; if (tail != NULL) { tail->next = node; } tail = node; } else { // general insertion // iterate to one node before the insertion point, can't be null // since we know n > 0 and n < nodeCount KWQListNode *prevNode = head; for (uint i = 0; i < n - 1; i++) { prevNode = prevNode->next; } node->prev = prevNode; node->next = prevNode->next; if (node->next != NULL) { node->next->prev = node; } prevNode->next = node; } nodeCount++; cur = node; return true;}bool KWQListImpl::remove(bool shouldDeleteItem){ KWQListNode *node = cur; if (node == NULL) { return false; } if (node->prev == NULL) { head = node->next; } else { node->prev->next = node->next; } if (node->next == NULL) { tail = node->prev; } else { node->next->prev = node->prev; } if (node->next != NULL) { cur = node->next; } else { cur = node->prev; } for (KWQListIteratorImpl *it = iterators; it != NULL; it = it->next) { if (it->node == node) { it->node = cur; } } if (shouldDeleteItem) { deleteItem(node->data); } delete node; nodeCount--; return true;}bool KWQListImpl::remove(uint n, bool deleteItem){ if (n >= nodeCount) { return false; } at(n); return remove(deleteItem);}bool KWQListImpl::removeFirst(bool deleteItem){ return remove(0, deleteItem);}bool KWQListImpl::removeLast(bool deleteItem){ return remove(nodeCount - 1, deleteItem);}bool KWQListImpl::remove(const void *item, bool deleteItem, int (*compareFunc)(void *a, void *b, void *data), void *data){ KWQListNode *node; node = head; while (node != NULL && compareFunc((void *)item, node->data, data) != 0) { node = node->next; } if (node == NULL) { return false; } cur = node; return remove(deleteItem);}bool KWQListImpl::removeRef(const void *item, bool deleteItem){ KWQListNode *node; node = head; while (node != NULL && item != node->data) { node = node->next; } if (node == NULL) { return false; } cur = node; return remove(deleteItem);}void *KWQListImpl::getFirst() const{ return head ? head->data : 0;}void *KWQListImpl::getLast() const{ return tail ? tail->data : 0;}void *KWQListImpl::current() const{ if (cur != NULL) { return cur->data; } else { return NULL; }}void *KWQListImpl::first(){ cur = head; return current();}void *KWQListImpl::last(){ cur = tail; return current();}void *KWQListImpl::next(){ if (cur != NULL) { cur = cur->next; } return current();}void *KWQListImpl::prev(){ if (cur != NULL) { cur = cur->prev; } return current();}void *KWQListImpl::take(uint n){ void *retval = at(n); remove(false); return retval;}void *KWQListImpl::take(){ void *retval = current(); remove(false); return retval;}void KWQListImpl::append(const void *item){ insert(nodeCount, item);}void KWQListImpl::prepend(const void *item){ insert(0, item);}uint KWQListImpl::containsRef(const void *item) const{ uint count = 0; for (KWQListNode *node = head; node != NULL; node = node->next) { if (item == node->data) { ++count; } } return count;}KWQListImpl &KWQListImpl::assign(const KWQListImpl &impl, bool deleteItems){ clear(deleteItems); KWQListImpl(impl).swap(*this); return *this;}void KWQListImpl::addIterator(KWQListIteratorImpl *iter) const{ iter->next = iterators; iter->prev = NULL; if (iterators != NULL) { iterators->prev = iter; } iterators = iter;}void KWQListImpl::removeIterator(KWQListIteratorImpl *iter) const{ if (iter->prev == NULL) { iterators = iter->next; } else { iter->prev->next = iter->next; } if (iter->next != NULL) { iter->next->prev = iter->prev; }}void KWQListImpl::swap(KWQListImpl &other){ ASSERT(iterators == NULL); ASSERT(other.iterators == NULL); std::swap(head, other.head); std::swap(tail, other.tail); std::swap(cur, other.cur); std::swap(nodeCount, other.nodeCount); std::swap(deleteItem, other.deleteItem);}KWQListIteratorImpl::KWQListIteratorImpl() : list(NULL), node(NULL){}KWQListIteratorImpl::KWQListIteratorImpl(const KWQListImpl &impl) : list(&impl), node(impl.head){ impl.addIterator(this);}KWQListIteratorImpl::~KWQListIteratorImpl(){ if (list != NULL) { list->removeIterator(this); }}KWQListIteratorImpl::KWQListIteratorImpl(const KWQListIteratorImpl &impl) : list(impl.list), node(impl.node){ if (list != NULL) { list->addIterator(this); }}uint KWQListIteratorImpl::count() const{ return list == NULL ? 0 : list->count();}void *KWQListIteratorImpl::toFirst(){ if (list != NULL) { node = list->head; } return current();}void *KWQListIteratorImpl::toLast(){ if (list != NULL) { node = list->tail; } return current();}void *KWQListIteratorImpl::current() const{ return node == NULL ? NULL : node->data;}void *KWQListIteratorImpl::operator--(){ if (node != NULL) { node = node->prev; } return current();}void *KWQListIteratorImpl::operator++(){ if (node != NULL) { node = node->next; } return current();}KWQListIteratorImpl &KWQListIteratorImpl::operator=(const KWQListIteratorImpl &impl){ if (list != NULL) { list->removeIterator(this); } list = impl.list; node = impl.node; if (list != NULL) { list->addIterator(this); } return *this;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -