1 module libd.algorithm.common;
2 
3 import libd.meta : isSlice, ElementType;
4 
5 @nogc nothrow:
6 
7 enum isInputRange(alias RangeT) =
8 (
9     __traits(hasMember, RangeT, "front")
10  && __traits(hasMember, RangeT, "popFront")
11  && __traits(hasMember, RangeT, "empty")
12 )
13  || isSlice!RangeT;
14 
15 enum isOutputRange(alias RangeT, alias ElementT) =
16     __traits(compiles, RangeT.init.put(ElementT.init));
17 
18 enum isCollection(alias CollectionT, alias ElementT) =
19     __traits(hasMember, CollectionT, "insertAt")
20  && __traits(hasMember, CollectionT, "removeAt")
21  && __traits(hasMember, CollectionT, "getAt")
22  && __traits(hasMember, CollectionT, "length")
23  && is(typeof(CollectionT.init.getAt(0)) == ElementT)
24  && providesRange!CollectionT
25  && isOutputRange!(CollectionT, ElementT);
26 
27 enum providesRange(alias T) = 
28     __traits(hasMember, T, "range");
29 
30 enum canForeach(alias T) =
31     __traits(compiles, { foreach(a; T.init){} });
32 
33 enum canForeachOrProvidesRange(alias T) =
34     canForeach!T
35  || (
36         providesRange!T 
37      && canForeach!(typeof(T.range()))
38     );
39 
40 enum OptimisationHint
41 {
42     none = 0,
43 
44     rangeFasterThanIndex = 1 << 0,
45     preferMoveOverCopy = 1 << 1
46 }
47 
48 pragma(inline, true)
49 bool empty(T)(const scope auto ref T array)
50 if(isSlice!T)
51 {
52     return array.length == 0;
53 }
54 
55 pragma(inline, true)
56 inout(ElementType!T) front(T)(scope auto ref inout(T) array)
57 if(isSlice!T)
58 {
59     assert(array.length, "Cannot use value of empty array.");
60     return array[0];
61 }
62 
63 pragma(inline, true)
64 void popFront(T)(scope auto ref T array)
65 if(isSlice!T)
66 {
67     array = array[1..$];
68 }