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