Skip to content

Commit a3f205a

Browse files
committed
fix 16501 and fix issue 16501
1 parent ca39f61 commit a3f205a

File tree

4 files changed

+540
-266
lines changed

4 files changed

+540
-266
lines changed

std/experimental/ndslice/internal.d

Lines changed: 294 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,303 @@
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+
template PtrTuple(Names...)
9+
{
10+
@LikePtr struct PtrTuple(Ptrs...)
11+
if (allSatisfy!(isSlicePointer, Ptrs) && Ptrs.length == Names.length)
12+
{
13+
Ptrs ptrs;
14+
15+
void opOpAssign(string op)(sizediff_t shift)
16+
if (op == `+` || op == `-`)
17+
{
18+
foreach (ref ptr; ptrs)
19+
mixin (`ptr ` ~ op ~ `= shift;`);
20+
}
21+
22+
auto opBinary(string op)(sizediff_t shift)
23+
if (op == `+` || op == `-`)
24+
{
25+
auto ret = this;
26+
ret.opOpAssign!op(shift);
27+
return ret;
28+
}
29+
30+
public struct Index
31+
{
32+
Ptrs _ptrs__;
33+
mixin (PtrTupleFrontMembers!Names);
34+
}
35+
36+
auto opIndex(sizediff_t index)
37+
{
38+
auto p = ptrs;
39+
foreach (ref ptr; p)
40+
ptr += index;
41+
return Index(p);
42+
}
43+
}
44+
}
45+
46+
// ISSUE 16501
47+
unittest
48+
{
49+
import std.experimental.ndslice;
50+
alias sab = sliced!("a", "b");
51+
auto sl = sab(new double[12], new double[12], 3, 4);
52+
auto psl = sl.pack!1;
53+
}
54+
55+
56+
struct PtrShell(Range)
57+
{
58+
sizediff_t _shift;
59+
Range _range;
60+
61+
enum hasAccessByRef = isPointer!Range ||
62+
__traits(compiles, &_range[0]);
63+
64+
void opOpAssign(string op)(sizediff_t shift)
65+
if (op == `+` || op == `-`)
66+
{
67+
mixin (`_shift ` ~ op ~ `= shift;`);
68+
}
69+
70+
auto opBinary(string op)(sizediff_t shift)
71+
if (op == `+` || op == `-`)
72+
{
73+
mixin (`return typeof(this)(_shift ` ~ op ~ ` shift, _range);`);
74+
}
75+
76+
auto opUnary(string op)()
77+
if (op == `++` || op == `--`)
78+
{
79+
mixin(op ~ `_shift;`);
80+
return this;
81+
}
82+
83+
auto ref opIndex(sizediff_t index)
84+
in
85+
{
86+
assert(_shift + index >= 0);
87+
static if (hasLength!Range)
88+
assert(_shift + index <= _range.length);
89+
}
90+
body
91+
{
92+
return _range[_shift + index];
93+
}
94+
95+
static if (!hasAccessByRef)
96+
{
97+
auto ref opIndexAssign(T)(T value, sizediff_t index)
98+
in
99+
{
100+
assert(_shift + index >= 0);
101+
static if (hasLength!Range)
102+
assert(_shift + index <= _range.length);
103+
}
104+
body
105+
{
106+
return _range[_shift + index] = value;
107+
}
108+
109+
auto ref opIndexOpAssign(string op, T)(T value, sizediff_t index)
110+
in
111+
{
112+
assert(_shift + index >= 0);
113+
static if (hasLength!Range)
114+
assert(_shift + index <= _range.length);
115+
}
116+
body
117+
{
118+
mixin (`return _range[_shift + index] ` ~ op ~ `= value;`);
119+
}
120+
121+
auto ref opIndexUnary(string op)(sizediff_t index)
122+
in
123+
{
124+
assert(_shift + index >= 0);
125+
static if (hasLength!Range)
126+
assert(_shift + index <= _range.length);
127+
}
128+
body
129+
{
130+
mixin (`return ` ~ op ~ `_range[_shift + index];`);
131+
}
132+
}
133+
134+
auto save() @property
135+
{
136+
return this;
137+
}
138+
}
139+
140+
auto ptrShell(Range)(Range range, sizediff_t shift = 0)
141+
{
142+
return PtrShell!Range(shift, range);
143+
}
144+
145+
@safe pure nothrow unittest
146+
{
147+
import std.internal.test.dummyrange;
148+
foreach (RB; AliasSeq!(ReturnBy.Reference, ReturnBy.Value))
149+
{
150+
DummyRange!(RB, Length.Yes, RangeType.Random) range;
151+
range.reinit;
152+
assert(range.length >= 10);
153+
auto ptr = range.ptrShell;
154+
assert(ptr[0] == range[0]);
155+
auto save0 = range[0];
156+
ptr[0] += 10;
157+
++ptr[0];
158+
assert(ptr[0] == save0 + 11);
159+
(ptr + 5)[2] = 333;
160+
assert(range[7] == 333);
161+
162+
auto ptrCopy = ptr.save;
163+
ptrCopy._range.popFront;
164+
ptr[1] = 2;
165+
assert(ptr[0] == save0 + 11);
166+
assert(ptrCopy[0] == 2);
167+
}
168+
}
169+
170+
private template PtrTupleFrontMembers(Names...)
171+
if (Names.length <= 32)
172+
{
173+
static if (Names.length)
174+
{
175+
alias Top = Names[0..$-1];
176+
enum int m = Top.length;
177+
enum PtrTupleFrontMembers = PtrTupleFrontMembers!Top
178+
~ "
179+
@property auto ref " ~ Names[$-1] ~ "() {
180+
return _ptrs__[" ~ m.stringof ~ "][0];
181+
}
182+
static if (!__traits(compiles, &(_ptrs__[" ~ m.stringof ~ "][0])))
183+
@property auto ref " ~ Names[$-1] ~ "(T)(auto ref T value) {
184+
return _ptrs__[" ~ m.stringof ~ "][0] = value;
185+
}
186+
";
187+
}
188+
else
189+
{
190+
enum PtrTupleFrontMembers = "";
191+
}
192+
}
193+
194+
@LikePtr struct Pack(size_t N, Range)
195+
{
196+
alias Elem = Slice!(N, Range);
197+
alias PureN = Elem.PureN;
198+
alias PureRange = Elem.PureRange;
199+
200+
size_t[PureN] _lengths;
201+
sizediff_t[PureN] _strides;
202+
203+
SlicePtr!PureRange _ptr;
204+
mixin PropagatePtr;
205+
206+
Elem opIndex(size_t index)
207+
{
208+
return Elem(_lengths, _strides, _ptr + index);
209+
}
210+
}
211+
212+
@LikePtr struct Map(Range, alias fun)
213+
{
214+
Range _ptr;
215+
mixin PropagatePtr;
216+
217+
auto ref opIndex(size_t index)
218+
{
219+
return fun(_ptr[index]);
220+
}
221+
}
222+
223+
private mixin template PropagatePtr()
224+
{
225+
void opOpAssign(string op)(sizediff_t shift)
226+
if (op == `+` || op == `-`)
227+
{
228+
mixin (`_ptr ` ~ op ~ `= shift;`);
229+
}
230+
231+
auto opBinary(string op)(sizediff_t shift)
232+
if (op == `+` || op == `-`)
233+
{
234+
auto ret = this;
235+
ret.opOpAssign!op(shift);
236+
return ret;
237+
}
238+
239+
auto opUnary(string op)()
240+
if (op == `++` || op == `--`)
241+
{
242+
mixin(op ~ `_ptr;`);
243+
return this;
244+
}
245+
}
5246

