/iolists.d
D | 250 lines | 213 code | 26 blank | 11 comment | 31 complexity | d4b98459d7102969bd7e829c1ed7930c MD5 | raw file
1module iolists; 2 3/** Immutable list based implementation, simple and fast for small strings, or for append/prepend only 4 * Sometime calles IoList 5 * 6 * Actually this is just binary tree, without rebalancing 7 * 8 * Few methods which is known to be slow (like opIndexAssign) are removed, because if you really need such functionality, 9 * you should use another structure. Other mutating methods and slicing (which are also slow), are there for some usages. 10 */ 11final class cord_l2(T) { 12 final class node { 13 T[] v; 14 node next; 15 this() { 16 v = null; 17 } 18 this(in T[] s) { 19 v = s; 20 } 21 this(in T[] s, node n) { 22 v = s; 23 next = n; 24 } 25 } 26 27 node* head; 28 29 this() { 30 first = last = new node(); // guard 31 } 32 33 this(in T[] s) { 34 first = last = new node(s); 35 } 36 37 // inplace 38 void opCatAssign(in T[] s) { 39 last = (last.next = new node(s)); 40 } 41 42 cord_l2!(T) opCat(in T[] s) 43 out (res) { 44 assert(res.length == this.length + s.length); 45 } 46 body { 47 auto r = this.clone(); 48 r ~= s; 49 return r; 50 } 51 52 cord_l2!(T) opCat_r(in T[] s) 53 out (res) { 54 assert(res.length == this.length + s.length); 55 } 56 body { 57 auto r = this.clone(); 58 r.prepend(s); 59 return r; 60 } 61 62 63 // inplace 64 void prepend(in T[] s) { 65 first = new node(s, first); 66 } 67 68 int opApply(int delegate(inout T[] chunk) dg) { 69 int ret; 70 node current = first; 71 while (current) { 72 auto s = cast(T[])current.v; 73 if ((ret = dg(s)) != 0) { 74 break; 75 } 76 current = current.next; 77 } 78 return ret; 79 } 80 81 size_t length() { 82 size_t l = 0; 83 foreach (chunk; this) { 84 l += chunk.length; 85 } 86 return l; 87 } 88 89 override invariant(T)[] toString() 90 out (res) { 91 assert(res.length == this.length); 92 } 93 body { 94 T[] ret; 95 ret.length = this.length; 96 size_t i = 0; 97 foreach (chunk; this) { 98 ret[i .. i+chunk.length] = chunk; 99 i += chunk.length; 100 } 101 return cast(invariant)ret; 102 } 103 104 T opIndex(size_t i) { 105 foreach (chunk; this) { 106 if (i < chunk.length) { 107 return chunk[i]; 108 } 109 i -= chunk.length; 110 } 111 throw new Exception("CordBoundsException"); 112 } 113 114 cord_l2!(T) clone() 115 out (res) { 116 assert(res.length == this.length); 117 } 118 body { 119 auto r = new cord_l2!(T)(); 120 foreach (chunk; this) { 121 r ~= chunk; 122 } 123 return r; 124 } 125 126 cord_l2!(T) opSlice(size_t j1, size_t j2) 127 in { 128 assert(j1 <= j2); 129 assert(j2 <= this.length); 130 } 131 out (res) { 132 assert(res.length == j2-j1); 133 assert(res.toString() == (this.toString())[j1..j2]); 134 } 135 body { 136 auto r = new cord_l2!(T)(); 137 size_t i = 0; 138 foreach (chunk; this) { 139 auto i_end = i+chunk.length; 140 if (i_end <= j1) { 141 ; 142 } else if (i > j2) { 143 break; 144 } else if (i <= j1) { 145 r ~= chunk[j1-i .. $]; 146 } else if (i_end > j2) { 147 r ~= chunk[0 .. j2-i]; 148 break; 149 } else { 150 r ~= chunk; 151 } 152 i = i_end; 153 } 154 return r; 155 } 156 157 cord_l2!(T) opCat(cord_l2!(T) b) 158 out (res) { 159 assert(res.length == this.length + b.length); 160 } 161 body { 162 auto r = this.clone(); 163 foreach (chunk; b) { 164 r ~= chunk; 165 } 166 return r; 167 } 168 169 // inplace 170 void opCatAssign(cord_l2!(T) b) { 171 foreach (chunk; b) { 172 this ~= chunk; 173 } 174 } 175 176 cord_l2!(T) change(size_t j1, size_t j2, cord_l2!(T) b) 177 in { 178 assert(j1 <= j2); 179 assert(j2 <= this.length); 180 } 181 out (res) { 182 assert(res.length == this.length - (j2-j1) + b.length); 183 } 184 body { 185 auto r = this[0..j1]; 186 r ~= b; 187 r ~= this[j2..this.length]; 188 return r; 189 } 190 191 cord_l2!(T) change(size_t j1, size_t j2, in T[] b) 192 in { 193 assert(j1 <= j2); 194 assert(j2 <= this.length); 195 } 196 out (res) { 197 assert(res.length == this.length - (j2-j1) + b.length); 198 } 199 body { 200 auto r = this[0..j1]; 201 r ~= b; 202 r ~= this[j2..this.length]; 203 return r; 204 } 205 206 cord_l2!(T) remove(size_t j1, size_t j2) 207 in { 208 assert(j1 <= j2); 209 assert(j2 <= this.length); 210 } 211 out (res) { 212 assert(res.length == this.length - (j2-j1)); 213 } 214 body { 215 auto r = this[0..j1]; 216 r ~= this[j2..this.length]; 217 return r; 218 } 219} 220 221alias cord_l2!(char) cord; 222 223unittest { 224 auto r = new cord("a"); 225 r ~= "xx"; 226 assert(r.length == 3); 227 r ~= "yyy"; 228 assert(r.length == 6); 229 r ~= "zzz"; 230 assert(r.length == 9); 231 assert(r.toString() == "axxyyyzzz"); 232 233 r.prepend("aaxa"); 234 235 r ~= "zazz"; 236 r ~= "zaadz"; 237 r ~= "agnz"; 238 r ~= "cbzz"; 239 r ~= "zasdz"; 240 241 auto r0 = r[5..26]; 242 assert(r0.length == 21); 243 for (int i = 0; i < r0.length; i++) { 244 assert(r0[i] == r[5+i]); 245 } 246 247 auto x = new cord("ala") ~ new cord(" ma ") ~ new cord("kota"); 248 assert(x.length == 11); 249 assert(x.toString() == "ala ma kota"); 250}