1 module dmdtags.span;
2 
3 // extern(C++) compatible slice type
4 struct Span(T)
5 {
6 	private T* _ptr;
7 	private size_t _length;
8 
9 	this(inout(T)[] slice) inout
10 	{
11 		_ptr = &slice[0];
12 		_length = slice.length;
13 	}
14 
15 	inout(T)* ptr() inout { return _ptr; }
16 	size_t length() const { return _length; }
17 
18 	inout(T)[] opIndex() inout
19 	{
20 		return ptr[0 .. length];
21 	}
22 
23 	ref inout(T) opIndex(size_t i) inout
24 	{
25 		assert(i < length);
26 		return ptr[i];
27 	}
28 
29 	size_t[2] opSlice(size_t dim)(size_t start, size_t end) const
30 	{
31 		return [start, end];
32 	}
33 
34 	alias opDollar(size_t dim) = length;
35 
36 	inout(T)[] opIndex(size_t[2] bounds) inout
37 	{
38 		size_t start = bounds[0], end = bounds[1];
39 		assert(start <= end && end <= length);
40 		return ptr[start .. end];
41 	}
42 
43 	bool opEquals(const Span rhs) const
44 	{
45 		return this[] == rhs[];
46 	}
47 
48 	int opCmp(const Span rhs) const
49 	{
50 		import std.algorithm.comparison: cmp;
51 
52 		return this[].cmp(rhs[]);
53 	}
54 
55 	// qual(Span!T) -> Span!(qual(T))
56 	auto headMutable(this This)()
57 	{
58 		import std.traits: CopyTypeQualifiers;
59 
60 		return Span!(CopyTypeQualifiers!(This, T))(this[]);
61 	}
62 
63 	void toString(Sink)(ref Sink sink)
64 	{
65 		import std.algorithm.mutation: copy;
66 
67 		copy(this[], sink);
68 	}
69 }
70 
71 inout(Span!T) span(T)(inout(T)[] slice)
72 {
73 	return inout(Span!T)(slice);
74 }
75 
76 unittest {
77 	int[] arr = [1, 2, 3];
78 	auto span = span(arr);
79 
80 	assert(span.length == arr.length);
81 	assert(span.ptr == arr.ptr);
82 	assert(span[0] == 1);
83 	assert(span[] == arr);
84 	import std.stdio;
85 	debug writeln(span[1 .. $]);
86 	assert(span[1 .. $] == arr[1 .. $]);
87 }