Skip to content

Commit a5e9353

Browse files
authored
Merge pull request #4781 from 9il/mapSlice
add mapSlice and fix Issue 16501
2 parents 5813fac + 99532a8 commit a5e9353

File tree

5 files changed

+594
-280
lines changed

5 files changed

+594
-280
lines changed

std/experimental/ndslice/internal.d

Lines changed: 324 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,333 @@
11
module std.experimental.ndslice.internal;
22

3+
import std.range.primitives;
34
import std.traits;
4-
import std.meta; //: AliasSeq, anySatisfy, Filter, Reverse;
5+
import std.meta;
6+
import std.experimental.ndslice.slice;
7+
8+
/+
9+
fastmath do nothing here,
10+
but remove constraint for LDC that operations for pointer's computations
11+
maybe mixed up with callers computations if both computations has fastmath attribute.
12+
So, it is just a bridge between two fastmath functions.
13+
fmb alias is used to relax users.
14+
+/
15+
package alias fmb = fastmath;
16+
17+
version(LDC)
18+
{
19+
static import ldc.attributes;
20+
alias fastmath = ldc.attributes.fastmath;
21+
}
22+
else
23+
{
24+
alias fastmath = fastmathDummy;
25+
}
26+
27+
enum FastmathDummy { init }
28+
FastmathDummy fastmathDummy() { return FastmathDummy.init; }
29+
30+
template PtrTuple(Names...)
31+
{
32+
@LikePtr struct PtrTuple(Ptrs...)
33+
if (allSatisfy!(isSlicePointer, Ptrs) && Ptrs.length == Names.length)
34+
{
35+
@fmb:
36+
37+
Ptrs ptrs;
38+
39+
void opOpAssign(string op)(sizediff_t shift)
40+
if (op == `+` || op == `-`)
41+
{
42+
foreach (ref ptr; ptrs)
43+
mixin (`ptr ` ~ op ~ `= shift;`);
44+
}
45+
46+
auto opBinary(string op)(sizediff_t shift)
47+
if (op == `+` || op == `-`)
48+
{
49+
auto ret = this;
50+
ret.opOpAssign!op(shift);
51+
return ret;
52+
}
53+
54+
public struct Index
55+
{
56+
Ptrs _ptrs__;
57+
mixin (PtrTupleFrontMembers!Names);
58+
}
59+
60+
auto opIndex(sizediff_t index)
61+
{
62+
auto p = ptrs;
63+
foreach (ref ptr; p)
64+
ptr += index;
65+
return Index(p);
66+
}
67+
}
68+
}
69+
70+
// ISSUE 16501
71+
unittest
72+
{
73+
import std.experimental.ndslice;
74+
alias sab = sliced!("a", "b");
75+
auto sl = sab(new double[12], new double[12], 3, 4);
76+
auto psl = sl.pack!1;
77+
}
78+
79+
80+
struct PtrShell(Range)
81+
{
82+
sizediff_t _shift;
83+
Range _range;
84+
@fmb:
85+
86+
enum hasAccessByRef = isPointer!Range ||
87+
__traits(compiles, &_range[0]);
88+
89+
void opOpAssign(string op)(sizediff_t shift)
90+
if (op == `+` || op == `-`)
91+
{
92+
mixin (`_shift ` ~ op ~ `= shift;`);
93+
}
94+
95+
auto opBinary(string op)(sizediff_t shift)
96+
if (op == `+` || op == `-`)
97+
{
98+
mixin (`return typeof(this)(_shift ` ~ op ~ ` shift, _range);`);
99+
}
100+
101+
auto opUnary(string op)()
102+
if (op == `++` || op == `--`)
103+
{
104+
mixin(op ~ `_shift;`);
105+
return this;
106+
}
107+
108+
auto ref opIndex(sizediff_t index)
109+
in
110+
{
111+
assert(_shift + index >= 0);
112+
static if (hasLength!Range)
113+
assert(_shift + index <= _range.length);
114+
}
115+
body
116+
{
117+
return _range[_shift + index];
118+
}
119+
120+
static if (!hasAccessByRef)
121+
{
122+
auto ref opIndexAssign(T)(T value, sizediff_t index)
123+
in
124+
{
125+
assert(_shift + index >= 0);
126+
static if (hasLength!Range)
127+
assert(_shift + index <= _range.length);
128+
}
129+
body
130+
{
131+
return _range[_shift + index] = value;
132+
}
133+
134+
auto ref opIndexOpAssign(string op, T)(T value, sizediff_t index)
135+
in
136+
{
137+
assert(_shift + index >= 0);
138+
static if (hasLength!Range)
139+
assert(_shift + index <= _range.length);
140+
}
141+
body
142+
{
143+
mixin (`return _range[_shift + index] ` ~ op ~ `= value;`);
144+
}
145+
146+
auto ref opIndexUnary(string op)(sizediff_t index)
147+
in
148+
{
149+
assert(_shift + index >= 0);
150+
static if (hasLength!Range)
151+
assert(_shift + index <= _range.length);
152+
}
153+
body
154+
{
155+
mixin (`return ` ~ op ~ `_range[_shift + index];`);
156+
}
157+
}
158+
159+
auto save() @property
160+
{
161+
return this;
162+
}
163+
}
164+
165+
auto ptrShell(Range)(Range range, sizediff_t shift = 0)
166+
{
167+
return PtrShell!Range(shift, range);
168+
}
169+
170+
@safe pure nothrow unittest
171+
{
172+
import std.internal.test.dummyrange;
173+
foreach (RB; AliasSeq!(ReturnBy.Reference, ReturnBy.Value))
174+
{
175+
DummyRange!(RB, Length.Yes, RangeType.Random) range;
176+
range.reinit;
177+
assert(range.length >= 10);
178+
auto ptr = range.ptrShell;
179+
assert(ptr[0] == range[0]);
180+
auto save0 = range[0];
181+
ptr[0] += 10;
182+
++ptr[0];
183+
assert(ptr[0] == save0 + 11);
184+
(ptr + 5)[2] = 333;
185+
assert(range[7] == 333);
186+
187+
auto ptrCopy = ptr.save;
188+
ptrCopy._range.popFront;
189+
ptr[1] = 2;
190+
assert(ptr[0] == save0 + 11);
191+
assert(ptrCopy[0] == 2);
192+
}
193+
}
194+
195+
private template PtrTupleFrontMembers(Names...)
196+
if (Names.length <= 32)
197+
{
198+
static if (Names.length)
199+
{
200+
alias Top = Names[0..$-1];
201+
enum int m = Top.length;
202+
/+
203+
fastmath do nothing here,
204+
but remove constraint for LDC that operations for pointer's computations
205+
maybe mixed up with callers computations if both computations has fastmath attribute.
206+
So, it is just a bridge between two fastmath functions.
207+
+/
208+
enum PtrTupleFrontMembers = PtrTupleFrontMembers!Top
209+
~ "
210+
@fmb @property auto ref " ~ Names[$-1] ~ "() {
211+
return _ptrs__[" ~ m.stringof ~ "][0];
212+
}
213+
static if (!__traits(compiles, &(_ptrs__[" ~ m.stringof ~ "][0])))
214+
@fmb @property auto ref " ~ Names[$-1] ~ "(T)(auto ref T value) {
215+
return _ptrs__[" ~ m.stringof ~ "][0] = value;
216+
}
217+
";
218+
}
219+
else
220+
{
221+
enum PtrTupleFrontMembers = "";
222+
}
223+
}
224+
225+
@LikePtr struct Pack(size_t N, Range)
226+
{
227+
@fmb:
228+
alias Elem = Slice!(N, Range);
229+
alias PureN = Elem.PureN;
230+
alias PureRange = Elem.PureRange;
231+
232+
size_t[PureN] _lengths;
233+
sizediff_t[PureN] _strides;
234+
235+
SlicePtr!PureRange _ptr;
236+
mixin PropagatePtr;
237+
238+
Elem opIndex(size_t index)
239+
{
240+
return Elem(_lengths, _strides, _ptr + index);
241+
}
242+
}
243+
244+
@LikePtr struct Map(Range, alias fun)
245+
{
246+
Range _ptr;
247+
// can not use @fmb here because fun maybe an LLVM function.
248+
auto ref opIndex(size_t index)
249+
{
250+
return fun(_ptr[index]);
251+
}
252+
mixin PropagatePtr;
253+
}
254+
255+
private mixin template PropagatePtr()
256+
{
257+
@fmb void opOpAssign(string op)(sizediff_t shift)
258+
if (op == `+` || op == `-`)
259+
{
260+
mixin (`_ptr ` ~ op ~ `= shift;`);
261+
}
262+
263+
@fmb auto opBinary(string op)(sizediff_t shift)
264+
if (op == `+` || op == `-`)
265+
{
266+
auto ret = this;
267+
ret.opOpAssign!op(shift);
268+
return ret;
269+
}
270+
271+
@fmb auto opUnary(string op)()
272+
if (op == `++` || op == `--`)
273+
{
274+
mixin(op ~ `_ptr;`);
275+
return this;
276+
}
277+
}
5278

