PageRenderTime 24ms CodeModel.GetById 1ms app.highlight 19ms RepoModel.GetById 2ms app.codeStats 0ms

/iolists.d

http://github.com/baryluk/cords
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}