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