// This may look like C code, but it is really -*- C++ -*- /* Copyright (C) 1988 Free Software Foundation written by Doug Lea (dl@rocky.oswego.edu) This file is part of the GNU C++ Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef __GNUG__ #pragma implementation #endif #include #include ".List.h" ListNode NilListNode; class init_NilListNode { public: init_NilListNode() { NilListNode.tl = &NilListNode; NilListNode.ref = -1; } }; static init_NilListNode NilListNode_initializer; List& List::operator = (const List& a) { reference(a.P); dereference(P); P = a.P; return *this; } List::pop() { res = P->hd; ListNode* tail = P->tl; reference(tail); dereference(P); P = tail; return res; } void List::set_tail(List& a) { reference(a.P); dereference(P->tl); P->tl = a.P; } List List::nth(int n) { ListNode* p; for (p = P; n-- > 0; p = p->tl); reference(p); return List(p); } List List::last() { ListNode* p = P; if (p != &NilListNode) while (p->tl != &NilListNode) p = p->tl; reference(p); return List(p); } void List::append(List& l) { ListNode* p = P; ListNode* a = l.P; reference(a); if (p != &NilListNode) { while (p->tl != &NilListNode) p = p->tl; p->tl = a; } else P = a; } int List::length() { int l = 0; for (ListNode* p = P; p != &NilListNode; p = p->tl) ++l; return l; } & List::operator [] (int n) { ListNode* p; for (p = P; n-- > 0; p = p->tl); return (p->hd); } int operator == (const List& x, const List& y) { ListNode* a = x.P; ListNode* b = y.P; for (;;) { if (a == &NilListNode) return b == &NilListNode; else if (b == &NilListNode) return 0; else if (EQ(a->hd, b->hd)) { a = a->tl; b = b->tl; } else return 0; } } void List::apply(Procedure f) { for(ListNode* p = P; p != &NilListNode; p = p->tl) (*f)((p->hd)); } void List::subst( old, repl) { for(ListNode* p = P; p != &NilListNode; p = p->tl) if (EQ(p->hd, old)) p->hd = repl; } List::reduce(Combiner f, base) { r = base; for(ListNode* p = P; p != &NilListNode; p = p->tl) r = (*f)(r, (p->hd)); return r; } int List::position( targ) { int l = 0; ListNode* p = P; for (;;) { if (p == &NilListNode) return -1; else if (EQ(p->hd, targ)) return l; else { ++l; p = p->tl; } } } int List::contains( targ) { ListNode* p = P; for (;;) { if (p == &NilListNode) return 0; else if (EQ(p->hd, targ)) return 1; else p = p->tl; } } List List::find( targ) { ListNode* p = P; while (p != &NilListNode && !EQ(p->hd, targ)) p=p->tl; reference(p); return List(p); } Pix List::seek( targ) const { const ListNode* p = P; for (;;) { if (p == &NilListNode) return 0; else if (EQ(p->hd, targ)) return Pix(p); else p = p->tl; } } int List::owns(Pix i) { ListNode* p = P; for (;;) { if (p == &NilListNode) return 0; else if (Pix(p) == i) return 1; else p = p->tl; } } List List::find(List& target) { ListNode* targ = target.P; if (targ == &NilListNode) return List(targ); ListNode* p = P; while (p != &NilListNode) { if (EQ(p->hd, targ->hd)) { ListNode* a = p->tl; ListNode* t = targ->tl; for(;;) { if (t == &NilListNode) { reference(p); return List(p); } else if (a == &NilListNode || !EQ(a->hd, t->hd)) break; else { a = a->tl; t = t->tl; } } } p = p->tl; } return List(&NilListNode); } int List::contains(List& target) { ListNode* targ = target.P; if (targ == &NilListNode) return 0; ListNode* p = P; while (p != &NilListNode) { if (EQ(p->hd, targ->hd)) { ListNode* a = p->tl; ListNode* t = targ->tl; for(;;) { if (t == &NilListNode) return 1; else if (a == &NilListNode || !EQ(a->hd, t->hd)) break; else { a = a->tl; t = t->tl; } } } p = p->tl; } return 0; } void List::del( targ) { ListNode* h = P; // Former bug: targ can be a reference to a element in this list // So do not dereference a element if targ is the element, // until targ is no longer needed, as dereferencing it may destroy it. ListNode* to_be_dereferenced = 0; for (;;) { if (h == &NilListNode) { P = h; if (to_be_dereferenced) dereference(to_be_dereferenced); return; } else if (EQ(h->hd, targ)) { ListNode* nxt = h->tl; reference(nxt); if ((&targ == &h->hd) && (to_be_dereferenced == 0)) to_be_dereferenced = h; else dereference(h); h = nxt; } else break; } ListNode* trail = h; ListNode* p = h->tl; while (p != &NilListNode) { if (EQ(p->hd, targ)) { ListNode* nxt = p->tl; reference(nxt); if ((&targ == &p->hd) && (to_be_dereferenced == 0)) to_be_dereferenced = p; else dereference(p); trail->tl = nxt; p = nxt; } else { trail = p; p = p->tl; } } P = h; if (to_be_dereferenced) dereference(to_be_dereferenced); } void List::del(Predicate f) { ListNode* h = P; for (;;) { if (h == &NilListNode) { P = h; return; } else if ((*f)(h->hd)) { ListNode* nxt = h->tl; reference(nxt); dereference(h); h = nxt; } else break; } ListNode* trail = h; ListNode* p = h->tl; while (p != &NilListNode) { if ((*f)(p->hd)) { ListNode* nxt = p->tl; reference(nxt); dereference(p); trail->tl = nxt; p = nxt; } else { trail = p; p = p->tl; } } P = h; } void List::select(Predicate f) { ListNode* h = P; for (;;) { if (h == &NilListNode) { P = h; return; } else if (!(*f)(h->hd)) { ListNode* nxt = h->tl; reference(nxt); dereference(h); h = nxt; } else break; } ListNode* trail = h; ListNode* p = h->tl; while (p != &NilListNode) { if (!(*f)(p->hd)) { ListNode* nxt = p->tl; reference(nxt); dereference(p); trail->tl = nxt; p = nxt; } else { trail = p; p = p->tl; } } P = h; } void List::reverse() { ListNode* l = &NilListNode; ListNode* p = P; while (p != &NilListNode) { ListNode* nxt = p->tl; p->tl = l; l = p; p = nxt; } P = l; } List copy(const List& x) { const ListNode* a = x.P; if (a == &NilListNode) return List(&NilListNode); else { ListNode* h = newListNode(a->hd); ListNode* trail = h; for(a = a->tl; a != &NilListNode; a = a->tl) { ListNode* n = newListNode(a->hd); trail->tl = n; trail = n; } trail->tl = &NilListNode; return List(h); } } List subst( old, repl, List& x) { ListNode* a = x.P; if (a == &NilListNode) return List(a); else { ListNode* h = new ListNode; h->ref = 1; if (EQ(a->hd, old)) h->hd = repl; else h->hd = a->hd; ListNode* trail = h; for(a = a->tl; a != &NilListNode; a = a->tl) { ListNode* n = new ListNode; n->ref = 1; if (EQ(a->hd, old)) n->hd = repl; else n->hd = a->hd; trail->tl = n; trail = n; } trail->tl = &NilListNode; return List(h); } } List combine(Combiner f, List& x, List& y) { ListNode* a = x.P; ListNode* b = y.P; if (a == &NilListNode || b == &NilListNode) return List(&NilListNode); else { ListNode* h = newListNode((*f)(a->hd, b->hd)); ListNode* trail = h; a = a->tl; b = b->tl; while (a != &NilListNode && b != &NilListNode) { ListNode* n = newListNode((*f)(a->hd, b->hd)); trail->tl = n; trail = n; a = a->tl; b = b->tl; } trail->tl = &NilListNode; return List(h); } } List reverse(List& x) { ListNode* a = x.P; if (a == &NilListNode) return List(a); else { ListNode* l = newListNode(a->hd); l->tl = &NilListNode; for(a = a->tl; a != &NilListNode; a = a->tl) { ListNode* n = newListNode(a->hd); n->tl = l; l = n; } return List(l); } } List append(List& x, List& y) { ListNode* a = x.P; ListNode* b = y.P; reference(b); if (a != &NilListNode) { ListNode* h = newListNode(a->hd); ListNode* trail = h; for(a = a->tl; a != &NilListNode; a = a->tl) { ListNode* n = newListNode(a->hd); trail->tl = n; trail = n; } trail->tl = b; return List(h); } else return List(b); } void List::prepend(List& y) { ListNode* b = y.P; if (b != &NilListNode) { ListNode* h = newListNode(b->hd); ListNode* trail = h; for(b = b->tl; b != &NilListNode; b = b->tl) { ListNode* n = newListNode(b->hd); trail->tl = n; trail = n; } trail->tl = P; P = h; } } List concat(List& x, List& y) { ListNode* a = x.P; ListNode* b = y.P; if (a != &NilListNode) { ListNode* h = newListNode(a->hd); ListNode* trail = h; for(a = a->tl; a != &NilListNode; a = a->tl) { ListNode* n = newListNode(a->hd); trail->tl = n; trail = n; }; for(;b != &NilListNode; b = b->tl) { ListNode* n = newListNode(b->hd); trail->tl = n; trail = n; } trail->tl = &NilListNode; return List(h); } else if (b != &NilListNode) { ListNode* h = newListNode(b->hd); ListNode* trail = h; for(b = b->tl; b != &NilListNode; b = b->tl) { ListNode* n = newListNode(b->hd); trail->tl = n; trail = n; } trail->tl = &NilListNode; return List(h); } else return List(&NilListNode); } List select(Predicate f, List& x) { ListNode* a = x.P; ListNode* h = &NilListNode; while (a != &NilListNode) { if ((*f)(a->hd)) { h = newListNode(a->hd); ListNode* trail = h; for(a = a->tl; a != &NilListNode; a = a->tl) { if ((*f)(a->hd)) { ListNode* n = newListNode(a->hd); trail->tl = n; trail = n; } } trail->tl = &NilListNode; break; } else a = a->tl; } return List(h); } List remove(Predicate f, List& x) { ListNode* a = x.P; ListNode* h = &NilListNode; while (a != &NilListNode) { if (!(*f)(a->hd)) { h = newListNode(a->hd); ListNode* trail = h; for(a = a->tl; a != &NilListNode; a = a->tl) { if (!(*f)(a->hd)) { ListNode* n = newListNode(a->hd); trail->tl = n; trail = n; } } trail->tl = &NilListNode; break; } else a = a->tl; } return List(h); } List remove( targ, List& x) { ListNode* a = x.P; ListNode* h = &NilListNode; while (a != &NilListNode) { if (!(EQ(a->hd, targ))) { h = newListNode(a->hd); ListNode* trail = h; for(a = a->tl; a != &NilListNode; a = a->tl) { if (!EQ(a->hd, targ)) { ListNode* n = newListNode(a->hd); trail->tl = n; trail = n; } } trail->tl = &NilListNode; break; } else a = a->tl; } return List(h); } List map(Mapper f, List& x) { ListNode* a = x.P; ListNode* h = &NilListNode; if (a != &NilListNode) { h = newListNode((*f)(a->hd)); ListNode* trail = h; for(a = a->tl; a != &NilListNode; a = a->tl) { ListNode* n = newListNode((*f)(a->hd)); trail->tl = n; trail = n; } trail->tl = &NilListNode; } return List(h); } List merge(List& x, List& y, Comparator f) { ListNode* a = x.P; ListNode* b = y.P; if (a == &NilListNode) { if (b == &NilListNode) return List(&NilListNode); else return copy(y); } else if (b == &NilListNode) return copy(x); ListNode* h = new ListNode; h->ref = 1; if ((*f)(a->hd, b->hd) <= 0) { h->hd = a->hd; a = a->tl; } else { h->hd = b->hd; b = b->tl; } ListNode* r = h; for(;;) { if (a == &NilListNode) { while (b != &NilListNode) { ListNode* n = new ListNode; n->ref = 1; n->hd = b->hd; r->tl = n; r = n; b = b->tl; } r->tl = &NilListNode; return List(h); } else if (b == &NilListNode) { while (a != &NilListNode) { ListNode* n = new ListNode; n->ref = 1; n->hd = a->hd; r->tl = n; r = n; a = a->tl; } r->tl = &NilListNode; return List(h); } else if ((*f)(a->hd, b->hd) <= 0) { ListNode* n = new ListNode; n->ref = 1; n->hd = a->hd; r->tl = n; r = n; a = a->tl; } else { ListNode* n = new ListNode; n->ref = 1; n->hd = b->hd; r->tl = n; r = n; b = b->tl; } } } void List::sort(Comparator f) { // strategy: place runs in queue, merge runs until done // This is often very fast if (P == &NilListNode || P->tl == &NilListNode) return; int qlen = 250; // guess a good queue size, realloc if necessary ListNode** queue = (ListNode**)malloc(qlen * sizeof(ListNode*)); ListNode* h = P; ListNode* a = h; ListNode* b = a->tl; int qin = 0; while (b != &NilListNode) { if ((*f)(a->hd, b->hd) > 0) { if (h == a) // minor optimization: ensure runlen >= 2 { h = b; a->tl = b->tl; b->tl = a; b = a->tl; } else { if (qin >= qlen) { qlen *= 2; queue = (ListNode**)realloc(queue, qlen * sizeof(ListNode*)); } queue[qin++] = h; a->tl = &NilListNode; h = a = b; b = b->tl; } } else { a = b; b = b->tl; } } int count = qin; queue[qin] = h; if (++qin >= qlen) qin = 0; int qout = 0; while (count-- > 0) { a = queue[qout]; if (++qout >= qlen) qout = 0; b = queue[qout]; if (++qout >= qlen) qout = 0; if ((*f)(a->hd, b->hd) <= 0) { h = a; a = a->tl; } else { h = b; b = b->tl; } queue[qin] = h; if (++qin >= qlen) qin = 0; for (;;) { if (a == &NilListNode) { h->tl = b; break; } else if (b == &NilListNode) { h->tl = a; break; } else if ((*f)(a->hd, b->hd) <= 0) { h->tl = a; h = a; a = a->tl; } else { h->tl = b; h = b; b = b->tl; } } } P = queue[qout]; free(queue); } int List::list_length() { ListNode* fast = P; if (fast == &NilListNode) return 0; ListNode* slow = fast->tl; if (slow == &NilListNode) return 1; fast = slow->tl; int n = 2; for (;;) { if (fast == &NilListNode) return n; else if (fast->tl == &NilListNode) return n+1; else if (fast == slow) return -1; else { n += 2; fast = fast->tl->tl; slow = slow->tl; } } } void List::error(const char* msg) { (*lib_error_handler)("List", msg); } int List::OK() { int v = P != 0; // have a node // check that all nodes OK, even if circular: ListNode* fast = P; if (fast != &NilListNode) { v &= fast->ref != 0; ListNode* slow = fast->tl; v &= slow->ref != 0; if (v && slow != &NilListNode) { fast = slow->tl; v &= fast->ref != 0; while (v) { if (fast == &NilListNode) break; else if (fast->tl == &NilListNode) break; else if (fast == slow) break; else { v &= fast->ref != 0 && slow->ref != 0; fast = fast->tl->tl; slow = slow->tl; } } } } if (!v) error ("invariant failure"); return v; }