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