From d0ae3caca5828675335d3b19ab5dd987e7369b23 Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Wed, 14 Jul 2004 16:21:44 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r1857, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/tb/; revision=1858 --- sc4pd/headers/server/SC_List.h | 229 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100755 sc4pd/headers/server/SC_List.h (limited to 'sc4pd/headers/server/SC_List.h') diff --git a/sc4pd/headers/server/SC_List.h b/sc4pd/headers/server/SC_List.h new file mode 100755 index 0000000..d5bed41 --- /dev/null +++ b/sc4pd/headers/server/SC_List.h @@ -0,0 +1,229 @@ +/* + 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) { + //postbuf("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 -- cgit v1.2.1