Skip to content

Commit c5d074b

Browse files
pbackusdlang-bot
authored andcommitted
Refactor: access SumType value by index, not type
Previously, code that already knew the desired index was forced to compute a type to pass to get!T or memberName!T, just for get!T or memberName!T to turn that type back into an index. Removing this unnecessary round trip simplifies the code. Additionally, since memberName is no longer dependent on SumType.Types, it can be moved to module scope, and its instantiations can be shared across different SumType instances.
1 parent 9971927 commit c5d074b

File tree

1 file changed

+43
-50
lines changed

1 file changed

+43
-50
lines changed

std/sumtype.d

Lines changed: 43 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@ private enum hasPostblit(T) = __traits(hasPostblit, T);
254254

255255
private enum isInout(T) = is(T == inout);
256256

257+
private enum memberName(size_t tid) = "values_" ~ toCtString!tid;
258+
257259
/**
258260
* A [tagged union](https://en.wikipedia.org/wiki/Tagged_union) that can hold a
259261
* single value from any of a specified set of types.
@@ -290,45 +292,42 @@ private:
290292

291293
union Storage
292294
{
293-
// Workaround for https://issues.dlang.org/show_bug.cgi?id=20068
294-
template memberName(T)
295-
if (IndexOf!(T, Types) >= 0)
296-
{
297-
enum tid = IndexOf!(T, Types);
298-
mixin("enum memberName = `values_", toCtString!tid, "`;");
299-
}
300295

301-
static foreach (T; Types)
296+
static foreach (tid, T; Types)
302297
{
303-
mixin("T ", memberName!T, ";");
298+
/+
299+
Giving these fields individual names makes it possible to use brace
300+
initialization for Storage.
301+
+/
302+
mixin("T ", memberName!tid, ";");
304303
}
305304
}
306305

307306
Storage storage;
308307
Tag tag;
309308

310-
/* Accesses the value stored in a SumType.
309+
/* Accesses the value stored in a SumType by its index.
311310
*
312311
* This method is memory-safe, provided that:
313312
*
314313
* 1. A SumType's tag is always accurate.
315-
* 2. A SumType cannot be assigned to in @safe code if that assignment
316-
* could cause unsafe aliasing.
314+
* 2. A SumType's value cannot be unsafely aliased in @safe code.
317315
*
318316
* All code that accesses a SumType's tag or storage directly, including
319317
* @safe code in this module, must be manually checked to ensure that it
320318
* does not violate either of the above requirements.
321319
*/
322320
@trusted
323-
ref inout(T) get(T)() inout
324-
if (IndexOf!(T, Types) >= 0)
321+
// Explicit return type omitted
322+
// Workaround for https://github.com/dlang/dmd/issues/20549
323+
ref get(size_t tid)() inout
324+
if (tid < Types.length)
325325
{
326-
enum tid = IndexOf!(T, Types);
327326
assert(tag == tid,
328-
"This `" ~ SumType.stringof ~
329-
"` does not contain a(n) `" ~ T.stringof ~ "`"
327+
"This `" ~ SumType.stringof ~ "`" ~
328+
"does not contain a(n) `" ~ Types[tid].stringof ~ "`"
330329
);
331-
return __traits(getMember, storage, Storage.memberName!T);
330+
return storage.tupleof[tid];
332331
}
333332

334333
public:
@@ -363,11 +362,11 @@ public:
363362
static if (isCopyable!T)
364363
{
365364
// Workaround for https://issues.dlang.org/show_bug.cgi?id=21542
366-
__traits(getMember, storage, Storage.memberName!T) = __ctfe ? value : forward!value;
365+
storage.tupleof[tid] = __ctfe ? value : forward!value;
367366
}
368367
else
369368
{
370-
__traits(getMember, storage, Storage.memberName!T) = forward!value;
369+
storage.tupleof[tid] = forward!value;
371370
}
372371

