1 /**
2     Static introspection utilties for ranges
3 */
4 module bolts.range;
5 
6 import bolts.internal;
7 import std.range : isInputRange;
8 import std.meta : allSatisfy;
9 
10 /**
11     True if R is a `SortedRange`
12 
13     See_Also:
14         `std.range.SortedRange`
15 */
16 template isSortedRange(R...) if (R.length == 1) {
17     import std.range: SortedRange;
18     import bolts.traits: TypesOf;
19     alias T = TypesOf!R[0];
20     enum isSortedRange = is(T : SortedRange!U, U...);
21 }
22 
23 ///
24 unittest {
25     import std.algorithm: sort;
26     import std.range: assumeSorted;
27     static assert(isSortedRange!(typeof([0, 1, 2])) == false);
28     static assert(isSortedRange!([0, 1, 2].sort) == true);
29     static assert(isSortedRange!(typeof([0, 1, 2].assumeSorted)) == true);
30     static assert(isSortedRange!int == false);
31 }
32 
33 /**
34     Given a `SortedRange` R, `sortingPredicate!R(a, b)` will call in to the predicate
35     that was used to create the `SortedRange`
36 
37     Params:
38         Args[0] = the range to extract the predicate from
39         Args[1] = the sorting predicate to fallback to if `Range` is not a `SortedRange`
40 */
41 template sortingPredicate(Args...)
42 if ((Args.length == 1 || Args.length == 2) && isInputRange!(from.bolts.traits.TypesOf!Args[0])) {
43     import bolts.traits: TypesOf;
44     import std.range: SortedRange;
45     import std.functional: binaryFun;
46     alias R = TypesOf!Args[0];
47     static if (is(R : SortedRange!P, P...)) {
48         alias sortingPredicate = binaryFun!(P[1]);
49     } else {
50         static if (Args.length == 2) {
51             alias pred = binaryFun!(Args[1]);
52         } else {
53             alias pred = (a, b) => a < b;
54         }
55         alias sortingPredicate = pred;
56     }
57 }
58 
59 ///
60 unittest {
61     import std.algorithm: sort;
62 
63     // As a type
64     assert(sortingPredicate!(typeof([1].sort!"a < b"))(1, 2) == true);
65     assert(sortingPredicate!(typeof([1].sort!((a, b) => a > b)))(1, 2) == false);
66 
67     // As a value
68     assert(sortingPredicate!([1].sort!"a > b")(1, 2) == false);
69     assert(sortingPredicate!([1].sort!((a, b) => a < b))(1, 2) == true);
70 
71     // Default predicate
72     assert(sortingPredicate!(int[])(1, 2) == true);
73 }
74 
75 /// Finds the CommonType of a list of ranges
76 template CommonTypeOfRanges(Rs...) if (allSatisfy!(isInputRange, Rs)) {
77     import std.traits: CommonType;
78     import std.meta: staticMap;
79     import std.range: ElementType;
80     alias CommonTypeOfRanges = CommonType!(staticMap!(ElementType, Rs));
81 }
82 
83 ///
84 unittest {
85     auto a = [1, 2];
86     auto b = [1.0, 2.0];
87     static assert(is(CommonTypeOfRanges!(typeof(a), typeof(b)) == double));
88 }