1 /** Helpers used by containers.
2  */
3 module nxt.container.common;
4 
5 /** Flag for use of dynamic version of Rust-style ownership-and borrowing.
6  */
7 enum BorrowCheckFlag : ubyte { no, yes }
8 
9 /** Flag that a container is grow-only, that doesn’t support any removals of elements.
10  */
11 enum GrowOnlyFlag : ubyte { no, yes }
12 
13 /** Growth strategy.
14  */
15 enum GrowthStrategy {
16 	grow_2,						// 2.0
17 	grow_3over2,				// 1.5
18 }
19 
20 /** Reserve room for `extra` more elements in `x`.
21  */
22 size_t reserveWithGrowth(GrowthStrategy gs, T)(ref T x, size_t extra)
23 if (is(typeof(T.init.capacity) : size_t) &&
24 	is(typeof(x.reserve(size_t.init)) == size_t)) {
25 	const newCapacity = x.capacity + extra;
26 	static	  if (gs == GrowthStrategy.grow_2)
27 		return x.reserve(newCapacity);
28 	else static if (gs == GrowthStrategy.grow_3over2)
29 		return x.reserve(newCapacity);
30 	else
31 		static assert(0, "Unknown growth strategy " ~ gs.stringof);
32 }
33 
34 pure nothrow @safe unittest {
35 	int[] x;
36 	x.reserve(2);
37 	x.reserveWithGrowth!(GrowthStrategy.grow_2)(1);
38 	assert(x.capacity >= 3);
39 }
40 
41 /** Try to pop first occurrence of `needle` in `haystack` (if any).
42 	Returns: `true` iff pop was made, `false` otherwise.
43  */
44 bool popFirstMaybe(alias pred = "a == b", C, E)(ref C haystack, in E needle)
45 if (__traits(hasMember, C, "length") &&
46 	__traits(hasMember, C, "popAt"))
47 	/+ TODO: activate this restriction +/
48 	// if (hasSlicing!C &&
49 	//	 is(ElementType!C == E.init))
50 {
51 	import std.functional : binaryFun;
52 	// doesn't work for uncopyable element types: import std.algorithm.searching : countUntil;
53 	size_t offset = 0;
54 	foreach (const ref e; haystack[]) {
55 		if (binaryFun!pred(e, needle))
56 			break;
57 		offset += 1;
58 	}
59 	if (offset != haystack.length) {
60 		haystack.popAt(offset);
61 		return true;
62 	}
63 	return false;
64 }
65 
66 /** Remove element at index `index` in `r`.
67  *
68  * TODO: reuse in array*.d
69  * TODO: better name removeAt
70  */
71 void shiftToFrontAt(T)(T[] r, size_t index) @trusted
72 {
73 	assert(index + 1 <= r.length);
74 
75 	/+ TODO: use this instead: +/
76 	// immutable si = index + 1;   // source index
77 	// immutable ti = index;	   // target index
78 	// immutable restLength = this.length - (index + 1);
79 	// moveEmplaceAll(_store.ptr[si .. si + restLength],
80 	//				_store.ptr[ti .. ti + restLength]);
81 
82 	// for each element index that needs to be moved
83 	foreach (immutable i; 0 .. r.length - (index + 1)) {
84 		immutable si = index + i + 1; // source index
85 		immutable ti = index + i;	 // target index
86 		import core.lifetime : moveEmplace;
87 		moveEmplace(r.ptr[si], /+ TODO: remove when compiler does this +/
88 					r.ptr[ti]);
89 	}
90 }
91 
92 pure nothrow @safe @nogc unittest {
93 	int[4] x = [11, 12, 13, 14];
94 	x[].shiftToFrontAt(1);
95 	assert(x == [11, 13, 14, 14]);
96 }