6279
struct LikePtr {}
7280

8-
alias isMemory = isPointer;
281+
template SlicePtr(Range)
282+
{
283+
static if (hasPtrBehavior!Range)
284+
alias SlicePtr = Range;
285+
else
286+
alias SlicePtr = PtrShell!Range;
287+
}
288+
289+
enum isSlicePointer(T) = isPointer!T || is(T : PtrShell!R, R);
290+
291+
template hasPtrBehavior(T)
292+
{
293+
static if (isPointer!T)
294+
enum hasPtrBehavior = true;
295+
else
296+
static if (!isAggregateType!T)
297+
enum hasPtrBehavior = false;
298+
else
299+
enum hasPtrBehavior = hasUDA!(T, LikePtr);
300+
}
301+
302+
alias RangeOf(T : Slice!(N, Range), size_t N, Range) = Range;
303+
304+
template isMemory(T)
305+
{
306+
static if (isPointer!T)
307+
enum isMemory = true;
308+
else
309+
static if (is(T : Map!(Range, fun), Range, alias fun))
310+
enum isMemory = .isMemory!Range;
311+
else
312+
static if (__traits(compiles, __traits(isSame, PtrTuple, TemplateOf!(TemplateOf!T))))
313+
static if (__traits(isSame, PtrTuple, TemplateOf!(TemplateOf!T)))
314+
enum isMemory = allSatisfy!(.isMemory, TemplateArgsOf!T);
315+
else
316+
enum isMemory = false;
317+
else
318+
enum isMemory = false;
319+
}
320+
321+
unittest
322+
{
323+
import std.experimental.ndslice.slice : PtrTuple;
324+
import std.experimental.ndslice.selection : Map;
325+
static assert(isMemory!(int*));
326+
alias R = PtrTuple!("a", "b");
327+
alias F = R!(double*, double*);
328+
static assert(isMemory!F);
329+
static assert(isMemory!(Map!(F, a => a)));
330+
}
9331

10332
enum indexError(size_t pos, size_t N) =
11333
"index at position " ~ pos.stringof

0 commit comments

Comments
 (0)