1 /**
2 Provides methods for accessing the front of a range
3 */
4 module ddash.range.front;
5
6 ///
7 unittest {
8 import std.algorithm: filter;
9 import std.range: iota, takeNone, drop;
10 import optional: some, none;
11 auto evens = 10.iota.filter!"a % 2 == 0".drop(2);
12 assert(evens.withFront!"a" == some(4));
13 assert(evens.takeNone.maybeFront == none);
14 assert(evens.takeNone.frontOr(100) == 100);
15 }
16
17 import ddash.common;
18
19 /**
20 Retrieves the front of a range or a default value
21
22 Since:
23 - 0.0.1
24 */
25 auto frontOr(Range, T)(Range range, lazy T defaultValue)
26 if (from!"std.range".isInputRange!Range && is(T : from!"std.range".ElementType!Range)) {
27 import std.range: empty, front;
28 return range.empty ? defaultValue : range.front;
29 }
30
31 ///
32 unittest {
33 assert((int[]).init.frontOr(7) == 7);
34 assert([1, 2].frontOr(3) == 1);
35 }
36
37 /**
38 Takes a unary function that is called on front of range if it is there
39
40 Since:
41 - 0.0.1
42 */
43 auto withFront(alias fun, Range)(Range range) if (from!"std.range".isInputRange!Range) {
44 import std.range: empty, front, ElementType;
45 import std.functional: unaryFun;
46 alias f = unaryFun!fun;
47 alias R = typeof(f(ElementType!Range.init));
48 static if (is(R == void))
49 {
50 import optional: some;
51 if (!range.empty) {
52 f(range.front);
53 }
54 }
55 else
56 {
57 import optional: some, no;
58 return range.empty ? no!R : some(f(range.front));
59 }
60 }
61
62 ///
63 unittest {
64 import optional: some, none;
65 assert((int[]).init.withFront!(a => a * a) == none);
66 assert([3, 2].withFront!(a => a * a) == some(9));
67 assert([3, 2].withFront!"a + 1" == some(4));
68 }
69
70 /**
71 Returns an `Optional` of the front of a range
72
73 Since:
74 - 0.0.1
75 */
76 auto maybeFront(Range)(Range range) if (from!"std.range".isInputRange!Range) {
77 import std.range: ElementType, empty, front;
78 import optional: no, some;
79 return range.empty ? no!(ElementType!Range) : some!(ElementType!Range)(range.front);
80 }
81
82 ///
83 unittest {
84 assert((int[]).init.maybeFront.empty == true);
85 assert([1, 2].maybeFront.front == 1);
86 }
87
88 unittest {
89 const(string)[] args = [];
90 static assert(__traits(compiles, { args.maybeFront; }));
91 }
92
93 ///
94 unittest {
95 import std.algorithm: filter;
96 import optional: some, none, dispatch;
97 struct A {
98 int x;
99 int f() {
100 return x;
101 }
102 }
103
104 assert((A[]).init.maybeFront.dispatch.f == none);
105 assert([A(3), A(5)].maybeFront.dispatch.f == some(3));
106 }