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