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