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.Slink;
18 
19 import tango.util.container.model.IContainer;
20 
21 /*******************************************************************************
22 
23         Slink instances provide standard linked list next-fields, and
24         support standard operations upon them. Slink structures are pure
25         implementation tools, and perform no argument checking, no result
26         screening, and no synchronization. They rely on user-level classes
27         (see HashSet, for example) to do such things.
28 
29         Still, Slink is made `public' so that you can use it to build other
30         kinds of containers
31         
32         Note that when K is specified, support for keys are enabled. When
33         Identity is stipulated as 'true', those keys are compared using an
34         identity-comparison instead of equality (using 'is'). Similarly, if
35         HashCache is set true, an additional attribute is create in order to
36         retain the hash of K
37 
38 *******************************************************************************/
39 
40 alias int KeyDummy;
41 
42 struct Slink (V, K=KeyDummy, bool Identity = false, bool HashCache = false)
43 {
44         alias Slink!(V, K, Identity, HashCache) Type;
45         alias Type                              *Ref;
46         alias Compare!(V)                       Comparator;
47 
48         Ref             next;           // pointer to next
49         V               value;          // element value
50 
51         static if (HashCache == true)
52         {
53         hash_t       cache;             // retain hash value?
54         }
55                 
56         /***********************************************************************
57 
58                 add support for keys also?
59                 
60         ***********************************************************************/
61 
62         static if (!is(typeof(K) == KeyDummy))
63         {
64                 K key;
65 
66                 final Ref set (K k, V v, Ref n)
67                 {
68                         key = k;
69                         return set (v, n);
70                 }
71 
72                 final hash_t hash()
73                 {
74                         return typeid(K).getHash(&key);
75                 }
76 
77                 final Ref findKey (K key)
78                 {
79                         static if (Identity == true)
80                         {
81                            for (auto p=&this; p; p = p.next)
82                                 if (key is p.key)
83                                     return p;
84                         }
85                         else
86                         {
87                            for (auto p=&this; p; p = p.next)
88                                 if (key == p.key)
89                                     return p;
90                         }
91                         return null;
92                 }
93 
94                 final Ref findPair (K key, V value)
95                 {
96                         static if (Identity == true)
97                         {
98                            for (auto p=&this; p; p = p.next)
99                                 if (key is p.key && value == p.value)
100                                     return p;
101                         }
102                         else
103                         {
104                            for (auto p=&this; p; p = p.next)
105                                 if (key == p.key && value == p.value)
106                                     return p;
107                         }
108                         return null;
109                 }
110 
111                 final const int indexKey (K key)
112                 {
113                         int i = 0;
114                         static if (Identity == true)
115                         {
116                            for (auto p=&this; p; p = p.next, ++i)
117                                 if (key is p.key)
118                                     return i;
119                         }
120                         else
121                         {
122                            for (auto p=&this; p; p = p.next, ++i)
123                                 if (key == p.key)
124                                     return i;
125                         }
126                         return -1;
127                 }
128 
129                 final const int indexPair (K key, V value)
130                 {
131                         int i = 0;
132                         static if (Identity == true)
133                         {
134                            for (auto p=&this; p; p = p.next, ++i)
135                                 if (key is p.key && value == p.value)
136                                     return i;
137                         }
138                         else
139                         {
140                            for (auto p=&this; p; p = p.next, ++i)
141                                 if (key == p.key && value == p.value)
142                                     return i;
143                         }
144                         return -1;
145                 }
146 
147                 final int countKey (K key)
148                 {
149                         int c = 0;
150                         static if (Identity == true)
151                         {
152                            for (auto p=&this; p; p = p.next)
153                                 if (key is p.key)
154                                     ++c;
155                         }
156                         else
157                         {
158                            for (auto p=&this; p; p = p.next)
159                                 if (key == p.key)
160                                     ++c;
161                         }
162                         return c;
163                 }
164 
165                 final int countPair (K key, V value)
166                 {
167                         int c = 0;
168                         static if (Identity == true)
169                         {
170                            for (auto p=&this; p; p = p.next)
171                                 if (key is p.key && value == p.value)
172                                     ++c;
173                         }
174                         else
175                         {
176                            for (auto p=&this; p; p = p.next)
177                                 if (key == p.key && value == p.value)
178                                     ++c;
179                         }
180                         return c;
181                 }
182         }
183         
184         /***********************************************************************
185 
186                  Set to point to n as next cell
187 
188                  param: n, the new next cell
189                         
190         ***********************************************************************/
191 
192         final Ref set (V v, Ref n)
193         {
194                 next = n;
195                 value = v;
196                 return &this;
197         }
198 
199         /***********************************************************************
200 
201                  Splice in p between current cell and whatever it was
202                  previously pointing to
203 
204                  param: p, the cell to splice
205                         
206         ***********************************************************************/
207 
208         final void attach (Ref p)
209         {
210                 if (p)
211                     p.next = next;
212                 next = p;
213         }
214 
215         /***********************************************************************
216 
217                 Cause current cell to skip over the current next() one, 
218                 effectively removing the next element from the list
219                         
220         ***********************************************************************/
221 
222         final void detachNext()
223         {
224                 if (next)
225                     next = next.next;
226         }
227 
228         /***********************************************************************
229 
230                  Linear search down the list looking for element
231                  
232                  param: element to look for
233                  Returns: the cell containing element, or null if no such
234                  
235         ***********************************************************************/
236 
237         final Ref find (V element)
238         {
239                 for (auto p = &this; p; p = p.next)
240                      if (element == p.value)
241                          return p;
242                 return null;
243         }
244 
245         /***********************************************************************
246 
247                 Return the number of cells traversed to find first occurrence
248                 of a cell with element() element, or -1 if not present
249                         
250         ***********************************************************************/
251 
252         final const int index (V element)
253         {
254                 int i;
255                 for (auto p = &this; p; p = p.next, ++i)
256                      if (element == p.value)
257                          return i;
258 
259                 return -1;
260         }
261 
262         /***********************************************************************
263 
264                 Count the number of occurrences of element in list
265                         
266         ***********************************************************************/
267 
268         final const int count (V element)
269         {
270                 int c;
271                 for (auto p = &this; p; p = p.next)
272                      if (element == p.value)
273                          ++c;
274                 return c;
275         }
276 
277         /***********************************************************************
278 
279                  Return the number of cells in the list
280                         
281         ***********************************************************************/
282 
283         final const int count ()
284         {
285                 int c;
286                 for (auto p = &this; p; p = p.next)
287                      ++c;
288                 return c;
289         }
290 
291         /***********************************************************************
292 
293                 Return the cell representing the last element of the list
294                 (i.e., the one whose next() is null
295                         
296         ***********************************************************************/
297 
298         final Ref tail ()
299         {
300                 auto p = &this;
301                 while (p.next)
302                        p = p.next;
303                 return p;
304         }
305 
306         /***********************************************************************
307 
308                 Return the nth cell of the list, or null if no such
309                         
310         ***********************************************************************/
311 
312         final Ref nth (int n)
313         {
314                 auto p = &this;
315                 for (int i; i < n; ++i)
316                      p = p.next;
317                 return p;
318         }
319 
320         /***********************************************************************
321 
322                 Make a copy of the list; i.e., a new list containing new cells
323                 but including the same elements in the same order
324                         
325         ***********************************************************************/
326 
327         final Ref copy (scope Ref delegate() alloc)
328         {
329                 auto newlist = dup (alloc);
330                 auto current = newlist;
331 
332                 for (auto p = next; p; p = p.next)
333                     {
334                     current.next = p.dup (alloc);
335                     current = current.next;
336                     }
337                 current.next = null;
338                 return newlist;
339         }
340 
341         /***********************************************************************
342 
343                 dup is shallow; i.e., just makes a copy of the current cell
344                         
345         ***********************************************************************/
346 
347         Ref dup (scope Ref delegate() alloc)
348         {
349                 auto ret = alloc();
350                 static if (is(typeof(K) == KeyDummy))
351                            ret.set (value, next);
352                        else
353                           ret.set (key, value, next);
354                 return ret;
355         }
356 
357         /***********************************************************************
358 
359                 Basic linkedlist merge algorithm.
360                 Merges the lists head by fst and snd with respect to cmp
361          
362                 param: fst head of the first list
363                 param: snd head of the second list
364                 param: cmp a Comparator used to compare elements
365                 Returns: the merged ordered list
366                         
367         ***********************************************************************/
368 
369         static Ref merge (Ref fst, Ref snd, Comparator cmp)
370         {
371                 auto a = fst;
372                 auto b = snd;
373                 Ref hd = null;
374                 Ref current = null;
375 
376                 for (;;)
377                     {
378                     if (a is null)
379                        {
380                        if (hd is null)
381                            hd = b;
382                        else
383                           current.next = b;
384                        return hd;
385                        }
386                     else
387                        if (b is null)
388                           {
389                           if (hd is null)
390                               hd = a;
391                           else
392                              current.next = a;
393                           return hd;
394                           }
395 
396                     int diff = cmp (a.value, b.value);
397                     if (diff <= 0)
398                        {
399                        if (hd is null)
400                            hd = a;
401                        else
402                           current.next = a;
403                        current = a;
404                        a = a.next;
405                        }
406                     else
407                        {
408                        if (hd is null)
409                            hd = b;
410                        else
411                           current.next = b;
412                        current = b;
413                        b = b.next;
414                        }
415                     }
416         }
417 
418         /***********************************************************************
419 
420                 Standard list splitter, used by sort.
421                 Splits the list in half. Returns the head of the second half
422 
423                 param: s the head of the list
424                 Returns: the head of the second half
425 
426         ***********************************************************************/
427 
428         static Ref split (Ref s)
429         {
430                 auto fast = s;
431                 auto slow = s;
432 
433                 if (fast is null || fast.next is null)
434                     return null;
435 
436                 while (fast)
437                       {
438                       fast = fast.next;
439                       if (fast && fast.next)
440                          {
441                          fast = fast.next;
442                          slow = slow.next;
443                          }
444                       }
445 
446                 auto r = slow.next;
447                 slow.next = null;
448                 return r;
449 
450         }
451 
452         /***********************************************************************
453 
454                  Standard merge sort algorithm
455                  
456                  param: s the list to sort
457                  param: cmp, the comparator to use for ordering
458                  Returns: the head of the sorted list
459                         
460         ***********************************************************************/
461 
462         static Ref sort (Ref s, Comparator cmp)
463         {
464                 if (s is null || s.next is null)
465                     return s;
466                 else
467                    {
468                    auto right = split (s);
469                    auto left = s;
470                    left = sort (left, cmp);
471                    right = sort (right, cmp);
472                    return merge (left, right, cmp);
473                    }
474         }
475 
476 }
477