| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 | /******************************************************************************* copyright: Copyright (c) 2008 Kris Bell. All rights reserved license: BSD style: $(LICENSE) version: Apr 2008: Initial release authors: Kris Since: 0.99.7 Based upon Doug Lea's Java collection package *******************************************************************************/ module tango.util.container.Clink; /******************************************************************************* Clinks are links that are always arranged in circular lists. *******************************************************************************/ struct Clink (V) { alias Clink!(V) Type; alias Type *Ref; Ref prev, // pointer to prev next; // pointer to next V value; // element value /*********************************************************************** Set to point to ourselves ***********************************************************************/ Ref set (V v) { return set (v, &this, &this); } /*********************************************************************** Set to point to n as next cell and p as the prior cell param: n, the new next cell param: p, the new prior cell ***********************************************************************/ Ref set (V v, Ref p, Ref n) { value = v; prev = p; next = n; return &this; } /** * Return true if current cell is the only one on the list **/ @property const bool singleton() { return next is &this; } void linkNext (Ref p) { if (p) { next.prev = p; p.next = next; p.prev = &this; next = p; } } /** * Make a cell holding v and link it immediately after current cell **/ void addNext (V v, scope Ref delegate() alloc) { auto p = alloc().set (v, &this, next); next.prev = p; next = p; } /** * make a node holding v, link it before the current cell, and return it **/ Ref addPrev (V v, scope Ref delegate() alloc) { auto p = prev; auto c = alloc().set (v, p, &this); p.next = c; prev = c; return c; } /** * link p before current cell **/ void linkPrev (Ref p) { if (p) { prev.next = p; p.prev = prev; p.next = &this; prev = p; } } /** * return the number of cells in the list **/ @property const int size() { int c = 0; auto p = &this; do { ++c; p = p.next; } while (p !is &this); return c; } /** * return the first cell holding element found in a circular traversal starting * at current cell, or null if no such **/ Ref find (V element) { auto p = &this; do { if (element == p.value) return p; p = p.next; } while (p !is &this); return null; } /** * return the number of cells holding element found in a circular * traversal **/ const int count (V element) { int c = 0; auto p = &this; do { if (element == p.value) ++c; p = p.next; } while (p !is &this); return c; } /** * return the nth cell traversed from here. It may wrap around. **/ Ref nth (size_t n) { auto p = &this; for (int i = 0; i < n; ++i) p = p.next; return p; } /** * Unlink the next cell. * This has no effect on the list if isSingleton() **/ void unlinkNext () { auto nn = next.next; nn.prev = &this; next = nn; } /** * Unlink the previous cell. * This has no effect on the list if isSingleton() **/ void unlinkPrev () { auto pp = prev.prev; pp.next = &this; prev = pp; } /** * Unlink self from list it is in. * Causes it to be a singleton **/ void unlink () { auto p = prev; auto n = next; p.next = n; n.prev = p; prev = &this; next = &this; } /** * Make a copy of the list and return new head. **/ const Ref copyList (scope Ref delegate() alloc) { auto hd = &this; auto newlist = alloc().set (hd.value, null, null); auto current = newlist; for (const(Type)* p = next; p !is hd; p = p.next) { current.next = alloc().set (p.value, current, null); current = current.next; } newlist.prev = current; current.next = newlist; return newlist; } } |