Skip to content

Commit f3d92d9

Browse files
committed
sumtype: add fast path for single dispatch
This reduces the number of templates instantiated by matchImpl in the common case where only one SumType is being matched on.
1 parent be59d94 commit f3d92d9

File tree

1 file changed

+51
-32
lines changed

1 file changed

+51
-32
lines changed

std/sumtype.d

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1865,46 +1865,60 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
18651865
auto ref matchImpl(SumTypes...)(auto ref SumTypes args)
18661866
if (allSatisfy!(isSumType, SumTypes) && args.length > 0)
18671867
{
1868-
alias typeCounts = Map!(typeCount, SumTypes);
1869-
alias stride(size_t i) = .stride!(i, typeCounts);
1870-
alias TagTuple = .TagTuple!typeCounts;
1868+
// Single dispatch (fast path)
1869+
static if (args.length == 1)
1870+
{
1871+
/* When there's only one argument, the caseId is just that
1872+
* argument's tag, so there's no need for TagTuple.
1873+
*/
1874+
enum handlerArgs(size_t caseId) =
1875+
"args[0].get!(SumTypes[0].Types[" ~ toCtString!caseId ~ "])()";
18711876

1872-
alias handlerArgs(size_t caseId) = .handlerArgs!(caseId, typeCounts);
1877+
alias valueTypes(size_t caseId) =
1878+
typeof(args[0].get!(SumTypes[0].Types[caseId])());
18731879

1874-
/* An AliasSeq of the types of the member values in the argument list
1875-
* returned by `handlerArgs!caseId`.
1876-
*
1877-
* Note that these are the actual (that is, qualified) types of the
1878-
* member values, which may not be the same as the types listed in
1879-
* the arguments' `.Types` properties.
1880-
*/
1881-
template valueTypes(size_t caseId)
1880+
enum numCases = SumTypes[0].Types.length;
1881+
}
1882+
// Multiple dispatch (slow path)
1883+
else
18821884
{
1883-
enum tags = TagTuple.fromCaseId(caseId);
1885+
alias typeCounts = Map!(typeCount, SumTypes);
1886+
alias stride(size_t i) = .stride!(i, typeCounts);
1887+
alias TagTuple = .TagTuple!typeCounts;
18841888

1885-
template getType(size_t i)
1889+
alias handlerArgs(size_t caseId) = .handlerArgs!(caseId, typeCounts);
1890+
1891+
/* An AliasSeq of the types of the member values in the argument list
1892+
* returned by `handlerArgs!caseId`.
1893+
*
1894+
* Note that these are the actual (that is, qualified) types of the
1895+
* member values, which may not be the same as the types listed in
1896+
* the arguments' `.Types` properties.
1897+
*/
1898+
template valueTypes(size_t caseId)
18861899
{
1887-
enum tid = tags[i];
1888-
alias T = SumTypes[i].Types[tid];
1889-
alias getType = typeof(args[i].get!T());
1900+
enum tags = TagTuple.fromCaseId(caseId);
1901+
1902+
template getType(size_t i)
1903+
{
1904+
enum tid = tags[i];
1905+
alias T = SumTypes[i].Types[tid];
1906+
alias getType = typeof(args[i].get!T());
1907+
}
1908+
1909+
alias valueTypes = Map!(getType, Iota!(tags.length));
18901910
}
18911911

1892-
alias valueTypes = Map!(getType, Iota!(tags.length));
1912+
/* The total number of cases is
1913+
*
1914+
* Π SumTypes[i].Types.length for 0 ≤ i < SumTypes.length
1915+
*
1916+
* Conveniently, this is equal to stride!(SumTypes.length), so we can
1917+
* use that function to compute it.
1918+
*/
1919+
enum numCases = stride!(SumTypes.length);
18931920
}
18941921

1895-
/* The total number of cases is
1896-
*
1897-
* Π SumTypes[i].Types.length for 0 ≤ i < SumTypes.length
1898-
*
1899-
* Or, equivalently,
1900-
*
1901-
* ubyte[SumTypes[0].Types.length]...[SumTypes[$-1].Types.length].sizeof
1902-
*
1903-
* Conveniently, this is equal to stride!(SumTypes.length), so we can
1904-
* use that function to compute it.
1905-
*/
1906-
enum numCases = stride!(SumTypes.length);
1907-
19081922
/* Guaranteed to never be a valid handler index, since
19091923
* handlers.length <= size_t.max.
19101924
*/
@@ -1961,7 +1975,12 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
19611975
mixin("alias ", handlerName!hid, " = handler;");
19621976
}
19631977

1964-
immutable argsId = TagTuple(args).toCaseId;
1978+
// Single dispatch (fast path)
1979+
static if (args.length == 1)
1980+
immutable argsId = args[0].tag;
1981+
// Multiple dispatch (slow path)
1982+
else
1983+
immutable argsId = TagTuple(args).toCaseId;
19651984

19661985
final switch (argsId)
19671986
{

0 commit comments

Comments
 (0)