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