6247
struct LikePtr {}
7248

8-
alias isMemory = isPointer;
249+
template SlicePtr(Range)
250+
{
251+
static if (hasPtrBehavior!Range)
252+
alias SlicePtr = Range;
253+
else
254+
alias SlicePtr = PtrShell!Range;
255+
}
256+
257+
enum isSlicePointer(T) = isPointer!T || is(T : PtrShell!R, R);
258+
259+
template hasPtrBehavior(T)
260+
{
261+
static if (isPointer!T)
262+
enum hasPtrBehavior = true;
263+
else
264+
static if (!isAggregateType!T)
265+
enum hasPtrBehavior = false;
266+
else
267+
enum hasPtrBehavior = hasUDA!(T, LikePtr);
268+
}
269+
270+
alias RangeOf(T : Slice!(N, Range), size_t N, Range) = Range;
271+
272+
template isMemory(T)
273+
{
274+
import std.experimental.ndslice.slice : PtrTuple;
275+
import std.experimental.ndslice.selection : Map, Pack;
276+
static if (isPointer!T)
277+
enum isMemory = true;
278+
else
279+
static if (is(T : Map!(Range, fun), Range, alias fun))
280+
enum isMemory = .isMemory!Range;
281+
else
282+
static if (__traits(compiles, __traits(isSame, PtrTuple, TemplateOf!(TemplateOf!T))))
283+
static if (__traits(isSame, PtrTuple, TemplateOf!(TemplateOf!T)))
284+
enum isMemory = allSatisfy!(.isMemory, TemplateArgsOf!T);
285+
else
286+
enum isMemory = false;
287+
else
288+
enum isMemory = false;
289+
}
290+
291+
unittest
292+
{
293+
import std.experimental.ndslice.slice : PtrTuple;
294+
import std.experimental.ndslice.selection : Map;
295+
static assert(isMemory!(int*));
296+
alias R = PtrTuple!("a", "b");
297+
alias F = R!(double*, double*);
298+
static assert(isMemory!F);
299+
static assert(isMemory!(Map!(F, a => a)));
300+
}
9301

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

0 commit comments

Comments
 (0)