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 }