1 module memutils.vector;
2 
3 import std.traits : ForeachType, isNumeric, isSomeString, hasElaborateDestructor, isPointer, hasIndirections;
4 import std.range : popFront, front, ElementEncodingType, empty, isInputRange, isForwardRange, isRandomAccessRange, ElementType, refRange, RefRange, hasLength;
5 
6 import memutils.allocators;
7 import memutils.helpers;
8 import memutils.utils;
9 import memutils.refcounted;
10 
11 @trusted:
12 template isImplicitlyConvertibleLegacy(From, To)
13 {
14     enum bool isImplicitlyConvertibleLegacy = is(typeof({
15         void fun(ref From v)
16         {
17             void gun(To) {}
18             gun(v);
19         }
20     }));
21 }
22 
23 
24 template Array(T, ALLOC = ThreadMem) 
25 {
26 	alias Array = RefCounted!(Vector!(T, ALLOC), ALLOC);
27 }
28 
29 // TODO: Remove implicit string casting for Vector!ubyte! Encourage use of Vector!char [].idup instead.
30 
31 /// An array that uses a custom allocator.
32 
33 struct Vector(T, ALLOC = ThreadMem)
34 {	
35 nothrow:
36 	enum NOGC = true;
37 	static enum TSize = T.sizeof;
38 
39 	void opAssign()(ref T[] other) {
40 		this[] = other[];
41 	}
42 	
43 	// Payload cannot be copied
44 	private struct Payload
45 	{
46 		nothrow:
47 		size_t _capacity;
48 		T* _payload;
49 		size_t _length;
50 		
51 		// Convenience constructor
52 		this()(auto ref T[] p) 
53 		{ 
54 			if (p.length == 0) return;
55 
56 			length = p.length;
57 
58 			static if (isImplicitlyConvertibleLegacy!(T, T)) {
59 				if (_payload is p.ptr && _length == p.length) {
60 					if (!__ctfe) p = null;
61 				}
62 				else {
63 					foreach (i, ref item; _payload[0 .. _length]) {
64 						item = p[i];
65 					}
66 				}
67 			}
68 			else
69 			{
70 				foreach (i, ref item; _payload[0 .. _length]) {
71 					item = p[i];
72 				}
73 			}
74 		}
75 		
76 		// Destructor releases array memory
77 		~this() const nothrow
78 		{
79 			if (__ctfe) {
80 				return;
81 			} else {
82 			//try {
83 				if (_capacity == 0 || _payload is null)
84 					return;
85 				T[] data = cast(T[]) _payload[0 .. _capacity];
86 				freeArray!(T, ALLOC)(data, _length); // calls destructors and frees memory
87 			//} 
88 			//catch (Throwable e) { assert(false, "Vector.~this Exception: " ~ e.toString()); }
89 			}
90 		}
91 		
92 		void opAssign(Payload rhs)
93 		{
94 			assert(false);
95 		}
96 		
97 		// Duplicate data
98 		// @property Payload dup()
99 		// {
100 		//     Payload result;
101 		//     result._payload = _payload.dup;
102 		//     // Conservatively assume initial capacity == length
103 		//     result._capacity = result._length;
104 		//     return result;
105 		// }
106 		
107 		// length
108 		@property size_t length() const
109 		{
110 			return _length;
111 		}
112 		
113 		// length
114 		@property void length(size_t newLength)
115 		{
116 			logInfo("Set length: ", newLength);
117 			if (length > 0 && length >= newLength)
118 			{
119 				// shorten
120 				static if (hasElaborateDestructor!T) {
121 					foreach (ref e; _payload[newLength .. _length]) {
122 						static if (is(T == struct) && !isPointer!T) { // call destructors but not for indirections...
123 							logTrace("Destructing Vector item(s) ", T.stringof, " for newLength ", newLength);
124 							destructRecurse(e);
125 						}
126 					}
127 					
128 					// Zero out unused capacity to prevent gc from seeing
129 					// false pointers
130 					if (!__ctfe) memset(_payload + newLength, 0, (_length - newLength) * TSize);
131 				}
132 				_length = newLength;
133 				assert(_length == newLength, "Bad length attribution");
134 				return;
135 			}
136 			
137 			if (newLength > 0) {
138 				// enlarge
139 				auto startEmplace = length;
140 				reserve(newLength);
141 				_length = newLength;
142 				assert(_length == newLength, "Bad length attribution");
143 				if (!__ctfe) {
144 					static if (!isImplicitlyConvertibleLegacy!(T, T)) {					
145 						foreach (size_t i; startEmplace .. newLength) {
146 							T t = T();
147 							memmove(_payload + i, &t, TSize); 
148 						}
149 						
150 					} else {
151 						initializeAll(_payload[startEmplace .. newLength]);
152 					}
153 				}
154 			}
155 		}
156 		
157 		// capacity
158 		@property size_t capacity() const
159 		{
160 			return _capacity;
161 		}
162 		
163 		// reserve
164 		void reserve(size_t elements)
165 		{
166 			if (elements <= capacity) return;
167 			// TODO: allow vector to become smaller?
168 
169 			logTrace("Reserve ", length, " => ", elements, " elements with capacity ", capacity);
170 
171 			if (_capacity > 0) {
172 				size_t len = _length;
173 				_payload = reallocArray!(T, ALLOC)(_payload[0 .. _capacity], elements)[0 .. len].ptr;
174 			}
175 			else if (elements > 0) {
176 				size_t len = _length;
177 				_payload = allocArray!(T, ALLOC)(elements)[0 .. len].ptr;
178 			}
179 			_capacity = elements;
180 		}
181 
182 		static if (is(T == char))
183 		pragma(inline, true) size_t pushBack(Stuff)(Stuff stuff) 
184 			if (is(Stuff == char[]) || is(Stuff == string))
185 		{
186 			logTrace("Vector.append @disabled this(this)");
187 			if (_capacity <= length + stuff.length)
188 			{
189 				reserve(1 + (length + stuff.length) * 3 / 2);
190 			}
191 			assert(capacity >= length + stuff.length && _payload);
192 						
193 			if (__ctfe) {
194 				assert(__ctfe);
195 				_length += stuff.length;
196 				_payload[_length - stuff.length .. _length] = stuff[0 .. stuff.length];
197 			} else {
198 				memmove(_payload + _length, stuff.ptr, stuff.length);
199 				_length += stuff.length;
200 			}
201 			
202 			return 1;
203 		}
204 
205 		pragma(inline, true) size_t pushBack(Stuff)(auto ref Stuff stuff)
206 			if (!isImplicitlyConvertibleLegacy!(T, T) && is(T == Stuff))
207 		{
208 			logTrace("Vector.append @disabled this(this)");
209 			if (_capacity == length)
210 			{
211 				reserve(1 + capacity * 3 / 2);
212 			}
213 			assert(capacity > length && _payload);
214 			_length += 1;
215 			_payload[_length - 1] = cast(T)stuff;
216 			
217 			return 1;
218 		}
219 		
220 		// Insert one item
221 		pragma(inline, true) size_t pushBack(Stuff)(auto ref Stuff stuff)
222 			if (isImplicitlyConvertibleLegacy!(T, T) && isImplicitlyConvertibleLegacy!(Stuff, T))
223 		{
224 			logTrace("Vector.append");
225 			//logTrace("Capacity: ", _capacity, " length: ", length);
226 			if (_capacity == length)
227 			{
228 				reserve(1 + capacity * 3 / 2);
229 			}
230 			assert(capacity > length && _payload, "Payload pointer capacity is wrong");
231 			//emplace(_payload.ptr + _length, stuff);
232 			_length += 1;
233 			_payload[_length - 1] = stuff;
234 			return 1;
235 		}
236 		
237 		/// Insert a range of items
238 		pragma(inline, true) size_t pushBack(Stuff)(auto ref Stuff stuff)
239 			if (isInputRange!Stuff && (isImplicitlyConvertibleLegacy!(ElementType!Stuff, T) || is(T == ElementType!Stuff)))
240 		{
241 			logTrace("Vector.append 2");
242 			static if (hasLength!Stuff)
243 			{
244 				immutable oldLength = length;
245 				reserve(oldLength + stuff.length);
246 			}
247 			size_t result;
248 			foreach (ref item; stuff)
249 			{
250 				pushBack(item);
251 				++result;
252 			}
253 			static if (hasLength!Stuff)
254 			{
255 				assert(length == oldLength + stuff.length);
256 			}
257 			return result;
258 		}
259 	}
260 	
261 	private alias Data = Payload;
262 	private Data _data;
263 	
264 	this(size_t elms) {
265 		resize(elms);
266 	}
267 	
268 	/**
269         Constructor taking a number of items
270      */
271 	this(U)(U[] values...)
272 		if (isImplicitlyConvertibleLegacy!(U, T))
273 	{
274 		// TODO: This doesn't work with refcounted
275 		_data = Data(cast(T[])values);
276 	}
277 
278 	/**
279         Constructor taking an input range
280      */
281 	this(Stuff)(Stuff stuff)
282 		if (isInputRange!Stuff && isImplicitlyConvertibleLegacy!(UnConst!(ElementType!Stuff), T) && !is(Stuff == T[]))
283 	{
284 		insertBack(stuff);
285 	}
286 	
287 	/**
288 	 * Move Constructor
289 	*/
290 	this()(auto ref typeof(this) other) {
291 		if (__ctfe) return;
292 		if (this.ptr !is other.ptr)
293 			this.swap(other);
294 		else {
295 			typeof(this) ini;
296 			other.swap(ini);
297 		}
298 	}
299 
300 	void swap(ref Vector!(T, ALLOC) other) {
301 		import std.algorithm : swap;
302 		
303 		Vector!(T, ALLOC) vec = Vector!(T, ALLOC)(length);
304 		// swap each element with a duplicate
305 		foreach (size_t i, ref el; _data._payload[0 .. _data._length]) {
306 			T t = el;
307 			memmove(vec._data._payload + i, &t, TSize);
308 			memset(&t, 0, TSize);
309 		}
310 		this.swap(cast(T[])other[]);
311 		other.swap(cast(T[])vec[]);
312 				
313 		foreach (size_t i, ref el; vec._data._payload[0 .. _data._length]) {
314 			memset(vec._data._payload + i, 0, TSize);
315 		}
316 		vec._data._length = 0;
317 	}
318 
319 	void swap(T[] other) {
320 		this[] = other;
321 	}
322 	/**
323         Duplicates the container. The elements themselves are not transitively
324         duplicated.
325 
326         Complexity: $(BIGOH n).
327      */
328 	@property Vector!(T, ALLOC) dup() const
329 	{
330 		static if (__traits(compiles, { T a; T b; a = b; } ())) {
331 			auto ret = Vector!(T, ALLOC)(cast(T[])_data._payload[0 .. _data._length]);
332 			return ret.move;
333 		}
334 		else static if (__traits(hasMember, T, "dup")) // Element is @disable this(this) but has dup()
335 		{
336 			Vector!(T, ALLOC) vec = Vector!(T, ALLOC)(length);
337 			// swap each element with a duplicate
338 			foreach (size_t i, ref el; _data._payload[0 .. _data._length]) {
339 				T t = el.dup;
340 				memmove(vec._data._payload + i, &t, TSize);
341 				memset(&t, 0, TSize);
342 			}
343 			return vec.move();
344 		} else {
345 			static assert(false, "Cannot dup() the element" ~ T.stringof);
346 		}
347 	}
348 	
349 	/// ditto
350 	@property RefCounted!(Vector!(T, ALLOC), ThreadMem) dupr() const
351 	{
352 		return RefCounted!(Vector!(T, ALLOC), ThreadMem)(cast(T[])_data._payload[0 .. _data._length]);
353 	}
354 	
355 	@property Vector!(T, ALLOC) move() {
356 		return Vector!(T, ALLOC)(this);
357 	}
358 	
359 	/**
360         Property returning $(D true) if and only if the container has no
361         elements.
362 
363         Complexity: $(BIGOH 1)
364      */
365 	@property bool empty() const
366 	{
367 		return !_data._payload[0 .. _data._length] || _data._payload[0 .. _data._length].empty;
368 	}
369 	
370 	/**
371         Returns the number of elements in the container.
372 
373         Complexity: $(BIGOH 1).
374      */
375 	@property size_t length() const
376 	{
377 		return _data._length;
378 	}
379 	
380 	/// ditto
381 	size_t opDollar() const
382 	{
383 		return length;
384 	}
385 	
386 	@property T* ptr() inout {
387 		return cast(T*) _data._payload;
388 	}
389 	
390 	@property T* end() inout {
391 		return this.ptr + this.length;
392 	}
393 	
394 	/**
395         Returns the maximum number of elements the container can store without
396            (a) allocating memory, (b) invalidating iterators upon insertion.
397 
398         Complexity: $(BIGOH 1)
399      */
400 	@property size_t capacity() const
401 	{
402 		return _data._capacity;
403 	}
404 
405 	/*
406 	@property auto range() {
407 		return refRange(&_data._payload);
408 	}
409 	*/
410 	
411 	/**
412         Ensures sufficient capacity to accommodate $(D e) elements.
413 
414         Postcondition: $(D capacity >= e)
415 
416         Complexity: $(BIGOH 1)
417      */
418 	void reserve(size_t elements)
419 	{
420 		_data.reserve(elements);
421 	}
422 	
423 	/**
424         Returns an array that can be translated to a range using ($D refRange).
425 
426         Complexity: $(BIGOH 1)
427      */
428 	auto opSlice() inout @trusted
429 	{
430 		static if (is(T[] == char[]))
431 			return cast(string) _data._payload[0 .. _data._length];
432 		else
433 			return _data._payload[0 .. _data._length];
434 	}
435 	
436 	/**
437         Returns an array of the container from index $(D a) up to (excluding) index $(D b).
438 
439         Precondition: $(D a <= b && b <= length)
440 
441         Complexity: $(BIGOH 1)
442      */
443 	T[] opSlice(size_t i, size_t j) const
444 	{
445 		logTrace("Slicing Vector i=", i, ", j=", j);
446 		assert(!(i > j || j > length), "invalid opslice attempt");
447 		static if (isPointer!T) {
448 			return cast() (&(cast()&(cast()**_data._payload)))[i .. j];
449 		} else return cast() (&(cast()*_data._payload))[i .. j];
450 	}
451 	
452 	/**
453         Forward to $(D opSlice().front) and $(D opSlice().back), respectively.
454 
455         Precondition: $(D !empty)
456 
457         Complexity: $(BIGOH 1)
458      */
459 	@property ref T front()
460 	{
461 		return _data._payload[0];
462 	}
463 	
464 	/// ditto
465 	@property ref T back()
466 	{
467 		return _data._payload[length - 1];
468 	}
469 	
470 	/**
471         Indexing operators yield or modify the value at a specified index.
472 
473         Precondition: $(D i < length)
474 
475         Complexity: $(BIGOH 1)
476      */	
477 	ref T opIndex(size_t i) const
478 	{
479 		if (__ctfe) {
480 			assert(__ctfe);
481 			static if (isPointer!T) {
482 				return &cast()*_data._payload[i];
483 			} else
484 			
485 			return cast()_data._payload[i];
486 		}
487 		else return *cast(T*)&_data._payload[i];
488 	}
489 
490 	ref T getRef(size_t i) 
491 	{
492 		if (__ctfe) {
493 			assert(__ctfe);
494 			return _data._payload[i];
495 		}
496 		else return _data._payload[i];
497 	}
498 	
499 	
500 	void opIndexAssign(U)(auto ref U val, size_t i)
501 	{
502 		static enum USize = U.sizeof;
503 		static if (__traits(compiles, {_data._payload[i] = cast(T) val; }()))
504 			_data._payload[i] = cast(T) val;
505 		else { // swap
506 			memmove(_data._payload + i, &val, USize);
507 			memset(&val, 0, USize);
508 		}
509 	}
510 	/**
511         Slicing operations execute an operation on an entire slice.
512 
513         Precondition: $(D i < j && j < length)
514 
515         Complexity: $(BIGOH slice.length)
516      */
517 	void opSliceAssign(Stuff)(auto ref Stuff value)
518 	{
519 		/*static if (isRandomAccessRange!Stuff)
520 		{
521 			_data.length = value.length;
522 			foreach (i, ref item; value){
523 				_data._payload[i] = item;
524 			}
525 		} else */static if (is(UnConst!Stuff == Vector!(T, ALLOC))) {
526 			_data.length = value._data.length;
527 			
528 			foreach (i, ref item; value._data._payload[0 .. value._data._length]){
529 				_data._payload[i] = item;
530 			}
531 		}
532 		else static if (is(T[] == UnConst!Stuff) || isImplicitlyConvertibleLegacy!(T, ElementType!Stuff) || (is(T == char) && is(Stuff == string))) {
533 			_data.length = value.length;
534 			if (__ctfe) {
535 				assert(__ctfe);
536 				if (value.ptr != _data._payload)
537 					_data._payload[0 .. value.length] = value[0 .. $];
538 			} else {
539 				foreach (i, ref item; cast(T[])value){
540 					_data._payload[i] = item;
541 				}
542 			}
543 		} else static assert(false, "Can't convert " ~ Stuff.stringof ~ " to " ~ T.stringof ~ "[]");
544 	}
545 	
546 	/// ditto
547 	void opSliceAssign(Stuff)(Stuff value, size_t i, size_t j)
548 	{
549 		auto slice = _data._payload[0 .. _data._length];
550 		slice[i .. j] = value;
551 	}
552 	
553 	/// ditto
554 	void opSliceUnary(string op)()
555 		if(op == "++" || op == "--")
556 	{
557 		mixin(op~"_data._payload[];");
558 	}
559 	
560 	/// ditto
561 	void opSliceUnary(string op)(size_t i, size_t j)
562 		if(op == "++" || op == "--")
563 	{
564 		mixin(op~"slice[i .. j];");
565 	}
566 	
567 	/// ditto
568 	void opSliceOpAssign(string op)(T value)
569 	{
570 		mixin("_data._payload[] "~op~"= value;");
571 	}
572 	
573 	/// ditto
574 	void opSliceOpAssign(string op)(T value, size_t i, size_t j)
575 	{
576 		mixin("slice[i .. j] "~op~"= value;");
577 	}
578 	
579 	/**
580         Returns a new container that's the concatenation of $(D this) and its
581         argument. $(D opBinaryRight) is only defined if $(D Stuff) does not
582         define $(D opBinary).
583 
584         Complexity: $(BIGOH n + m), where m is the number of elements in $(D
585         stuff)
586      */
587 	auto opBinary(string op, Stuff)(Stuff stuff)
588 		if (op == "~")
589 	{
590 		logTrace("Appending stuff");
591 		Vector!(T, ALLOC) result;
592 		// @@@BUG@@ result ~= this[] doesn't work
593 		result ~= this[];
594 		assert(result.length == length);
595 		static if (__traits(compiles, stuff[]))
596 			result ~= stuff[];
597 		else
598 			result ~= stuff;
599 		return result.move();
600 	}
601 	
602 	void opOpAssign(string op, U)(auto ref U input)
603 		if (op == "^")
604 	{
605 		if (this.length < input.length)
606 			this.resize(input.length);
607 
608 		pure static void xorBuf(T)(T* output, const(T)* input, size_t length)
609 		{
610 			while (length >= 8)
611 			{
612 				output[0 .. 8] ^= input[0 .. 8];
613 				
614 				output += 8; input += 8; length -= 8;
615 			}
616 			
617 			output[0 .. length] ^= input[0 .. length];
618 		}
619 
620 		xorBuf(this.ptr, input.ptr, input.length);
621 	}
622 	
623 	/**
624         Forwards to $(D pushBack(stuff)).
625      */
626 	void opOpAssign(string op, Stuff)(auto ref Stuff stuff)
627 		if (op == "~")
628 	{
629 		static if (is (Stuff == typeof(this))) {
630 			insertBack(cast(T[]) stuff[]);
631 		}
632 		else
633 		{
634 			insertBack(stuff);
635 		}
636 	}
637 	
638 	/**
639         Removes all contents from the container. The container decides how $(D
640         capacity) is affected.
641 
642         Postcondition: $(D empty)
643 
644         Complexity: $(BIGOH n)
645      */
646 	void clear()
647 	{
648 		logTrace("Vector.clear()");
649 		_data.length = 0;
650 	}
651 	
652 	
653 	/**
654         Sets the number of elements in the container to $(D newSize). If $(D
655         newSize) is greater than $(D length), the added elements are added to
656         unspecified positions in the container and initialized with $(D
657         T.init).
658 
659         Complexity: $(BIGOH abs(n - newLength))
660 
661         Postcondition: $(D length == newLength)
662      */
663 	@property void length(size_t newLength)
664 	{
665 		_data.length = newLength;
666 	}
667 	
668 	void resize(size_t newLength)
669 	{
670 		logInfo("Resize to ", newLength);
671 		this.length = newLength;
672 	}
673 	
674 	
675 	int opCmp(Alloc)(auto const ref Vector!(T, Alloc) other) const 
676 	{
677 		if (this[] == other[])
678 			return 0;
679 		else if (this[] < other[])
680 			return -1;
681 		else
682 			return 0;
683 	}
684 	size_t pushBack(Stuff...)(Stuff stuff) 
685 		if (!isNumeric!Stuff || !is ( T == ubyte ))
686 	{
687 		return insertBack(stuff);
688 	}
689 	
690 	size_t pushBack(Stuff...)(Stuff stuff) 
691 		if (isNumeric!Stuff && is(T == ubyte))
692 	{
693 		return insertBack(cast(T) stuff);
694 	}
695 
696 	size_t insert(Stuff...)(Stuff stuff) {
697 		return insertBack(stuff);
698 	}
699 	
700 	/**
701         Inserts $(D value) to the front or back of the container. $(D stuff)
702         can be a value convertible to $(D T) or a range of objects convertible
703         to $(D T). The stable version behaves the same, but guarantees that
704         ranges iterating over the container are never invalidated.
705 
706         Returns: The number of elements inserted
707 
708         Complexity: $(BIGOH m * log(n)), where $(D m) is the number of
709         elements in $(D stuff)
710     */
711 	size_t insertBack(Stuff)(auto ref Stuff stuff)
712 	{
713 		static if (isImplicitlyConvertibleLegacy!(Stuff, T[]))
714 			return _data.pushBack(cast(T[])stuff);
715 		else static if (isSomeString!(Stuff) && !isImplicitlyConvertibleLegacy!(Stuff, T)) {
716 			return _data.pushBack(cast(T[])stuff);
717 		}
718 		else static if (isSomeString!(Stuff) && isImplicitlyConvertibleLegacy!(Stuff, T)) {
719 			return _data.pushBack(cast(T)stuff);
720 		}
721 		else static if (isInputRange!(Stuff) && isImplicitlyConvertibleLegacy!(ForeachType!Stuff, T)) {
722 			return _data.pushBack(stuff);
723 		}
724 		else
725 			return _data.pushBack(cast(T) stuff);
726 	}
727 
728 	/**
729         Removes the value at the back of the container. The stable version
730         behaves the same, but guarantees that ranges iterating over the
731         container are never invalidated.
732 
733         Precondition: $(D !empty)
734 
735         Complexity: $(BIGOH log(n)).
736     */
737 	void removeBack()
738 	{
739 		assert(!empty);
740 		static if (hasElaborateDestructor!T)
741 			destructRecurse(_data._payload[_data._length - 1]);
742 		if (__ctfe) {
743 			assert(__ctfe);
744 			_data._payload[_data._length - 1] = T.init;
745 		} else memset(_data._payload + _data._length - 1, 0, TSize);
746 		_data._length -= 1;
747 	}
748 	
749 	@trusted
750 	void removeFront() { 
751 	
752 		assert(!empty);
753 		static if (hasElaborateDestructor!T)
754 			destructRecurse(_data._payload[0]);
755 		
756 		if (_data._length > 1) {
757 			if (__ctfe) {
758 				assert(__ctfe);
759 				_data._payload[0 .. _data._length-1] = _data._payload[1 .. _data._length];
760 				_data._payload[_data._length-1] = T.init;
761 			} else {
762 				memmove(_data._payload, _data._payload + 1, TSize * (_data._length - 1));
763 				memset(_data._payload + _data._length - 1, 0, TSize);
764 			}
765 		}
766 		_data._length -= 1;
767 	}
768 	
769 	/**
770         Removes $(D howMany) values at the front or back of the
771         container. Unlike the unparameterized versions above, these functions
772         do not throw if they could not remove $(D howMany) elements. Instead,
773         if $(D howMany > n), all elements are removed. The returned value is
774         the effective number of elements removed. The stable version behaves
775         the same, but guarantees that ranges iterating over the container are
776         never invalidated.
777 
778         Returns: The number of elements removed
779 
780         Complexity: $(BIGOH howMany).
781     */
782 	size_t removeBack(size_t howMany)
783 	{
784 		if (howMany > length) howMany = length;
785 		static if (hasElaborateDestructor!T)
786 			foreach (ref e; _data._payload[_data._length - howMany .. _data._length])
787 				destructRecurse(e);
788 		memset(_data._payload + _data._length - howMany, 0, howMany*TSize);
789 		_data._length -= howMany;
790 		return howMany;
791 	}
792 
793 	/**
794         Inserts $(D stuff) before position i.
795 
796         Returns: The number of values inserted.
797 
798         Complexity: $(BIGOH n + m), where $(D m) is the length of $(D stuff)
799      */
800 	void insertBefore(Stuff)(size_t i, Stuff stuff)
801 		if (isImplicitlyConvertibleLegacy!(Stuff, T))
802 	{
803 		assert(i <= length);
804 		reserve(length + 1);
805 
806 		// Move elements over by one slot
807 		memmove(_data._payload + i + 1,
808 				_data._payload + i,
809 				TSize * (length - i));
810 		//emplace(_data._payload.ptr + i, stuff);
811 		T* slot = _data._payload + i;
812 		*slot = stuff;
813 		_data._length += 1;
814 	}
815 	
816 	/// ditto
817 	size_t insertBefore(Stuff)(size_t i, Stuff stuff)
818 		if (isInputRange!Stuff && isImplicitlyConvertibleLegacy!(ElementType!Stuff, T))
819 	{
820 		assert(i <= length);
821 		static if (isForwardRange!Stuff)
822 		{
823 			// Can find the length in advance
824 			auto extra = walkLength(stuff);
825 			if (!extra) return 0;
826 			reserve(length + extra);
827 			// Move elements over by extra slots
828 			memmove(_data._payload + i + extra,
829 				_data._payload + i,
830 				TSize * (length - i));
831 			foreach (p; _data._payload + i ..
832 				_data._payload + i + extra)
833 			{
834 				*p = stuff.front;
835 				//emplace(p, stuff.front);
836 				stuff.popFront();
837 			}
838 			_data._length += extra;
839 			return extra;
840 		}
841 		else
842 		{
843 			assert(_data);
844 			immutable offset = i;
845 			assert(offset <= length);
846 			auto result = pushBack(stuff);
847 			bringToFront(this[offset .. length - result],
848 						 this[length - result .. length]);
849 			return result;
850 		}
851 	}
852 	
853 	/// ditto
854 	size_t insertAfter(Stuff)(size_t i, Stuff stuff)
855 	{
856 		assert(r._outer._data is _data);
857 		// TODO: optimize
858 		immutable offset = i;
859 		assert(offset <= length);
860 		auto result = pushBack(stuff);
861 		bringToFront(this[offset .. length - result],
862 					 this[length - result .. length]);
863 		return result;
864 	}
865 
866 	bool opEquals()(auto const ref Vector!(T, ALLOC) other_) const {
867 		if (other_.empty && empty())
868 			return true;
869 		else if (other_.empty)
870 			return false;
871 		if (other_.length != length)
872 			return false;
873 
874 		return _data._payload[0 .. length] == other_._data._payload[0 .. length];
875 	}
876 
877 	bool opEquals()(auto const ref T[] other) {
878 		logTrace("other: ", other, " this: ", _data._payload);
879 		return other == _data._payload[0 .. _data._length];
880 	}
881 	
882 }
883 
884 auto array(T)(T[] val) 
885 {
886 	return Array!(Unqual!T)(val);
887 }
888 
889 auto vector(T)(T[] val)
890 {
891 	return Vector!(Unqual!T)(val);
892 }