1 /** 2 Provides methods for accessing the back of a range 3 */ 4 module ddash.range.back; 5 6 /// 7 unittest { 8 import std.algorithm: filter; 9 import std.range: iota, takeNone, array; 10 import optional: some, none; 11 auto evens = 10.iota.filter!"a % 2 == 0".array; 12 assert(evens.withBack!"a" == some(8)); 13 assert(evens.takeNone.maybeBack == none); 14 assert(evens.takeNone.backOr(100) == 100); 15 } 16 17 import ddash.common; 18 19 /** 20 Retrieves the back of a range or a default value 21 22 Since: 23 - 0.0.1 24 */ 25 auto backOr(Range, T)(Range range, lazy T defaultValue) 26 if (from!"std.range".isBidirectionalRange!Range && is(T : from!"std.range".ElementType!Range)) { 27 import std.range: empty, back; 28 return range.empty ? defaultValue : range.back; 29 } 30 31 /// 32 unittest { 33 assert((int[]).init.backOr(7) == 7); 34 assert([1, 2].backOr(3) == 2); 35 } 36 37 /** 38 Takes a unary function that is called on back of range if it is there 39 40 Since: 41 - 0.0.1 42 */ 43 auto withBack(alias fun, Range)(Range range) if (from!"std.range".isBidirectionalRange!Range) { 44 import std.range: empty, back, 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.back)); 59 } 60 } 61 62 /// 63 unittest { 64 import optional: some, none; 65 assert((int[]).init.withBack!(a => a * a) == none); 66 assert([3, 2].withBack!(a => a * a) == some(4)); 67 assert([3, 5].withBack!"a + 1" == some(6)); 68 } 69 70 /** 71 Returns an `Optional` of the back of range 72 73 Since: 74 - 0.0.1 75 */ 76 auto maybeBack(Range)(Range range) if (from!"std.range".isBidirectionalRange!Range) { 77 import std.range: ElementType, empty, back; 78 import optional: no, some; 79 return range.empty ? no!(ElementType!Range) : some!(ElementType!Range)(range.back); 80 } 81 82 /// 83 unittest { 84 assert((int[]).init.maybeBack.empty == true); 85 assert([1, 2].maybeBack.front == 2); 86 } 87 88 unittest { 89 const(string)[] args = []; 90 static assert(__traits(compiles, { args.maybeBack; })); 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.maybeBack.dispatch.f == none); 105 assert([A(3), A(5)].maybeBack.dispatch.f == some(5)); 106 }