1 /** 2 * Provides extended functionality to std.range 3 */ 4 module daffodil.util.range; 5 6 public import std.range; 7 8 import daffodil.colorspace; 9 10 template isImageRange(R, E) { 11 enum bool isImageRange = isImageRange!R && is(ElementType!R == E); 12 } 13 14 template isImageRange(R) { 15 enum bool isImageRange = isInputRange!R && is(typeof( 16 (inout int = 0) { 17 R r = R.init; 18 size_t w = r.width; 19 size_t h = r.height; 20 size_t c = r.channelCount; 21 const ColorSpace* s = r.colorSpace; 22 } 23 )); 24 } 25 26 template isRandomAccessImageRange(R) { 27 enum bool isRandomAccessImageRange = isImageRange!R && is(typeof( 28 (inout int = 0) { 29 R r = R.init; 30 ElementType!R e = r[0, 0]; 31 } 32 )); 33 } 34 35 interface ImageRange(E) : InputRange!E { 36 @property size_t width(); 37 @property size_t height(); 38 @property size_t channelCount(); 39 @property const(ColorSpace*) colorSpace(); 40 } 41 42 unittest { 43 static assert(isImageRange!(ImageRange!int)); 44 } 45 46 interface RandomAccessImageRange(E) : ImageRange!E { 47 E opIndex(size_t x, size_t y); 48 } 49 50 unittest { 51 static assert(isRandomAccessImageRange!(RandomAccessImageRange!int)); 52 } 53 54 template MostDerivedImageRange(R) if (isImageRange!R) { 55 alias E = ElementType!R; 56 57 static if (isRandomAccessImageRange!R) { 58 alias MostDerivedImageRange = RandomAccessImageRange!E; 59 } else { 60 alias MostDerivedImageRange = ImageRange!E; 61 } 62 } 63 64 class ImageRangeObject(R) : MostDerivedImageRange!R if (isImageRange!R) { 65 private alias E = ElementType!R; 66 67 private R _range; 68 69 this(R range) { 70 _range = range; 71 } 72 73 @property E front() { return _range.front; } 74 void popFront() { _range.popFront(); } 75 @property bool empty() { return _range.empty; } 76 @property size_t width() { return _range.width; } 77 @property size_t height() { return _range.height; } 78 @property size_t channelCount() { return _range.channelCount; } 79 @property const(ColorSpace*) colorSpace() { return _range.colorSpace; } 80 81 E moveFront() { 82 return .moveFront(_range); 83 } 84 85 // Optimization: One delegate call is faster than three virtual 86 // function calls. Use opApply for foreach syntax. 87 int opApply(scope int delegate(E) dg) { 88 int res; 89 90 foreach (i, e; this) { 91 res = dg(e); 92 if (res) break; 93 } 94 95 return res; 96 } 97 98 int opApply(scope int delegate(size_t, E) dg) { 99 int res; 100 101 size_t i = 0; 102 for(; !empty; popFront()) { 103 res = dg(i, front); 104 if (res) break; 105 i++; 106 } 107 108 return res; 109 } 110 111 static if (isRandomAccessImageRange!R) { 112 113 E opIndex(size_t x, size_t y) { 114 return _range[x, y]; 115 } 116 117 } 118 } 119 120 unittest { 121 static assert(isImageRange!(ImageRangeObject!(ImageRange!int))); 122 static assert(isRandomAccessImageRange!(ImageRangeObject!(RandomAccessImageRange!int))); 123 } 124 125 ImageRangeObject!R imageRangeObject(R)(R range) if (isImageRange!R) { 126 static if (is(R : ImageRange!(ElementType!R))) { 127 return range; 128 } else { 129 return new ImageRangeObject!R(range); 130 } 131 } 132 133 class Iter(R) if (isRandomAccessRange!R) { 134 private R range; 135 136 this(R r) { 137 range = r; 138 } 139 140 void popFront() { 141 range = range[1..$]; 142 } 143 144 @property bool empty() { return range.length == 0; } 145 @property ubyte front() { return range[0]; } 146 } 147 148 auto iter(R)(R range) if (isRandomAccessRange!R) { 149 return new Iter!R(range); 150 }