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 }