1 /*******************************************************************************
2 
3         Based upon Doug Lea's Java collection package
4 
5         Copyright:
6             Copyright (c) 2008 Kris Bell.
7             Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH.
8             All rights reserved.
9 
10         License:
11             Tango Dual License: 3-Clause BSD License / Academic Free License v3.0.
12             See LICENSE_TANGO.txt for details.
13 
14         Version: Apr 2008: Initial release
15 
16         Authors: Kris
17 
18 *******************************************************************************/
19 
20 module ocean.util.container.Clink;
21 
22 /*******************************************************************************
23 
24     Clinks are links that are always arranged in circular lists.
25 
26 *******************************************************************************/
27 
28 struct Clink (V)
29 {
30     alias Clink!(V)    Type;
31     alias Type         *Ref;
32 
33     Ref     prev,           // pointer to prev
34             next;           // pointer to next
35     V       value;          // element value
36 
37     /***********************************************************************
38 
39         Set to point to ourselves
40 
41     ***********************************************************************/
42 
43     Ref set (V v)
44     {
45             return set (v, &this, &this);
46     }
47 
48     /***********************************************************************
49 
50         Set to point to n as next cell and p as the prior cell
51 
52         param: n, the new next cell
53         param: p, the new prior cell
54 
55     ***********************************************************************/
56 
57     Ref set (V v, Ref p, Ref n)
58     {
59             value = v;
60             prev = p;
61             next = n;
62             return &this;
63     }
64 
65     /**
66      * Return true if current cell is the only one on the list
67     **/
68 
69     bool singleton()
70     {
71             return next is &this;
72     }
73 
74     void linkNext (Ref p)
75     {
76             if (p)
77                {
78                next.prev = p;
79                p.next = next;
80                p.prev = &this;
81                next = p;
82                }
83     }
84 
85     /**
86      * Make a cell holding v and link it immediately after current cell
87     **/
88 
89     void addNext (V v, scope Ref delegate() alloc)
90     {
91             auto p = alloc().set (v, &this, next);
92             next.prev = p;
93             next = p;
94     }
95 
96     /**
97      * make a node holding v, link it before the current cell, and return it
98     **/
99 
100     Ref addPrev (V v, scope Ref delegate() alloc)
101     {
102             auto p = prev;
103             auto c = alloc().set (v, p, &this);
104             p.next = c;
105             prev = c;
106             return c;
107     }
108 
109     /**
110      * link p before current cell
111     **/
112 
113     void linkPrev (Ref p)
114     {
115             if (p)
116                {
117                prev.next = p;
118                p.prev = prev;
119                p.next = &this;
120                prev = p;
121                }
122     }
123 
124     /**
125      * return the number of cells in the list
126     **/
127 
128     int size()
129     {
130             int c = 0;
131             auto p = &this;
132             do {
133                ++c;
134                p = p.next;
135                } while (p !is &this);
136             return c;
137     }
138 
139     /**
140      * return the first cell holding element found in a circular traversal starting
141      * at current cell, or null if no such
142     **/
143 
144     Ref find (V element)
145     {
146             auto p = &this;
147             do {
148                if (element == p.value)
149                    return p;
150                p = p.next;
151                } while (p !is &this);
152             return null;
153     }
154 
155     /**
156      * return the number of cells holding element found in a circular
157      * traversal
158     **/
159 
160     int count (V element)
161     {
162             int c = 0;
163             auto p = &this;
164             do {
165                if (element == p.value)
166                    ++c;
167                p = p.next;
168                } while (p !is &this);
169             return c;
170     }
171 
172     /**
173      * return the nth cell traversed from here. It may wrap around.
174     **/
175 
176     Ref nth (size_t n)
177     {
178             auto p = &this;
179             for (ptrdiff_t i = 0; i < n; ++i)
180                  p = p.next;
181             return p;
182     }
183 
184 
185     /**
186      * Unlink the next cell.
187      * This has no effect on the list if isSingleton()
188     **/
189 
190     void unlinkNext ()
191     {
192             auto nn = next.next;
193             nn.prev = &this;
194             next = nn;
195     }
196 
197     /**
198      * Unlink the previous cell.
199      * This has no effect on the list if isSingleton()
200     **/
201 
202     void unlinkPrev ()
203     {
204             auto pp = prev.prev;
205             pp.next = &this;
206             prev = pp;
207     }
208 
209 
210     /**
211      * Unlink self from list it is in.
212      * Causes it to be a singleton
213     **/
214 
215     void unlink ()
216     {
217             auto p = prev;
218             auto n = next;
219             p.next = n;
220             n.prev = p;
221             prev = &this;
222             next = &this;
223     }
224 
225     /**
226      * Make a copy of the list and return new head.
227     **/
228 
229     Ref copyList (scope Ref delegate() alloc)
230     {
231             auto hd = &this;
232 
233             auto newlist = alloc().set (hd.value, null, null);
234             auto current = newlist;
235 
236             for (auto p = next; p !is hd; p = p.next)
237                  {
238                  current.next = alloc().set (p.value, current, null);
239                  current = current.next;
240                  }
241             newlist.prev = current;
242             current.next = newlist;
243             return newlist;
244     }
245 }