1 module darray;
2 
3 import std.array : back;
4 
5 import exceptionhandling;
6 
7 struct DArraySlice(FSA,T) {
8 	FSA* fsa;
9 	short low;
10 	short high;
11 
12 	pragma(inline, true)
13 	this(FSA* fsa, short low, short high) {
14 		this.fsa = fsa;
15 		this.low = low;
16 		this.high = high;
17 	}
18 
19 	pragma(inline, true)
20 	@property bool empty() const pure @safe nothrow @nogc {
21 		return this.low >= this.high;
22 	}
23 
24 	pragma(inline, true)
25 	@property size_t length() pure @safe nothrow @nogc {
26 		return cast(size_t)(this.high - this.low);
27 	}
28 
29 	pragma(inline, true)
30 	@property ref T front() @nogc {
31 		return (*this.fsa)[cast(size_t)this.low];
32 	}
33 
34 	pragma(inline, true)
35 	@property ref const(T) front() const @nogc {
36 		return (*this.fsa)[cast(size_t)this.low];
37 	}
38 
39 	pragma(inline, true)
40 	@property ref T back() @nogc {
41 		return (*this.fsa)[cast(size_t)(this.high - 1)];
42 	}
43 
44 	pragma(inline, true)
45 	@property ref const(T) back() const @nogc {
46 		return (*this.fsa)[cast(size_t)(this.high - 1)];
47 	}
48 
49 	pragma(inline, true)
50 	void insertBack(S)(auto ref S s) {
51 		(*this.fsa).insertBack(s);
52 	}
53 
54 	/// Ditto
55 	alias put = insertBack;
56 
57 	pragma(inline, true)
58 	ref T opIndex(const size_t idx) @nogc {
59 		return (*this.fsa)[this.low + idx];
60 	}
61 
62 	pragma(inline, true)
63 	void popFront() pure @safe nothrow @nogc {
64 		++this.low;
65 	}
66 
67 	pragma(inline, true)
68 	void popBack() pure @safe nothrow @nogc {
69 		--this.high;
70 	}
71 
72 	pragma(inline, true)
73 	@property typeof(this) save() pure @safe nothrow @nogc {
74 		return this;
75 	}
76 
77 	pragma(inline, true)
78 	@property const(typeof(this)) save() const pure @safe nothrow @nogc {
79 		return this;
80 	}
81 
82 	pragma(inline, true)
83 	typeof(this) opIndex() pure @safe nothrow @nogc {
84 		return this;
85 	}
86 
87 	pragma(inline, true)
88 	typeof(this) opIndex(size_t l, size_t h) pure @safe nothrow @nogc {
89 		return this.opSlice(l, h);
90 	}
91 
92 	pragma(inline, true)
93 	typeof(this) opSlice(size_t l, size_t h) pure @safe nothrow @nogc {
94 		assert(l <= h);
95 		return typeof(this)(this.fsa, 
96 				cast(short)(this.low + l),
97 				cast(short)(this.low + h)
98 			);
99 	}
100 }
101 
102 struct DArray(T) {
103 	import std.traits;
104 
105 	T[] data;
106 	long base;
107 	long len;
108 
109 	private void buildCapacity() {
110 		if(this.len + 1 >= this.data.length) {
111 			this.data.length = (this.data.length + 10) * 2;
112 		}
113 	}
114 
115 	pragma(inline, true)
116 	this(Args...)(Args args) {
117 		foreach(it; args) {
118 			static if(isAssignable!(T,typeof(it))) {
119 				this.insertBack(it);
120 			}
121 		}
122 	}
123 
124 	pragma(inline, true)
125 	size_t capacity() const @nogc @safe pure nothrow {
126 		return this.data.length;
127 	}
128 
129 	/** This function inserts an `S` element at the back if there is space.
130 	Otherwise the behaviour is undefined.
131 	*/
132 	pragma(inline, true)
133 	void insertBack(S)(auto ref S t) @trusted if(is(Unqual!(S) == T)) {
134 		this.buildCapacity();
135 
136 		this.data[
137 			cast(size_t)((this.base + this.len) %
138 				this.data.length)
139 		] = t;
140 		++this.len;
141 	}
142 
143 	/// Ditto
144 	pragma(inline, true)
145 	void insertBack(S)(auto ref S s) @trusted if(!is(Unqual!(S) == T)) {
146 		this.buildCapacity();
147 		this.data[
148 			cast(size_t)((this.base + this.len) %
149 				this.len)
150 		] = s;
151 	}
152 
153 	/// Ditto
154 	pragma(inline, true)
155 	void insertBack(S)(auto ref S defaultValue, size_t num) {
156 		for(size_t i = 0; i < num; ++i) {
157 			this.insertBack(defaultValue);
158 		}
159 	}
160 	/** This function inserts an `S` element at the front if there is space.
161 	Otherwise the behaviour is undefined.
162 	*/
163 	pragma(inline, true)
164 	void insertFront(S)(auto ref S t) @trusted if(is(Unqual!(S) == T)) {
165 		this.buildCapacity();
166 		--this.base;
167 		if(this.base < 0) {
168 			this.base =
169 				cast(typeof(this.base))(this.data.length - 1);
170 		}
171 
172 		this.data[cast(size_t)this.base] = t;
173 		++this.len;
174 	}
175 
176 	/** This function removes an element form the back of the array.
177 	*/
178 	pragma(inline, true)
179 	void removeBack() {
180 		assert(!this.empty);
181 
182 		--this.len;
183 	}
184 
185 	/** This function removes an element form the front of the array.
186 	*/
187 	pragma(inline, true)
188 	void removeFront() {
189 		assert(!this.empty);
190 
191 		//this.begin = (this.begin + T.sizeof) % (Size * T.sizeof);
192 		++this.base;
193 		if(this.base >= this.data.length) {
194 			this.base = 0;
195 		}
196 		--this.len;
197 	}
198 
199 	/** This function removes all elements from the array.
200 	*/
201 	pragma(inline, true)
202 	void removeAll() {
203 		while(!this.empty) {
204 			this.removeBack();
205 		}
206 	}
207 
208 	pragma(inline, true)
209 	void remove(ulong idx) {
210 		import std.stdio;
211 		if(idx == 0) {
212 			this.removeFront();
213 		} else if(idx == this.length - 1) {
214 			this.removeBack();
215 		} else {
216 			for(long i = idx + 1; i < this.length; ++i) {
217 				this[cast(size_t)(i - 1)] = this[cast(size_t)i];
218 			}
219 			this.removeBack();
220 		}
221 	}
222 
223 	/** Access the last or the first element of the array.
224 	*/
225 	pragma(inline, true)
226 	@property ref T back() @trusted @nogc {
227 		debug ensure(!this.empty);
228 		return this.data[
229 			cast(size_t)(this.base + this.len - 1) % this.data.length
230 		];
231 	}
232 
233 	pragma(inline, true)
234 	@property ref const(T) back() const @trusted @nogc {
235 		debug ensure(!this.empty);
236 		return this.data[
237 			cast(size_t)(this.base + this.len - 1) % this.data.length
238 		];
239 	}
240 
241 	/// Ditto
242 	pragma(inline, true)
243 	@property ref T front() @trusted @nogc {
244 		debug ensure(!this.empty);
245 		return this.data[cast(size_t)this.base];
246 	}
247 
248 	pragma(inline, true)
249 	@property ref const(T) front() const @trusted @nogc {
250 		debug ensure(!this.empty);
251 		return this.data[cast(size_t)this.base];
252 	}
253 
254 	/** Use an index to access the array.
255 	*/
256 	pragma(inline, true)
257 	ref T opIndex(const size_t idx) @trusted @nogc {
258 		debug ensure(idx < this.length);
259 		return this.data[cast(size_t)((this.base + idx) % this.data.length)];
260 	}
261 
262 	/// Ditto
263 	pragma(inline, true)
264 	ref const(T) opIndex(const size_t idx) @trusted const @nogc {
265 		debug ensure(idx < this.length);
266 		return this.data[cast(size_t)((this.base + idx) % this.data.length)];
267 	}
268 
269 
270 	pragma(inline, true)
271 	DArraySlice!(typeof(this),T) opSlice() pure @nogc @safe nothrow {
272 		return DArraySlice!(typeof(this),T)(&this, cast(short)0, 
273 				cast(short)this.length
274 		);
275 	}
276 	
277 	pragma(inline, true)
278 	DArraySlice!(typeof(this),T) opSlice(const size_t low, 
279 			const size_t high) 
280 			pure @nogc @safe nothrow 
281 	{
282 		return DArraySlice!(typeof(this),T)(&this, cast(short)low, 
283 				cast(short)high
284 		);
285 	}
286 
287 	pragma(inline, true)
288 	auto opSlice() pure @nogc @safe nothrow const {
289 		return DArraySlice!(typeof(this),const(T))
290 			(&this, cast(short)0, cast(short)this.length);
291 	}
292 	
293 	pragma(inline, true)
294 	auto opSlice(const size_t low, const size_t high) pure @nogc @safe nothrow const 
295 	{
296 		return DArraySlice!(typeof(this),const(T))
297 			(&this, cast(short)low, cast(short)high);
298 	}
299 
300 	/// Gives the length of the array.
301 	pragma(inline, true)
302 	@property size_t length() const pure @nogc nothrow {
303 		return this.len;
304 	}
305 	
306 	/// Ditto
307 	pragma(inline, true)
308 	@property bool empty() const pure @nogc nothrow {
309 		return this.len == 0;
310 	}
311 
312 }
313 
314 version(unittest) {
315 	import std.stdio;
316 }
317 
318 @safe unittest {
319 	DArray!(int) fsa;
320 	fsa.insertFront(1337);
321 	assert(fsa.length == 1);
322 	assert(fsa[0] == 1337);
323 	assert(fsa.front == 1337);
324 	assert(fsa.back == 1337);
325 
326 	fsa.removeBack();
327 	assert(fsa.length == 0);
328 	assert(fsa.empty);
329 	fsa.insertFront(1336);
330 
331 	assert(fsa.length == 1);
332 	assert(fsa[0] == 1336);
333 	assert(fsa.front == 1336);
334 	assert(fsa.back == 1336);
335 }
336 
337 @safe unittest {
338 	DArray!(int) fsa;
339 	for(int i = 0; i < 32; ++i) {
340 		fsa.insertFront(i);
341 		assert(fsa.length == 1);
342 		assert(!fsa.empty);
343 		assert(fsa.front == i);
344 		assert(fsa.back == i);
345 		fsa.removeFront();
346 		assert(fsa.length == 0);
347 		assert(fsa.empty);
348 	}
349 }
350 
351 @safe unittest {
352 	DArray!(int) fsa;
353 	for(int i = 0; i < 32; ++i) {
354 		fsa.insertFront(i);
355 		assert(fsa.length == 1);
356 		assert(!fsa.empty);
357 		assert(fsa.front == i);
358 		assert(fsa.back == i);
359 		fsa.removeBack();
360 		assert(fsa.length == 0);
361 		assert(fsa.empty);
362 	}
363 }
364 
365 @safe unittest {
366 	DArray!(int) fsa;
367 	for(int i = 0; i < 32; ++i) {
368 		fsa.insertBack(i);
369 		assert(fsa.length == 1);
370 		assert(!fsa.empty);
371 		assert(fsa.front == i);
372 		assert(fsa.back == i);
373 		fsa.removeFront();
374 		assert(fsa.length == 0);
375 		assert(fsa.empty);
376 	}
377 }
378 
379 ///
380 @safe unittest {
381 	DArray!(int) fsa;
382 	fsa.insertBack(1337);
383 	assert(fsa.length == 1);
384 	assert(fsa[0] == 1337);
385 
386 	fsa.insertBack(99, 5);
387 
388 	foreach(it; fsa[1 .. fsa.length]) {
389 		assert(it == 99);
390 	}
391 }
392 
393 @safe unittest {
394 	DArray!(int) fsa;
395 	fsa.insertBack(1337);
396 	assert(fsa.length == 1);
397 	assert(fsa[0] == 1337);
398 	
399 	fsa.removeBack();
400 	assert(fsa.length == 0);
401 	assert(fsa.empty);
402 }
403 
404 @safe unittest {
405 	DArray!(int) fsa;
406 	fsa.insertBack(1337);
407 	fsa.insertBack(1338);
408 	assert(fsa.length == 2);
409 	assert(fsa[0] == 1337);
410 	assert(fsa[1] == 1338);
411 	
412 	fsa.removeAll();
413 	assert(fsa.length == 0);
414 	assert(fsa.empty);
415 }
416 
417 unittest {
418 	DArray!(int) fsa;
419 	foreach(i; 0..10) {
420 		fsa.insertBack(i);
421 	}
422 	fsa.remove(1);
423 	foreach(idx, i; [0,2,3,4,5,6,7,8,9]) {
424 		assert(fsa[idx] == i);
425 	}
426 	fsa.remove(0);
427 	foreach(idx, i; [2,3,4,5,6,7,8,9]) {
428 		assert(fsa[idx] == i);
429 	}
430 	fsa.remove(7);
431 	foreach(idx, i; [2,3,4,5,6,7,8]) {
432 		assert(fsa[idx] == i);
433 	}
434 	fsa.remove(5);
435 	foreach(idx, i; [2,3,4,5,6,8]) {
436 		assert(fsa[idx] == i);
437 	}
438 	fsa.remove(1);
439 	foreach(idx, i; [2,4,5,6,8]) {
440 		assert(fsa[idx] == i);
441 	}
442 	fsa.remove(0);
443 	foreach(idx, i; [4,5,6,8]) {
444 		assert(fsa[idx] == i);
445 	}
446 	fsa.remove(0);
447 	foreach(idx, i; [5,6,8]) {
448 		assert(fsa[idx] == i);
449 	}
450 }
451 
452 
453 ///
454 @safe unittest {
455 	DArray!(int) fsa;
456 	assertEqual(fsa.capacity, 0);
457 	fsa.insertBack(1337);
458 	fsa.insertBack(1338);
459 	assert(fsa.capacity > 0);
460 	assert(fsa.length == 2);
461 
462 	assert(fsa.front == 1337);
463 	assert(fsa.back == 1338);
464 
465 	void f(ref const(DArray!int) d) {
466 		assert(d.front == 1337);
467 		assert(d.back == 1338);
468 	}
469 
470 	f(fsa);
471 }
472 
473 
474 ///
475 @safe unittest {
476 	DArray!(int) fsa;
477 	fsa.insertBack(1337);
478 	fsa.insertBack(1338);
479 	assert(fsa.length == 2);
480 
481 	assert(fsa[0] == 1337);
482 	assert(fsa[1] == 1338);
483 
484 	void f(ref const(DArray!int) d) {
485 		assert(d[0] == 1337);
486 		assert(d[1] == 1338);
487 	}
488 
489 	f(fsa);
490 }
491 ///
492 @safe unittest {
493 	DArray!(int) fsa;
494 	assert(fsa.empty);
495 	assert(fsa.length == 0);
496 
497 	fsa.insertBack(1337);
498 	fsa.insertBack(1338);
499 
500 	assert(fsa.length == 2);
501 	assert(!fsa.empty);
502 }
503 
504 unittest {
505 	DArray!int d;
506 	assertEqual(d.length, 0);
507 	assert(d.empty);
508 
509 	for(int i = 0; i < 20; ++i) {
510 		d.insertBack(i);
511 		assertEqual(d.length, i+1);
512 	}
513 	assertEqual(d.length, 20);
514 
515 	DArray!int d2 = d;
516 	assertEqual(d.length, 20);
517 	assertEqual(d2.length, 20);
518 
519 	d2.insertBack(21);
520 	assertEqual(d.length, 20);
521 	assertEqual(d2.length, 21);
522 }
523 
524 unittest {
525 	import exceptionhandling;
526 	import std.stdio;
527 
528 	DArray!(int) fsa;
529 	assert(fsa.empty);
530 	cast(void)assertEqual(fsa.length, 0);
531 
532 	fsa.insertBack(1);
533 	assert(!fsa.empty);
534 	cast(void)assertEqual(fsa.length, 1);
535 	cast(void)assertEqual(fsa.front, 1);
536 	cast(void)assertEqual(fsa.back, 1);
537 
538 	fsa.insertBack(2);
539 	assert(!fsa.empty);
540 	cast(void)assertEqual(fsa.length, 2);
541 	cast(void)assertEqual(fsa.front, 1);
542 	cast(void)assertEqual(fsa.back, 2);
543 
544 	fsa.removeFront();
545 	assert(!fsa.empty);
546 	cast(void)assertEqual(fsa.length, 1);
547 	cast(void)assertEqual(fsa.front, 2);
548 	cast(void)assertEqual(fsa.back, 2);
549 
550 	fsa.removeBack();
551 	//writefln("%s %s", fsa.begin, fsa.end);
552 	assert(fsa.empty);
553 	cast(void)assertEqual(fsa.length, 0);
554 }
555 
556 unittest {
557 	import std.format;
558 
559 	DArray!(char) fsa;
560 	formattedWrite(fsa[], "%s %s %s", "Hello", "World", 42);
561 	//assert(cast(string)fsa == "Hello World 42", cast(string)fsa);
562 }
563 
564 unittest {
565 	import exceptionhandling;
566 
567 	DArray!(int) fsa;
568 	auto a = [0,1,2,4,32,64,1024,2048,65000];
569 	foreach(idx, it; a) {
570 		fsa.insertBack(it);
571 		assertEqual(fsa.length, idx + 1);
572 		assertEqual(fsa.back, it);
573 		for(int i = 0; i < idx; ++i) {
574 			assertEqual(fsa[i], a[i]);
575 		}
576 	}
577 }
578 
579 unittest {
580 	import exceptionhandling;
581 	import std.traits;
582 	import std.meta;
583 	import std.range;
584 	import std.stdio;
585 	import std.conv : to;
586 	foreach(Type; AliasSeq!(byte,int,long)) {
587 		DArray!(Type) fsa2;
588 		static assert(isInputRange!(typeof(fsa2[])));
589 		static assert(isForwardRange!(typeof(fsa2[])));
590 		static assert(isBidirectionalRange!(typeof(fsa2[])));
591 		foreach(idx, it; [[0], [0,1,2,3,4], [2,3,6,5,6,21,9,36,61,62]]) {
592 			DArray!(Type) fsa;
593 			foreach(jdx, jt; it) {
594 				fsa.insertBack(to!Type(jt));
595 				//writefln("%s idx %d jdx %d length %d", Type.stringof, idx, jdx, fsa.length);
596 				cast(void)assertEqual(fsa.length, jdx + 1);
597 				foreach(kdx, kt; it[0 .. jdx]) {
598 					assertEqual(fsa[kdx], kt);
599 				}
600 
601 				{
602 					auto forward = fsa[];
603 					auto forward2 = forward;
604 					cast(void)assertEqual(forward.length, jdx + 1);
605 					for(size_t i = 0; i < forward.length; ++i) {
606 						cast(void)assertEqual(forward[i], it[i]);
607 						cast(void)assertEqual(forward2.front, it[i]);
608 						forward2.popFront();
609 					}
610 					assert(forward2.empty);
611 
612 					auto backward = fsa[];
613 					auto backward2 = backward.save;
614 					cast(void)assertEqual(backward.length, jdx + 1);
615 					for(size_t i = 0; i < backward.length; ++i) {
616 						cast(void)assertEqual(backward[backward.length - i - 1],
617 								it[jdx - i]
618 						);
619 
620 						cast(void)assertEqual(backward2.back, 
621 								it[0 .. jdx + 1 - i].back
622 						);
623 						backward2.popBack();
624 					}
625 					assert(backward2.empty);
626 					auto forward3 = fsa[].save;
627 					auto forward4 = fsa[0 .. jdx + 1];
628 
629 					while(!forward3.empty && !forward4.empty) {
630 						cast(void)assertEqual(forward3.front, forward4.front);
631 						cast(void)assertEqual(forward3.back, forward4.back);
632 						forward3.popFront();
633 						forward4.popFront();
634 					}
635 					assert(forward3.empty);
636 					assert(forward4.empty);
637 				}
638 
639 				{
640 					const(DArray!(Type))* constFsa;
641 					constFsa = &fsa;
642 					auto forward = (*constFsa)[];
643 					auto forward2 = forward.save;
644 					cast(void)assertEqual(forward.length, jdx + 1);
645 					for(size_t i = 0; i < forward.length; ++i) {
646 						cast(void)assertEqual(cast(int)forward[i], it[i]);
647 						cast(void)assertEqual(cast(int)forward2.front, it[i]);
648 						forward2.popFront();
649 					}
650 					assert(forward2.empty);
651 
652 					auto backward = (*constFsa)[];
653 					auto backward2 = backward.save;
654 					cast(void)assertEqual(backward.length, jdx + 1);
655 					for(size_t i = 0; i < backward.length; ++i) {
656 						cast(void)assertEqual(backward[backward.length - i - 1],
657 								it[jdx - i]
658 						);
659 
660 						cast(void)assertEqual(backward2.back, 
661 								it[0 .. jdx + 1 - i].back
662 						);
663 						backward2.popBack();
664 					}
665 					assert(backward2.empty);
666 					auto forward3 = (*constFsa)[];
667 					auto forward4 = (*constFsa)[0 .. jdx + 1];
668 
669 					while(!forward3.empty && !forward4.empty) {
670 						cast(void)assertEqual(forward3.front, forward4.front);
671 						cast(void)assertEqual(forward3.back, forward4.back);
672 						forward3.popFront();
673 						forward4.popFront();
674 					}
675 					assert(forward3.empty);
676 					assert(forward4.empty);
677 				}
678 			}
679 		}
680 	}
681 }
682 
683 // Test case Issue #2
684 unittest {
685 	import exceptionhandling;
686 
687 	DArray!(int) fsa;
688 	fsa.insertBack(0);
689 	assert(fsa.length == 1);
690 	fsa.insertBack(1);
691 
692 	assertEqual(fsa[0], 0);	
693 	assertEqual(fsa[1], 1);	
694 	assertEqual(fsa.front, 0);
695 	assertEqual(fsa.back, 1);
696 }
697 
698 unittest {
699 	import std.stdio;
700 	import core.memory;
701 	enum size = 128;
702 	DArray!(int)[size] arrays;
703 	foreach (i; 0..size) {
704 	    foreach (j; 0..size) {
705 			assert(arrays[i].length == j);
706 	        arrays[i].insertBack(i * 1000 + j);
707 	    }
708 	}
709 	bool[int] o;
710 	foreach (i; 0..size) {
711 	    foreach (j; 0..size) {
712 			assert(arrays[i][j] !in o);
713 	        o[arrays[i][j]] = true;
714 	    }
715 	}
716 	assert(size * size == o.length);
717 }
718 
719 // issue #1 won't fix not sure why
720 unittest {
721 	import std.stdio;
722 	import core.memory;
723 	enum size = 256;
724 	DArray!(Object) arrays;
725 	foreach (i; 0..size) {
726 		auto o = new Object();
727 		assert(arrays.length == i);
728 		foreach(it; arrays[]) {
729 			assert(it !is null);
730 			assert(it.toHash());
731 		}
732 	    arrays.insertBack(o);
733 		assert(arrays.back is o);
734 		assert(!arrays.empty);
735 		assert(arrays.length == i + 1);
736 	}
737 
738 	assert(arrays.length == size);
739 	for(int i = 0; i < size; ++i) {
740 		assert(arrays[i] !is null);
741 		assert(arrays[i].toHash());
742 	}
743 	bool[Object] o;
744 	foreach (i; 0..size) {
745 		assert(arrays[i] !is null);
746 		assert(arrays[i] !in o);
747 	    o[arrays[i]] = true;
748 	    
749 	}
750 	assert(size == o.length);
751 }
752 
753 unittest {
754 	import exceptionhandling;
755 	DArray!(int) fsa;
756 	fsa.insertFront(1337);
757 	assert(!fsa.empty);
758 	assertEqual(fsa.length, 1);
759 	assertEqual(fsa.back, 1337);
760 	assertEqual(fsa.front, 1337);
761 }
762 
763 // Test case Issue #2
764 unittest {
765 	enum size = 256;
766 	DArray!(Object)[size] arrays;
767 	foreach (i; 0..size) {
768 	    foreach (j; 0..size) {
769 	        arrays[i].insertBack(new Object);
770 	    }
771 	}
772 	bool[Object] o;
773 	foreach (i; 0..size) {
774 	    foreach (j; 0..size) {
775 	        o[arrays[i][j]] = true;
776 	    }
777 	}
778 	assert(o.length == size * size);
779 }
780 
781 unittest {
782 	import std.range.primitives : hasAssignableElements, hasSlicing, isRandomAccessRange;
783 	DArray!(int) fsa;
784 	auto s = fsa[];
785 	static assert(hasSlicing!(typeof(s)));
786 	static assert(isRandomAccessRange!(typeof(s)));
787 	static assert(hasAssignableElements!(typeof(s)));
788 }
789 
790 unittest {
791 	import exceptionhandling;
792 
793 	DArray!(int) fsa;
794 	for(int i = 0; i < 32; ++i) {
795 		fsa.insertBack(i);	
796 	}
797 
798 	auto s = fsa[];
799 	for(int i = 0; i < 32; ++i) {
800 		assert(s[i] == i);
801 	}
802 	s = s[0 .. 33];
803 	for(int i = 0; i < 32; ++i) {
804 		assert(s[i] == i);
805 	}
806 
807 	auto t = s.save;
808 	s.popFront();
809 	for(int i = 0; i < 32; ++i) {
810 		assert(t[i] == i);
811 	}
812 
813 	auto r = t[10, 20];
814 	for(int i = 10; i < 20; ++i) {
815 		assertEqual(r[i-10], fsa[i]);
816 	}
817 
818 	foreach(ref it; r) {
819 		it = 0;
820 	}
821 
822 	for(int i = 10; i < 20; ++i) {
823 		assertEqual(r[i-10], 0);
824 	}
825 }
826 
827 unittest {
828 	DArray!(int) fsaM;
829 	for(int i = 0; i < 32; ++i) {
830 		fsaM.insertBack(i);	
831 	}
832 
833 	const(DArray!(int)) fsa = fsaM;
834 
835 	auto s = fsa[];
836 	for(int i = 0; i < 32; ++i) {
837 		assert(s[i] == i);
838 	}
839 	s = s[0 .. 33];
840 	for(int i = 0; i < 32; ++i) {
841 		assert(s[i] == i);
842 	}
843 
844 	auto t = s.save;
845 	s.popFront();
846 	for(int i = 0; i < 32; ++i) {
847 		assert(t[i] == i);
848 	}
849 }
850 
851 unittest {
852 	import std.random : Random, uniform;
853 	import std.format : format;
854 	struct Data {
855 		ulong a, b, c, d, e;
856 	}
857 
858 	auto rnd = Random(1337);
859 	DArray!(Data) a;
860 	for(size_t i = 0; i < 4096; ++i) {
861 		Data d;
862 		d.a = i;
863 		d.b = i;
864 		d.c = i;
865 		d.d = i;
866 		d.e = i;
867 
868 		a.insertBack(d);
869 
870 		int c = uniform(4,10, rnd);
871 		while(a.length > c) {
872 			a.removeFront();
873 		}
874 		assert(!a.empty);
875 		assert(a.length <= c, format("%d < %d", a.length, c));
876 
877 		auto r = a[];
878 		assert(r.back.a == i);
879 		assert(r.front.a <= i);
880 
881 		foreach(it; r[]) {
882 			assert(it.a <= i);
883 		}
884 
885 		auto cr = (*(cast(const(typeof(a))*)(&a)));
886 		assert(cr.back.a == i);
887 		assert(cr.front.a <= i);
888 
889 		auto crr = cr[];
890 		assert(crr.front.a <= i);
891 		assert(crr.back.a <= i);
892 		foreach(it; crr.save) {
893 			assert(it.a <= i);
894 		}
895 	}
896 }