1 /** 2 * ae.utils.range 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.utils.range; 15 16 import ae.utils.meta : isDebug; 17 18 /// An equivalent of an array range, but which maintains 19 /// a start and end pointer instead of a start pointer 20 /// and length. This allows .popFront to be faster. 21 /// Optionally, omits bounds checking for even more speed. 22 // TODO: Can we make CHECKED implicit, controlled by 23 // -release, like regular arrays? 24 // TODO: Does this actually make a difference in practice? 25 // Run some benchmarks... 26 struct FastArrayRange(T, bool CHECKED=isDebug) 27 { 28 T* ptr, end; 29 30 this(T[] arr) 31 { 32 ptr = arr.ptr; 33 end = ptr + arr.length; 34 } 35 36 @property T front() 37 { 38 static if (CHECKED) 39 assert(!empty); 40 return *ptr; 41 } 42 43 void popFront() 44 { 45 static if (CHECKED) 46 assert(!empty); 47 ptr++; 48 } 49 50 @property bool empty() { return ptr==end; } 51 52 @property ref typeof(this) save() { return this; } 53 54 T opIndex(size_t index) 55 { 56 static if (CHECKED) 57 assert(index < end-ptr); 58 return ptr[index]; 59 } 60 61 T[] opSlice() 62 { 63 return ptrSlice(ptr, end); 64 } 65 66 T[] opSlice(size_t from, size_t to) 67 { 68 static if (CHECKED) 69 assert(from <= to && to <= end-ptr); 70 return ptr[from..to]; 71 } 72 } 73 74 auto fastArrayRange(T)(T[] arr) { return FastArrayRange!T(arr); } 75 76 T[] ptrSlice(T)(T* a, T* b) 77 { 78 return a[0..b-a]; 79 } 80 81 unittest 82 { 83 FastArrayRange!ubyte r; 84 auto x = r.save; 85 } 86 87 // ************************************************************************ 88 89 /// Apply a predicate over each consecutive pair. 90 template pairwise(alias pred) 91 { 92 import std.range : zip, dropOne; 93 import std.algorithm.iteration : map; 94 import std.functional : binaryFun; 95 96 auto pairwise(R)(R r) 97 { 98 return zip(r, r.dropOne).map!(pair => binaryFun!pred(pair[0], pair[1])); 99 } 100 } 101 102 /// 103 unittest 104 { 105 import std.algorithm.comparison : equal; 106 assert(equal(pairwise!"a+b"([1, 2, 3]), [3, 5])); 107 assert(equal(pairwise!"b-a"([1, 2, 3]), [1, 1])); 108 }