| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478 | /******************************************************************************* 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.Slink; import tango.util.container.model.IContainer; /******************************************************************************* Slink instances provide standard linked list next-fields, and support standard operations upon them. Slink structures are pure implementation tools, and perform no argument checking, no result screening, and no synchronization. They rely on user-level classes (see HashSet, for example) to do such things. Still, Slink is made `public' so that you can use it to build other kinds of containers Note that when K is specified, support for keys are enabled. When Identity is stipulated as 'true', those keys are compared using an identity-comparison instead of equality (using 'is'). Similarly, if HashCache is set true, an additional attribute is create in order to retain the hash of K *******************************************************************************/ alias int KeyDummy; struct Slink (V, K=KeyDummy, bool Identity = false, bool HashCache = false) { alias Slink!(V, K, Identity, HashCache) Type; alias Type *Ref; alias Compare!(V) Comparator; Ref next; // pointer to next V value; // element value static if (HashCache == true) { hash_t cache; // retain hash value? } /*********************************************************************** add support for keys also? ***********************************************************************/ static if (!is(typeof(K) == KeyDummy)) { K key; final Ref set (K k, V v, Ref n) { key = k; return set (v, n); } final hash_t hash() { return typeid(K).getHash(&key); } final Ref findKey (K key) { static if (Identity == true) { for (auto p=&this; p; p = p.next) if (key is p.key) return p; } else { for (auto p=&this; p; p = p.next) if (key == p.key) return p; } return null; } final Ref findPair (K key, V value) { static if (Identity == true) { for (auto p=&this; p; p = p.next) if (key is p.key && value == p.value) return p; } else { for (auto p=&this; p; p = p.next) if (key == p.key && value == p.value) return p; } return null; } final const int indexKey (K key) { int i = 0; static if (Identity == true) { for (auto p=&this; p; p = p.next, ++i) if (key is p.key) return i; } else { for (auto p=&this; p; p = p.next, ++i) if (key == p.key) return i; } return -1; } final const int indexPair (K key, V value) { int i = 0; static if (Identity == true) { for (auto p=&this; p; p = p.next, ++i) if (key is p.key && value == p.value) return i; } else { for (auto p=&this; p; p = p.next, ++i) if (key == p.key && value == p.value) return i; } return -1; } final int countKey (K key) { int c = 0; static if (Identity == true) { for (auto p=&this; p; p = p.next) if (key is p.key) ++c; } else { for (auto p=&this; p; p = p.next) if (key == p.key) ++c; } return c; } final int countPair (K key, V value) { int c = 0; static if (Identity == true) { for (auto p=&this; p; p = p.next) if (key is p.key && value == p.value) ++c; } else { for (auto p=&this; p; p = p.next) if (key == p.key && value == p.value) ++c; } return c; } } /*********************************************************************** Set to point to n as next cell param: n, the new next cell ***********************************************************************/ final Ref set (V v, Ref n) { next = n; value = v; return &this; } /*********************************************************************** Splice in p between current cell and whatever it was previously pointing to param: p, the cell to splice ***********************************************************************/ final void attach (Ref p) { if (p) p.next = next; next = p; } /*********************************************************************** Cause current cell to skip over the current next() one, effectively removing the next element from the list ***********************************************************************/ final void detachNext() { if (next) next = next.next; } /*********************************************************************** Linear search down the list looking for element param: element to look for Returns: the cell containing element, or null if no such ***********************************************************************/ final Ref find (V element) { for (auto p = &this; p; p = p.next) if (element == p.value) return p; return null; } /*********************************************************************** Return the number of cells traversed to find first occurrence of a cell with element() element, or -1 if not present ***********************************************************************/ final const int index (V element) { int i; for (auto p = &this; p; p = p.next, ++i) if (element == p.value) return i; return -1; } /*********************************************************************** Count the number of occurrences of element in list ***********************************************************************/ final const int count (V element) { int c; for (auto p = &this; p; p = p.next) if (element == p.value) ++c; return c; } /*********************************************************************** Return the number of cells in the list ***********************************************************************/ final const int count () { int c; for (auto p = &this; p; p = p.next) ++c; return c; } /*********************************************************************** Return the cell representing the last element of the list (i.e., the one whose next() is null ***********************************************************************/ final Ref tail () { auto p = &this; while (p.next) p = p.next; return p; } /*********************************************************************** Return the nth cell of the list, or null if no such ***********************************************************************/ final Ref nth (int n) { auto p = &this; for (int i; i < n; ++i) p = p.next; return p; } /*********************************************************************** Make a copy of the list; i.e., a new list containing new cells but including the same elements in the same order ***********************************************************************/ final Ref copy (scope Ref delegate() alloc) { auto newlist = dup (alloc); auto current = newlist; for (auto p = next; p; p = p.next) { current.next = p.dup (alloc); current = current.next; } current.next = null; return newlist; } /*********************************************************************** dup is shallow; i.e., just makes a copy of the current cell ***********************************************************************/ Ref dup (scope Ref delegate() alloc) { auto ret = alloc(); static if (is(typeof(K) == KeyDummy)) ret.set (value, next); else ret.set (key, value, next); return ret; } /*********************************************************************** Basic linkedlist merge algorithm. Merges the lists head by fst and snd with respect to cmp param: fst head of the first list param: snd head of the second list param: cmp a Comparator used to compare elements Returns: the merged ordered list ***********************************************************************/ static Ref merge (Ref fst, Ref snd, Comparator cmp) { auto a = fst; auto b = snd; Ref hd = null; Ref current = null; for (;;) { if (a is null) { if (hd is null) hd = b; else current.next = b; return hd; } else if (b is null) { if (hd is null) hd = a; else current.next = a; return hd; } int diff = cmp (a.value, b.value); if (diff <= 0) { if (hd is null) hd = a; else current.next = a; current = a; a = a.next; } else { if (hd is null) hd = b; else current.next = b; current = b; b = b.next; } } } /*********************************************************************** Standard list splitter, used by sort. Splits the list in half. Returns the head of the second half param: s the head of the list Returns: the head of the second half ***********************************************************************/ static Ref split (Ref s) { auto fast = s; auto slow = s; if (fast is null || fast.next is null) return null; while (fast) { fast = fast.next; if (fast && fast.next) { fast = fast.next; slow = slow.next; } } auto r = slow.next; slow.next = null; return r; } /*********************************************************************** Standard merge sort algorithm param: s the list to sort param: cmp, the comparator to use for ordering Returns: the head of the sorted list ***********************************************************************/ static Ref sort (Ref s, Comparator cmp) { if (s is null || s.next is null) return s; else { auto right = split (s); auto left = s; left = sort (left, cmp); right = sort (right, cmp); return merge (left, right, cmp); } } } |