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 }