/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* A doubly linked list template. */ #ifndef _SC_List_ #define _SC_List_ #include #ifndef NDEBUG # define NDEBUG #endif #include // A Link can be a node in a list or a list itself. template class Link { public: Link() : mNext(this), mPrev(this) {} T* Prev() { return static_cast(mPrev); } T* Next() { return static_cast(mNext); } void RemoveLeaveDangling() { mPrev->mNext = mNext; mNext->mPrev = mPrev; } void Remove() { RemoveLeaveDangling(); mNext = mPrev = this; } void InsertAfter(T *inLink) { mPrev = inLink; mNext = inLink->mNext; mNext->mPrev = this; mPrev->mNext = this; } void InsertBefore(T *inLink) { mNext = inLink; mPrev = inLink->mPrev; mNext->mPrev = this; mPrev->mNext = this; } T* Head() { return static_cast(mNext); } T* Tail() { return static_cast(mPrev); } T* PopHead(); T* PopTail(); void PushHead(T* inBuf); void PushTail(T* inBuf); bool ContainsBuf(T* inBuf); bool IsEmpty() { return mNext == this; } void BeEmpty() { mNext = mPrev = this; } void Cat(T* inLink); bool SanityCheck(); void DebugDump(); //private: // Codewarrior refuses to inline Next() in some places.. Link *mNext, *mPrev; }; template void MakeListEmpty(Link *inLink, Alloc* inAlloc) { Link* link = inLink->mNext; while (link != inLink) { Link* nextlink = link->mNext; // SC uses placement new extensively, so here we do a 'placement delete'. // Using DestructSelf allows me to have either virtual // or non virtual destructors in subclasses at the discretion of the subclass. ((T*)(link))->DestructSelf(); inAlloc->Free(static_cast(link)); link = nextlink; } inLink->mNext = inLink->mPrev = inLink; } template void Link::PushHead(T* inLink) { assert(SanityCheck()); Link* link = static_cast*>(inLink); link->InsertAfter(static_cast(this)); assert(SanityCheck()); } template T* Link::PopHead() { assert(SanityCheck()); if (IsEmpty()) return 0; Link* link = mNext; link->Remove(); assert(SanityCheck()); return static_cast(link); } template void Link::PushTail(T* inLink) { assert(SanityCheck()); Link* link = static_cast*>(inLink); link->InsertBefore(static_cast(this)); assert(SanityCheck()); } template T* Link::PopTail() { assert(SanityCheck()); if (IsEmpty()) return 0; Link* link = mPrev; link->Remove(); assert(SanityCheck()); return static_cast(link); } template void Link::Cat(T* inLink) { assert(SanityCheck()); Link* link = static_cast*>(inLink); if (link->IsEmpty()) return; if (IsEmpty()) { mNext = link->mNext; mPrev = link->mPrev; link->mNext->mPrev = this; link->mPrev->mNext = this; } else { link->mNext->mPrev = mPrev; link->mPrev->mNext = this; mPrev->mNext = link->mNext; mPrev = link->mPrev; } link->mPrev = link; link->mNext = link; assert(SanityCheck()); } template bool Link::ContainsBuf(T* inLink) { Link* link = static_cast*>(inLink); Link* curLink = mNext; while (curLink != this) { if (curLink == link) return true; curLink = curLink->mNext; } return false; } template void Link::DebugDump() { Link* link = mNext; while (link != this) { //post("Link-> %08X next %08X prev %08X\n", // link, link->mNext, link->mPrev); link = link->mNext; } } template bool Link::SanityCheck() { Link* link = mNext; while (link != this) { if (link->mPrev->mNext != link) { throw std::runtime_error("Link: bad link <-,->"); } if (link->mNext->mPrev != link) { throw std::runtime_error("Link: bad link ->,<-"); } link = link->mNext; } return true; } #endif