373372
tag = tid;
@@ -380,7 +379,7 @@ public:
380379
/// ditto
381380
this(const(T) value) const
382381
{
383-
__traits(getMember, storage, Storage.memberName!T) = value;
382+
storage.tupleof[tid] = value;
384383
tag = tid;
385384
}
386385
}
@@ -397,7 +396,7 @@ public:
397396
/// ditto
398397
this(immutable(T) value) immutable
399398
{
400-
__traits(getMember, storage, Storage.memberName!T) = value;
399+
storage.tupleof[tid] = value;
401400
tag = tid;
402401
}
403402
}
@@ -415,7 +414,7 @@ public:
415414
this(Value)(Value value) inout
416415
if (is(Value == DeducedParameterType!(inout(T))))
417416
{
418-
__traits(getMember, storage, Storage.memberName!T) = value;
417+
storage.tupleof[tid] = value;
419418
tag = tid;
420419
}
421420
}
@@ -442,10 +441,9 @@ public:
442441
storage = other.match!((ref value) {
443442
alias OtherTypes = Map!(InoutOf, Types);
444443
enum tid = IndexOf!(typeof(value), OtherTypes);
445-
alias T = Types[tid];
446444

447445
mixin("inout(Storage) newStorage = { ",
448-
Storage.memberName!T, ": value",
446+
memberName!tid, ": value",
449447
" };");
450448

451449
return newStorage;
@@ -462,10 +460,10 @@ public:
462460
this(ref SumType other)
463461
{
464462
storage = other.match!((ref value) {
465-
alias T = typeof(value);
463+
enum tid = IndexOf!(typeof(value), Types);
466464

467465
mixin("Storage newStorage = { ",
468-
Storage.memberName!T, ": value",
466+
memberName!tid, ": value",
469467
" };");
470468

471469
return newStorage;
@@ -487,10 +485,9 @@ public:
487485
storage = other.match!((ref value) {
488486
alias OtherTypes = Map!(ConstOf, Types);
489487
enum tid = IndexOf!(typeof(value), OtherTypes);
490-
alias T = Types[tid];
491488

492489
mixin("const(Storage) newStorage = { ",
493-
Storage.memberName!T, ": value",
490+
memberName!tid, ": value",
494491
" };");
495492

496493
return newStorage;
@@ -512,10 +509,9 @@ public:
512509
storage = other.match!((ref value) {
513510
alias OtherTypes = Map!(ImmutableOf, Types);
514511
enum tid = IndexOf!(typeof(value), OtherTypes);
515-
alias T = Types[tid];
516512

517513
mixin("immutable(Storage) newStorage = { ",
518-
Storage.memberName!T, ": value",
514+
memberName!tid, ": value",
519515
" };");
520516

521517
return newStorage;
@@ -637,13 +633,13 @@ public:
637633
{
638634
// Workaround for https://issues.dlang.org/show_bug.cgi?id=21542
639635
mixin("Storage newStorage = { ",
640-
Storage.memberName!T, ": __ctfe ? rhs : forward!rhs",
636+
memberName!tid, ": __ctfe ? rhs : forward!rhs",
641637
" };");
642638
}
643639
else
644640
{
645641
mixin("Storage newStorage = { ",
646-
Storage.memberName!T, ": forward!rhs",
642+
memberName!tid, ": forward!rhs",
647643
" };");
648644
}
649645

@@ -1146,7 +1142,7 @@ version (D_BetterC) {} else
11461142
alias MySum = SumType!(ubyte, void*[2]);
11471143

11481144
MySum x = [null, cast(void*) 0x12345678];
1149-
void** p = &x.get!(void*[2])[1];
1145+
void** p = &x.get!1[1];
11501146
x = ubyte(123);
11511147

11521148
assert(*p != cast(void*) 0x12345678);
@@ -1178,8 +1174,8 @@ version (D_BetterC) {} else
11781174
catch (Exception e) {}
11791175

11801176
assert(
1181-
(x.tag == 0 && x.get!A.value == 123) ||
1182-
(x.tag == 1 && x.get!B.value == 456)
1177+
(x.tag == 0 && x.get!0.value == 123) ||
1178+
(x.tag == 1 && x.get!1.value == 456)
11831179
);
11841180
}
11851181

@@ -1238,8 +1234,8 @@ version (D_BetterC) {} else
12381234
SumType!(S[1]) x = [S(0)];
12391235
SumType!(S[1]) y = x;
12401236

1241-
auto xval = x.get!(S[1])[0].n;
1242-
auto yval = y.get!(S[1])[0].n;
1237+
auto xval = x.get!0[0].n;
1238+
auto yval = y.get!0[0].n;
12431239

12441240
assert(xval != yval);
12451241
}
@@ -1324,8 +1320,8 @@ version (D_BetterC) {} else
13241320
SumType!S y;
13251321
y = x;
13261322

1327-
auto xval = x.get!S.n;
1328-
auto yval = y.get!S.n;
1323+
auto xval = x.get!0.n;
1324+
auto yval = y.get!0.n;
13291325

13301326
assert(xval != yval);
13311327
}
@@ -1399,8 +1395,8 @@ version (D_BetterC) {} else
13991395
SumType!S x = S();
14001396
SumType!S y = x;
14011397

1402-
auto xval = x.get!S.n;
1403-
auto yval = y.get!S.n;
1398+
auto xval = x.get!0.n;
1399+
auto yval = y.get!0.n;
14041400

14051401
assert(xval != yval);
14061402
}
@@ -1872,10 +1868,10 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
18721868
* argument's tag, so there's no need for TagTuple.
18731869
*/
18741870
enum handlerArgs(size_t caseId) =
1875-
"args[0].get!(SumTypes[0].Types[" ~ toCtString!caseId ~ "])()";
1871+
"args[0].get!(" ~ toCtString!caseId ~ ")()";
18761872

18771873
alias valueTypes(size_t caseId) =
1878-
typeof(args[0].get!(SumTypes[0].Types[caseId])());
1874+
typeof(args[0].get!(caseId)());
18791875

18801876
enum numCases = SumTypes[0].Types.length;
18811877
}
@@ -1901,9 +1897,7 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
19011897

19021898
template getType(size_t i)
19031899
{
1904-
enum tid = tags[i];
1905-
alias T = SumTypes[i].Types[tid];
1906-
alias getType = typeof(args[i].get!T());
1900+
alias getType = typeof(args[i].get!(tags[i])());
19071901
}
19081902

19091903
alias valueTypes = Map!(getType, Iota!(tags.length));
@@ -2128,8 +2122,7 @@ private template handlerArgs(size_t caseId, typeCounts...)
21282122
{
21292123
handlerArgs = AliasSeq!(
21302124
handlerArgs,
2131-
"args[" ~ toCtString!i ~ "].get!(SumTypes[" ~ toCtString!i ~ "]" ~
2132-
".Types[" ~ toCtString!(tags[i]) ~ "])(), "
2125+
"args[" ~ toCtString!i ~ "].get!(" ~ toCtString!(tags[i]) ~ ")(), "
21332126
);
21342127
}
21352128
}
@@ -2393,7 +2386,7 @@ version (D_Exceptions)
23932386
(ref double d) { d *= 2; }
23942387
);
23952388

2396-
assert(value.get!double.isClose(6.28));
2389+
assert(value.get!1.isClose(6.28));
23972390
}
23982391

23992392
// Unreachable handlers

0 commit comments

Comments
 (0)