Skip to content

Commit ee35912

Browse files
authored
Merge pull request #92 from pbackus/access-by-index
Refactor: access SumType value by index, not type
2 parents ac1f24f + 0d0298f commit ee35912

File tree

1 file changed

+44
-51
lines changed

1 file changed

+44
-51
lines changed

src/sumtype.d

Lines changed: 44 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ private enum hasPostblit(T) = __traits(hasPostblit, T);
256256

257257
private enum isInout(T) = is(T == inout);
258258

259+
private enum memberName(size_t tid) = "values_" ~ toCtString!tid;
260+
259261
// Workaround for dlang issue 19669
260262
private enum haveDip1000 = __traits(compiles, () @safe {
261263
int x;
@@ -300,45 +302,41 @@ private:
300302

301303
union Storage
302304
{
303-
// Workaround for dlang issue 20068
304-
template memberName(T)
305-
if (IndexOf!(T, Types) >= 0)
306-
{
307-
enum tid = IndexOf!(T, Types);
308-
mixin("enum memberName = `values_", toCtString!tid, "`;");
309-
}
310-
311-
static foreach (T; Types) {
312-
mixin("T ", memberName!T, ";");
305+
static foreach (tid, T; Types) {
306+
/+
307+
Giving these fields individual names makes it possible to use brace
308+
initialization for Storage.
309+
+/
310+
mixin("T ", memberName!tid, ";");
313311
}
314312
}
315313

316314
Storage storage;
317315
Tag tag;
318316

319317
/**
320-
* Accesses the value stored in a SumType.
318+
* Accesses the value stored in a SumType by its index.
321319
*
322320
* This method is memory-safe, provided that:
323321
*
324322
* 1. A SumType's tag is always accurate.
325-
* 2. A SumType cannot be assigned to in @safe code if that assignment
326-
* could cause unsafe aliasing.
323+
* 2. A SumType's value cannot be unsafely aliased in @safe code.
327324
*
328325
* All code that accesses a SumType's tag or storage directly, including
329326
* @safe code in this module, must be manually checked to ensure that it
330327
* does not violate either of the above requirements.
331328
*/
332329
@trusted
333-
ref inout(T) get(T)() inout
334-
if (IndexOf!(T, Types) >= 0)
330+
// Explicit return type omitted
331+
// Workaround for https://github.com/dlang/dmd/issues/20549
332+
ref get(size_t tid)() inout
333+
if (tid < Types.length)
335334
{
336-
enum tid = IndexOf!(T, Types);
337335
assert(tag == tid,
338-
"This `" ~ SumType.stringof ~
339-
"` does not contain a(n) `" ~ T.stringof ~ "`"
336+
"This `" ~ SumType.stringof ~ "`" ~
337+
"does not contain a(n) `" ~ Types[tid].stringof ~ "`"
340338
);
341-
return __traits(getMember, storage, Storage.memberName!T);
339+
return storage.tupleof[tid];
342340
}
343341

344342
public:
@@ -351,9 +349,9 @@ public:
351349

352350
static if (isCopyable!T) {
353351
// Workaround for dlang issue 21542
354-
__traits(getMember, storage, Storage.memberName!T) = __ctfe ? value : forward!value;
352+
storage.tupleof[tid] = __ctfe ? value : forward!value;
355353
} else {
356-
__traits(getMember, storage, Storage.memberName!T) = forward!value;
354+
storage.tupleof[tid] = forward!value;
357355
}
358356

359357
tag = tid;
@@ -365,7 +363,7 @@ public:
365363
/// ditto
366364
this(const(T) value) const
367365
{
368-
__traits(getMember, storage, Storage.memberName!T) = value;
366+
storage.tupleof[tid] = value;
369367
tag = tid;
370368
}
371369
}
@@ -378,7 +376,7 @@ public:
378376
/// ditto
379377
this(immutable(T) value) immutable
380378
{
381-
__traits(getMember, storage, Storage.memberName!T) = value;
379+
storage.tupleof[tid] = value;
382380
tag = tid;
383381
}
384382
}
@@ -392,7 +390,7 @@ public:
392390
this(Value)(Value value) inout
393391
if (is(Value == DeducedParameterType!(inout(T))))
394392
{
395-
__traits(getMember, storage, Storage.memberName!T) = value;
393+
storage.tupleof[tid] = value;
396394
tag = tid;
397395
}
398396
}
@@ -414,10 +412,9 @@ public:
414412
storage = other.match!((ref value) {
415413
alias OtherTypes = Map!(InoutOf, Types);
416414
enum tid = IndexOf!(typeof(value), OtherTypes);
417-
alias T = Types[tid];
418415

419416
mixin("inout(Storage) newStorage = { ",
420-
Storage.memberName!T, ": value",
417+
memberName!tid, ": value",
421418
" };");
422419

423420
return newStorage;
@@ -431,10 +428,10 @@ public:
431428
this(ref SumType other)
432429
{
433430
storage = other.match!((ref value) {
434-
alias T = typeof(value);
431+
enum tid = IndexOf!(typeof(value), Types);
435432

436433
mixin("Storage newStorage = { ",
437-
Storage.memberName!T, ": value",
434+
memberName!tid, ": value",
438435
" };");
439436

440437
return newStorage;
@@ -453,10 +450,9 @@ public:
453450
storage = other.match!((ref value) {
454451
alias OtherTypes = Map!(ConstOf, Types);
455452
enum tid = IndexOf!(typeof(value), OtherTypes);
456-
alias T = Types[tid];
457453

458454
mixin("const(Storage) newStorage = { ",
459-
Storage.memberName!T, ": value",
455+
memberName!tid, ": value",
460456
" };");
461457

462458
return newStorage;
@@ -475,10 +471,9 @@ public:
475471
storage = other.match!((ref value) {
476472
alias OtherTypes = Map!(ImmutableOf, Types);
477473
enum tid = IndexOf!(typeof(value), OtherTypes);
478-
alias T = Types[tid];
479474

480475
mixin("immutable(Storage) newStorage = { ",
481-
Storage.memberName!T, ": value",
476+
memberName!tid, ": value",
482477
" };");
483478

484479
return newStorage;
@@ -549,12 +544,13 @@ public:
549544
this.match!destroyIfOwner;
550545

551546
static if (isCopyable!T) {
547+
// Workaround for dlang issue 21542
552548
mixin("Storage newStorage = { ",
553-
Storage.memberName!T, ": __ctfe ? rhs : forward!rhs",
549+
memberName!tid, ": __ctfe ? rhs : forward!rhs",
554550
" };");
555551
} else {
556552
mixin("Storage newStorage = { ",
557-
Storage.memberName!T, ": forward!rhs",
553+
memberName!tid, ": forward!rhs",
558554
" };");
559555
}
560556

@@ -1005,7 +1001,7 @@ version (D_BetterC) {} else
10051001
alias MySum = SumType!(ubyte, void*[2]);
10061002

10071003
MySum x = [null, cast(void*) 0x12345678];
1008-
void** p = &x.get!(void*[2])[1];
1004+
void** p = &x.get!1[1];
10091005
x = ubyte(123);
10101006

10111007
assert(*p != cast(void*) 0x12345678);
@@ -1034,8 +1030,8 @@ version (D_BetterC) {} else
10341030
} catch (Exception e) {}
10351031

10361032
assert(
1037-
(x.tag == 0 && x.get!A.value == 123) ||
1038-
(x.tag == 1 && x.get!B.value == 456)
1033+
(x.tag == 0 && x.get!0.value == 123) ||
1034+
(x.tag == 1 && x.get!1.value == 456)
10391035
);
10401036
}
10411037

@@ -1093,8 +1089,8 @@ version (D_BetterC) {} else
10931089
SumType!(S[1]) x = [S(0)];
10941090
SumType!(S[1]) y = x;
10951091

1096-
auto xval = x.get!(S[1])[0].n;
1097-
auto yval = y.get!(S[1])[0].n;
1092+
auto xval = x.get!0[0].n;
1093+
auto yval = y.get!0[0].n;
10981094

10991095
assert(xval != yval);
11001096
}
@@ -1169,8 +1165,8 @@ version (D_BetterC) {} else
11691165
SumType!S y;
11701166
y = x;
11711167

1172-
auto xval = x.get!S.n;
1173-
auto yval = y.get!S.n;
1168+
auto xval = x.get!0.n;
1169+
auto yval = y.get!0.n;
11741170

11751171
assert(xval != yval);
11761172
}
@@ -1241,8 +1237,8 @@ version (D_BetterC) {} else
12411237
SumType!S x = S();
12421238
SumType!S y = x;
12431239

1244-
auto xval = x.get!S.n;
1245-
auto yval = y.get!S.n;
1240+
auto xval = x.get!0.n;
1241+
auto yval = y.get!0.n;
12461242

12471243
assert(xval != yval);
12481244
}
@@ -1783,10 +1779,10 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
17831779
* argument's tag, so there's no need to use TagTuple.
17841780
*/
17851781
enum handlerArgs(size_t caseId) =
1786-
"args[0].get!(SumTypes[0].Types[" ~ toCtString!caseId ~ "])()";
1782+
"args[0].get!(" ~ toCtString!caseId ~ ")()";
17871783

17881784
alias valueTypes(size_t caseId) =
1789-
typeof(args[0].get!(SumTypes[0].Types[caseId])());
1785+
typeof(args[0].get!(caseId)());
17901786

17911787
enum numCases = SumTypes[0].Types.length;
17921788
// Multiple dispatch (slow path)
@@ -1810,9 +1806,7 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
18101806

18111807
template getType(size_t i)
18121808
{
1813-
enum tid = tags[i];
1814-
alias T = SumTypes[i].Types[tid];
1815-
alias getType = typeof(args[i].get!T());
1809+
alias getType = typeof(args[i].get!(tags[i])());
18161810
}
18171811

18181812
alias valueTypes = Map!(getType, Iota!(tags.length));
@@ -2015,8 +2009,7 @@ template handlerArgs(size_t caseId, typeCounts...)
20152009
static foreach (i; 0 .. tags.length) {
20162010
handlerArgs = AliasSeq!(
20172011
handlerArgs,
2018-
"args[" ~ toCtString!i ~ "].get!(SumTypes[" ~ toCtString!i ~ "]" ~
2019-
".Types[" ~ toCtString!(tags[i]) ~ "])(), "
2012+
"args[" ~ toCtString!i ~ "].get!(" ~ toCtString!(tags[i]) ~ ")(), "
20202013
);
20212014
}
20222015
}
@@ -2264,7 +2257,7 @@ version (D_Exceptions)
22642257
(ref double d) { d *= 2; }
22652258
);
22662259

2267-
assert(value.get!double.isClose(6.28));
2260+
assert(value.get!1.isClose(6.28));
22682261
}
22692262

22702263
// Handlers that return by ref

0 commit comments

Comments
 (0)