/**
* Machine-readable `--bench-json` reports: every measured row plus a
* provenance block as one deterministic JSON document, so benchmark baselines
* can be committed, diffed, and regenerated (see the wired bench's `results/`
* snapshots).
*
* The emission is an explicit writer, not `std.json`: baselines must be
* byte-stable (fixed field order, sorted label keys) and floats must not
* render in D's 17-significant-digit default form (which the repo's
* `pretty-format-json` pre-commit hook rejects) — `jsonNumber` renders
* integral values as integers and everything else to 6 significant digits,
* far above benchmark noise. `nan`/infinities (unavailable counters) become
* `null`, mirroring the table's em dash.
*/
module (package) sparklessparkles.(package) sparkles.test_runnertest_runner.(module) sparkles.test_runner.bench_jsonMachine-readable --bench-json reports: every measured row plus a
provenance block as one deterministic JSON document, so benchmark baselines
can be committed, diffed, and regenerated (see the wired bench's results/
snapshots).
The emission is an explicit writer, not std.json: baselines must be
byte-stable (fixed field order, sorted label keys) and floats must not
render in D's 17-significant-digit default form (which the repo's
pretty-format-json pre-commit hook rejects) — jsonNumber renders
integral values as integers and everything else to 6 significant digits,
far above benchmark noise. nan/infinities (unavailable counters) become
null, mirroring the table's em dash.
bench_json;
import (package) sparklessparkles.(package) sparkles.test_runnertest_runner.(module) sparkles.test_runner.benchBenchmark measurement: auto-scaling iteration counts, basic robust
statistics, and an optimizer barrier.
@benchmark unittest blocks are executed by the runner's --bench`` mode.
By default the whole test body is the measured unit. To time only part of
the body (excluding setup), call benchIter inside the test:
@("sort.bench")
@benchmark @safe
unittest
{
import sparkles.test_runner.bench : benchIter, blackBox;
auto data = makeInput(); // setup — not measured
benchIter({ blackBox(data.dup.sort()); }); // measured
}
The measurement protocol follows Rust libtest's Bencher: the iteration
count per sample is doubled until a sample takes at least
BenchConfig.minSampleTime, then BenchConfig.sampleCount samples are
collected and summarized as median / median-absolute-deviation / min / max
nanoseconds per iteration.
bench : (struct) sparkles.test_runner.bench.BenchConfigTuning knobs of one benchmark run.
BenchConfig, (struct) sparkles.test_runner.bench.BenchStatsSummary statistics of one benchmark row, in nanoseconds per iteration. A row
with a non-empty error is a failure row (its timing fields are unset).
BenchStats;
import (package) sparklessparkles.(package) sparkles.test_runnertest_runner.(module) sparkles.test_runner.metricsThe benchmark metric catalog: a unified, named, filterable view over every
measured column — client throughput/level Metrics and hardware PerfStats
counters today, cheap /proc counters and syscall counts as later sources.
Each column is one named MetricCell (per row), described by a
MetricDescriptor (per catalog). A MetricClass tags every metric
quantitative (near-zero perturbation — the only inputs a reported number may
read) or diagnostic (perturbs — explains a result, never a headline). This
is the single seam the reporting layer renders through and that
--metrics/`--list-`metrics select over.
Units-of-measure alignment (see the roadmap): a Unit is treated as an
open-basis "mint-by-name" symbol label, not a dimension. All unit/rate/format
semantics — the scaled/fixed formatters and the rate ÷time derivation in
clientCells — live here, so a later sparkles.quantities swap is a localized
change to this module and nothing else in the catalog.
metrics : (alias) sparkles.test_runner.bench_json.catalog = sparkles.test_runner.metrics.MetricDescriptor[] sparkles.test_runner.metrics.catalog(in sparkles.test_runner.bench.BenchStats[] rows) pure nothrow @safeThe catalog across all rows: client columns (first-seen order, always
available) followed by the perf family (available iff any row carries
counters). This is the universe --list-metrics and --metrics range over.
catalog, (alias) sparkles.test_runner.bench_json.rowCells = sparkles.test_runner.metrics.MetricCell[] sparkles.test_runner.metrics.rowCells(in sparkles.test_runner.bench.BenchStats row) pure nothrow @safeEvery metric cell of one row: client columns first (in call order), then perf,
then tier0 — each present only when the row carries that source.
rowCells;
import (package) sparklessparkles.(package) sparkles.test_runnertest_runner.(module) sparkles.test_runner.workloadThe @workload`` window measurement model: one window, counter deltas.
Where @benchmark runs a body many times and reports per-iteration
statistics, a workload runs once (or a few reps) and reports what happened
across the window: every open counter source's delta between two edge
snapshots, plus a wall-clock decomposition into on-CPU time (rusage),
runqueue wait (schedstat), and a clamped residual. Sources are read
cumulatively at the edges (no per-iteration ioctl bracket, no RESET —
see sparkles.test_runner.perf_group.GroupSnapshot), so the driver's
whole-body candidate window and in-body workloadWindow calls overlap
freely in a single pass — a workload body is never re-run for counting,
because it may be expensive or non-idempotent.
Edge-snapshot nesting order (outer → inner): psi, wall clock, wall
source (rusage/schedstat), syscalls, raw, tier-0, perf — so the cycle
counters see only the body, and each tier's window contains at most the
inner tiers' edge reads (a handful of syscalls per edge, negligible at
window granularity and disclosed here rather than hidden). Psi sits
outermost — outside even the wall clock and rusage windows — so its six
file reads per edge (~20 µs) contribute zero apparatus anywhere in the
decomposition; a system-wide µs-resolution integral's own window being a
few µs wider than the wall clock is immaterial.
Decomposition honesty: only runqueue wait is a true per-cause duration
today; everything else off-CPU — locks, sleeps, disk — lands in
offCpuOtherNs, which clamps at zero and says so in note rather than
fabricating a cause. PSI stall integrals ride alongside as system-wide
diagnostics (WorkloadWindow.psi) — /proc/pressure cannot attribute to
the measured thread, so disk attribution waits for M8's cgroup scoping.
On Linux the decomposition is thread-scoped (RUSAGE_THREAD +
/proc/thread-self/schedstat — the only scoping under which
wall = onCpu + runqueue + other is arithmetically meaningful); the
process-wide reading is captured too, purely to disclose CPU burned by
other threads. Thread coverage caveats (counters follow clone inheritance,
the decomposition follows the driving thread) match the bench modes.
workload : (struct) sparkles.test_runner.workload.WorkloadWindowOne measured window. Deliberately NOT BenchStats: its per-iteration
timing fields would misrepresent a single window — counter stats here are
window totals (iters == 1).
WorkloadWindow;
/// Provenance and the effective measurement knobs stamped onto a report, so a
/// committed baseline is self-describing (the budget it was measured under is
/// part of the data, not tribal knowledge).
struct (struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta
{
(alias) object.string = stringstring (field) string sparkles.test_runner.bench_json.BenchMeta.dateISO day, e.g. "2026-07-10"
date; /// ISO day, e.g. "2026-07-10"
(alias) object.string = stringstring (field) string sparkles.test_runner.bench_json.BenchMeta.hostname"" when unavailable
hostname; /// "" when unavailable
(alias) object.string = stringstring (field) string sparkles.test_runner.bench_json.BenchMeta.osos;
(alias) object.string = stringstring (field) string sparkles.test_runner.bench_json.BenchMeta.archarch;
(alias) object.string = stringstring (field) string sparkles.test_runner.bench_json.BenchMeta.compilere.g. "LDC (front-end 2.111)"
compiler; /// e.g. "LDC (front-end 2.111)"
(alias) object.string = stringstring (field) string sparkles.test_runner.bench_json.BenchMeta.cpu/proc/cpuinfo model name; "" off Linux
cpu; /// /proc/cpuinfo model name; "" off Linux
long (field) long sparkles.test_runner.bench_json.BenchMeta.minSampleTimeMseffective per-sample/total budget (--bench-min-time)
minSampleTimeMs; /// effective per-sample/total budget (--bench-min-time)
uint (field) uint sparkles.test_runner.bench_json.BenchMeta.sampleCounteffective BenchConfig.sampleCount
sampleCount; /// effective BenchConfig.sampleCount
const((alias) object.string = stringstring)[] (field) const(string)[] sparkles.test_runner.bench_json.BenchMeta.provenancesuite-registered lines (benchProvenance)
provenance; /// suite-registered lines (`benchProvenance`)
}
/// Collects host/toolchain provenance and the run's effective knobs.
(struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta sparkles.test_runner.bench_json.BenchMeta sparkles.test_runner.bench_json.collectBenchMeta(in sparkles.test_runner.bench.BenchConfig config) @safeCollects host/toolchain provenance and the run's effective knobs.
collectBenchMeta(in (struct) sparkles.test_runner.bench.BenchConfigTuning knobs of one benchmark run.
BenchConfig (parameter) const(sparkles.test_runner.bench.BenchConfig) configconfig) @safe
{
import (package) stdstd.(module) std.compilerIdentify the compiler used and its various features.
Source
std/compiler.d
compiler : (alias immutable global) name = immutable(string) std.compiler.nameVendor specific string naming the compiler, for example: "Digital Mars D".
name, (alias immutable global) version_major = immutable(uint) std.compiler.version_majorThe vendor specific version number, as in
version_major.version_minor
version_major, (alias immutable global) version_minor = immutable(uint) std.compiler.version_minorThe vendor specific version number, as in
version_major.version_minor
version_minor;
import (package) stdstd.(package) std.datetimedatetime.(module) std.datetime.dateCategory Functions Main date types Date DateTime Other date types Month DayOfWeek TimeOfDay Date checking valid validTimeUnits yearIsLeapYear isTimePoint enforceValid Date conversion daysToDayOfWeek monthsToMonth Time units cmpTimeUnits timeStrings Other AllowDayOverflow DateTimeException
Source
std/datetime/date.d
date : (struct) std.datetime.date.DateRepresents a date in the
Proleptic
Gregorian Calendar ranging from 32,768 B.C. to 32,767 A.D. Positive years
are A.D. Non-positive years are B.C.
Year, month, and day are kept separately internally so that Date is
optimized for calendar-based operations.
Date uses the Proleptic Gregorian Calendar, so it assumes the Gregorian
leap year calculations for its entire length. As per
ISO 8601, it treats 1 B.C. as
year 0, i.e. 1 B.C. is 0, 2 B.C. is -1, etc. Use yearBC to use B.C.
as a positive integer with 1 B.C. being the year prior to 1 A.D.
Year 0 is a leap year.
Examples
import core.time : days;
auto d = Date(2000, 6, 1);
assert(d.dayOfYear == 153);
assert(d.dayOfWeek == DayOfWeek.thu);
d += 10.days;
assert(d == Date(2000, 6, 11));
assert(d.toISOExtString() == "2000-06-11");
assert(d.toISOString() == "20000611");
assert(d.toSimpleString() == "2000-Jun-11");
assert(Date.fromISOExtString("2018-01-01") == Date(2018, 1, 1));
assert(Date.fromISOString("20180101") == Date(2018, 1, 1));
assert(Date.fromSimpleString("2018-Jan-01") == Date(2018, 1, 1));
Date;
import (package) stdstd.(package) std.datetimedatetime.(module) std.datetime.systimeCategory Functions Types Clock SysTime DosFileTime Conversion parseRFC822DateTime DosFileTimeToSysTime FILETIMEToStdTime FILETIMEToSysTime stdTimeToFILETIME stdTimeToUnixTime SYSTEMTIMEToSysTime SysTimeToDosFileTime SysTimeToFILETIME SysTimeToSYSTEMTIME unixTimeToStdTime
Source
std/datetime/systime.d
systime : (class) std.datetime.systime.ClockEffectively a namespace to make it clear that the methods it contains are
getting the time from the system clock. It cannot be instantiated.
Examples
Get the current time as a SysTime
import std.datetime.timezone : LocalTime;
SysTime today = Clock.currTime();
assert(today.timezone is LocalTime());
Clock;
import (package) stdstd.(module) std.formatThis package provides string formatting functionality using
printf style format strings.
Submodule Function Name Description package format Converts its arguments according to a format string into a string.
| package |
sformat |
Converts its arguments according to a format string into a buffer. |
| package |
FormatException |
Signals a problem while formatting. |
| write |
formattedWrite |
Converts its arguments according to a format string and writes
the result to an output range. |
| write |
formatValue |
Formats a value of any type according to a format specifier and
writes the result to an output range. |
| read |
formattedRead |
Reads an input range according to a format string and stores the read
values into its arguments. |
| read |
unformatValue |
Reads a value from the given input range and converts it according to
a format specifier. |
| spec |
FormatSpec |
A general handler for format strings. |
| spec |
singleSpec |
Helper function that returns a FormatSpec for a single format specifier. |
Limitation
This package does not support localization, but
adheres to the rounding mode of the floating point unit, if
available.
Format Strings
The functions contained in this package use format strings. A
format string describes the layout of another string for reading or
writing purposes. A format string is composed of normal text
interspersed with format specifiers. A format specifier starts
with a percentage sign '%', optionally followed by one or more
parameters and ends with a format indicator. A format
indicator may be a simple format character or a compound
indicator.
Format strings are composed according to the following grammar:
FormatString:
FormatStringItem FormatString
FormatStringItem:
Character
FormatSpecifier
FormatSpecifier:
'%' Parameters FormatIndicator
FormatIndicator:
FormatCharacter
CompoundIndicator
FormatCharacter:
see remark below
CompoundIndicator:
'(' FormatString '%)'
'(' FormatString '%|' Delimiter '%)'
Delimiter
empty
Character Delimiter
Parameters:
Position Flags Width Precision Separator
Position:
empty
Integer '$'**
*Integer* **':'** *Integer* **'$'
Integer ':' '$'**
*Flags*:
*empty*
*Flag* *Flags*
*Flag*:
**'-'**|**'+'**|**' '**|**'0'**|**'#'**|**'='**
*Width*:
*OptionalPositionalInteger*
*Precision*:
*empty*
**'.'** *OptionalPositionalInteger*
*Separator*:
*empty*
**','** *OptionalInteger*
**','** *OptionalInteger* **'?'**
*OptionalInteger*:
*empty*
*Integer*
**'*'**
*OptionalPositionalInteger*:
*OptionalInteger*
**'*'** *Integer* **'$'
Character
'%%'
AnyCharacterExceptPercent
Integer:
NonZeroDigit Digits
Digits:
empty
Digit Digits
NonZeroDigit:
'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
Digit:
'0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
Note
FormatCharacter is unspecified. It can be any character
that has no other purpose in this grammar, but it is
recommended to assign (lower- and uppercase) letters.
Note
The Parameters of a CompoundIndicator are currently
limited to a '-' flag.
Format Indicator
The format indicator can either be a single character or an
expression surrounded by '%(' and '%)'. It specifies the
basic manner in which a value will be formatted and is the minimum
requirement to format a value.
The following characters can be used as format characters:
FormatCharacter Semantics 's' To be formatted in a human readable format. Can be used with all types. 'c' To be formatted as a character. 'd' To be formatted as a signed decimal integer. 'u' To be formatted as a decimal image of the underlying bit representation. 'b' To be formatted as a binary image of the underlying bit representation. 'o' To be formatted as an octal image of the underlying bit representation. 'x' / 'X' To be formatted as a hexadecimal image of the underlying bit representation. 'e' / 'E' To be formatted as a real number in decimal scientific notation. 'f' / 'F' To be formatted as a real number in decimal natural notation. 'g' / 'G' To be formatted as a real number in decimal short notation. Depending on the number, a scientific notation or a natural notation is used. 'a' / 'A' To be formatted as a real number in hexadecimal scientific notation. 'r' To be formatted as raw bytes. The output may not be printable and depends on endianness.
The compound indicator can be used to describe compound types
like arrays or structs in more detail. A compound type is enclosed
within '%(' and '%)'. The enclosed sub-format string is
applied to individual elements. The trailing portion of the
sub-format string following the specifier for the element is
interpreted as the delimiter, and is therefore omitted following the
last element. The '%|' specifier may be used to explicitly
indicate the start of the delimiter, so that the preceding portion of
the string will be included following the last element.
The format string inside of the compound indicator should
contain exactly one format specifier (two in case of associative
arrays), which specifies the formatting mode of the elements of the
compound type. This format specifier can be a compound
indicator itself.
Note
Inside a compound indicator, strings and characters are
escaped automatically. To avoid this behavior, use "%-("
instead of "%(".
Flags
There are several flags that affect the outcome of the formatting.
Flag Semantics '-' When the formatted result is shorter than the value given by the width parameter, the output is left justified. Without the '-' flag, the output remains right justified.
There are two exceptions where the '-' flag has a
different meaning: (1) with 'r' it denotes to use little
endian and (2) in case of a compound indicator it means that
no special handling of the members is applied. |
| '=' |
When the formatted result is shorter than the value
given by the width parameter, the output is centered.
If the central position is not possible it is moved slightly
to the right. In this case, if '-' flag is present in
addition to the '=' flag, it is moved slightly to the left. |
| '+' / *' '* |
Applies to numerical values. By default, positive numbers are not
formatted to include the + sign. With one of these two flags present,
positive numbers are preceded by a plus sign or a space.
When both flags are present, a plus sign is used.
In case of 'r', a big endian format is used. |
| '0' |
Is applied to numerical values that are printed right justified.
If the zero flag is present, the space left to the number is
filled with zeros instead of spaces. |
| '#' |
Denotes that an alternative output must be used. This depends on the type
to be formatted and the format character used. See the
sections below for more information. |
Width, Precision and Separator
The width parameter specifies the minimum width of the result.
The meaning of precision depends on the format indicator. For
integers it denotes the minimum number of digits printed, for
real numbers it denotes the number of fractional digits and for
strings and compound types it denotes the maximum number of elements
that are included in the output.
A separator is used for formatting numbers. If it is specified,
the output is divided into chunks of three digits, separated by a ','. The number of digits in a chunk can be given explicitly by
providing a number or a ''* after the ','.
In all three cases the number of digits can be replaced by a ''*. In this scenario, the next argument is used as the number of
digits. If the argument is a negative number, the precision and
separator parameters are considered unspecified. For width,
the absolute value is used and the '-' flag is set.
The separator can also be followed by a '?'. In that case,
an additional argument is used to specify the symbol that should be
used to separate the chunks.
Position
By default, the arguments are processed in the provided order. With
the position parameter it is possible to address arguments
directly. It is also possible to denote a series of arguments with
two numbers separated by ':', that are all processed in the same
way. The second number can be omitted. In that case the series ends
with the last argument.
It's also possible to use positional arguments for width, precision and separator by adding a number and a '$' after the ''*.
Types
This section describes the result of combining types with format
characters. It is organized in 2 subsections: a list of general
information regarding the formatting of types in the presence of
format characters and a table that contains details for every
available combination of type and format character.
When formatting types, the following rules apply:
If the format character is upper case, the resulting string will
be formatted using upper case letters.
The default precision for floating point numbers is 6 digits.
Rounding of floating point numbers adheres to the rounding mode
of the floating point unit, if available.
The floating point values NaN and Infinity are formatted as
nan and inf, possibly preceded by '+' or '-' sign.
Formatting reals is only supported for 64 bit reals and 80 bit reals.
All other reals are cast to double before they are formatted. This will
cause the result to be inf for very large numbers.
Characters and strings formatted with the 's' format character
inside of compound types are surrounded by single and double quotes
and unprintable characters are escaped. To avoid this, a '-'
flag can be specified for the compound specifier
(e.g. "%-(%s%)" instead of "%(%s%)" ).
Structs, unions, classes and interfaces are formatted by calling a
toString method if available.
See module std.format.write for more
details.
Only part of these combinations can be used for reading. See
module std.format.read for more
detailed information.
This table contains descriptions for every possible combination of
type and format character:
<th scope="col" width="20%">Type</th> <th scope="col" width="20%">Format Character</th> Formatted as... <td rowspan="1">null</td> 's' null
|<td rowspan="3">bool</td> 's' |
false or true |
| 'b', 'd', 'o', 'u', 'x', 'X' |
As the integrals 0 or 1 with the same format character.
Please note, that 'o' and 'x' with '#' flag
might produce unexpected results due to special handling of
the value 0. |
| 'r' |
\0 or \1 |
|<td rowspan="4">Integral</td> 's', 'd' |
A signed decimal number. The '#' flag is ignored. |
| 'b', 'o', 'u', 'x', 'X' |
An unsigned binary, decimal, octal or hexadecimal number.
In case of 'o' and 'x', the '#' flag
denotes that the number must be preceded by 0 and 0x, with
the exception of the value 0, where this does not apply. For
'b' and 'u' the '#' flag has no effect. |
| 'e', 'E', 'f', 'F', 'g', 'G', 'a', 'A' |
As a floating point value with the same specifier.
Default precision is large enough to add all digits
of the integral value.
In case of 'a' and 'A', the integral digit can be
any hexadecimal digit.
|
| 'r' |
Characters taken directly from the binary representation. |
|<td rowspan="5">Floating Point</td> 'e', 'E' |
Scientific notation: Exactly one integral digit followed by a dot
and fractional digits, followed by the exponent.
The exponent is formatted as 'e' followed by
a '+' or '-' sign, followed by at least
two digits.
When there are no fractional digits and the '#' flag
is not present, the dot is omitted. |
| 'f', 'F' |
Natural notation: Integral digits followed by a dot and
fractional digits.
When there are no fractional digits and the '#' flag
is not present, the dot is omitted.
Please note: the difference between 'f' and 'F'
is only visible for NaN and Infinity. |
| 's', 'g', 'G' |
Short notation: If the absolute value is larger than 10 ^^ precision
or smaller than 0.0001, the scientific notation is used.
If not, the natural notation is applied.
In both cases precision denotes the count of all digits, including
the integral digits. Trailing zeros (including a trailing dot) are removed.
If '#' flag is present, trailing zeros are not removed. |
| 'a', 'A' |
Hexadecimal scientific notation: 0x followed by 1
(or 0 in case of value zero or denormalized number)
followed by a dot, fractional digits in hexadecimal
notation and an exponent. The exponent is build by p,
followed by a sign and the exponent in decimal notation.
When there are no fractional digits and the '#' flag
is not present, the dot is omitted. |
| 'r' |
Characters taken directly from the binary representation. |
|<td rowspan="3">Character</td> 's', 'c' |
As the character.
Inside of a compound indicator 's' is treated differently: The
character is surrounded by single quotes and non printable
characters are escaped. This can be avoided by preceding
the compound indicator with a '-' flag
(e.g. "%-(%s%)"). |
| 'b', 'd', 'o', 'u', 'x', 'X' |
As the integral that represents the character. |
| 'r' |
Characters taken directly from the binary representation. |
|<td rowspan="3">String</td> 's' |
The sequence of characters that form the string.
Inside of a compound indicator the string is surrounded by double quotes
and non printable characters are escaped. This can be avoided
by preceding the compound indicator with a '-' flag
(e.g. "%-(%s%)"). |
| 'r' |
The sequence of characters, each formatted with 'r'. |
| compound |
As an array of characters. |
|<td rowspan="3">Array</td> 's' |
When the elements are characters, the array is formatted as
a string. In all other cases the array is surrounded by square brackets
and the elements are separated by a comma and a space. If the elements
are strings, they are surrounded by double quotes and non
printable characters are escaped. |
| 'r' |
The sequence of the elements, each formatted with 'r'. |
| compound |
The sequence of the elements, each formatted according to the specifications
given inside of the compound specifier. |
|<td rowspan="2">Associative Array</td> 's' |
As a sequence of the elements in unpredictable order. The output is
surrounded by square brackets. The elements are separated by a
comma and a space. The elements are formatted as key:value. |
| compound |
As a sequence of the elements in unpredictable order. Each element
is formatted according to the specifications given inside of the
compound specifier. The first specifier is used for formatting
the key and the second specifier is used for formatting the value.
The order can be changed with positional arguments. For example
"%(%2$s (%1$s), %)" will write the value, followed by the key in
parenthesis. |
|<td rowspan="2">Enum</td> 's' |
The name of the value. If the name is not available, the base value
is used, preceeded by a cast. |
| All, but 's' |
Enums can be formatted with all format characters that can be used
with the base value. In that case they are formatted like the base value. |
|<td rowspan="3">Input Range</td> 's' |
When the elements of the range are characters, they are written like a string.
In all other cases, the elements are enclosed by square brackets and separated
by a comma and a space. |
| 'r' |
The sequence of the elements, each formatted with 'r'. |
| compound |
The sequence of the elements, each formatted according to the specifications
given inside of the compound specifier. |
|<td rowspan="1">Struct</td> 's' |
When the struct has neither an applicable toString
nor is an input range, it is formatted as follows:
StructType(field1, field2, ...). |
|<td rowspan="1">Class</td> 's' |
When the class has neither an applicable toString
nor is an input range, it is formatted as the
fully qualified name of the class. |
|<td rowspan="1">Union</td> 's' |
When the union has neither an applicable toString
nor is an input range, it is formatted as its base name. |
|<td rowspan="2">Pointer</td> 's' |
A null pointer is formatted as 'null'. All other pointers are
formatted as hexadecimal numbers with the format character 'X'. |
| 'x', 'X' |
Formatted as a hexadecimal number. |
|<td rowspan="3">SIMD vector</td> 's' |
The array is surrounded by square brackets
and the elements are separated by a comma and a space. |
| 'r' |
The sequence of the elements, each formatted with 'r'. |
| compound |
The sequence of the elements, each formatted according to the specifications
given inside of the compound specifier. |
|<td rowspan="1">Delegate</td> 's', 'r', compound |
As the .stringof of this delegate treated as a string.
Please note: The implementation is currently buggy
and its use is discouraged. |
Source
std/format/package.d
Examples
Simple use:
// Easiest way is to use `%s` everywhere:
assert(format("I got %s %s for %s euros.", 30, "eggs", 5.27) == "I got 30 eggs for 5.27 euros.");
// Other format characters provide more control:
assert(format("I got %b %(%X%) for %f euros.", 30, "eggs", 5.27) == "I got 11110 65676773 for 5.270000 euros.");
Compound specifiers allow formatting arrays and other compound types:
/*
The trailing end of the sub-format string following the specifier for
each item is interpreted as the array delimiter, and is therefore
omitted following the last array item:
*/
assert(format("My items are %(%s %).", [1,2,3]) == "My items are 1 2 3.");
assert(format("My items are %(%s, %).", [1,2,3]) == "My items are 1, 2, 3.");
/*
The "%|" delimiter specifier may be used to indicate where the
delimiter begins, so that the portion of the format string prior to
it will be retained in the last array element:
*/
assert(format("My items are %(-%s-%|, %).", [1,2,3]) == "My items are -1-, -2-, -3-.");
/*
These compound format specifiers may be nested in the case of a
nested array argument:
*/
auto mat = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]];
assert(format("%(%(%d %) - %)", mat), "1 2 3 - 4 5 6 - 7 8 9");
assert(format("[%(%(%d %) - %)]", mat), "[1 2 3 - 4 5 6 - 7 8 9]");
assert(format("[%([%(%d %)]%| - %)]", mat), "[1 2 3] - [4 5 6] - [7 8 9]");
/*
Strings and characters are escaped automatically inside compound
format specifiers. To avoid this behavior, use "%-(" instead of "%(":
*/
assert(format("My friends are %s.", ["John", "Nancy"]) == `My friends are ["John", "Nancy"].`);
assert(format("My friends are %(%s, %).", ["John", "Nancy"]) == `My friends are "John", "Nancy".`);
assert(format("My friends are %-(%s, %).", ["John", "Nancy"]) == `My friends are John, Nancy.`);
Using parameters:
// Flags can be used to influence to outcome:
assert(format("%g != %+#g", 3.14, 3.14) == "3.14 != +3.14000");
// Width and precision help to arrange the formatted result:
assert(format(">%10.2f<", 1234.56789) == "> 1234.57<");
// Numbers can be grouped:
assert(format("%,4d", int.max) == "21,4748,3647");
// It's possible to specify the position of an argument:
assert(format("%3$s %1$s", 3, 17, 5) == "5 3");
Providing parameters as arguments:
// Width as argument
assert(format(">%*s<", 10, "abc") == "> abc<");
// Precision as argument
assert(format(">%.*f<", 5, 123.2) == ">123.20000<");
// Grouping as argument
assert(format("%,*d", 1, int.max) == "2,1,4,7,4,8,3,6,4,7");
// Grouping separator as argument
assert(format("%,3?d", '_', int.max) == "2_147_483_647");
// All at once
assert(format("%*.*,*?d", 20, 15, 6, '/', int.max) == " 000/002147/483647");
format : (alias template) format = std.format.format(Char, Args...)(in Char[] fmt, Args args) if (isSomeChar!Char)Converts its arguments according to a format string into a string.
The second version of format takes the format string as template
argument. In this case, it is checked for consistency at
compile-time and produces slightly faster code, because the length of
the output buffer can be estimated in advance.
Params:
fmt = a $(MREF_ALTTEXT format string, std,format)
args = a variadic list of arguments to be formatted
Char = character type of fmt
Args = a variadic list of types of the arguments
Returns:
The formatted string.
Throws:
A $(LREF FormatException) if formatting did not succeed.
See_Also:
$(LREF sformat) for a variant, that tries to avoid garbage collection.
format;
(struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta (local variable) sparkles.test_runner.bench_json.BenchMeta mm;
(local variable) sparkles.test_runner.bench_json.BenchMeta mm.(field) string sparkles.test_runner.bench_json.BenchMeta.dateISO day, e.g. "2026-07-10"
date = (cast((struct) std.datetime.date.DateRepresents a date in the
Proleptic
Gregorian Calendar ranging from 32,768 B.C. to 32,767 A.D. Positive years
are A.D. Non-positive years are B.C.
Year, month, and day are kept separately internally so that Date is
optimized for calendar-based operations.
Date uses the Proleptic Gregorian Calendar, so it assumes the Gregorian
leap year calculations for its entire length. As per
ISO 8601, it treats 1 B.C. as
year 0, i.e. 1 B.C. is 0, 2 B.C. is -1, etc. Use yearBC to use B.C.
as a positive integer with 1 B.C. being the year prior to 1 A.D.
Year 0 is a leap year.
Examples
import core.time : days;
auto d = Date(2000, 6, 1);
assert(d.dayOfYear == 153);
assert(d.dayOfWeek == DayOfWeek.thu);
d += 10.days;
assert(d == Date(2000, 6, 11));
assert(d.toISOExtString() == "2000-06-11");
assert(d.toISOString() == "20000611");
assert(d.toSimpleString() == "2000-Jun-11");
assert(Date.fromISOExtString("2018-01-01") == Date(2018, 1, 1));
assert(Date.fromISOString("20180101") == Date(2018, 1, 1));
assert(Date.fromSimpleString("2018-Jan-01") == Date(2018, 1, 1));
Date) (class) std.datetime.systime.ClockEffectively a namespace to make it clear that the methods it contains are
getting the time from the system clock. It cannot be instantiated.
Examples
Get the current time as a SysTime
import std.datetime.timezone : LocalTime;
SysTime today = Clock.currTime();
assert(today.timezone is LocalTime());
Clock.std.datetime.systime.SysTime std.datetime.systime.Clock.currTime!(ClockType.normal)(immutable(std.datetime.timezone.TimeZone) tz = opCall()) nothrow @safeReturns the current time in the given time zone.
currTime).string std.datetime.date.Date.toISOExtString() const pure nothrow @safeConverts this Date to a string with the format YYYY-MM-DD.
If writer is set, the resulting string will be written directly
to it.
Examples
assert(Date(2010, 7, 4).toISOExtString() == "2010-07-04");
assert(Date(1998, 12, 25).toISOExtString() == "1998-12-25");
assert(Date(0, 1, 5).toISOExtString() == "0000-01-05");
assert(Date(-4, 1, 5).toISOExtString() == "-0004-01-05");
toISOExtString();
(local variable) sparkles.test_runner.bench_json.BenchMeta mm.(field) string sparkles.test_runner.bench_json.BenchMeta.hostname"" when unavailable
hostname = string sparkles.test_runner.bench_json.hostName() @safehostName();
version (linuxlinux)
(local variable) sparkles.test_runner.bench_json.BenchMeta mm.(field) string sparkles.test_runner.bench_json.BenchMeta.osos = "linux";
else version (OSX)
m.os = "macos";
else version (Windows)
m.os = "windows";
else version (Posix)
m.os = "posix";
else
m.os = "unknown";
version (X86_64X86_64)
(local variable) sparkles.test_runner.bench_json.BenchMeta mm.(field) string sparkles.test_runner.bench_json.BenchMeta.archarch = "x86_64";
else version (AArch64)
m.arch = "aarch64";
else version (X86)
m.arch = "x86";
else
m.arch = "unknown";
(local variable) sparkles.test_runner.bench_json.BenchMeta mm.(field) string sparkles.test_runner.bench_json.BenchMeta.compilere.g. "LDC (front-end 2.111)"
compiler = string std.format.format!("%s (front-end %s.%03d)", string, immutable(uint), immutable(uint))(string __param_0, immutable(uint) __param_1, immutable(uint) __param_2) pure @safeExamples
The format string can be checked at compile-time:
auto s = format!"%s is %s"("Pi", 3.14);
assert(s == "Pi is 3.14");
// This line doesn't compile, because 3.14 cannot be formatted with %d:
// s = format!"%s is %d"("Pi", 3.14);
format!"%s (front-end %s.%03d)"((immutable global) immutable(string) std.compiler.nameVendor specific string naming the compiler, for example: "Digital Mars D".
name, (immutable global) immutable(uint) std.compiler.version_majorThe vendor specific version number, as in
version_major.version_minor
version_major, (immutable global) immutable(uint) std.compiler.version_minorThe vendor specific version number, as in
version_major.version_minor
version_minor);
(local variable) sparkles.test_runner.bench_json.BenchMeta mm.(field) string sparkles.test_runner.bench_json.BenchMeta.cpu/proc/cpuinfo model name; "" off Linux
cpu = string sparkles.test_runner.bench_json.cpuModel() @safecpuModel();
(local variable) sparkles.test_runner.bench_json.BenchMeta mm.(field) long sparkles.test_runner.bench_json.BenchMeta.minSampleTimeMseffective per-sample/total budget (--bench-min-time)
minSampleTimeMs = (parameter) const(sparkles.test_runner.bench.BenchConfig) configconfig.(field) core.time.Duration sparkles.test_runner.bench.BenchConfig.minSampleTimeAuto-scaling target duration of one sample.
minSampleTime.long core.time.Duration.total!"msecs"() const pure nothrow @nogc @property @safeReturns the total number of the given units in this Duration.
So, unlike split, it does not strip out the larger units.
Examples
assert(dur!"weeks"(12).total!"weeks" == 12);
assert(dur!"weeks"(12).total!"days" == 84);
assert(dur!"days"(13).total!"weeks" == 1);
assert(dur!"days"(13).total!"days" == 13);
assert(dur!"hours"(49).total!"days" == 2);
assert(dur!"hours"(49).total!"hours" == 49);
assert(dur!"nsecs"(2007).total!"hnsecs" == 20);
assert(dur!"nsecs"(2007).total!"nsecs" == 2000);
total!"msecs";
(local variable) sparkles.test_runner.bench_json.BenchMeta mm.(field) uint sparkles.test_runner.bench_json.BenchMeta.sampleCounteffective BenchConfig.sampleCount
sampleCount = (parameter) const(sparkles.test_runner.bench.BenchConfig) configconfig.(field) uint sparkles.test_runner.bench.BenchConfig.sampleCountNumber of samples to collect.
sampleCount;
return (local variable) sparkles.test_runner.bench_json.BenchMeta mm;
}
private (alias) object.string = stringstring string sparkles.test_runner.bench_json.hostName() @safehostName() @safe
{
version (PosixPosix)
{
import (package) corecore.(package) core.syssys.(package) core.sys.posixposix.(module) core.sys.posix.unistdD header file for POSIX.
unistd : (alias) gethostname = int core.sys.posix.unistd.gethostname(char*, ulong) nothrow @nogcgethostname;
char[256] (local variable) char[256] bufbuf = 0;
const (local variable) const(bool) okok = (() @trusted => int core.sys.posix.unistd.gethostname(char*, ulong) nothrow @nogcgethostname((local variable) char[256] bufbuf.(constant) char* char[256].ptr = &bufptr, (local variable) char[256] bufbuf.(constant) ulong char[256].length = 256LUlength))() == 0;
if (!(local variable) const(bool) okok)
return "";
foreach ((parameter) ulong ii, (parameter) char chch; (local variable) char[256] bufbuf)
if ((local variable) char chch == '\0')
return (local variable) char[256] bufbuf[0 .. (local variable) ulong ii].string object.idup!char(char[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup;
return (local variable) char[256] bufbuf[].string object.idup!char(char[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup;
}
else version (Windows)
{
import std.process : environment;
return environment.get("COMPUTERNAME", "");
}
else
return "";
}
private (alias) object.string = stringstring string sparkles.test_runner.bench_json.cpuModel() @safecpuModel() @safe
{
version (linuxlinux)
{
import (package) stdstd.(package) std.algorithmalgorithm.(module) std.algorithm.searchingThis is a submodule of std.algorithm.
It contains generic searching algorithms.
Function Name Description all all!"a > 0"([1, 2, 3, 4]) returns true because all elements are positive any any!"a > 0"([1, 2, -3, -4]) returns true because at least one element is positive balancedParens balancedParens("((1 + 1) / 2)", '(', ')') returns true because the string has balanced parentheses. boyerMooreFinder find("hello world", boyerMooreFinder("or")) returns "orld" using the Boyer-Moore algorithm. canFind canFind("hello world", "or") returns true. count Counts all elements or elements matching a predicate, specific element or sub-range.
count([1, 2, 1]) returns 3,
count([1, 2, 1], 1) returns 2 and
count!"a < 0"([1, -3, 0]) returns 1. |
| countUntil | countUntil(a, b) returns the number of steps taken in a to reach b; for example, countUntil("hello!", "o") returns 4. |
| commonPrefix | commonPrefix("parakeet", "parachute") returns "para". |
| endsWith | endsWith("rocks", "ks") returns true. |
| extrema | extrema([2, 1, 3, 5, 4]) returns [1, 5]. |
| find | find("hello world", "or") returns "orld" using linear search. (For binary search refer to SortedRange.) |
| findAdjacent | findAdjacent([1, 2, 3, 3, 4]) returns the subrange starting with two equal adjacent elements, i.e. [3, 3, 4]. |
| findAmong | findAmong("abcd", "qcx") returns "cd" because 'c' is among "qcx". |
| findSkip | If a = "abcde", then findSkip(a, "x") returns false and leaves a unchanged, whereas findSkip(a, "c") advances a to "de" and returns true. |
| findSplit | findSplit("abcdefg", "de") returns a tuple of three ranges "abc", "de", and "fg". |
| findSplitAfter | findSplitAfter("abcdefg", "de") returns a tuple of two ranges "abcde" and "fg". |
| findSplitBefore | findSplitBefore("abcdefg", "de") returns a tuple of two ranges "abc" and "defg". |
| minCount | minCount([2, 1, 1, 4, 1]) returns tuple(1, 3). |
| maxCount | maxCount([2, 4, 1, 4, 1]) returns tuple(4, 2). |
| minElement | Selects the minimal element of a range. minElement([3, 4, 1, 2]) returns 1. |
| maxElement | Selects the maximal element of a range. maxElement([3, 4, 1, 2]) returns 4. |
| minIndex | Index of the minimal element of a range. minIndex([3, 4, 1, 2]) returns 2. |
| maxIndex | Index of the maximal element of a range. maxIndex([3, 4, 1, 2]) returns 1. |
| minPos | minPos([2, 3, 1, 3, 4, 1]) returns the subrange [1, 3, 4, 1], i.e., positions the range at the first occurrence of its minimal element. |
| maxPos | maxPos([2, 3, 1, 3, 4, 1]) returns the subrange [4, 1], i.e., positions the range at the first occurrence of its maximal element. |
| skipOver | Assume a = "blah". Then skipOver(a, "bi") leaves a unchanged and returns false, whereas skipOver(a, "bl") advances a to refer to "ah" and returns true. |
| startsWith | startsWith("hello, world", "hello") returns true. |
| until | Lazily iterates a range until a specific value is found. |
Source
std/algorithm/searching.d
searching : (alias template) startsWith = std.algorithm.searching.startsWith(alias pred = (a, b) => a == b, Range, Needles...)(Range doesThisStart, Needles withOneOfThese) if (isInputRange!Range && (Needles.length > 1) && allSatisfy!(canTestStartsWith!(pred, Range), Needles))Checks whether the given
$(REF_ALTTEXT input range, isInputRange, std,range,primitives) starts with (one
of) the given needle(s) or, if no needles are given,
if its front element fulfils predicate pred.
For more information about pred see $(LREF find).
Params:
pred = Predicate to use in comparing the elements of the haystack and the
needle(s). Mandatory if no needles are given.
doesThisStart = The input range to check.
withOneOfThese = The needles against which the range is to be checked,
which may be individual elements or input ranges of elements.
withThis = The single needle to check, which may be either a single element
or an input range of elements.
Returns:
0 if the needle(s) do not occur at the beginning of the given range;
otherwise the position of the matching needle, that is, 1 if the range starts
with withOneOfThese[0], 2 if it starts with withOneOfThese[1], and so
on.
In the case where doesThisStart starts with multiple of the ranges or
elements in withOneOfThese, then the shortest one matches (if there are
two which match which are of the same length (e.g. "a" and 'a'), then
the left-most of them in the argument
list matches).
In the case when no needle parameters are given, return true iff front of
doesThisStart fulfils predicate pred.
startsWith;
import (package) stdstd.(module) std.fileUtilities for manipulating files and scanning directories. Functions
in this module handle files as a unit, e.g., read or write one file
at a time. For opening files and manipulating them via handles refer
to module std.stdio.
Category Functions General exists isDir isFile isSymlink rename thisExePath Directories chdir dirEntries getcwd mkdir mkdirRecurse rmdir rmdirRecurse tempDir Files append copy read readText remove slurp write Symlinks symlink readLink Attributes attrIsDir attrIsFile attrIsSymlink getAttributes getLinkAttributes getSize setAttributes Timestamp getTimes getTimesWin setTimes timeLastModified timeLastAccessed timeStatusChanged Other DirEntry FileException PreserveAttributes SpanMode getAvailableDiskSpace
Source
std/file.d
file : (alias template) readText = std.file.readText(S = string, R)(auto ref R name) if (isSomeString!S && (isSomeFiniteCharInputRange!R || is(StringTypeOf!R)))Reads and validates (using $(REF validate, std, utf)) a text file. S can be
an array of any character type. However, no width or endian conversions are
performed. So, if the width or endianness of the characters in the given
file differ from the width or endianness of the element type of S, then
validation will fail.
Params:
S = the string type of the file
name = string or range of characters representing the file _name
Returns: Array of characters read.
Throws: $(LREF FileException) if there is an error reading the file,
$(REF UTFException, std, utf) on UTF decoding error.
See_Also: $(REF read, std,file) for reading a binary file.
readText;
import (package) stdstd.(module) std.stringString handling functions.
Category Functions Searching column indexOf indexOfAny indexOfNeither lastIndexOf lastIndexOfAny lastIndexOfNeither Comparison isNumeric Mutation capitalize Pruning and Filling center chomp chompPrefix chop detabber detab entab entabber leftJustify outdent rightJustify strip stripLeft stripRight wrap Substitution abbrev soundex soundexer succ tr translate Miscellaneous assumeUTF fromStringz lineSplitter representation splitLines toStringz Objects of types string, wstring, and dstring are value types and cannot be mutated element-by-element. For using mutation during building strings, use char[], wchar[], or dchar[]. The xxxstring types are preferable because they don't exhibit undesired aliasing, thus making code more robust.
The following functions are publicly imported:
Module Functions Publicly imported functions std.algorithm cmp, std,algorithm,comparison count, std,algorithm,searching endsWith, std,algorithm,searching startsWith, std,algorithm,searching std.array join, std,array replace, std,array replaceInPlace, std,array split, std,array empty, std,array std.format format, std,format sformat, std,format std.uni icmp, std,uni toLower, std,uni toLowerInPlace, std,uni toUpper, std,uni toUpperInPlace, std,uni There is a rich set of functions for string handling defined in other modules. Functions related to Unicode and ASCII are found in std.uni and std.ascii, respectively. Other functions that have a wider generality than just strings can be found in std.algorithm and std.range.
Source
std/string.d
string : (alias template) indexOf = std.string.indexOf(Range)(Range s, dchar c, CaseSensitive cs = Yes.caseSensitive) if (isInputRange!Range && isSomeChar!(ElementType!Range) && !isSomeString!Range)Searches for a character in a string or range.
Params:
s = string or InputRange of characters to search for `c` in
c = character to search for in `s`
startIdx = index to a well-formed code point in `s` to start
searching from; defaults to 0
cs = specifies whether comparisons are case-sensitive
(`Yes.caseSensitive`) or not (`No.caseSensitive`).
Returns:
If `c` is found in `s`, then the index of its first occurrence is
returned. If `c` is not found or `startIdx` is greater than or equal to
`s.length`, then -1 is returned. If the parameters are not valid UTF,
the result will still be either -1 or in the range [`startIdx` ..
`s.length`], but will not be reliable otherwise.
Throws:
If the sequence starting at `startIdx` does not represent a well-formed
code point, then a $(REF UTFException, std,utf) may be thrown.
See_Also: $(REF countUntil, std,algorithm,searching)
indexOf, (alias template) lineSplitter = std.string.lineSplitter(Flag keepTerm = No.keepTerminator, Range)(Range r) if (hasSlicing!Range && hasLength!Range && isSomeChar!(ElementType!Range) && !isSomeString!Range)Split an array or slicable range of characters into a range of lines
using '\r', '\n', '\v', '\f', "\r\n",
$(REF lineSep, std,uni), $(REF paraSep, std,uni) and '\u0085' (NEL)
as delimiters. If keepTerm is set to Yes.keepTerminator, then the
delimiter is included in the slices returned.
Does not throw on invalid UTF; such is simply passed unchanged
to the output.
Adheres to $(HTTP www.unicode.org/versions/Unicode7.0.0/ch05.pdf, Unicode 7.0).
Does not allocate memory.
Params:
r = array of chars, wchars, or dchars or a slicable range
keepTerm = whether delimiter is included or not in the results
Returns:
range of slices of the input range r
See_Also:
$(LREF splitLines)
$(REF splitter, std,algorithm)
$(REF splitter, std,regex)
lineSplitter, (alias template) strip = std.string.strip(Range)(Range str) if (isSomeString!Range || isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range && !isConvertibleToString!Range && isSomeChar!(ElementEncodingType!Range))Strips both leading and trailing whitespace (as defined by
$(REF isWhite, std,uni)) or as specified in the second argument.
Params:
str = string or random access range of characters
chars = string of characters to be stripped
leftChars = string of leading characters to be stripped
rightChars = string of trailing characters to be stripped
Returns:
slice of `str` stripped of leading and trailing whitespace
or characters as specified in the second argument.
See_Also:
Generic stripping on ranges: $(REF _strip, std, algorithm, mutation)
strip;
try
{
foreach ((local variable) string lineline; string std.file.readText!(string, string)(string name) @safeReads and validates (using validate) a text file. S can be
an array of any character type. However, no width or endian conversions are
performed. So, if the width or endianness of the characters in the given
file differ from the width or endianness of the element type of S, then
validation will fail.
Examples
Read file with UTF-8 text.
write(deleteme, "abc"); // deleteme is the name of a temporary file
scope(exit) remove(deleteme);
string content = readText(deleteme);
assert(content == "abc");
readText("/proc/cpuinfo").std.string.LineSplitter!(Flag.no, string) std.string.lineSplitter!(Flag.no, immutable(char))(string r) pure nothrow @nogc @safeSplit an array or slicable range of characters into a range of lines
using '\r', '\n', '\v', '\f', "\r\n",
lineSep, paraSep and '\u0085' (NEL)
as delimiters. If keepTerm is set to Yes.keepTerminator, then the
delimiter is included in the slices returned.
Does not throw on invalid UTF; such is simply passed unchanged
to the output.
Adheres to Unicode 7.0.
Does not allocate memory.
Examples
import std.array : array;
string s = "Hello\nmy\rname\nis";
/* notice the call to 'array' to turn the lazy range created by
lineSplitter comparable to the string[] created by splitLines.
*/
assert(lineSplitter(s).array == splitLines(s));
auto s = "\rpeter\n\rpaul\r\njerry\u2028ice\u2029cream\n\nsunday\nmon\u2030day\n";
auto lines = s.lineSplitter();
static immutable witness = ["", "peter", "", "paul", "jerry", "ice", "cream", "", "sunday", "mon\u2030day"];
uint i;
foreach (line; lines)
{
assert(line == witness[i++]);
}
assert(i == witness.length);
lineSplitter)
if ((local variable) string lineline.bool std.algorithm.searching.startsWith!("a == b", string, string)(string doesThisStart, string withThis) pure nothrow @nogc @safeChecks whether the given
input range starts with (one
of) the given needle(s) or, if no needles are given,
if its front element fulfils predicate pred.
For more information about pred see find.
startsWith("model name"))
{
const (local variable) const(long) coloncolon = (local variable) string lineline.long std.string.indexOf!char(scope const(char)[] s, dchar c, std.typecons.Flag!"caseSensitive" cs = Flag.yes) pure nothrow @nogc @safeSearches for a character in a string or range.
indexOf(':');
if ((local variable) const(long) coloncolon >= 0)
return (local variable) string lineline[(local variable) const(long) coloncolon + 1 .. $].string std.string.strip!string(string str) pure nothrow @nogc @safeStrips both leading and trailing whitespace (as defined by
isWhite) or as specified in the second argument.
Examples
import std.uni : lineSep, paraSep;
assert(strip(" hello world ") ==
"hello world");
assert(strip("\n\t\v\rhello world\n\t\v\r") ==
"hello world");
assert(strip("hello world") ==
"hello world");
assert(strip([lineSep] ~ "hello world" ~ [lineSep]) ==
"hello world");
assert(strip([paraSep] ~ "hello world" ~ [paraSep]) ==
"hello world");
strip;
}
}
catch ((class) object.ExceptionThe base class of all errors that are safe to catch and handle.
In principle, only thrown objects derived from this class are safe to catch
inside a catch block. Thrown objects not derived from Exception
represent runtime errors that should not be caught, as certain runtime
guarantees may not hold, making it unsafe to continue program execution.
Examples
bool gotCaught;
try
{
throw new Exception("msg");
}
catch (Exception e)
{
gotCaught = true;
assert(e.msg == "msg");
}
assert(gotCaught);
Exception)
{
}
return "";
}
else
return "";
}
/// One JSON number: `nan`/infinities → `null` (an unavailable counter, the
/// table's em dash); integral doubles below 2^53 render as integers; the rest
/// to 6 significant digits (never D's 17-digit default).
package(sparkles.test_runner)
(alias) object.string = stringstring string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber(double (parameter) double vv) @safe
{
import (package) stdstd.(module) std.formatThis package provides string formatting functionality using
printf style format strings.
Submodule Function Name Description package format Converts its arguments according to a format string into a string.
| package |
sformat |
Converts its arguments according to a format string into a buffer. |
| package |
FormatException |
Signals a problem while formatting. |
| write |
formattedWrite |
Converts its arguments according to a format string and writes
the result to an output range. |
| write |
formatValue |
Formats a value of any type according to a format specifier and
writes the result to an output range. |
| read |
formattedRead |
Reads an input range according to a format string and stores the read
values into its arguments. |
| read |
unformatValue |
Reads a value from the given input range and converts it according to
a format specifier. |
| spec |
FormatSpec |
A general handler for format strings. |
| spec |
singleSpec |
Helper function that returns a FormatSpec for a single format specifier. |
Limitation
This package does not support localization, but
adheres to the rounding mode of the floating point unit, if
available.
Format Strings
The functions contained in this package use format strings. A
format string describes the layout of another string for reading or
writing purposes. A format string is composed of normal text
interspersed with format specifiers. A format specifier starts
with a percentage sign '%', optionally followed by one or more
parameters and ends with a format indicator. A format
indicator may be a simple format character or a compound
indicator.
Format strings are composed according to the following grammar:
FormatString:
FormatStringItem FormatString
FormatStringItem:
Character
FormatSpecifier
FormatSpecifier:
'%' Parameters FormatIndicator
FormatIndicator:
FormatCharacter
CompoundIndicator
FormatCharacter:
see remark below
CompoundIndicator:
'(' FormatString '%)'
'(' FormatString '%|' Delimiter '%)'
Delimiter
empty
Character Delimiter
Parameters:
Position Flags Width Precision Separator
Position:
empty
Integer '$'**
*Integer* **':'** *Integer* **'$'
Integer ':' '$'**
*Flags*:
*empty*
*Flag* *Flags*
*Flag*:
**'-'**|**'+'**|**' '**|**'0'**|**'#'**|**'='**
*Width*:
*OptionalPositionalInteger*
*Precision*:
*empty*
**'.'** *OptionalPositionalInteger*
*Separator*:
*empty*
**','** *OptionalInteger*
**','** *OptionalInteger* **'?'**
*OptionalInteger*:
*empty*
*Integer*
**'*'**
*OptionalPositionalInteger*:
*OptionalInteger*
**'*'** *Integer* **'$'
Character
'%%'
AnyCharacterExceptPercent
Integer:
NonZeroDigit Digits
Digits:
empty
Digit Digits
NonZeroDigit:
'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
Digit:
'0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
Note
FormatCharacter is unspecified. It can be any character
that has no other purpose in this grammar, but it is
recommended to assign (lower- and uppercase) letters.
Note
The Parameters of a CompoundIndicator are currently
limited to a '-' flag.
Format Indicator
The format indicator can either be a single character or an
expression surrounded by '%(' and '%)'. It specifies the
basic manner in which a value will be formatted and is the minimum
requirement to format a value.
The following characters can be used as format characters:
FormatCharacter Semantics 's' To be formatted in a human readable format. Can be used with all types. 'c' To be formatted as a character. 'd' To be formatted as a signed decimal integer. 'u' To be formatted as a decimal image of the underlying bit representation. 'b' To be formatted as a binary image of the underlying bit representation. 'o' To be formatted as an octal image of the underlying bit representation. 'x' / 'X' To be formatted as a hexadecimal image of the underlying bit representation. 'e' / 'E' To be formatted as a real number in decimal scientific notation. 'f' / 'F' To be formatted as a real number in decimal natural notation. 'g' / 'G' To be formatted as a real number in decimal short notation. Depending on the number, a scientific notation or a natural notation is used. 'a' / 'A' To be formatted as a real number in hexadecimal scientific notation. 'r' To be formatted as raw bytes. The output may not be printable and depends on endianness.
The compound indicator can be used to describe compound types
like arrays or structs in more detail. A compound type is enclosed
within '%(' and '%)'. The enclosed sub-format string is
applied to individual elements. The trailing portion of the
sub-format string following the specifier for the element is
interpreted as the delimiter, and is therefore omitted following the
last element. The '%|' specifier may be used to explicitly
indicate the start of the delimiter, so that the preceding portion of
the string will be included following the last element.
The format string inside of the compound indicator should
contain exactly one format specifier (two in case of associative
arrays), which specifies the formatting mode of the elements of the
compound type. This format specifier can be a compound
indicator itself.
Note
Inside a compound indicator, strings and characters are
escaped automatically. To avoid this behavior, use "%-("
instead of "%(".
Flags
There are several flags that affect the outcome of the formatting.
Flag Semantics '-' When the formatted result is shorter than the value given by the width parameter, the output is left justified. Without the '-' flag, the output remains right justified.
There are two exceptions where the '-' flag has a
different meaning: (1) with 'r' it denotes to use little
endian and (2) in case of a compound indicator it means that
no special handling of the members is applied. |
| '=' |
When the formatted result is shorter than the value
given by the width parameter, the output is centered.
If the central position is not possible it is moved slightly
to the right. In this case, if '-' flag is present in
addition to the '=' flag, it is moved slightly to the left. |
| '+' / *' '* |
Applies to numerical values. By default, positive numbers are not
formatted to include the + sign. With one of these two flags present,
positive numbers are preceded by a plus sign or a space.
When both flags are present, a plus sign is used.
In case of 'r', a big endian format is used. |
| '0' |
Is applied to numerical values that are printed right justified.
If the zero flag is present, the space left to the number is
filled with zeros instead of spaces. |
| '#' |
Denotes that an alternative output must be used. This depends on the type
to be formatted and the format character used. See the
sections below for more information. |
Width, Precision and Separator
The width parameter specifies the minimum width of the result.
The meaning of precision depends on the format indicator. For
integers it denotes the minimum number of digits printed, for
real numbers it denotes the number of fractional digits and for
strings and compound types it denotes the maximum number of elements
that are included in the output.
A separator is used for formatting numbers. If it is specified,
the output is divided into chunks of three digits, separated by a ','. The number of digits in a chunk can be given explicitly by
providing a number or a ''* after the ','.
In all three cases the number of digits can be replaced by a ''*. In this scenario, the next argument is used as the number of
digits. If the argument is a negative number, the precision and
separator parameters are considered unspecified. For width,
the absolute value is used and the '-' flag is set.
The separator can also be followed by a '?'. In that case,
an additional argument is used to specify the symbol that should be
used to separate the chunks.
Position
By default, the arguments are processed in the provided order. With
the position parameter it is possible to address arguments
directly. It is also possible to denote a series of arguments with
two numbers separated by ':', that are all processed in the same
way. The second number can be omitted. In that case the series ends
with the last argument.
It's also possible to use positional arguments for width, precision and separator by adding a number and a '$' after the ''*.
Types
This section describes the result of combining types with format
characters. It is organized in 2 subsections: a list of general
information regarding the formatting of types in the presence of
format characters and a table that contains details for every
available combination of type and format character.
When formatting types, the following rules apply:
If the format character is upper case, the resulting string will
be formatted using upper case letters.
The default precision for floating point numbers is 6 digits.
Rounding of floating point numbers adheres to the rounding mode
of the floating point unit, if available.
The floating point values NaN and Infinity are formatted as
nan and inf, possibly preceded by '+' or '-' sign.
Formatting reals is only supported for 64 bit reals and 80 bit reals.
All other reals are cast to double before they are formatted. This will
cause the result to be inf for very large numbers.
Characters and strings formatted with the 's' format character
inside of compound types are surrounded by single and double quotes
and unprintable characters are escaped. To avoid this, a '-'
flag can be specified for the compound specifier
(e.g. "%-(%s%)" instead of "%(%s%)" ).
Structs, unions, classes and interfaces are formatted by calling a
toString method if available.
See module std.format.write for more
details.
Only part of these combinations can be used for reading. See
module std.format.read for more
detailed information.
This table contains descriptions for every possible combination of
type and format character:
<th scope="col" width="20%">Type</th> <th scope="col" width="20%">Format Character</th> Formatted as... <td rowspan="1">null</td> 's' null
|<td rowspan="3">bool</td> 's' |
false or true |
| 'b', 'd', 'o', 'u', 'x', 'X' |
As the integrals 0 or 1 with the same format character.
Please note, that 'o' and 'x' with '#' flag
might produce unexpected results due to special handling of
the value 0. |
| 'r' |
\0 or \1 |
|<td rowspan="4">Integral</td> 's', 'd' |
A signed decimal number. The '#' flag is ignored. |
| 'b', 'o', 'u', 'x', 'X' |
An unsigned binary, decimal, octal or hexadecimal number.
In case of 'o' and 'x', the '#' flag
denotes that the number must be preceded by 0 and 0x, with
the exception of the value 0, where this does not apply. For
'b' and 'u' the '#' flag has no effect. |
| 'e', 'E', 'f', 'F', 'g', 'G', 'a', 'A' |
As a floating point value with the same specifier.
Default precision is large enough to add all digits
of the integral value.
In case of 'a' and 'A', the integral digit can be
any hexadecimal digit.
|
| 'r' |
Characters taken directly from the binary representation. |
|<td rowspan="5">Floating Point</td> 'e', 'E' |
Scientific notation: Exactly one integral digit followed by a dot
and fractional digits, followed by the exponent.
The exponent is formatted as 'e' followed by
a '+' or '-' sign, followed by at least
two digits.
When there are no fractional digits and the '#' flag
is not present, the dot is omitted. |
| 'f', 'F' |
Natural notation: Integral digits followed by a dot and
fractional digits.
When there are no fractional digits and the '#' flag
is not present, the dot is omitted.
Please note: the difference between 'f' and 'F'
is only visible for NaN and Infinity. |
| 's', 'g', 'G' |
Short notation: If the absolute value is larger than 10 ^^ precision
or smaller than 0.0001, the scientific notation is used.
If not, the natural notation is applied.
In both cases precision denotes the count of all digits, including
the integral digits. Trailing zeros (including a trailing dot) are removed.
If '#' flag is present, trailing zeros are not removed. |
| 'a', 'A' |
Hexadecimal scientific notation: 0x followed by 1
(or 0 in case of value zero or denormalized number)
followed by a dot, fractional digits in hexadecimal
notation and an exponent. The exponent is build by p,
followed by a sign and the exponent in decimal notation.
When there are no fractional digits and the '#' flag
is not present, the dot is omitted. |
| 'r' |
Characters taken directly from the binary representation. |
|<td rowspan="3">Character</td> 's', 'c' |
As the character.
Inside of a compound indicator 's' is treated differently: The
character is surrounded by single quotes and non printable
characters are escaped. This can be avoided by preceding
the compound indicator with a '-' flag
(e.g. "%-(%s%)"). |
| 'b', 'd', 'o', 'u', 'x', 'X' |
As the integral that represents the character. |
| 'r' |
Characters taken directly from the binary representation. |
|<td rowspan="3">String</td> 's' |
The sequence of characters that form the string.
Inside of a compound indicator the string is surrounded by double quotes
and non printable characters are escaped. This can be avoided
by preceding the compound indicator with a '-' flag
(e.g. "%-(%s%)"). |
| 'r' |
The sequence of characters, each formatted with 'r'. |
| compound |
As an array of characters. |
|<td rowspan="3">Array</td> 's' |
When the elements are characters, the array is formatted as
a string. In all other cases the array is surrounded by square brackets
and the elements are separated by a comma and a space. If the elements
are strings, they are surrounded by double quotes and non
printable characters are escaped. |
| 'r' |
The sequence of the elements, each formatted with 'r'. |
| compound |
The sequence of the elements, each formatted according to the specifications
given inside of the compound specifier. |
|<td rowspan="2">Associative Array</td> 's' |
As a sequence of the elements in unpredictable order. The output is
surrounded by square brackets. The elements are separated by a
comma and a space. The elements are formatted as key:value. |
| compound |
As a sequence of the elements in unpredictable order. Each element
is formatted according to the specifications given inside of the
compound specifier. The first specifier is used for formatting
the key and the second specifier is used for formatting the value.
The order can be changed with positional arguments. For example
"%(%2$s (%1$s), %)" will write the value, followed by the key in
parenthesis. |
|<td rowspan="2">Enum</td> 's' |
The name of the value. If the name is not available, the base value
is used, preceeded by a cast. |
| All, but 's' |
Enums can be formatted with all format characters that can be used
with the base value. In that case they are formatted like the base value. |
|<td rowspan="3">Input Range</td> 's' |
When the elements of the range are characters, they are written like a string.
In all other cases, the elements are enclosed by square brackets and separated
by a comma and a space. |
| 'r' |
The sequence of the elements, each formatted with 'r'. |
| compound |
The sequence of the elements, each formatted according to the specifications
given inside of the compound specifier. |
|<td rowspan="1">Struct</td> 's' |
When the struct has neither an applicable toString
nor is an input range, it is formatted as follows:
StructType(field1, field2, ...). |
|<td rowspan="1">Class</td> 's' |
When the class has neither an applicable toString
nor is an input range, it is formatted as the
fully qualified name of the class. |
|<td rowspan="1">Union</td> 's' |
When the union has neither an applicable toString
nor is an input range, it is formatted as its base name. |
|<td rowspan="2">Pointer</td> 's' |
A null pointer is formatted as 'null'. All other pointers are
formatted as hexadecimal numbers with the format character 'X'. |
| 'x', 'X' |
Formatted as a hexadecimal number. |
|<td rowspan="3">SIMD vector</td> 's' |
The array is surrounded by square brackets
and the elements are separated by a comma and a space. |
| 'r' |
The sequence of the elements, each formatted with 'r'. |
| compound |
The sequence of the elements, each formatted according to the specifications
given inside of the compound specifier. |
|<td rowspan="1">Delegate</td> 's', 'r', compound |
As the .stringof of this delegate treated as a string.
Please note: The implementation is currently buggy
and its use is discouraged. |
Source
std/format/package.d
Examples
Simple use:
// Easiest way is to use `%s` everywhere:
assert(format("I got %s %s for %s euros.", 30, "eggs", 5.27) == "I got 30 eggs for 5.27 euros.");
// Other format characters provide more control:
assert(format("I got %b %(%X%) for %f euros.", 30, "eggs", 5.27) == "I got 11110 65676773 for 5.270000 euros.");
Compound specifiers allow formatting arrays and other compound types:
/*
The trailing end of the sub-format string following the specifier for
each item is interpreted as the array delimiter, and is therefore
omitted following the last array item:
*/
assert(format("My items are %(%s %).", [1,2,3]) == "My items are 1 2 3.");
assert(format("My items are %(%s, %).", [1,2,3]) == "My items are 1, 2, 3.");
/*
The "%|" delimiter specifier may be used to indicate where the
delimiter begins, so that the portion of the format string prior to
it will be retained in the last array element:
*/
assert(format("My items are %(-%s-%|, %).", [1,2,3]) == "My items are -1-, -2-, -3-.");
/*
These compound format specifiers may be nested in the case of a
nested array argument:
*/
auto mat = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]];
assert(format("%(%(%d %) - %)", mat), "1 2 3 - 4 5 6 - 7 8 9");
assert(format("[%(%(%d %) - %)]", mat), "[1 2 3 - 4 5 6 - 7 8 9]");
assert(format("[%([%(%d %)]%| - %)]", mat), "[1 2 3] - [4 5 6] - [7 8 9]");
/*
Strings and characters are escaped automatically inside compound
format specifiers. To avoid this behavior, use "%-(" instead of "%(":
*/
assert(format("My friends are %s.", ["John", "Nancy"]) == `My friends are ["John", "Nancy"].`);
assert(format("My friends are %(%s, %).", ["John", "Nancy"]) == `My friends are "John", "Nancy".`);
assert(format("My friends are %-(%s, %).", ["John", "Nancy"]) == `My friends are John, Nancy.`);
Using parameters:
// Flags can be used to influence to outcome:
assert(format("%g != %+#g", 3.14, 3.14) == "3.14 != +3.14000");
// Width and precision help to arrange the formatted result:
assert(format(">%10.2f<", 1234.56789) == "> 1234.57<");
// Numbers can be grouped:
assert(format("%,4d", int.max) == "21,4748,3647");
// It's possible to specify the position of an argument:
assert(format("%3$s %1$s", 3, 17, 5) == "5 3");
Providing parameters as arguments:
// Width as argument
assert(format(">%*s<", 10, "abc") == "> abc<");
// Precision as argument
assert(format(">%.*f<", 5, 123.2) == ">123.20000<");
// Grouping as argument
assert(format("%,*d", 1, int.max) == "2,1,4,7,4,8,3,6,4,7");
// Grouping separator as argument
assert(format("%,3?d", '_', int.max) == "2_147_483_647");
// All at once
assert(format("%*.*,*?d", 20, 15, 6, '/', int.max) == " 000/002147/483647");
format : (alias template) format = std.format.format(Char, Args...)(in Char[] fmt, Args args) if (isSomeChar!Char)Converts its arguments according to a format string into a string.
The second version of format takes the format string as template
argument. In this case, it is checked for consistency at
compile-time and produces slightly faster code, because the length of
the output buffer can be estimated in advance.
Params:
fmt = a $(MREF_ALTTEXT format string, std,format)
args = a variadic list of arguments to be formatted
Char = character type of fmt
Args = a variadic list of types of the arguments
Returns:
The formatted string.
Throws:
A $(LREF FormatException) if formatting did not succeed.
See_Also:
$(LREF sformat) for a variant, that tries to avoid garbage collection.
format;
import (package) stdstd.(package) std.mathmath.(module) std.math.roundingThis is a submodule of std.math.
It contains several functions for rounding floating point numbers.
Source
std/math/rounding.d
rounding : (alias) floor = real std.math.rounding.floor(real x) pure nothrow @nogc @trustedReturns the value of x rounded downward to the next integer
(toward negative infinity).
floor;
import (package) stdstd.(package) std.mathmath.(module) std.math.traitsThis is a submodule of std.math.
It contains several functions for introspection on numerical values.
Source
std/math/traits.d
traits : (alias template) isFinite = std.math.traits.isFinite(X)(X x)Determines if $(D_PARAM x) is finite.
Params:
x = a floating point number.
Returns:
`true` if $(D_PARAM x) is finite.
isFinite;
if (!(parameter) double vv.bool std.math.traits.isFinite!double(double x) pure nothrow @nogc @trustedDetermines if x is finite.
Examples
assert( isFinite(1.23f));
assert( isFinite(float.max));
assert( isFinite(float.min_normal));
assert(!isFinite(float.nan));
assert(!isFinite(float.infinity));
isFinite)
return "null";
if ((parameter) double vv == double std.math.rounding.floor(double x) pure nothrow @nogc @trustedfloor((parameter) double vv) && (parameter) double vv >= -9_007_199_254_740_992.0 && (parameter) double vv <= 9_007_199_254_740_992.0)
return string std.format.format!("%.0f", double)(double __param_0) pure @safeExamples
The format string can be checked at compile-time:
auto s = format!"%s is %s"("Pi", 3.14);
assert(s == "Pi is 3.14");
// This line doesn't compile, because 3.14 cannot be formatted with %d:
// s = format!"%s is %d"("Pi", 3.14);
format!"%.0f"((parameter) double vv);
return string std.format.format!("%.6g", double)(double __param_0) pure @safeExamples
The format string can be checked at compile-time:
auto s = format!"%s is %s"("Pi", 3.14);
assert(s == "Pi is 3.14");
// This line doesn't compile, because 3.14 cannot be formatted with %d:
// s = format!"%s is %d"("Pi", 3.14);
format!"%.6g"((parameter) double vv);
}
@("benchJson.number.formatting")
@safe
unittest
{
assert(string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber(double.(constant) double double.nan = nannan) == "null");
assert(string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber(double.(constant) double double.infinity = infinfinity) == "null");
assert(string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber(3_823_300.0) == "3823300", "integral doubles print as integers");
assert(string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber(0.1) == "0.1");
assert(string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber(1.651754321e8) == "1.65175e+08", "6 significant digits");
}
/// The row's counting-pass iteration count: every counter tier shares one
/// per-pass count, so the first present source carries it. `0` = no counting
/// pass ran.
private ulong ulong sparkles.test_runner.bench_json.countIterations(in sparkles.test_runner.bench.BenchStats row) pure nothrow @nogc @safeThe row's counting-pass iteration count: every counter tier shares one
per-pass count, so the first present source carries it. 0 = no counting
pass ran.
countIterations(in (struct) sparkles.test_runner.bench.BenchStatsSummary statistics of one benchmark row, in nanoseconds per iteration. A row
with a non-empty error is a failure row (its timing fields are unset).
BenchStats (parameter) const(sparkles.test_runner.bench.BenchStats) rowrow) @safe pure nothrow @nogc
{
if (!(parameter) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) std.typecons.Nullable!(PerfStats) sparkles.test_runner.bench.BenchStats.perfhardware counters under --perf`` (empty otherwise)
perf.bool std.typecons.Nullable!(sparkles.test_runner.perf.PerfStats).isNull() const pure nothrow @nogc @property @safeCheck if this is in the null state.
isNull)
return (parameter) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) std.typecons.Nullable!(PerfStats) sparkles.test_runner.bench.BenchStats.perfhardware counters under --perf`` (empty otherwise)
perf.inout(sparkles.test_runner.perf.PerfStats) std.typecons.Nullable!(sparkles.test_runner.perf.PerfStats).get() inout pure nothrow @nogc @property ref @safeGets the value if not null. If this is in the null state, and the optional
parameter fallback was provided, it will be returned. Without fallback,
calling get with a null state is invalid.
When the fallback type is different from the Nullable type, ``get(T) returns
the common type.
get.(field) ulong sparkles.test_runner.perf.PerfStats.iterscounting-pass iterations
iters;
if (!(parameter) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) std.typecons.Nullable!(Tier0Stats) sparkles.test_runner.bench.BenchStats.tier0cheap /proc counters when a tier0 metric is selected
tier0.bool std.typecons.Nullable!(sparkles.test_runner.tier0.Tier0Stats).isNull() const pure nothrow @nogc @property @safeCheck if this is in the null state.
isNull)
return (parameter) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) std.typecons.Nullable!(Tier0Stats) sparkles.test_runner.bench.BenchStats.tier0cheap /proc counters when a tier0 metric is selected
tier0.inout(sparkles.test_runner.tier0.Tier0Stats) std.typecons.Nullable!(sparkles.test_runner.tier0.Tier0Stats).get() inout pure nothrow @nogc @property ref @safeGets the value if not null. If this is in the null state, and the optional
parameter fallback was provided, it will be returned. Without fallback,
calling get with a null state is invalid.
When the fallback type is different from the Nullable type, ``get(T) returns
the common type.
get.(field) ulong sparkles.test_runner.tier0.Tier0Stats.iterscounting-pass iterations
iters;
if (!(parameter) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) std.typecons.Nullable!(SyscallStats) sparkles.test_runner.bench.BenchStats.syscallssyscall tracepoint counts under --syscalls``
syscalls.bool std.typecons.Nullable!(sparkles.test_runner.syscalls.SyscallStats).isNull() const pure nothrow @nogc @property @safeCheck if this is in the null state.
isNull)
return (parameter) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) std.typecons.Nullable!(SyscallStats) sparkles.test_runner.bench.BenchStats.syscallssyscall tracepoint counts under --syscalls``
syscalls.inout(sparkles.test_runner.syscalls.SyscallStats) std.typecons.Nullable!(sparkles.test_runner.syscalls.SyscallStats).get() inout pure nothrow @nogc @property ref @safeGets the value if not null. If this is in the null state, and the optional
parameter fallback was provided, it will be returned. Without fallback,
calling get with a null state is invalid.
When the fallback type is different from the Nullable type, ``get(T) returns
the common type.
get.(field) ulong sparkles.test_runner.syscalls.SyscallStats.itersiters;
if (!(parameter) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) std.typecons.Nullable!(RawStats) sparkles.test_runner.bench.BenchStats.rawraw hardware events named via --metrics=raw:…
raw.bool std.typecons.Nullable!(sparkles.test_runner.raw.RawStats).isNull() const pure nothrow @nogc @property @safeCheck if this is in the null state.
isNull)
return (parameter) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) std.typecons.Nullable!(RawStats) sparkles.test_runner.bench.BenchStats.rawraw hardware events named via --metrics=raw:…
raw.inout(sparkles.test_runner.raw.RawStats) std.typecons.Nullable!(sparkles.test_runner.raw.RawStats).get() inout pure nothrow @nogc @property ref @safeGets the value if not null. If this is in the null state, and the optional
parameter fallback was provided, it will be returned. Without fallback,
calling get with a null state is invalid.
When the fallback type is different from the Nullable type, ``get(T) returns
the common type.
get.(field) ulong sparkles.test_runner.raw.RawStats.iterscounting-pass iterations
iters;
return 0;
}
/// RFC 8259 string escaping: `"`, `\`, and control characters.
package(sparkles.test_runner)
(alias) object.string = stringstring string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape(scope const(char)[] (parameter) const(char)[] ss) @safe pure
{
import (package) stdstd.(module) std.arrayFunctions and types that manipulate built-in arrays and associative arrays.
This module provides all kinds of functions to create, manipulate or convert arrays:
Function Name Description
| array |
Returns a copy of the input in a newly allocated dynamic array.
|
| appender |
Returns a new Appender or RefAppender initialized with a given array.
|
| assocArray |
Returns a newly allocated associative array from a range/ranges of keys and values.
|
| byPair |
Construct a range iterating over an associative array by key/value tuples.
|
| insertInPlace |
Inserts into an existing array at a given position.
|
| join |
Concatenates a range of ranges into one array.
|
| minimallyInitializedArray |
Returns a new array of type T.
|
| replace |
Returns a new array with all occurrences of a certain subrange replaced.
|
| replaceFirst |
Returns a new array with the first occurrence of a certain subrange replaced.
|
| replaceInPlace |
Replaces all occurrences of a certain subrange and puts the result into a given array.
|
| replaceInto |
Replaces all occurrences of a certain subrange and puts the result into an output range.
|
| replaceLast |
Returns a new array with the last occurrence of a certain subrange replaced.
|
| replaceSlice |
Returns a new array with a given slice replaced.
|
| replicate |
Creates a new array out of several copies of an input array or range.
|
| sameHead |
Checks if the initial segments of two arrays refer to the same
place in memory.
|
| sameTail |
Checks if the final segments of two arrays refer to the same place
in memory.
|
| split |
Eagerly split a range or string into an array.
|
| staticArray |
Creates a new static array from given data.
|
| uninitializedArray |
Returns a new array of type T without initializing its elements.
|
Source
std/array.d
array : (alias template) appender = std.array.appender(A)() if (isDynamicArray!A)Convenience function that returns an $(LREF Appender) instance,
optionally initialized with array.
appender;
import (package) stdstd.(module) std.formatThis package provides string formatting functionality using
printf style format strings.
Submodule Function Name Description package format Converts its arguments according to a format string into a string.
| package |
sformat |
Converts its arguments according to a format string into a buffer. |
| package |
FormatException |
Signals a problem while formatting. |
| write |
formattedWrite |
Converts its arguments according to a format string and writes
the result to an output range. |
| write |
formatValue |
Formats a value of any type according to a format specifier and
writes the result to an output range. |
| read |
formattedRead |
Reads an input range according to a format string and stores the read
values into its arguments. |
| read |
unformatValue |
Reads a value from the given input range and converts it according to
a format specifier. |
| spec |
FormatSpec |
A general handler for format strings. |
| spec |
singleSpec |
Helper function that returns a FormatSpec for a single format specifier. |
Limitation
This package does not support localization, but
adheres to the rounding mode of the floating point unit, if
available.
Format Strings
The functions contained in this package use format strings. A
format string describes the layout of another string for reading or
writing purposes. A format string is composed of normal text
interspersed with format specifiers. A format specifier starts
with a percentage sign '%', optionally followed by one or more
parameters and ends with a format indicator. A format
indicator may be a simple format character or a compound
indicator.
Format strings are composed according to the following grammar:
FormatString:
FormatStringItem FormatString
FormatStringItem:
Character
FormatSpecifier
FormatSpecifier:
'%' Parameters FormatIndicator
FormatIndicator:
FormatCharacter
CompoundIndicator
FormatCharacter:
see remark below
CompoundIndicator:
'(' FormatString '%)'
'(' FormatString '%|' Delimiter '%)'
Delimiter
empty
Character Delimiter
Parameters:
Position Flags Width Precision Separator
Position:
empty
Integer '$'**
*Integer* **':'** *Integer* **'$'
Integer ':' '$'**
*Flags*:
*empty*
*Flag* *Flags*
*Flag*:
**'-'**|**'+'**|**' '**|**'0'**|**'#'**|**'='**
*Width*:
*OptionalPositionalInteger*
*Precision*:
*empty*
**'.'** *OptionalPositionalInteger*
*Separator*:
*empty*
**','** *OptionalInteger*
**','** *OptionalInteger* **'?'**
*OptionalInteger*:
*empty*
*Integer*
**'*'**
*OptionalPositionalInteger*:
*OptionalInteger*
**'*'** *Integer* **'$'
Character
'%%'
AnyCharacterExceptPercent
Integer:
NonZeroDigit Digits
Digits:
empty
Digit Digits
NonZeroDigit:
'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
Digit:
'0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
Note
FormatCharacter is unspecified. It can be any character
that has no other purpose in this grammar, but it is
recommended to assign (lower- and uppercase) letters.
Note
The Parameters of a CompoundIndicator are currently
limited to a '-' flag.
Format Indicator
The format indicator can either be a single character or an
expression surrounded by '%(' and '%)'. It specifies the
basic manner in which a value will be formatted and is the minimum
requirement to format a value.
The following characters can be used as format characters:
FormatCharacter Semantics 's' To be formatted in a human readable format. Can be used with all types. 'c' To be formatted as a character. 'd' To be formatted as a signed decimal integer. 'u' To be formatted as a decimal image of the underlying bit representation. 'b' To be formatted as a binary image of the underlying bit representation. 'o' To be formatted as an octal image of the underlying bit representation. 'x' / 'X' To be formatted as a hexadecimal image of the underlying bit representation. 'e' / 'E' To be formatted as a real number in decimal scientific notation. 'f' / 'F' To be formatted as a real number in decimal natural notation. 'g' / 'G' To be formatted as a real number in decimal short notation. Depending on the number, a scientific notation or a natural notation is used. 'a' / 'A' To be formatted as a real number in hexadecimal scientific notation. 'r' To be formatted as raw bytes. The output may not be printable and depends on endianness.
The compound indicator can be used to describe compound types
like arrays or structs in more detail. A compound type is enclosed
within '%(' and '%)'. The enclosed sub-format string is
applied to individual elements. The trailing portion of the
sub-format string following the specifier for the element is
interpreted as the delimiter, and is therefore omitted following the
last element. The '%|' specifier may be used to explicitly
indicate the start of the delimiter, so that the preceding portion of
the string will be included following the last element.
The format string inside of the compound indicator should
contain exactly one format specifier (two in case of associative
arrays), which specifies the formatting mode of the elements of the
compound type. This format specifier can be a compound
indicator itself.
Note
Inside a compound indicator, strings and characters are
escaped automatically. To avoid this behavior, use "%-("
instead of "%(".
Flags
There are several flags that affect the outcome of the formatting.
Flag Semantics '-' When the formatted result is shorter than the value given by the width parameter, the output is left justified. Without the '-' flag, the output remains right justified.
There are two exceptions where the '-' flag has a
different meaning: (1) with 'r' it denotes to use little
endian and (2) in case of a compound indicator it means that
no special handling of the members is applied. |
| '=' |
When the formatted result is shorter than the value
given by the width parameter, the output is centered.
If the central position is not possible it is moved slightly
to the right. In this case, if '-' flag is present in
addition to the '=' flag, it is moved slightly to the left. |
| '+' / *' '* |
Applies to numerical values. By default, positive numbers are not
formatted to include the + sign. With one of these two flags present,
positive numbers are preceded by a plus sign or a space.
When both flags are present, a plus sign is used.
In case of 'r', a big endian format is used. |
| '0' |
Is applied to numerical values that are printed right justified.
If the zero flag is present, the space left to the number is
filled with zeros instead of spaces. |
| '#' |
Denotes that an alternative output must be used. This depends on the type
to be formatted and the format character used. See the
sections below for more information. |
Width, Precision and Separator
The width parameter specifies the minimum width of the result.
The meaning of precision depends on the format indicator. For
integers it denotes the minimum number of digits printed, for
real numbers it denotes the number of fractional digits and for
strings and compound types it denotes the maximum number of elements
that are included in the output.
A separator is used for formatting numbers. If it is specified,
the output is divided into chunks of three digits, separated by a ','. The number of digits in a chunk can be given explicitly by
providing a number or a ''* after the ','.
In all three cases the number of digits can be replaced by a ''*. In this scenario, the next argument is used as the number of
digits. If the argument is a negative number, the precision and
separator parameters are considered unspecified. For width,
the absolute value is used and the '-' flag is set.
The separator can also be followed by a '?'. In that case,
an additional argument is used to specify the symbol that should be
used to separate the chunks.
Position
By default, the arguments are processed in the provided order. With
the position parameter it is possible to address arguments
directly. It is also possible to denote a series of arguments with
two numbers separated by ':', that are all processed in the same
way. The second number can be omitted. In that case the series ends
with the last argument.
It's also possible to use positional arguments for width, precision and separator by adding a number and a '$' after the ''*.
Types
This section describes the result of combining types with format
characters. It is organized in 2 subsections: a list of general
information regarding the formatting of types in the presence of
format characters and a table that contains details for every
available combination of type and format character.
When formatting types, the following rules apply:
If the format character is upper case, the resulting string will
be formatted using upper case letters.
The default precision for floating point numbers is 6 digits.
Rounding of floating point numbers adheres to the rounding mode
of the floating point unit, if available.
The floating point values NaN and Infinity are formatted as
nan and inf, possibly preceded by '+' or '-' sign.
Formatting reals is only supported for 64 bit reals and 80 bit reals.
All other reals are cast to double before they are formatted. This will
cause the result to be inf for very large numbers.
Characters and strings formatted with the 's' format character
inside of compound types are surrounded by single and double quotes
and unprintable characters are escaped. To avoid this, a '-'
flag can be specified for the compound specifier
(e.g. "%-(%s%)" instead of "%(%s%)" ).
Structs, unions, classes and interfaces are formatted by calling a
toString method if available.
See module std.format.write for more
details.
Only part of these combinations can be used for reading. See
module std.format.read for more
detailed information.
This table contains descriptions for every possible combination of
type and format character:
<th scope="col" width="20%">Type</th> <th scope="col" width="20%">Format Character</th> Formatted as... <td rowspan="1">null</td> 's' null
|<td rowspan="3">bool</td> 's' |
false or true |
| 'b', 'd', 'o', 'u', 'x', 'X' |
As the integrals 0 or 1 with the same format character.
Please note, that 'o' and 'x' with '#' flag
might produce unexpected results due to special handling of
the value 0. |
| 'r' |
\0 or \1 |
|<td rowspan="4">Integral</td> 's', 'd' |
A signed decimal number. The '#' flag is ignored. |
| 'b', 'o', 'u', 'x', 'X' |
An unsigned binary, decimal, octal or hexadecimal number.
In case of 'o' and 'x', the '#' flag
denotes that the number must be preceded by 0 and 0x, with
the exception of the value 0, where this does not apply. For
'b' and 'u' the '#' flag has no effect. |
| 'e', 'E', 'f', 'F', 'g', 'G', 'a', 'A' |
As a floating point value with the same specifier.
Default precision is large enough to add all digits
of the integral value.
In case of 'a' and 'A', the integral digit can be
any hexadecimal digit.
|
| 'r' |
Characters taken directly from the binary representation. |
|<td rowspan="5">Floating Point</td> 'e', 'E' |
Scientific notation: Exactly one integral digit followed by a dot
and fractional digits, followed by the exponent.
The exponent is formatted as 'e' followed by
a '+' or '-' sign, followed by at least
two digits.
When there are no fractional digits and the '#' flag
is not present, the dot is omitted. |
| 'f', 'F' |
Natural notation: Integral digits followed by a dot and
fractional digits.
When there are no fractional digits and the '#' flag
is not present, the dot is omitted.
Please note: the difference between 'f' and 'F'
is only visible for NaN and Infinity. |
| 's', 'g', 'G' |
Short notation: If the absolute value is larger than 10 ^^ precision
or smaller than 0.0001, the scientific notation is used.
If not, the natural notation is applied.
In both cases precision denotes the count of all digits, including
the integral digits. Trailing zeros (including a trailing dot) are removed.
If '#' flag is present, trailing zeros are not removed. |
| 'a', 'A' |
Hexadecimal scientific notation: 0x followed by 1
(or 0 in case of value zero or denormalized number)
followed by a dot, fractional digits in hexadecimal
notation and an exponent. The exponent is build by p,
followed by a sign and the exponent in decimal notation.
When there are no fractional digits and the '#' flag
is not present, the dot is omitted. |
| 'r' |
Characters taken directly from the binary representation. |
|<td rowspan="3">Character</td> 's', 'c' |
As the character.
Inside of a compound indicator 's' is treated differently: The
character is surrounded by single quotes and non printable
characters are escaped. This can be avoided by preceding
the compound indicator with a '-' flag
(e.g. "%-(%s%)"). |
| 'b', 'd', 'o', 'u', 'x', 'X' |
As the integral that represents the character. |
| 'r' |
Characters taken directly from the binary representation. |
|<td rowspan="3">String</td> 's' |
The sequence of characters that form the string.
Inside of a compound indicator the string is surrounded by double quotes
and non printable characters are escaped. This can be avoided
by preceding the compound indicator with a '-' flag
(e.g. "%-(%s%)"). |
| 'r' |
The sequence of characters, each formatted with 'r'. |
| compound |
As an array of characters. |
|<td rowspan="3">Array</td> 's' |
When the elements are characters, the array is formatted as
a string. In all other cases the array is surrounded by square brackets
and the elements are separated by a comma and a space. If the elements
are strings, they are surrounded by double quotes and non
printable characters are escaped. |
| 'r' |
The sequence of the elements, each formatted with 'r'. |
| compound |
The sequence of the elements, each formatted according to the specifications
given inside of the compound specifier. |
|<td rowspan="2">Associative Array</td> 's' |
As a sequence of the elements in unpredictable order. The output is
surrounded by square brackets. The elements are separated by a
comma and a space. The elements are formatted as key:value. |
| compound |
As a sequence of the elements in unpredictable order. Each element
is formatted according to the specifications given inside of the
compound specifier. The first specifier is used for formatting
the key and the second specifier is used for formatting the value.
The order can be changed with positional arguments. For example
"%(%2$s (%1$s), %)" will write the value, followed by the key in
parenthesis. |
|<td rowspan="2">Enum</td> 's' |
The name of the value. If the name is not available, the base value
is used, preceeded by a cast. |
| All, but 's' |
Enums can be formatted with all format characters that can be used
with the base value. In that case they are formatted like the base value. |
|<td rowspan="3">Input Range</td> 's' |
When the elements of the range are characters, they are written like a string.
In all other cases, the elements are enclosed by square brackets and separated
by a comma and a space. |
| 'r' |
The sequence of the elements, each formatted with 'r'. |
| compound |
The sequence of the elements, each formatted according to the specifications
given inside of the compound specifier. |
|<td rowspan="1">Struct</td> 's' |
When the struct has neither an applicable toString
nor is an input range, it is formatted as follows:
StructType(field1, field2, ...). |
|<td rowspan="1">Class</td> 's' |
When the class has neither an applicable toString
nor is an input range, it is formatted as the
fully qualified name of the class. |
|<td rowspan="1">Union</td> 's' |
When the union has neither an applicable toString
nor is an input range, it is formatted as its base name. |
|<td rowspan="2">Pointer</td> 's' |
A null pointer is formatted as 'null'. All other pointers are
formatted as hexadecimal numbers with the format character 'X'. |
| 'x', 'X' |
Formatted as a hexadecimal number. |
|<td rowspan="3">SIMD vector</td> 's' |
The array is surrounded by square brackets
and the elements are separated by a comma and a space. |
| 'r' |
The sequence of the elements, each formatted with 'r'. |
| compound |
The sequence of the elements, each formatted according to the specifications
given inside of the compound specifier. |
|<td rowspan="1">Delegate</td> 's', 'r', compound |
As the .stringof of this delegate treated as a string.
Please note: The implementation is currently buggy
and its use is discouraged. |
Source
std/format/package.d
Examples
Simple use:
// Easiest way is to use `%s` everywhere:
assert(format("I got %s %s for %s euros.", 30, "eggs", 5.27) == "I got 30 eggs for 5.27 euros.");
// Other format characters provide more control:
assert(format("I got %b %(%X%) for %f euros.", 30, "eggs", 5.27) == "I got 11110 65676773 for 5.270000 euros.");
Compound specifiers allow formatting arrays and other compound types:
/*
The trailing end of the sub-format string following the specifier for
each item is interpreted as the array delimiter, and is therefore
omitted following the last array item:
*/
assert(format("My items are %(%s %).", [1,2,3]) == "My items are 1 2 3.");
assert(format("My items are %(%s, %).", [1,2,3]) == "My items are 1, 2, 3.");
/*
The "%|" delimiter specifier may be used to indicate where the
delimiter begins, so that the portion of the format string prior to
it will be retained in the last array element:
*/
assert(format("My items are %(-%s-%|, %).", [1,2,3]) == "My items are -1-, -2-, -3-.");
/*
These compound format specifiers may be nested in the case of a
nested array argument:
*/
auto mat = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]];
assert(format("%(%(%d %) - %)", mat), "1 2 3 - 4 5 6 - 7 8 9");
assert(format("[%(%(%d %) - %)]", mat), "[1 2 3 - 4 5 6 - 7 8 9]");
assert(format("[%([%(%d %)]%| - %)]", mat), "[1 2 3] - [4 5 6] - [7 8 9]");
/*
Strings and characters are escaped automatically inside compound
format specifiers. To avoid this behavior, use "%-(" instead of "%(":
*/
assert(format("My friends are %s.", ["John", "Nancy"]) == `My friends are ["John", "Nancy"].`);
assert(format("My friends are %(%s, %).", ["John", "Nancy"]) == `My friends are "John", "Nancy".`);
assert(format("My friends are %-(%s, %).", ["John", "Nancy"]) == `My friends are John, Nancy.`);
Using parameters:
// Flags can be used to influence to outcome:
assert(format("%g != %+#g", 3.14, 3.14) == "3.14 != +3.14000");
// Width and precision help to arrange the formatted result:
assert(format(">%10.2f<", 1234.56789) == "> 1234.57<");
// Numbers can be grouped:
assert(format("%,4d", int.max) == "21,4748,3647");
// It's possible to specify the position of an argument:
assert(format("%3$s %1$s", 3, 17, 5) == "5 3");
Providing parameters as arguments:
// Width as argument
assert(format(">%*s<", 10, "abc") == "> abc<");
// Precision as argument
assert(format(">%.*f<", 5, 123.2) == ">123.20000<");
// Grouping as argument
assert(format("%,*d", 1, int.max) == "2,1,4,7,4,8,3,6,4,7");
// Grouping separator as argument
assert(format("%,3?d", '_', int.max) == "2_147_483_647");
// All at once
assert(format("%*.*,*?d", 20, 15, 6, '/', int.max) == " 000/002147/483647");
format : (alias template) format = std.format.format(Char, Args...)(in Char[] fmt, Args args) if (isSomeChar!Char)Converts its arguments according to a format string into a string.
The second version of format takes the format string as template
argument. In this case, it is checked for consistency at
compile-time and produces slightly faster code, because the length of
the output buffer can be estimated in advance.
Params:
fmt = a $(MREF_ALTTEXT format string, std,format)
args = a variadic list of arguments to be formatted
Char = character type of fmt
Args = a variadic list of types of the arguments
Returns:
The formatted string.
Throws:
A $(LREF FormatException) if formatting did not succeed.
See_Also:
$(LREF sformat) for a variant, that tries to avoid garbage collection.
format;
auto (local variable) std.array.Appender!string appapp = std.array.Appender!string std.array.appender!string() pure nothrow @safeConvenience function that returns an Appender instance,
optionally initialized with array.
appender!(alias) object.string = stringstring;
foreach ((parameter) const(char) chch; (parameter) const(char)[] ss)
switch ((local variable) const(char) chch)
{
case '"': (local variable) std.array.Appender!string appapp ~= `\"`; break;
case '\\': (local variable) std.array.Appender!string appapp ~= `\\`; break;
case '\n': (local variable) std.array.Appender!string appapp ~= `\n`; break;
case '\r': (local variable) std.array.Appender!string appapp ~= `\r`; break;
case '\t': (local variable) std.array.Appender!string appapp ~= `\t`; break;
default:
if ((local variable) const(char) chch < 0x20)
(local variable) std.array.Appender!string appapp ~= string std.format.format!("\\u%04x", const(char))(const(char) __param_0) pure @safeExamples
The format string can be checked at compile-time:
auto s = format!"%s is %s"("Pi", 3.14);
assert(s == "Pi is 3.14");
// This line doesn't compile, because 3.14 cannot be formatted with %d:
// s = format!"%s is %d"("Pi", 3.14);
format!"\\u%04x"((local variable) const(char) chch);
else
(local variable) std.array.Appender!string appapp ~= (local variable) const(char) chch;
}
return (local variable) std.array.Appender!string appapp[];
}
/// The full report document: `{schema, meta, columns, rows}`, pretty-printed
/// with 2-space indent. `rows` keep measurement order (grouping/sorting are
/// presentation concerns; the group dimensions travel in each row's `labels`,
/// whose keys are emitted sorted). `columns` describe the available catalog
/// metrics for these rows, so `metrics` keys match `--list-metrics` names.
/// Schema 2 adds the optional per-row `estimatedMetrics` array naming the
/// `metrics` keys whose values are multiplex-scaled estimates (absent =
/// every metric exact), and — when `@workload` tests ran — a `windows`
/// sibling array of window objects: wall decomposition fields (`null` =
/// unattributable on this host, exactly the table's em dash) and one nested
/// per-source totals object per attached source. Window values are window
/// TOTALS with their own field names, deliberately never the per-iteration
/// `metrics` catalog keys — reusing those names would quietly overload
/// their semantics. A run without workloads emits no `windows` key and is
/// byte-identical to the pre-window document.
(alias) object.string = stringstring string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson(in (struct) sparkles.test_runner.bench.BenchStatsSummary statistics of one benchmark row, in nanoseconds per iteration. A row
with a non-empty error is a failure row (its timing fields are unset).
BenchStats[] (parameter) const(sparkles.test_runner.bench.BenchStats[]) rowsrows, in (struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta (parameter) const(sparkles.test_runner.bench_json.BenchMeta) metameta,
in (struct) sparkles.test_runner.workload.WorkloadWindowOne measured window. Deliberately NOT BenchStats: its per-iteration
timing fields would misrepresent a single window — counter stats here are
window totals (iters == 1).
WorkloadWindow[] (parameter) const(sparkles.test_runner.workload.WorkloadWindow[]) windowswindows = null) @safe
{
import (package) stdstd.(package) std.algorithmalgorithm.(module) std.algorithm.sortingThis is a submodule of std.algorithm.
It contains generic sorting algorithms.
Function Name Description completeSort If a = [10, 20, 30] and b = [40, 6, 15], then completeSort(a, b) leaves a = [6, 10, 15] and b = [20, 30, 40]. The range a must be sorted prior to the call, and as a result the combination ``chain(a, b) is sorted. isPartitioned isPartitioned!"a < 0"([-1, -2, 1, 0, 2]) returns true because the predicate is true for a portion of the range and false afterwards. isSorted isSorted([1, 1, 2, 3]) returns true. isStrictlyMonotonic isStrictlyMonotonic([1, 1, 2, 3]) returns false. ordered ordered(1, 1, 2, 3) returns true. strictlyOrdered strictlyOrdered(1, 1, 2, 3) returns false. makeIndex Creates a separate index for a range. merge Lazily merges two or more sorted ranges. multiSort Sorts by multiple keys. nextEvenPermutation Computes the next lexicographically greater even permutation of a range in-place. nextPermutation Computes the next lexicographically greater permutation of a range in-place. nthPermutation Computes the nth permutation of a range in-place. partialSort If a = [5, 4, 3, 2, 1], then partialSort(a, 3) leaves a[0 .. 3] = [1, 2, 3]. The other elements of a are left in an unspecified order. partition Partitions a range according to a unary predicate. partition3 Partitions a range according to a binary predicate in three parts (less than, equal, greater than the given pivot). Pivot is not given as an index, but instead as an element independent from the range's content. pivotPartition Partitions a range according to a binary predicate in two parts: less than or equal, and greater than or equal to the given pivot, passed as an index in the range. schwartzSort Sorts with the help of the Schwartzian transform. sort Sorts. topN Separates the top elements in a range, akin to Quickselect. topNCopy Copies out the top elements of a range. topNIndex Builds an index of the top elements of a range.
Source
std/algorithm/sorting.d
sorting : (alias template) sort = std.algorithm.sorting.sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r)Sorts a random-access range according to the predicate less.
Performs $(BIGOH r.length * log(r.length)) evaluations of `less`. If `less` involves
expensive computations on the _sort key, it may be worthwhile to use
$(LREF schwartzSort) instead.
Stable sorting requires hasAssignableElements!Range to be true.
sort returns a $(REF SortedRange, std,range) over the original range,
allowing functions that can take advantage of sorted data to know that the
range is sorted and adjust accordingly. The $(REF SortedRange, std,range) is a
wrapper around the original range, so both it and the original range are sorted.
Other functions can't know that the original range has been sorted, but
they $(I can) know that $(REF SortedRange, std,range) has been sorted.
Preconditions:
The predicate is expected to satisfy certain rules in order for sort to
behave as expected - otherwise, the program may fail on certain inputs (but not
others) when not compiled in release mode, due to the cursory assumeSorted
check. Specifically, sort expects less(a,b) && less(b,c) to imply
less(a,c) (transitivity), and, conversely, !less(a,b) && !less(b,c) to
imply !less(a,c). Note that the default predicate ("a < b") does not
always satisfy these conditions for floating point types, because the expression
will always be false when either a or b is NaN.
Use $(REF cmp, std,math) instead.
Params:
less = The predicate to sort by.
ss = The swapping strategy to use.
r = The range to sort.
Returns: The initial range wrapped as a SortedRange with the predicate
binaryFun!less.
Algorithms: $(HTTP en.wikipedia.org/wiki/Introsort, Introsort) is used for unstable sorting and
$(HTTP en.wikipedia.org/wiki/Timsort, Timsort) is used for stable sorting.
Each algorithm has benefits beyond stability. Introsort is generally faster but
Timsort may achieve greater speeds on data with low entropy or if predicate calls
are expensive. Introsort performs no allocations whereas Timsort will perform one
or more allocations per call. Both algorithms have $(BIGOH n log n) worst-case
time complexity.
See_Also:
$(REF assumeSorted, std,range)$(BR)
$(REF SortedRange, std,range)$(BR)
$(REF SwapStrategy, std,algorithm,mutation)$(BR)
$(REF binaryFun, std,functional)
sort;
import (package) stdstd.(module) std.arrayFunctions and types that manipulate built-in arrays and associative arrays.
This module provides all kinds of functions to create, manipulate or convert arrays:
Function Name Description
| array |
Returns a copy of the input in a newly allocated dynamic array.
|
| appender |
Returns a new Appender or RefAppender initialized with a given array.
|
| assocArray |
Returns a newly allocated associative array from a range/ranges of keys and values.
|
| byPair |
Construct a range iterating over an associative array by key/value tuples.
|
| insertInPlace |
Inserts into an existing array at a given position.
|
| join |
Concatenates a range of ranges into one array.
|
| minimallyInitializedArray |
Returns a new array of type T.
|
| replace |
Returns a new array with all occurrences of a certain subrange replaced.
|
| replaceFirst |
Returns a new array with the first occurrence of a certain subrange replaced.
|
| replaceInPlace |
Replaces all occurrences of a certain subrange and puts the result into a given array.
|
| replaceInto |
Replaces all occurrences of a certain subrange and puts the result into an output range.
|
| replaceLast |
Returns a new array with the last occurrence of a certain subrange replaced.
|
| replaceSlice |
Returns a new array with a given slice replaced.
|
| replicate |
Creates a new array out of several copies of an input array or range.
|
| sameHead |
Checks if the initial segments of two arrays refer to the same
place in memory.
|
| sameTail |
Checks if the final segments of two arrays refer to the same place
in memory.
|
| split |
Eagerly split a range or string into an array.
|
| staticArray |
Creates a new static array from given data.
|
| uninitializedArray |
Returns a new array of type T without initializing its elements.
|
Source
std/array.d
array : (alias template) appender = std.array.appender(A)() if (isDynamicArray!A)Convenience function that returns an $(LREF Appender) instance,
optionally initialized with array.
appender;
import (package) stdstd.(module) std.convA one-stop shop for converting values from one type to another.
Category Functions Generic asOriginalType castFrom parse to toChars bitCast Strings text wtext dtext writeText writeWText writeDText hexString Numeric octal roundTo signed unsigned Exceptions ConvException ConvOverflowException
Source
std/conv.d
conv : (alias template) to = std.conv.to(T)The to template converts a value from one type _to another.
The source type is deduced and the target type must be specified, for example the
expression to!int(42.0) converts the number 42 from
double _to int. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., to!double(42) does not do
any checking because any int fits in a double.
Conversions from string _to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings _to signed types, the grammar recognized is:
$(PRE $(I Integer):
$(I Sign UnsignedInteger)
$(I UnsignedInteger)
$(I Sign):
$(B +)
$(B -))
For conversion _to unsigned types, the grammar recognized is:
$(PRE $(I UnsignedInteger):
$(I DecimalDigit)
$(I DecimalDigit) $(I UnsignedInteger))
to;
auto (local variable) std.array.Appender!string oo = std.array.Appender!string std.array.appender!string() pure nothrow @safeConvenience function that returns an Appender instance,
optionally initialized with array.
appender!(alias) object.string = stringstring;
(local variable) std.array.Appender!string oo ~= "{\n";
(local variable) std.array.Appender!string oo ~= " \"schema\": 2,\n";
(local variable) std.array.Appender!string oo ~= " \"meta\": {\n";
(local variable) std.array.Appender!string oo ~= " \"date\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((parameter) const(sparkles.test_runner.bench_json.BenchMeta) metameta.(field) string sparkles.test_runner.bench_json.BenchMeta.dateISO day, e.g. "2026-07-10"
date) ~ "\",\n";
(local variable) std.array.Appender!string oo ~= " \"hostname\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((parameter) const(sparkles.test_runner.bench_json.BenchMeta) metameta.(field) string sparkles.test_runner.bench_json.BenchMeta.hostname"" when unavailable
hostname) ~ "\",\n";
(local variable) std.array.Appender!string oo ~= " \"os\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((parameter) const(sparkles.test_runner.bench_json.BenchMeta) metameta.(field) string sparkles.test_runner.bench_json.BenchMeta.osos) ~ "\",\n";
(local variable) std.array.Appender!string oo ~= " \"arch\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((parameter) const(sparkles.test_runner.bench_json.BenchMeta) metameta.(field) string sparkles.test_runner.bench_json.BenchMeta.archarch) ~ "\",\n";
(local variable) std.array.Appender!string oo ~= " \"compiler\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((parameter) const(sparkles.test_runner.bench_json.BenchMeta) metameta.(field) string sparkles.test_runner.bench_json.BenchMeta.compilere.g. "LDC (front-end 2.111)"
compiler) ~ "\",\n";
(local variable) std.array.Appender!string oo ~= " \"cpu\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((parameter) const(sparkles.test_runner.bench_json.BenchMeta) metameta.(field) string sparkles.test_runner.bench_json.BenchMeta.cpu/proc/cpuinfo model name; "" off Linux
cpu) ~ "\",\n";
(local variable) std.array.Appender!string oo ~= " \"minSampleTimeMs\": " ~ (parameter) const(sparkles.test_runner.bench_json.BenchMeta) metameta.(field) long sparkles.test_runner.bench_json.BenchMeta.minSampleTimeMseffective per-sample/total budget (--bench-min-time)
minSampleTimeMs.string std.conv.to!string.to!(const(long))(const(long) __param_0) pure nothrow @safeThe to template converts a value from one type to another.
The source type is deduced and the target type must be specified, for example the
expression to`!int(42.0)` converts the number 42 from
`double` to `int`. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., ``to!double(42) does not do
any checking because any int fits in a double.
Conversions from string to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings to signed types, the grammar recognized is:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
Examples
Converting a value to its own type (useful mostly for generic code)
simply returns its argument.
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14
Converting among numeric types is a safe way to cast them around.
Conversions from floating-point types to integral types allow loss of
precision (the fractional part of a floating-point number). The
conversion is truncating towards zero, the same way a cast would
truncate. (To round a floating point value when casting to an
integral, use roundTo.)
import std.exception : assertThrown;
int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));
assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
When converting strings to numeric types, note that D hexadecimal and binary
literals are not handled. Neither the prefixes that indicate the base, nor the
horizontal bar used to separate groups of digits are recognized. This also
applies to the suffixes that indicate the type.
To work around this, you can specify a radix for conversions involving numbers.
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
Conversions from integral types to floating-point types always
succeed, but might lose accuracy. The largest integers with a
predecessor representable in floating-point format are 2^24-1 for
float, 2^53-1 for double, and 2^64-1 for real (when
real is 80-bit, e.g. on Intel machines).
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
Conversion from string types to char types enforces the input
to consist of a single code point, and said code point must
fit in the target type. Otherwise, ConvException is thrown.
import std.exception : assertThrown;
assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');
// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');
// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));
Converting an array to another array type works by converting each
element in turn. Associative arrays can be converted to associative
arrays as long as keys and values can in turn be converted.
import std.string : split;
int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
Conversions operate transitively, meaning that they work on arrays and
associative arrays of any complexity.
This conversion works because to`!short` applies to an `int`, to!wstring
applies to a string, to`!string` applies to a `double`, and
to!(double[]) applies to an int[]. The conversion might throw an
exception because ``to!short might fail the range check.
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
Object-to-object conversions by dynamic casting throw exception when
the source is non-null and the target is null.
import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
Stringize conversion from all types is supported.
String to string conversion works for any two string types having
(char, wchar, dchar) character widths and any
combination of qualifiers (mutable, const, or immutable).
Converts array (other than strings) to string.
Each element is converted by calling ``to!T.
Associative array to string conversion.
Each element is converted by calling ``to!T.
Object to string conversion calls toString against the object or
returns "null" if the object is null.
Struct to string conversion calls toString against the struct if
it is defined.
For structs that do not define toString, the conversion to string
produces the list of fields.
Enumerated types are converted to strings as their symbolic names.
Boolean values are converted to "true" or "false".
char, wchar, dchar to a string type.
Unsigned or signed integers to strings.
: Convert integral value to string in radix radix.
radix must be a value from 2 to 36.
value is treated as a signed value only if radix is 10.
The characters A through Z are used to represent values 10 through 36
and their case is determined by the letterCase parameter.
All floating point types to all string types.
Pointer to string conversions convert the pointer to a size_t value.
If pointer is char*, treat it as C-style strings.
In that case, this function is @system.
See formatValue on how toString should be defined.
// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");
// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
to!string(associativeArray) == `["1":2, "0":1]`);
// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");
// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);
auto c = to!(wchar[])(b);
assert(c == "abcx");
Strings can be converted to enum types. The enum member with the same name as the
input string is returned. The comparison is case-sensitive.
A ConvException is thrown if the enum does not have the specified member.
import std.exception : assertThrown;
enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to!(alias) object.string = stringstring ~ ",\n";
(local variable) std.array.Appender!string oo ~= " \"sampleCount\": " ~ (parameter) const(sparkles.test_runner.bench_json.BenchMeta) metameta.(field) uint sparkles.test_runner.bench_json.BenchMeta.sampleCounteffective BenchConfig.sampleCount
sampleCount.string std.conv.to!string.to!(const(uint))(const(uint) __param_0) pure nothrow @safeThe to template converts a value from one type to another.
The source type is deduced and the target type must be specified, for example the
expression to`!int(42.0)` converts the number 42 from
`double` to `int`. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., ``to!double(42) does not do
any checking because any int fits in a double.
Conversions from string to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings to signed types, the grammar recognized is:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
Examples
Converting a value to its own type (useful mostly for generic code)
simply returns its argument.
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14
Converting among numeric types is a safe way to cast them around.
Conversions from floating-point types to integral types allow loss of
precision (the fractional part of a floating-point number). The
conversion is truncating towards zero, the same way a cast would
truncate. (To round a floating point value when casting to an
integral, use roundTo.)
import std.exception : assertThrown;
int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));
assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
When converting strings to numeric types, note that D hexadecimal and binary
literals are not handled. Neither the prefixes that indicate the base, nor the
horizontal bar used to separate groups of digits are recognized. This also
applies to the suffixes that indicate the type.
To work around this, you can specify a radix for conversions involving numbers.
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
Conversions from integral types to floating-point types always
succeed, but might lose accuracy. The largest integers with a
predecessor representable in floating-point format are 2^24-1 for
float, 2^53-1 for double, and 2^64-1 for real (when
real is 80-bit, e.g. on Intel machines).
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
Conversion from string types to char types enforces the input
to consist of a single code point, and said code point must
fit in the target type. Otherwise, ConvException is thrown.
import std.exception : assertThrown;
assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');
// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');
// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));
Converting an array to another array type works by converting each
element in turn. Associative arrays can be converted to associative
arrays as long as keys and values can in turn be converted.
import std.string : split;
int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
Conversions operate transitively, meaning that they work on arrays and
associative arrays of any complexity.
This conversion works because to`!short` applies to an `int`, to!wstring
applies to a string, to`!string` applies to a `double`, and
to!(double[]) applies to an int[]. The conversion might throw an
exception because ``to!short might fail the range check.
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
Object-to-object conversions by dynamic casting throw exception when
the source is non-null and the target is null.
import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
Stringize conversion from all types is supported.
String to string conversion works for any two string types having
(char, wchar, dchar) character widths and any
combination of qualifiers (mutable, const, or immutable).
Converts array (other than strings) to string.
Each element is converted by calling ``to!T.
Associative array to string conversion.
Each element is converted by calling ``to!T.
Object to string conversion calls toString against the object or
returns "null" if the object is null.
Struct to string conversion calls toString against the struct if
it is defined.
For structs that do not define toString, the conversion to string
produces the list of fields.
Enumerated types are converted to strings as their symbolic names.
Boolean values are converted to "true" or "false".
char, wchar, dchar to a string type.
Unsigned or signed integers to strings.
: Convert integral value to string in radix radix.
radix must be a value from 2 to 36.
value is treated as a signed value only if radix is 10.
The characters A through Z are used to represent values 10 through 36
and their case is determined by the letterCase parameter.
All floating point types to all string types.
Pointer to string conversions convert the pointer to a size_t value.
If pointer is char*, treat it as C-style strings.
In that case, this function is @system.
See formatValue on how toString should be defined.
// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");
// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
to!string(associativeArray) == `["1":2, "0":1]`);
// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");
// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);
auto c = to!(wchar[])(b);
assert(c == "abcx");
Strings can be converted to enum types. The enum member with the same name as the
input string is returned. The comparison is case-sensitive.
A ConvException is thrown if the enum does not have the specified member.
import std.exception : assertThrown;
enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to!(alias) object.string = stringstring;
// Suite-registered provenance (benchProvenance) — only when present, so
// a suite that registers nothing keeps the pre-provenance meta shape.
if ((parameter) const(sparkles.test_runner.bench_json.BenchMeta) metameta.(field) const(string)[] sparkles.test_runner.bench_json.BenchMeta.provenancesuite-registered lines (benchProvenance)
provenance.(field) ulong const(string[]).lengthlength)
{
(local variable) std.array.Appender!string oo ~= ",\n \"provenance\": [";
foreach ((parameter) ulong ii, (parameter) const(string) lineline; (parameter) const(sparkles.test_runner.bench_json.BenchMeta) metameta.(field) const(string)[] sparkles.test_runner.bench_json.BenchMeta.provenancesuite-registered lines (benchProvenance)
provenance)
{
(local variable) std.array.Appender!string oo ~= (local variable) ulong ii ? ", " : " ";
(local variable) std.array.Appender!string oo ~= "\"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((local variable) const(string) lineline) ~ "\"";
}
(local variable) std.array.Appender!string oo ~= " ]";
}
(local variable) std.array.Appender!string oo ~= "\n },\n";
(local variable) std.array.Appender!string oo ~= " \"columns\": [";
bool (local variable) bool firstColfirstCol = true;
foreach (ref (parameter) sparkles.test_runner.metrics.MetricDescriptor dd; sparkles.test_runner.metrics.MetricDescriptor[] sparkles.test_runner.metrics.catalog(in sparkles.test_runner.bench.BenchStats[] rows) pure nothrow @safeThe catalog across all rows: client columns (first-seen order, always
available) followed by the perf family (available iff any row carries
counters). This is the universe --list-metrics and --metrics range over.
catalog((parameter) const(sparkles.test_runner.bench.BenchStats[]) rowsrows))
{
if (!(local variable) sparkles.test_runner.metrics.MetricDescriptor dd.(field) bool sparkles.test_runner.metrics.MetricDescriptor.availableproducible on this run (perf opened / present in the rows)
available)
continue;
(local variable) std.array.Appender!string oo ~= (local variable) bool firstColfirstCol ? "\n" : ",\n";
(local variable) bool firstColfirstCol = false;
(local variable) std.array.Appender!string oo ~= " { \"name\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((local variable) sparkles.test_runner.metrics.MetricDescriptor dd.(field) string sparkles.test_runner.metrics.MetricDescriptor.namename)
~ "\", \"header\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((local variable) sparkles.test_runner.metrics.MetricDescriptor dd.(field) string sparkles.test_runner.metrics.MetricDescriptor.headerheader)
~ "\", \"format\": \"" ~ (local variable) sparkles.test_runner.metrics.MetricDescriptor dd.(field) sparkles.test_runner.metrics.MetricFormat sparkles.test_runner.metrics.MetricDescriptor.formatformat.string std.conv.to!string.to!(sparkles.test_runner.metrics.MetricFormat)(sparkles.test_runner.metrics.MetricFormat __param_0) pure @safeThe to template converts a value from one type to another.
The source type is deduced and the target type must be specified, for example the
expression to`!int(42.0)` converts the number 42 from
`double` to `int`. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., ``to!double(42) does not do
any checking because any int fits in a double.
Conversions from string to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings to signed types, the grammar recognized is:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
Examples
Converting a value to its own type (useful mostly for generic code)
simply returns its argument.
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14
Converting among numeric types is a safe way to cast them around.
Conversions from floating-point types to integral types allow loss of
precision (the fractional part of a floating-point number). The
conversion is truncating towards zero, the same way a cast would
truncate. (To round a floating point value when casting to an
integral, use roundTo.)
import std.exception : assertThrown;
int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));
assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
When converting strings to numeric types, note that D hexadecimal and binary
literals are not handled. Neither the prefixes that indicate the base, nor the
horizontal bar used to separate groups of digits are recognized. This also
applies to the suffixes that indicate the type.
To work around this, you can specify a radix for conversions involving numbers.
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
Conversions from integral types to floating-point types always
succeed, but might lose accuracy. The largest integers with a
predecessor representable in floating-point format are 2^24-1 for
float, 2^53-1 for double, and 2^64-1 for real (when
real is 80-bit, e.g. on Intel machines).
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
Conversion from string types to char types enforces the input
to consist of a single code point, and said code point must
fit in the target type. Otherwise, ConvException is thrown.
import std.exception : assertThrown;
assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');
// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');
// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));
Converting an array to another array type works by converting each
element in turn. Associative arrays can be converted to associative
arrays as long as keys and values can in turn be converted.
import std.string : split;
int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
Conversions operate transitively, meaning that they work on arrays and
associative arrays of any complexity.
This conversion works because to`!short` applies to an `int`, to!wstring
applies to a string, to`!string` applies to a `double`, and
to!(double[]) applies to an int[]. The conversion might throw an
exception because ``to!short might fail the range check.
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
Object-to-object conversions by dynamic casting throw exception when
the source is non-null and the target is null.
import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
Stringize conversion from all types is supported.
String to string conversion works for any two string types having
(char, wchar, dchar) character widths and any
combination of qualifiers (mutable, const, or immutable).
Converts array (other than strings) to string.
Each element is converted by calling ``to!T.
Associative array to string conversion.
Each element is converted by calling ``to!T.
Object to string conversion calls toString against the object or
returns "null" if the object is null.
Struct to string conversion calls toString against the struct if
it is defined.
For structs that do not define toString, the conversion to string
produces the list of fields.
Enumerated types are converted to strings as their symbolic names.
Boolean values are converted to "true" or "false".
char, wchar, dchar to a string type.
Unsigned or signed integers to strings.
: Convert integral value to string in radix radix.
radix must be a value from 2 to 36.
value is treated as a signed value only if radix is 10.
The characters A through Z are used to represent values 10 through 36
and their case is determined by the letterCase parameter.
All floating point types to all string types.
Pointer to string conversions convert the pointer to a size_t value.
If pointer is char*, treat it as C-style strings.
In that case, this function is @system.
See formatValue on how toString should be defined.
// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");
// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
to!string(associativeArray) == `["1":2, "0":1]`);
// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");
// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);
auto c = to!(wchar[])(b);
assert(c == "abcx");
Strings can be converted to enum types. The enum member with the same name as the
input string is returned. The comparison is case-sensitive.
A ConvException is thrown if the enum does not have the specified member.
import std.exception : assertThrown;
enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to!(alias) object.string = stringstring
~ "\", \"class\": \"" ~ (local variable) sparkles.test_runner.metrics.MetricDescriptor dd.(field) sparkles.test_runner.metrics.MetricClass sparkles.test_runner.metrics.MetricDescriptor.clscls.string std.conv.to!string.to!(sparkles.test_runner.metrics.MetricClass)(sparkles.test_runner.metrics.MetricClass __param_0) pure @safeThe to template converts a value from one type to another.
The source type is deduced and the target type must be specified, for example the
expression to`!int(42.0)` converts the number 42 from
`double` to `int`. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., ``to!double(42) does not do
any checking because any int fits in a double.
Conversions from string to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings to signed types, the grammar recognized is:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
Examples
Converting a value to its own type (useful mostly for generic code)
simply returns its argument.
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14
Converting among numeric types is a safe way to cast them around.
Conversions from floating-point types to integral types allow loss of
precision (the fractional part of a floating-point number). The
conversion is truncating towards zero, the same way a cast would
truncate. (To round a floating point value when casting to an
integral, use roundTo.)
import std.exception : assertThrown;
int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));
assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
When converting strings to numeric types, note that D hexadecimal and binary
literals are not handled. Neither the prefixes that indicate the base, nor the
horizontal bar used to separate groups of digits are recognized. This also
applies to the suffixes that indicate the type.
To work around this, you can specify a radix for conversions involving numbers.
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
Conversions from integral types to floating-point types always
succeed, but might lose accuracy. The largest integers with a
predecessor representable in floating-point format are 2^24-1 for
float, 2^53-1 for double, and 2^64-1 for real (when
real is 80-bit, e.g. on Intel machines).
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
Conversion from string types to char types enforces the input
to consist of a single code point, and said code point must
fit in the target type. Otherwise, ConvException is thrown.
import std.exception : assertThrown;
assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');
// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');
// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));
Converting an array to another array type works by converting each
element in turn. Associative arrays can be converted to associative
arrays as long as keys and values can in turn be converted.
import std.string : split;
int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
Conversions operate transitively, meaning that they work on arrays and
associative arrays of any complexity.
This conversion works because to`!short` applies to an `int`, to!wstring
applies to a string, to`!string` applies to a `double`, and
to!(double[]) applies to an int[]. The conversion might throw an
exception because ``to!short might fail the range check.
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
Object-to-object conversions by dynamic casting throw exception when
the source is non-null and the target is null.
import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
Stringize conversion from all types is supported.
String to string conversion works for any two string types having
(char, wchar, dchar) character widths and any
combination of qualifiers (mutable, const, or immutable).
Converts array (other than strings) to string.
Each element is converted by calling ``to!T.
Associative array to string conversion.
Each element is converted by calling ``to!T.
Object to string conversion calls toString against the object or
returns "null" if the object is null.
Struct to string conversion calls toString against the struct if
it is defined.
For structs that do not define toString, the conversion to string
produces the list of fields.
Enumerated types are converted to strings as their symbolic names.
Boolean values are converted to "true" or "false".
char, wchar, dchar to a string type.
Unsigned or signed integers to strings.
: Convert integral value to string in radix radix.
radix must be a value from 2 to 36.
value is treated as a signed value only if radix is 10.
The characters A through Z are used to represent values 10 through 36
and their case is determined by the letterCase parameter.
All floating point types to all string types.
Pointer to string conversions convert the pointer to a size_t value.
If pointer is char*, treat it as C-style strings.
In that case, this function is @system.
See formatValue on how toString should be defined.
// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");
// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
to!string(associativeArray) == `["1":2, "0":1]`);
// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");
// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);
auto c = to!(wchar[])(b);
assert(c == "abcx");
Strings can be converted to enum types. The enum member with the same name as the
input string is returned. The comparison is case-sensitive.
A ConvException is thrown if the enum does not have the specified member.
import std.exception : assertThrown;
enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to!(alias) object.string = stringstring
~ "\", \"source\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((local variable) sparkles.test_runner.metrics.MetricDescriptor dd.(field) string sparkles.test_runner.metrics.MetricDescriptor.source"client" | "perf" (later: "tier0" | "syscall")
source) ~ "\" }";
}
(local variable) std.array.Appender!string oo ~= (local variable) bool firstColfirstCol ? "],\n" : "\n ],\n";
(local variable) std.array.Appender!string oo ~= " \"rows\": [";
foreach ((parameter) ulong riri, ref (parameter) const(sparkles.test_runner.bench.BenchStats) rowrow; (parameter) const(sparkles.test_runner.bench.BenchStats[]) rowsrows)
{
(local variable) std.array.Appender!string oo ~= (local variable) ulong riri ? ",\n" : "\n";
const (local variable) const(bool) isErrorisError = (local variable) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) string sparkles.test_runner.bench.BenchStats.errornon-empty = an error row (a case whose after reported failure)
error.(field) ulong const(string).lengthlength > 0;
(local variable) std.array.Appender!string oo ~= " {\n";
(local variable) std.array.Appender!string oo ~= " \"name\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((local variable) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) string sparkles.test_runner.bench.BenchStats.namename) ~ "\",\n";
(local variable) std.array.Appender!string oo ~= " \"labels\": {";
auto (local variable) string[] keyskeys = (local variable) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) string[string] sparkles.test_runner.bench.BenchStats.labelsorthogonal grouping dimensions (from the case's labels)
labels.string[] object.keys!(const(string), string)(inout(const(string)[string]) aa) pure nothrow @property @safeReturns a newly allocated dynamic array containing a copy of the keys from
the associative array.
Note
emulated by the compiler during CTFE
keys;
(local variable) string[] keyskeys.std.range.SortedRange!(string[], "a < b", SortedRangeOptions.assumeSorted) std.algorithm.sorting.sort!("a < b", SwapStrategy.unstable, string[])(string[] r) pure nothrow @nogc @safeSorts a random-access range according to the predicate less.
Performs O(r.length * log(r.length)) evaluations of less. If less involves
expensive computations on the sort key, it may be worthwhile to use
schwartzSort instead.
Stable sorting requires hasAssignableElements!Range to be true.
sort returns a SortedRange over the original range,
allowing functions that can take advantage of sorted data to know that the
range is sorted and adjust accordingly. The SortedRange is a
wrapper around the original range, so both it and the original range are sorted.
Other functions can't know that the original range has been sorted, but
they can know that SortedRange has been sorted.
Preconditions
The predicate is expected to satisfy certain rules in order for sort to
behave as expected - otherwise, the program may fail on certain inputs (but not
others) when not compiled in release mode, due to the cursory assumeSorted
check. Specifically, sort expects less(a,b) && less(b,c) to imply
less(a,c) (transitivity), and, conversely, !less(a,b) && !less(b,c) to
imply !less(a,c). Note that the default predicate ("a < b") does not
always satisfy these conditions for floating point types, because the expression
will always be false when either a or b is NaN.
Use cmp instead.
Algorithms
Introsort is used for unstable sorting and
Timsort is used for stable sorting.
Each algorithm has benefits beyond stability. Introsort is generally faster but
Timsort may achieve greater speeds on data with low entropy or if predicate calls
are expensive. Introsort performs no allocations whereas Timsort will perform one
or more allocations per call. Both algorithms have O(n log n) worst-case
time complexity.
Examples
int[] array = [ 1, 2, 3, 4 ];
// sort in descending order
array.sort!("a > b");
assert(array == [ 4, 3, 2, 1 ]);
// sort in ascending order
array.sort();
assert(array == [ 1, 2, 3, 4 ]);
// sort with reusable comparator and chain
alias myComp = (x, y) => x > y;
assert(array.sort!(myComp).release == [ 4, 3, 2, 1 ]);
// Showcase stable sorting
import std.algorithm.mutation : SwapStrategy;
string[] words = [ "aBc", "a", "abc", "b", "ABC", "c" ];
sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable)(words);
assert(words == [ "a", "aBc", "abc", "ABC", "b", "c" ]);
// Sorting floating-point numbers in presence of NaN
double[] numbers = [-0.0, 3.0, -2.0, double.nan, 0.0, -double.nan];
import std.algorithm.comparison : equal;
import std.math.operations : cmp;
import std.math.traits : isIdentical;
sort!((a, b) => cmp(a, b) < 0)(numbers);
double[] sorted = [-double.nan, -2.0, -0.0, 0.0, 3.0, double.nan];
assert(numbers.equal!isIdentical(sorted));
sort; // AA order is unspecified; baselines must be byte-stable
foreach ((parameter) ulong kiki, (parameter) string kk; (local variable) string[] keyskeys)
{
(local variable) std.array.Appender!string oo ~= (local variable) ulong kiki ? ", " : " ";
(local variable) std.array.Appender!string oo ~= "\"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((local variable) string kk) ~ "\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((local variable) const(string)* __aaget1277row.(local variable) const(string)* __aaget1277labels[(local variable) string kk]) ~ "\"";
}
(local variable) std.array.Appender!string oo ~= (local variable) string[] keyskeys.(field) ulong string[].lengthlength ? " },\n" : "},\n";
if ((local variable) const(bool) isErrorisError)
{
(local variable) std.array.Appender!string oo ~= " \"iterations\": null,\n";
(local variable) std.array.Appender!string oo ~= " \"samples\": null,\n";
(local variable) std.array.Appender!string oo ~= " \"medianNs\": null,\n";
(local variable) std.array.Appender!string oo ~= " \"deviationNs\": null,\n";
(local variable) std.array.Appender!string oo ~= " \"minNs\": null,\n";
(local variable) std.array.Appender!string oo ~= " \"maxNs\": null,\n";
(local variable) std.array.Appender!string oo ~= " \"metrics\": {},\n";
}
else
{
(local variable) std.array.Appender!string oo ~= " \"iterations\": " ~ (local variable) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) ulong sparkles.test_runner.bench.BenchStats.iterationsiterations per sample
iterations.string std.conv.to!string.to!(const(ulong))(const(ulong) __param_0) pure nothrow @safeThe to template converts a value from one type to another.
The source type is deduced and the target type must be specified, for example the
expression to`!int(42.0)` converts the number 42 from
`double` to `int`. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., ``to!double(42) does not do
any checking because any int fits in a double.
Conversions from string to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings to signed types, the grammar recognized is:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
Examples
Converting a value to its own type (useful mostly for generic code)
simply returns its argument.
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14
Converting among numeric types is a safe way to cast them around.
Conversions from floating-point types to integral types allow loss of
precision (the fractional part of a floating-point number). The
conversion is truncating towards zero, the same way a cast would
truncate. (To round a floating point value when casting to an
integral, use roundTo.)
import std.exception : assertThrown;
int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));
assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
When converting strings to numeric types, note that D hexadecimal and binary
literals are not handled. Neither the prefixes that indicate the base, nor the
horizontal bar used to separate groups of digits are recognized. This also
applies to the suffixes that indicate the type.
To work around this, you can specify a radix for conversions involving numbers.
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
Conversions from integral types to floating-point types always
succeed, but might lose accuracy. The largest integers with a
predecessor representable in floating-point format are 2^24-1 for
float, 2^53-1 for double, and 2^64-1 for real (when
real is 80-bit, e.g. on Intel machines).
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
Conversion from string types to char types enforces the input
to consist of a single code point, and said code point must
fit in the target type. Otherwise, ConvException is thrown.
import std.exception : assertThrown;
assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');
// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');
// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));
Converting an array to another array type works by converting each
element in turn. Associative arrays can be converted to associative
arrays as long as keys and values can in turn be converted.
import std.string : split;
int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
Conversions operate transitively, meaning that they work on arrays and
associative arrays of any complexity.
This conversion works because to`!short` applies to an `int`, to!wstring
applies to a string, to`!string` applies to a `double`, and
to!(double[]) applies to an int[]. The conversion might throw an
exception because ``to!short might fail the range check.
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
Object-to-object conversions by dynamic casting throw exception when
the source is non-null and the target is null.
import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
Stringize conversion from all types is supported.
String to string conversion works for any two string types having
(char, wchar, dchar) character widths and any
combination of qualifiers (mutable, const, or immutable).
Converts array (other than strings) to string.
Each element is converted by calling ``to!T.
Associative array to string conversion.
Each element is converted by calling ``to!T.
Object to string conversion calls toString against the object or
returns "null" if the object is null.
Struct to string conversion calls toString against the struct if
it is defined.
For structs that do not define toString, the conversion to string
produces the list of fields.
Enumerated types are converted to strings as their symbolic names.
Boolean values are converted to "true" or "false".
char, wchar, dchar to a string type.
Unsigned or signed integers to strings.
: Convert integral value to string in radix radix.
radix must be a value from 2 to 36.
value is treated as a signed value only if radix is 10.
The characters A through Z are used to represent values 10 through 36
and their case is determined by the letterCase parameter.
All floating point types to all string types.
Pointer to string conversions convert the pointer to a size_t value.
If pointer is char*, treat it as C-style strings.
In that case, this function is @system.
See formatValue on how toString should be defined.
// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");
// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
to!string(associativeArray) == `["1":2, "0":1]`);
// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");
// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);
auto c = to!(wchar[])(b);
assert(c == "abcx");
Strings can be converted to enum types. The enum member with the same name as the
input string is returned. The comparison is case-sensitive.
A ConvException is thrown if the enum does not have the specified member.
import std.exception : assertThrown;
enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to!(alias) object.string = stringstring ~ ",\n";
(local variable) std.array.Appender!string oo ~= " \"samples\": " ~ (local variable) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) ulong sparkles.test_runner.bench.BenchStats.samplessamples.string std.conv.to!string.to!(const(ulong))(const(ulong) __param_0) pure nothrow @safeThe to template converts a value from one type to another.
The source type is deduced and the target type must be specified, for example the
expression to`!int(42.0)` converts the number 42 from
`double` to `int`. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., ``to!double(42) does not do
any checking because any int fits in a double.
Conversions from string to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings to signed types, the grammar recognized is:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
Examples
Converting a value to its own type (useful mostly for generic code)
simply returns its argument.
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14
Converting among numeric types is a safe way to cast them around.
Conversions from floating-point types to integral types allow loss of
precision (the fractional part of a floating-point number). The
conversion is truncating towards zero, the same way a cast would
truncate. (To round a floating point value when casting to an
integral, use roundTo.)
import std.exception : assertThrown;
int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));
assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
When converting strings to numeric types, note that D hexadecimal and binary
literals are not handled. Neither the prefixes that indicate the base, nor the
horizontal bar used to separate groups of digits are recognized. This also
applies to the suffixes that indicate the type.
To work around this, you can specify a radix for conversions involving numbers.
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
Conversions from integral types to floating-point types always
succeed, but might lose accuracy. The largest integers with a
predecessor representable in floating-point format are 2^24-1 for
float, 2^53-1 for double, and 2^64-1 for real (when
real is 80-bit, e.g. on Intel machines).
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
Conversion from string types to char types enforces the input
to consist of a single code point, and said code point must
fit in the target type. Otherwise, ConvException is thrown.
import std.exception : assertThrown;
assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');
// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');
// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));
Converting an array to another array type works by converting each
element in turn. Associative arrays can be converted to associative
arrays as long as keys and values can in turn be converted.
import std.string : split;
int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
Conversions operate transitively, meaning that they work on arrays and
associative arrays of any complexity.
This conversion works because to`!short` applies to an `int`, to!wstring
applies to a string, to`!string` applies to a `double`, and
to!(double[]) applies to an int[]. The conversion might throw an
exception because ``to!short might fail the range check.
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
Object-to-object conversions by dynamic casting throw exception when
the source is non-null and the target is null.
import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
Stringize conversion from all types is supported.
String to string conversion works for any two string types having
(char, wchar, dchar) character widths and any
combination of qualifiers (mutable, const, or immutable).
Converts array (other than strings) to string.
Each element is converted by calling ``to!T.
Associative array to string conversion.
Each element is converted by calling ``to!T.
Object to string conversion calls toString against the object or
returns "null" if the object is null.
Struct to string conversion calls toString against the struct if
it is defined.
For structs that do not define toString, the conversion to string
produces the list of fields.
Enumerated types are converted to strings as their symbolic names.
Boolean values are converted to "true" or "false".
char, wchar, dchar to a string type.
Unsigned or signed integers to strings.
: Convert integral value to string in radix radix.
radix must be a value from 2 to 36.
value is treated as a signed value only if radix is 10.
The characters A through Z are used to represent values 10 through 36
and their case is determined by the letterCase parameter.
All floating point types to all string types.
Pointer to string conversions convert the pointer to a size_t value.
If pointer is char*, treat it as C-style strings.
In that case, this function is @system.
See formatValue on how toString should be defined.
// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");
// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
to!string(associativeArray) == `["1":2, "0":1]`);
// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");
// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);
auto c = to!(wchar[])(b);
assert(c == "abcx");
Strings can be converted to enum types. The enum member with the same name as the
input string is returned. The comparison is case-sensitive.
A ConvException is thrown if the enum does not have the specified member.
import std.exception : assertThrown;
enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to!(alias) object.string = stringstring ~ ",\n";
(local variable) std.array.Appender!string oo ~= " \"medianNs\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) double sparkles.test_runner.bench.BenchStats.nsPerIterMediannsPerIterMedian) ~ ",\n";
(local variable) std.array.Appender!string oo ~= " \"deviationNs\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) double sparkles.test_runner.bench.BenchStats.nsPerIterDeviationmedian absolute deviation
nsPerIterDeviation) ~ ",\n";
(local variable) std.array.Appender!string oo ~= " \"minNs\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) double sparkles.test_runner.bench.BenchStats.nsPerIterMinnsPerIterMin) ~ ",\n";
(local variable) std.array.Appender!string oo ~= " \"maxNs\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) double sparkles.test_runner.bench.BenchStats.nsPerIterMaxnsPerIterMax) ~ ",\n";
(local variable) std.array.Appender!string oo ~= " \"metrics\": {";
bool (local variable) bool firstCellfirstCell = true;
(alias) object.string = stringstring (local variable) string estimatedestimated;
foreach (ref (parameter) sparkles.test_runner.metrics.MetricCell cc; sparkles.test_runner.metrics.MetricCell[] sparkles.test_runner.metrics.rowCells(in sparkles.test_runner.bench.BenchStats row) pure nothrow @safeEvery metric cell of one row: client columns first (in call order), then perf,
then tier0 — each present only when the row carries that source.
rowCells((local variable) const(sparkles.test_runner.bench.BenchStats) rowrow))
{
(local variable) std.array.Appender!string oo ~= (local variable) bool firstCellfirstCell ? " " : ", ";
(local variable) bool firstCellfirstCell = false;
(local variable) std.array.Appender!string oo ~= "\"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((local variable) sparkles.test_runner.metrics.MetricCell cc.(field) string sparkles.test_runner.metrics.MetricCell.namestable id, e.g. "ipc", "instr", "B/s"
name) ~ "\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) sparkles.test_runner.metrics.MetricCell cc.(field) double sparkles.test_runner.metrics.MetricCell.valuevalue);
if ((local variable) sparkles.test_runner.metrics.MetricCell cc.(field) bool sparkles.test_runner.metrics.MetricCell.estimatedmultiplex-scaled estimate, not an exact count (rendered ≈)
estimated)
(local variable) string estimatedestimated ~= ((local variable) string estimatedestimated.(field) ulong string.lengthlength ? ", \"" : "\"")
~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((local variable) sparkles.test_runner.metrics.MetricCell cc.(field) string sparkles.test_runner.metrics.MetricCell.namestable id, e.g. "ipc", "instr", "B/s"
name) ~ "\"";
}
(local variable) std.array.Appender!string oo ~= (local variable) bool firstCellfirstCell ? "},\n" : " },\n";
// Multiplex-scaled estimates are labeled machine-readably too, so
// a baseline comparison never mistakes an estimate for an exact
// count (schema 2; absent = every metric exact).
if ((local variable) string estimatedestimated.(field) ulong string.lengthlength)
(local variable) std.array.Appender!string oo ~= " \"estimatedMetrics\": [ " ~ (local variable) string estimatedestimated ~ " ],\n";
// The effective counting-pass iteration count (shared by every
// counter tier), so per-pass totals are auditable — a validator
// can multiply per-iteration cells back to what the pass counted.
// Absent when no counting pass ran (schema 2).
if (const (local variable) const(ulong) cici = ulong sparkles.test_runner.bench_json.countIterations(in sparkles.test_runner.bench.BenchStats row) pure nothrow @nogc @safeThe row's counting-pass iteration count: every counter tier shares one
per-pass count, so the first present source carries it. 0 = no counting
pass ran.
countIterations((local variable) const(sparkles.test_runner.bench.BenchStats) rowrow))
(local variable) std.array.Appender!string oo ~= " \"countIterations\": " ~ (local variable) const(ulong) cici.string std.conv.to!string.to!(const(ulong))(const(ulong) __param_0) pure nothrow @safeThe to template converts a value from one type to another.
The source type is deduced and the target type must be specified, for example the
expression to`!int(42.0)` converts the number 42 from
`double` to `int`. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., ``to!double(42) does not do
any checking because any int fits in a double.
Conversions from string to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings to signed types, the grammar recognized is:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
Examples
Converting a value to its own type (useful mostly for generic code)
simply returns its argument.
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14
Converting among numeric types is a safe way to cast them around.
Conversions from floating-point types to integral types allow loss of
precision (the fractional part of a floating-point number). The
conversion is truncating towards zero, the same way a cast would
truncate. (To round a floating point value when casting to an
integral, use roundTo.)
import std.exception : assertThrown;
int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));
assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
When converting strings to numeric types, note that D hexadecimal and binary
literals are not handled. Neither the prefixes that indicate the base, nor the
horizontal bar used to separate groups of digits are recognized. This also
applies to the suffixes that indicate the type.
To work around this, you can specify a radix for conversions involving numbers.
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
Conversions from integral types to floating-point types always
succeed, but might lose accuracy. The largest integers with a
predecessor representable in floating-point format are 2^24-1 for
float, 2^53-1 for double, and 2^64-1 for real (when
real is 80-bit, e.g. on Intel machines).
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
Conversion from string types to char types enforces the input
to consist of a single code point, and said code point must
fit in the target type. Otherwise, ConvException is thrown.
import std.exception : assertThrown;
assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');
// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');
// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));
Converting an array to another array type works by converting each
element in turn. Associative arrays can be converted to associative
arrays as long as keys and values can in turn be converted.
import std.string : split;
int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
Conversions operate transitively, meaning that they work on arrays and
associative arrays of any complexity.
This conversion works because to`!short` applies to an `int`, to!wstring
applies to a string, to`!string` applies to a `double`, and
to!(double[]) applies to an int[]. The conversion might throw an
exception because ``to!short might fail the range check.
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
Object-to-object conversions by dynamic casting throw exception when
the source is non-null and the target is null.
import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
Stringize conversion from all types is supported.
String to string conversion works for any two string types having
(char, wchar, dchar) character widths and any
combination of qualifiers (mutable, const, or immutable).
Converts array (other than strings) to string.
Each element is converted by calling ``to!T.
Associative array to string conversion.
Each element is converted by calling ``to!T.
Object to string conversion calls toString against the object or
returns "null" if the object is null.
Struct to string conversion calls toString against the struct if
it is defined.
For structs that do not define toString, the conversion to string
produces the list of fields.
Enumerated types are converted to strings as their symbolic names.
Boolean values are converted to "true" or "false".
char, wchar, dchar to a string type.
Unsigned or signed integers to strings.
: Convert integral value to string in radix radix.
radix must be a value from 2 to 36.
value is treated as a signed value only if radix is 10.
The characters A through Z are used to represent values 10 through 36
and their case is determined by the letterCase parameter.
All floating point types to all string types.
Pointer to string conversions convert the pointer to a size_t value.
If pointer is char*, treat it as C-style strings.
In that case, this function is @system.
See formatValue on how toString should be defined.
// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");
// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
to!string(associativeArray) == `["1":2, "0":1]`);
// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");
// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);
auto c = to!(wchar[])(b);
assert(c == "abcx");
Strings can be converted to enum types. The enum member with the same name as the
input string is returned. The comparison is case-sensitive.
A ConvException is thrown if the enum does not have the specified member.
import std.exception : assertThrown;
enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to!(alias) object.string = stringstring ~ ",\n";
}
(local variable) std.array.Appender!string oo ~= " \"error\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((local variable) const(sparkles.test_runner.bench.BenchStats) rowrow.(field) string sparkles.test_runner.bench.BenchStats.errornon-empty = an error row (a case whose after reported failure)
error) ~ "\"\n";
(local variable) std.array.Appender!string oo ~= " }";
}
(local variable) std.array.Appender!string oo ~= (parameter) const(sparkles.test_runner.bench.BenchStats[]) rowsrows.(field) ulong const(sparkles.test_runner.bench.BenchStats[]).lengthlength ? "\n ]" : "]";
if ((parameter) const(sparkles.test_runner.workload.WorkloadWindow[]) windowswindows.(field) ulong const(sparkles.test_runner.workload.WorkloadWindow[]).lengthlength)
{
(local variable) std.array.Appender!string oo ~= ",\n \"windows\": [";
foreach ((parameter) ulong wiwi, ref (parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww; (parameter) const(sparkles.test_runner.workload.WorkloadWindow[]) windowswindows)
{
(local variable) std.array.Appender!string oo ~= (local variable) ulong wiwi ? ",\n" : "\n";
(local variable) std.array.Appender!string oo ~= string sparkles.test_runner.bench_json.windowJson(in sparkles.test_runner.workload.WorkloadWindow w) @safeOne windows element. Field order is fixed for byte-stable baselines;
absent sources omit their keys (the Nullable contract), nan
components emit null, and skipped appears only when true.
windowJson((local variable) const(sparkles.test_runner.workload.WorkloadWindow) ww);
}
(local variable) std.array.Appender!string oo ~= "\n ]";
}
(local variable) std.array.Appender!string oo ~= "\n}\n";
return (local variable) std.array.Appender!string oo[];
}
/// The page-cache regime workloadFiles established for a window
/// (requested vs verified-effective; fractions nan→null); the note stays
/// separate from the wall note here even though the table composes them
/// into one cell. Emitted for error/skip windows too — the stamp predates
/// the window.
private void void sparkles.test_runner.bench_json.appendRegime!(std.array.Appender!string)(ref std.array.Appender!string o, in sparkles.test_runner.workload.WorkloadWindow w) @safeThe page-cache regime workloadFiles established for a window
(requested vs verified-effective; fractions nan→null); the note stays
separate from the wall note here even though the table composes them
into one cell. Emitted for error/skip windows too — the stamp predates
the window.
appendRegime(O)(ref (alias) O = std.array.Appender!stringO (parameter) std.array.Appender!string oo, in (struct) sparkles.test_runner.workload.WorkloadWindowOne measured window. Deliberately NOT BenchStats: its per-iteration
timing fields would misrepresent a single window — counter stats here are
window totals (iters == 1).
WorkloadWindow (parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww)
{
import (package) stdstd.(module) std.convA one-stop shop for converting values from one type to another.
Category Functions Generic asOriginalType castFrom parse to toChars bitCast Strings text wtext dtext writeText writeWText writeDText hexString Numeric octal roundTo signed unsigned Exceptions ConvException ConvOverflowException
Source
std/conv.d
conv : (alias template) to = std.conv.to(T)The to template converts a value from one type _to another.
The source type is deduced and the target type must be specified, for example the
expression to!int(42.0) converts the number 42 from
double _to int. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., to!double(42) does not do
any checking because any int fits in a double.
Conversions from string _to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings _to signed types, the grammar recognized is:
$(PRE $(I Integer):
$(I Sign UnsignedInteger)
$(I UnsignedInteger)
$(I Sign):
$(B +)
$(B -))
For conversion _to unsigned types, the grammar recognized is:
$(PRE $(I UnsignedInteger):
$(I DecimalDigit)
$(I DecimalDigit) $(I UnsignedInteger))
to;
if ((parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) std.typecons.Nullable!(CacheRegimeStamp) sparkles.test_runner.workload.WorkloadWindow.regimewhat workloadFiles established for this window
regime.bool std.typecons.Nullable!(sparkles.test_runner.cache_regime.CacheRegimeStamp).isNull() const pure nothrow @nogc @property @safeCheck if this is in the null state.
isNull)
return;
const (local variable) const(sparkles.test_runner.cache_regime.CacheRegimeStamp) gg = (parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) std.typecons.Nullable!(CacheRegimeStamp) sparkles.test_runner.workload.WorkloadWindow.regimewhat workloadFiles established for this window
regime.inout(sparkles.test_runner.cache_regime.CacheRegimeStamp) std.typecons.Nullable!(sparkles.test_runner.cache_regime.CacheRegimeStamp).get() inout pure nothrow @nogc @property ref @safeGets the value if not null. If this is in the null state, and the optional
parameter fallback was provided, it will be returned. Without fallback,
calling get with a null state is invalid.
When the fallback type is different from the Nullable type, ``get(T) returns
the common type.
get;
(parameter) std.array.Appender!string oo ~= " \"regime\": { \"requested\": \"" ~ (local variable) const(sparkles.test_runner.cache_regime.CacheRegimeStamp) gg.(field) sparkles.test_runner.attributes.CacheRegime sparkles.test_runner.cache_regime.CacheRegimeStamp.requestedrequested.string std.conv.to!string.to!(const(sparkles.test_runner.attributes.CacheRegime))(const(sparkles.test_runner.attributes.CacheRegime) __param_0) pure @safeThe to template converts a value from one type to another.
The source type is deduced and the target type must be specified, for example the
expression to`!int(42.0)` converts the number 42 from
`double` to `int`. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., ``to!double(42) does not do
any checking because any int fits in a double.
Conversions from string to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings to signed types, the grammar recognized is:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
Examples
Converting a value to its own type (useful mostly for generic code)
simply returns its argument.
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14
Converting among numeric types is a safe way to cast them around.
Conversions from floating-point types to integral types allow loss of
precision (the fractional part of a floating-point number). The
conversion is truncating towards zero, the same way a cast would
truncate. (To round a floating point value when casting to an
integral, use roundTo.)
import std.exception : assertThrown;
int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));
assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
When converting strings to numeric types, note that D hexadecimal and binary
literals are not handled. Neither the prefixes that indicate the base, nor the
horizontal bar used to separate groups of digits are recognized. This also
applies to the suffixes that indicate the type.
To work around this, you can specify a radix for conversions involving numbers.
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
Conversions from integral types to floating-point types always
succeed, but might lose accuracy. The largest integers with a
predecessor representable in floating-point format are 2^24-1 for
float, 2^53-1 for double, and 2^64-1 for real (when
real is 80-bit, e.g. on Intel machines).
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
Conversion from string types to char types enforces the input
to consist of a single code point, and said code point must
fit in the target type. Otherwise, ConvException is thrown.
import std.exception : assertThrown;
assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');
// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');
// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));
Converting an array to another array type works by converting each
element in turn. Associative arrays can be converted to associative
arrays as long as keys and values can in turn be converted.
import std.string : split;
int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
Conversions operate transitively, meaning that they work on arrays and
associative arrays of any complexity.
This conversion works because to`!short` applies to an `int`, to!wstring
applies to a string, to`!string` applies to a `double`, and
to!(double[]) applies to an int[]. The conversion might throw an
exception because ``to!short might fail the range check.
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
Object-to-object conversions by dynamic casting throw exception when
the source is non-null and the target is null.
import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
Stringize conversion from all types is supported.
String to string conversion works for any two string types having
(char, wchar, dchar) character widths and any
combination of qualifiers (mutable, const, or immutable).
Converts array (other than strings) to string.
Each element is converted by calling ``to!T.
Associative array to string conversion.
Each element is converted by calling ``to!T.
Object to string conversion calls toString against the object or
returns "null" if the object is null.
Struct to string conversion calls toString against the struct if
it is defined.
For structs that do not define toString, the conversion to string
produces the list of fields.
Enumerated types are converted to strings as their symbolic names.
Boolean values are converted to "true" or "false".
char, wchar, dchar to a string type.
Unsigned or signed integers to strings.
: Convert integral value to string in radix radix.
radix must be a value from 2 to 36.
value is treated as a signed value only if radix is 10.
The characters A through Z are used to represent values 10 through 36
and their case is determined by the letterCase parameter.
All floating point types to all string types.
Pointer to string conversions convert the pointer to a size_t value.
If pointer is char*, treat it as C-style strings.
In that case, this function is @system.
See formatValue on how toString should be defined.
// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");
// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
to!string(associativeArray) == `["1":2, "0":1]`);
// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");
// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);
auto c = to!(wchar[])(b);
assert(c == "abcx");
Strings can be converted to enum types. The enum member with the same name as the
input string is returned. The comparison is case-sensitive.
A ConvException is thrown if the enum does not have the specified member.
import std.exception : assertThrown;
enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to!(alias) object.string = stringstring
~ "\", \"effective\": \"" ~ (local variable) const(sparkles.test_runner.cache_regime.CacheRegimeStamp) gg.(field) sparkles.test_runner.attributes.CacheRegime sparkles.test_runner.cache_regime.CacheRegimeStamp.effectiveeffective.string std.conv.to!string.to!(const(sparkles.test_runner.attributes.CacheRegime))(const(sparkles.test_runner.attributes.CacheRegime) __param_0) pure @safeThe to template converts a value from one type to another.
The source type is deduced and the target type must be specified, for example the
expression to`!int(42.0)` converts the number 42 from
`double` to `int`. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., ``to!double(42) does not do
any checking because any int fits in a double.
Conversions from string to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings to signed types, the grammar recognized is:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
Examples
Converting a value to its own type (useful mostly for generic code)
simply returns its argument.
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14
Converting among numeric types is a safe way to cast them around.
Conversions from floating-point types to integral types allow loss of
precision (the fractional part of a floating-point number). The
conversion is truncating towards zero, the same way a cast would
truncate. (To round a floating point value when casting to an
integral, use roundTo.)
import std.exception : assertThrown;
int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));
assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
When converting strings to numeric types, note that D hexadecimal and binary
literals are not handled. Neither the prefixes that indicate the base, nor the
horizontal bar used to separate groups of digits are recognized. This also
applies to the suffixes that indicate the type.
To work around this, you can specify a radix for conversions involving numbers.
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
Conversions from integral types to floating-point types always
succeed, but might lose accuracy. The largest integers with a
predecessor representable in floating-point format are 2^24-1 for
float, 2^53-1 for double, and 2^64-1 for real (when
real is 80-bit, e.g. on Intel machines).
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
Conversion from string types to char types enforces the input
to consist of a single code point, and said code point must
fit in the target type. Otherwise, ConvException is thrown.
import std.exception : assertThrown;
assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');
// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');
// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));
Converting an array to another array type works by converting each
element in turn. Associative arrays can be converted to associative
arrays as long as keys and values can in turn be converted.
import std.string : split;
int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
Conversions operate transitively, meaning that they work on arrays and
associative arrays of any complexity.
This conversion works because to`!short` applies to an `int`, to!wstring
applies to a string, to`!string` applies to a `double`, and
to!(double[]) applies to an int[]. The conversion might throw an
exception because ``to!short might fail the range check.
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
Object-to-object conversions by dynamic casting throw exception when
the source is non-null and the target is null.
import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
Stringize conversion from all types is supported.
String to string conversion works for any two string types having
(char, wchar, dchar) character widths and any
combination of qualifiers (mutable, const, or immutable).
Converts array (other than strings) to string.
Each element is converted by calling ``to!T.
Associative array to string conversion.
Each element is converted by calling ``to!T.
Object to string conversion calls toString against the object or
returns "null" if the object is null.
Struct to string conversion calls toString against the struct if
it is defined.
For structs that do not define toString, the conversion to string
produces the list of fields.
Enumerated types are converted to strings as their symbolic names.
Boolean values are converted to "true" or "false".
char, wchar, dchar to a string type.
Unsigned or signed integers to strings.
: Convert integral value to string in radix radix.
radix must be a value from 2 to 36.
value is treated as a signed value only if radix is 10.
The characters A through Z are used to represent values 10 through 36
and their case is determined by the letterCase parameter.
All floating point types to all string types.
Pointer to string conversions convert the pointer to a size_t value.
If pointer is char*, treat it as C-style strings.
In that case, this function is @system.
See formatValue on how toString should be defined.
// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");
// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
to!string(associativeArray) == `["1":2, "0":1]`);
// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");
// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);
auto c = to!(wchar[])(b);
assert(c == "abcx");
Strings can be converted to enum types. The enum member with the same name as the
input string is returned. The comparison is case-sensitive.
A ConvException is thrown if the enum does not have the specified member.
import std.exception : assertThrown;
enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to!(alias) object.string = stringstring
~ "\", \"residentBefore\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.cache_regime.CacheRegimeStamp) gg.(field) double sparkles.test_runner.cache_regime.CacheRegimeStamp.residentBeforeresidentBefore)
~ ", \"residentAfter\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.cache_regime.CacheRegimeStamp) gg.(field) double sparkles.test_runner.cache_regime.CacheRegimeStamp.residentAfterresidentAfter);
if ((local variable) const(sparkles.test_runner.cache_regime.CacheRegimeStamp) gg.(field) string sparkles.test_runner.cache_regime.CacheRegimeStamp.notefs/downgrade/partial/unverified disclosures, "; "-joined
note.(field) ulong const(string).lengthlength)
(parameter) std.array.Appender!string oo ~= ", \"note\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((local variable) const(sparkles.test_runner.cache_regime.CacheRegimeStamp) gg.(field) string sparkles.test_runner.cache_regime.CacheRegimeStamp.notefs/downgrade/partial/unverified disclosures, "; "-joined
note) ~ "\"";
(parameter) std.array.Appender!string oo ~= " },\n";
}
/// One `windows` element. Field order is fixed for byte-stable baselines;
/// absent sources omit their keys (the `Nullable` contract), `nan`
/// components emit `null`, and `skipped` appears only when `true`.
private (alias) object.string = stringstring string sparkles.test_runner.bench_json.windowJson(in sparkles.test_runner.workload.WorkloadWindow w) @safeOne windows element. Field order is fixed for byte-stable baselines;
absent sources omit their keys (the Nullable contract), nan
components emit null, and skipped appears only when true.
windowJson(in (struct) sparkles.test_runner.workload.WorkloadWindowOne measured window. Deliberately NOT BenchStats: its per-iteration
timing fields would misrepresent a single window — counter stats here are
window totals (iters == 1).
WorkloadWindow (parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww) @safe
{
import (package) stdstd.(module) std.arrayFunctions and types that manipulate built-in arrays and associative arrays.
This module provides all kinds of functions to create, manipulate or convert arrays:
Function Name Description
| array |
Returns a copy of the input in a newly allocated dynamic array.
|
| appender |
Returns a new Appender or RefAppender initialized with a given array.
|
| assocArray |
Returns a newly allocated associative array from a range/ranges of keys and values.
|
| byPair |
Construct a range iterating over an associative array by key/value tuples.
|
| insertInPlace |
Inserts into an existing array at a given position.
|
| join |
Concatenates a range of ranges into one array.
|
| minimallyInitializedArray |
Returns a new array of type T.
|
| replace |
Returns a new array with all occurrences of a certain subrange replaced.
|
| replaceFirst |
Returns a new array with the first occurrence of a certain subrange replaced.
|
| replaceInPlace |
Replaces all occurrences of a certain subrange and puts the result into a given array.
|
| replaceInto |
Replaces all occurrences of a certain subrange and puts the result into an output range.
|
| replaceLast |
Returns a new array with the last occurrence of a certain subrange replaced.
|
| replaceSlice |
Returns a new array with a given slice replaced.
|
| replicate |
Creates a new array out of several copies of an input array or range.
|
| sameHead |
Checks if the initial segments of two arrays refer to the same
place in memory.
|
| sameTail |
Checks if the final segments of two arrays refer to the same place
in memory.
|
| split |
Eagerly split a range or string into an array.
|
| staticArray |
Creates a new static array from given data.
|
| uninitializedArray |
Returns a new array of type T without initializing its elements.
|
Source
std/array.d
array : (alias template) appender = std.array.appender(A)() if (isDynamicArray!A)Convenience function that returns an $(LREF Appender) instance,
optionally initialized with array.
appender;
import (package) stdstd.(module) std.convA one-stop shop for converting values from one type to another.
Category Functions Generic asOriginalType castFrom parse to toChars bitCast Strings text wtext dtext writeText writeWText writeDText hexString Numeric octal roundTo signed unsigned Exceptions ConvException ConvOverflowException
Source
std/conv.d
conv : (alias template) to = std.conv.to(T)The to template converts a value from one type _to another.
The source type is deduced and the target type must be specified, for example the
expression to!int(42.0) converts the number 42 from
double _to int. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., to!double(42) does not do
any checking because any int fits in a double.
Conversions from string _to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings _to signed types, the grammar recognized is:
$(PRE $(I Integer):
$(I Sign UnsignedInteger)
$(I UnsignedInteger)
$(I Sign):
$(B +)
$(B -))
For conversion _to unsigned types, the grammar recognized is:
$(PRE $(I UnsignedInteger):
$(I DecimalDigit)
$(I DecimalDigit) $(I UnsignedInteger))
to;
auto (local variable) std.array.Appender!string oo = std.array.Appender!string std.array.appender!string() pure nothrow @safeConvenience function that returns an Appender instance,
optionally initialized with array.
appender!(alias) object.string = stringstring;
(local variable) std.array.Appender!string oo ~= " {\n";
(local variable) std.array.Appender!string oo ~= " \"name\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) string sparkles.test_runner.workload.WorkloadWindow.namename) ~ "\",\n";
(local variable) std.array.Appender!string oo ~= " \"reps\": " ~ (parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) uint sparkles.test_runner.workload.WorkloadWindow.repstimes the window content ran inside this window
reps.string std.conv.to!string.to!(const(uint))(const(uint) __param_0) pure nothrow @safeThe to template converts a value from one type to another.
The source type is deduced and the target type must be specified, for example the
expression to`!int(42.0)` converts the number 42 from
`double` to `int`. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., ``to!double(42) does not do
any checking because any int fits in a double.
Conversions from string to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings to signed types, the grammar recognized is:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
Examples
Converting a value to its own type (useful mostly for generic code)
simply returns its argument.
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14
Converting among numeric types is a safe way to cast them around.
Conversions from floating-point types to integral types allow loss of
precision (the fractional part of a floating-point number). The
conversion is truncating towards zero, the same way a cast would
truncate. (To round a floating point value when casting to an
integral, use roundTo.)
import std.exception : assertThrown;
int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));
assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
When converting strings to numeric types, note that D hexadecimal and binary
literals are not handled. Neither the prefixes that indicate the base, nor the
horizontal bar used to separate groups of digits are recognized. This also
applies to the suffixes that indicate the type.
To work around this, you can specify a radix for conversions involving numbers.
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
Conversions from integral types to floating-point types always
succeed, but might lose accuracy. The largest integers with a
predecessor representable in floating-point format are 2^24-1 for
float, 2^53-1 for double, and 2^64-1 for real (when
real is 80-bit, e.g. on Intel machines).
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
Conversion from string types to char types enforces the input
to consist of a single code point, and said code point must
fit in the target type. Otherwise, ConvException is thrown.
import std.exception : assertThrown;
assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');
// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');
// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));
Converting an array to another array type works by converting each
element in turn. Associative arrays can be converted to associative
arrays as long as keys and values can in turn be converted.
import std.string : split;
int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
Conversions operate transitively, meaning that they work on arrays and
associative arrays of any complexity.
This conversion works because to`!short` applies to an `int`, to!wstring
applies to a string, to`!string` applies to a `double`, and
to!(double[]) applies to an int[]. The conversion might throw an
exception because ``to!short might fail the range check.
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
Object-to-object conversions by dynamic casting throw exception when
the source is non-null and the target is null.
import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
Stringize conversion from all types is supported.
String to string conversion works for any two string types having
(char, wchar, dchar) character widths and any
combination of qualifiers (mutable, const, or immutable).
Converts array (other than strings) to string.
Each element is converted by calling ``to!T.
Associative array to string conversion.
Each element is converted by calling ``to!T.
Object to string conversion calls toString against the object or
returns "null" if the object is null.
Struct to string conversion calls toString against the struct if
it is defined.
For structs that do not define toString, the conversion to string
produces the list of fields.
Enumerated types are converted to strings as their symbolic names.
Boolean values are converted to "true" or "false".
char, wchar, dchar to a string type.
Unsigned or signed integers to strings.
: Convert integral value to string in radix radix.
radix must be a value from 2 to 36.
value is treated as a signed value only if radix is 10.
The characters A through Z are used to represent values 10 through 36
and their case is determined by the letterCase parameter.
All floating point types to all string types.
Pointer to string conversions convert the pointer to a size_t value.
If pointer is char*, treat it as C-style strings.
In that case, this function is @system.
See formatValue on how toString should be defined.
// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");
// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
to!string(associativeArray) == `["1":2, "0":1]`);
// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");
// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);
auto c = to!(wchar[])(b);
assert(c == "abcx");
Strings can be converted to enum types. The enum member with the same name as the
input string is returned. The comparison is case-sensitive.
A ConvException is thrown if the enum does not have the specified member.
import std.exception : assertThrown;
enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to!(alias) object.string = stringstring ~ ",\n";
if ((parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) string sparkles.test_runner.workload.WorkloadWindow.errornon-empty = error (or, with skipped, skip) row
error.(field) ulong const(string).lengthlength)
{
// Mirror the error-row shape: every always-present key stays
// present as null, so consumers can read windows position-blind.
// The regime stamp survives — it describes state established
// BEFORE the window opened (possibly why the run failed), unlike
// the per-source measurements OF the failed window.
(local variable) std.array.Appender!string oo ~= " \"wallNs\": null,\n";
(local variable) std.array.Appender!string oo ~= " \"scope\": null,\n";
(local variable) std.array.Appender!string oo ~= " \"onCpuUserNs\": null,\n";
(local variable) std.array.Appender!string oo ~= " \"onCpuKernelNs\": null,\n";
(local variable) std.array.Appender!string oo ~= " \"offCpuRunqueueNs\": null,\n";
(local variable) std.array.Appender!string oo ~= " \"offCpuDiskNs\": null,\n";
(local variable) std.array.Appender!string oo ~= " \"offCpuOtherNs\": null,\n";
void sparkles.test_runner.bench_json.appendRegime!(std.array.Appender!string)(ref std.array.Appender!string o, in sparkles.test_runner.workload.WorkloadWindow w) @safeThe page-cache regime workloadFiles established for a window
(requested vs verified-effective; fractions nan→null); the note stays
separate from the wall note here even though the table composes them
into one cell. Emitted for error/skip windows too — the stamp predates
the window.
appendRegime((local variable) std.array.Appender!string oo, (parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww);
if ((parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) bool sparkles.test_runner.workload.WorkloadWindow.skippedskipped)
(local variable) std.array.Appender!string oo ~= " \"skipped\": true,\n";
(local variable) std.array.Appender!string oo ~= " \"error\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) string sparkles.test_runner.workload.WorkloadWindow.errornon-empty = error (or, with skipped, skip) row
error) ~ "\"\n";
(local variable) std.array.Appender!string oo ~= " }";
return (local variable) std.array.Appender!string oo[];
}
(local variable) std.array.Appender!string oo ~= " \"wallNs\": " ~ (parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) long sparkles.test_runner.workload.WallDecomposition.wallNsthe window's wall-clock duration
wallNs.string std.conv.to!string.to!(const(long))(const(long) __param_0) pure nothrow @safeThe to template converts a value from one type to another.
The source type is deduced and the target type must be specified, for example the
expression to`!int(42.0)` converts the number 42 from
`double` to `int`. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., ``to!double(42) does not do
any checking because any int fits in a double.
Conversions from string to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings to signed types, the grammar recognized is:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
Examples
Converting a value to its own type (useful mostly for generic code)
simply returns its argument.
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14
Converting among numeric types is a safe way to cast them around.
Conversions from floating-point types to integral types allow loss of
precision (the fractional part of a floating-point number). The
conversion is truncating towards zero, the same way a cast would
truncate. (To round a floating point value when casting to an
integral, use roundTo.)
import std.exception : assertThrown;
int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));
assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
When converting strings to numeric types, note that D hexadecimal and binary
literals are not handled. Neither the prefixes that indicate the base, nor the
horizontal bar used to separate groups of digits are recognized. This also
applies to the suffixes that indicate the type.
To work around this, you can specify a radix for conversions involving numbers.
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
Conversions from integral types to floating-point types always
succeed, but might lose accuracy. The largest integers with a
predecessor representable in floating-point format are 2^24-1 for
float, 2^53-1 for double, and 2^64-1 for real (when
real is 80-bit, e.g. on Intel machines).
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
Conversion from string types to char types enforces the input
to consist of a single code point, and said code point must
fit in the target type. Otherwise, ConvException is thrown.
import std.exception : assertThrown;
assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');
// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');
// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));
Converting an array to another array type works by converting each
element in turn. Associative arrays can be converted to associative
arrays as long as keys and values can in turn be converted.
import std.string : split;
int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
Conversions operate transitively, meaning that they work on arrays and
associative arrays of any complexity.
This conversion works because to`!short` applies to an `int`, to!wstring
applies to a string, to`!string` applies to a `double`, and
to!(double[]) applies to an int[]. The conversion might throw an
exception because ``to!short might fail the range check.
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
Object-to-object conversions by dynamic casting throw exception when
the source is non-null and the target is null.
import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
Stringize conversion from all types is supported.
String to string conversion works for any two string types having
(char, wchar, dchar) character widths and any
combination of qualifiers (mutable, const, or immutable).
Converts array (other than strings) to string.
Each element is converted by calling ``to!T.
Associative array to string conversion.
Each element is converted by calling ``to!T.
Object to string conversion calls toString against the object or
returns "null" if the object is null.
Struct to string conversion calls toString against the struct if
it is defined.
For structs that do not define toString, the conversion to string
produces the list of fields.
Enumerated types are converted to strings as their symbolic names.
Boolean values are converted to "true" or "false".
char, wchar, dchar to a string type.
Unsigned or signed integers to strings.
: Convert integral value to string in radix radix.
radix must be a value from 2 to 36.
value is treated as a signed value only if radix is 10.
The characters A through Z are used to represent values 10 through 36
and their case is determined by the letterCase parameter.
All floating point types to all string types.
Pointer to string conversions convert the pointer to a size_t value.
If pointer is char*, treat it as C-style strings.
In that case, this function is @system.
See formatValue on how toString should be defined.
// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");
// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
to!string(associativeArray) == `["1":2, "0":1]`);
// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");
// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);
auto c = to!(wchar[])(b);
assert(c == "abcx");
Strings can be converted to enum types. The enum member with the same name as the
input string is returned. The comparison is case-sensitive.
A ConvException is thrown if the enum does not have the specified member.
import std.exception : assertThrown;
enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to!(alias) object.string = stringstring ~ ",\n";
(local variable) std.array.Appender!string oo ~= " \"scope\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) string sparkles.test_runner.workload.WallDecomposition.scope_"thread" (Linux) or "process"
scope_) ~ "\",\n";
(local variable) std.array.Appender!string oo ~= " \"onCpuUserNs\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) double sparkles.test_runner.workload.WallDecomposition.onCpuUserNsrusage user time (µs resolution)
onCpuUserNs) ~ ",\n";
(local variable) std.array.Appender!string oo ~= " \"onCpuKernelNs\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) double sparkles.test_runner.workload.WallDecomposition.onCpuKernelNsrusage system time
onCpuKernelNs) ~ ",\n";
(local variable) std.array.Appender!string oo ~= " \"offCpuRunqueueNs\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) double sparkles.test_runner.workload.WallDecomposition.offCpuRunqueueNsschedstat runqueue wait
offCpuRunqueueNs) ~ ",\n";
(local variable) std.array.Appender!string oo ~= " \"offCpuDiskNs\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) double sparkles.test_runner.workload.WallDecomposition.offCpuDiskNsDisk-stall attribution — always nan today: /proc/pressure is
system-scoped, so a thread-scoped attribution would report other
processes' stalls as this workload's; it lands with M8's
cgroup-scoped PSI. The system-wide integrals ship as diagnostics
(WorkloadWindow.psi, the io-stall column) meanwhile.
offCpuDiskNs) ~ ",\n";
(local variable) std.array.Appender!string oo ~= " \"offCpuOtherNs\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) double sparkles.test_runner.workload.WallDecomposition.offCpuOtherNsclamped residual: locks, sleeps, the rest
offCpuOtherNs) ~ ",\n";
if (!(parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) std.typecons.Nullable!(PerfStats) sparkles.test_runner.workload.WorkloadWindow.perfperf.bool std.typecons.Nullable!(sparkles.test_runner.perf.PerfStats).isNull() const pure nothrow @nogc @property @safeCheck if this is in the null state.
isNull)
{
const (local variable) const(sparkles.test_runner.perf.PerfStats) pp = (parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) std.typecons.Nullable!(PerfStats) sparkles.test_runner.workload.WorkloadWindow.perfperf.inout(sparkles.test_runner.perf.PerfStats) std.typecons.Nullable!(sparkles.test_runner.perf.PerfStats).get() inout pure nothrow @nogc @property ref @safeGets the value if not null. If this is in the null state, and the optional
parameter fallback was provided, it will be returned. Without fallback,
calling get with a null state is invalid.
When the fallback type is different from the Nullable type, ``get(T) returns
the common type.
get;
(local variable) std.array.Appender!string oo ~= " \"perf\": { \"instructions\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.perf.PerfStats) pp.(field) double sparkles.test_runner.perf.PerfStats.instructionsretired instructions per iteration
instructions)
~ ", \"cycles\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.perf.PerfStats) pp.(field) double sparkles.test_runner.perf.PerfStats.cyclesCPU cycles per iteration
cycles)
~ ", \"branches\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.perf.PerfStats) pp.(field) double sparkles.test_runner.perf.PerfStats.branchesbranch instructions per iteration
branches)
~ ", \"branchMisses\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.perf.PerfStats) pp.(field) double sparkles.test_runner.perf.PerfStats.branchMissesmispredicted branches per iteration
branchMisses)
~ ", \"cacheReferences\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.perf.PerfStats) pp.(field) double sparkles.test_runner.perf.PerfStats.cacheReferencesLLC references per iteration
cacheReferences)
~ ", \"cacheMisses\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.perf.PerfStats) pp.(field) double sparkles.test_runner.perf.PerfStats.cacheMissesLLC misses per iteration
cacheMisses)
~ ", \"pageFaults\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.perf.PerfStats) pp.(field) double sparkles.test_runner.perf.PerfStats.pageFaultspage faults per iteration
pageFaults)
~ ", \"scale\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.perf.PerfStats) pp.(field) double sparkles.test_runner.perf.PerfStats.scalecounter running/enabled ratio (1 = clean)
scale)
~ ", \"userOnly\": " ~ ((local variable) const(sparkles.test_runner.perf.PerfStats) pp.(field) bool sparkles.test_runner.perf.PerfStats.userOnlytrue = kernel-side counting was refused
userOnly ? "true" : "false") ~ " },\n";
}
if (!(parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) std.typecons.Nullable!(Tier0Stats) sparkles.test_runner.workload.WorkloadWindow.tier0tier0.bool std.typecons.Nullable!(sparkles.test_runner.tier0.Tier0Stats).isNull() const pure nothrow @nogc @property @safeCheck if this is in the null state.
isNull)
{
const (local variable) const(sparkles.test_runner.tier0.Tier0Stats) tt = (parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) std.typecons.Nullable!(Tier0Stats) sparkles.test_runner.workload.WorkloadWindow.tier0tier0.inout(sparkles.test_runner.tier0.Tier0Stats) std.typecons.Nullable!(sparkles.test_runner.tier0.Tier0Stats).get() inout pure nothrow @nogc @property ref @safeGets the value if not null. If this is in the null state, and the optional
parameter fallback was provided, it will be returned. Without fallback,
calling get with a null state is invalid.
When the fallback type is different from the Nullable type, ``get(T) returns
the common type.
get;
(local variable) std.array.Appender!string oo ~= " \"tier0\": { \"minflt\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.tier0.Tier0Stats) tt.(field) double sparkles.test_runner.tier0.Tier0Stats.minfltminor page faults per iteration (getrusage)
minflt)
~ ", \"majflt\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.tier0.Tier0Stats) tt.(field) double sparkles.test_runner.tier0.Tier0Stats.majfltmajor page faults per iteration (getrusage)
majflt)
~ ", \"volCs\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.tier0.Tier0Stats) tt.(field) double sparkles.test_runner.tier0.Tier0Stats.volCsvoluntary context switches per iteration (blocked on I/O)
volCs)
~ ", \"involCs\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.tier0.Tier0Stats) tt.(field) double sparkles.test_runner.tier0.Tier0Stats.involCsinvoluntary context switches per iteration (preempted)
involCs)
~ ", \"syscr\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.tier0.Tier0Stats) tt.(field) double sparkles.test_runner.tier0.Tier0Stats.syscrread syscalls per iteration (/proc/self/io)
syscr)
~ ", \"syscw\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.tier0.Tier0Stats) tt.(field) double sparkles.test_runner.tier0.Tier0Stats.syscwwrite syscalls per iteration
syscw)
~ ", \"rchar\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.tier0.Tier0Stats) tt.(field) double sparkles.test_runner.tier0.Tier0Stats.rdCharsbytes read through the syscall layer (cache included)
rdChars)
~ ", \"wchar\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.tier0.Tier0Stats) tt.(field) double sparkles.test_runner.tier0.Tier0Stats.wrCharsbytes written through the syscall layer
wrChars)
~ ", \"readBytes\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.tier0.Tier0Stats) tt.(field) double sparkles.test_runner.tier0.Tier0Stats.rdBytesbytes that actually hit the block device (reads)
rdBytes)
~ ", \"writeBytes\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.tier0.Tier0Stats) tt.(field) double sparkles.test_runner.tier0.Tier0Stats.wrBytesbytes that actually hit the block device (writes)
wrBytes) ~ " },\n";
}
if (!(parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) std.typecons.Nullable!(SyscallStats) sparkles.test_runner.workload.WorkloadWindow.syscallssyscalls.bool std.typecons.Nullable!(sparkles.test_runner.syscalls.SyscallStats).isNull() const pure nothrow @nogc @property @safeCheck if this is in the null state.
isNull)
{
const (local variable) const(sparkles.test_runner.syscalls.SyscallStats) ss = (parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) std.typecons.Nullable!(SyscallStats) sparkles.test_runner.workload.WorkloadWindow.syscallssyscalls.inout(sparkles.test_runner.syscalls.SyscallStats) std.typecons.Nullable!(sparkles.test_runner.syscalls.SyscallStats).get() inout pure nothrow @nogc @property ref @safeGets the value if not null. If this is in the null state, and the optional
parameter fallback was provided, it will be returned. Without fallback,
calling get with a null state is invalid.
When the fallback type is different from the Nullable type, ``get(T) returns
the common type.
get;
(local variable) std.array.Appender!string oo ~= " \"syscalls\": { \"total\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.syscalls.SyscallStats) ss.(field) double sparkles.test_runner.syscalls.SyscallStats.totaltotal)
~ ", \"named\": {";
foreach ((parameter) ulong ii, (parameter) const(string) namename; (local variable) const(sparkles.test_runner.syscalls.SyscallStats) ss.(field) const(string)[] sparkles.test_runner.syscalls.SyscallStats.namednamed)
{
(local variable) std.array.Appender!string oo ~= (local variable) ulong ii ? ", " : " ";
(local variable) std.array.Appender!string oo ~= "\"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((local variable) const(string) namename) ~ "\": "
~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) ulong ii < (local variable) const(sparkles.test_runner.syscalls.SyscallStats) ss.(field) double[] sparkles.test_runner.syscalls.SyscallStats.countscounts.(field) ulong const(double[]).lengthlength ? (local variable) const(sparkles.test_runner.syscalls.SyscallStats) ss.(field) double[] sparkles.test_runner.syscalls.SyscallStats.countscounts[(local variable) ulong ii] : double.(constant) double double.nan = nannan);
}
(local variable) std.array.Appender!string oo ~= (local variable) const(sparkles.test_runner.syscalls.SyscallStats) ss.(field) const(string)[] sparkles.test_runner.syscalls.SyscallStats.namednamed.(field) ulong const(string[]).lengthlength ? " }" : "}";
(local variable) std.array.Appender!string oo ~= ", \"scale\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.syscalls.SyscallStats) ss.(field) double sparkles.test_runner.syscalls.SyscallStats.scalescale) ~ " },\n";
}
if (!(parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) std.typecons.Nullable!(RawStats) sparkles.test_runner.workload.WorkloadWindow.rawraw.bool std.typecons.Nullable!(sparkles.test_runner.raw.RawStats).isNull() const pure nothrow @nogc @property @safeCheck if this is in the null state.
isNull)
{
const (local variable) const(sparkles.test_runner.raw.RawStats) rr = (parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) std.typecons.Nullable!(RawStats) sparkles.test_runner.workload.WorkloadWindow.rawraw.inout(sparkles.test_runner.raw.RawStats) std.typecons.Nullable!(sparkles.test_runner.raw.RawStats).get() inout pure nothrow @nogc @property ref @safeGets the value if not null. If this is in the null state, and the optional
parameter fallback was provided, it will be returned. Without fallback,
calling get with a null state is invalid.
When the fallback type is different from the Nullable type, ``get(T) returns
the common type.
get;
(local variable) std.array.Appender!string oo ~= " \"raw\": { \"events\": {";
foreach ((parameter) ulong ii, (parameter) const(string) selsel; (local variable) const(sparkles.test_runner.raw.RawStats) rr.(field) const(string)[] sparkles.test_runner.raw.RawStats.selectorsrequested selectors, in request order
selectors)
{
(local variable) std.array.Appender!string oo ~= (local variable) ulong ii ? ", " : " ";
(local variable) std.array.Appender!string oo ~= "\"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((local variable) const(string) selsel) ~ "\": "
~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) ulong ii < (local variable) const(sparkles.test_runner.raw.RawStats) rr.(field) double[] sparkles.test_runner.raw.RawStats.valuesper-iteration averages (nan = unavailable)
values.(field) ulong const(double[]).lengthlength ? (local variable) const(sparkles.test_runner.raw.RawStats) rr.(field) double[] sparkles.test_runner.raw.RawStats.valuesper-iteration averages (nan = unavailable)
values[(local variable) ulong ii] : double.(constant) double double.nan = nannan);
}
(local variable) std.array.Appender!string oo ~= (local variable) const(sparkles.test_runner.raw.RawStats) rr.(field) const(string)[] sparkles.test_runner.raw.RawStats.selectorsrequested selectors, in request order
selectors.(field) ulong const(string[]).lengthlength ? " }" : "}";
(local variable) std.array.Appender!string oo ~= ", \"scale\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.raw.RawStats) rr.(field) double sparkles.test_runner.raw.RawStats.scalerunning/enabled ratio of the pass (1 = clean)
scale) ~ " },\n";
}
if (!(parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) std.typecons.Nullable!(PsiStats) sparkles.test_runner.workload.WorkloadWindow.psisystem-wide stall deltas — diagnostics, not attribution
psi.bool std.typecons.Nullable!(sparkles.test_runner.workload.PsiStats).isNull() const pure nothrow @nogc @property @safeCheck if this is in the null state.
isNull)
{
// System-wide stall integrals — diagnostics, self-described by the
// scope field (M8's cgroup-scoped source will emit "cgroup").
const (local variable) const(sparkles.test_runner.workload.PsiStats) pp = (parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) std.typecons.Nullable!(PsiStats) sparkles.test_runner.workload.WorkloadWindow.psisystem-wide stall deltas — diagnostics, not attribution
psi.inout(sparkles.test_runner.workload.PsiStats) std.typecons.Nullable!(sparkles.test_runner.workload.PsiStats).get() inout pure nothrow @nogc @property ref @safeGets the value if not null. If this is in the null state, and the optional
parameter fallback was provided, it will be returned. Without fallback,
calling get with a null state is invalid.
When the fallback type is different from the Nullable type, ``get(T) returns
the common type.
get;
(local variable) std.array.Appender!string oo ~= " \"psi\": { \"scope\": \"system\""
~ ", \"ioSomeNs\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.workload.PsiStats) pp.(field) double sparkles.test_runner.workload.PsiStats.ioSomeNs≥ 1 task stalled on io
ioSomeNs)
~ ", \"ioFullNs\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.workload.PsiStats) pp.(field) double sparkles.test_runner.workload.PsiStats.ioFullNsall non-idle tasks stalled on io
ioFullNs)
~ ", \"memSomeNs\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.workload.PsiStats) pp.(field) double sparkles.test_runner.workload.PsiStats.memSomeNsmemSomeNs)
~ ", \"memFullNs\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.workload.PsiStats) pp.(field) double sparkles.test_runner.workload.PsiStats.memFullNsmemFullNs)
~ ", \"cpuSomeNs\": " ~ string sparkles.test_runner.bench_json.jsonNumber(double v) @safeOne JSON number: nan/infinities → null (an unavailable counter, the
table's em dash); integral doubles below 2^53 render as integers; the rest
to 6 significant digits (never D's 17-digit default).
jsonNumber((local variable) const(sparkles.test_runner.workload.PsiStats) pp.(field) double sparkles.test_runner.workload.PsiStats.cpuSomeNscpuSomeNs) ~ " },\n";
}
void sparkles.test_runner.bench_json.appendRegime!(std.array.Appender!string)(ref std.array.Appender!string o, in sparkles.test_runner.workload.WorkloadWindow w) @safeThe page-cache regime workloadFiles established for a window
(requested vs verified-effective; fractions nan→null); the note stays
separate from the wall note here even though the table composes them
into one cell. Emitted for error/skip windows too — the stamp predates
the window.
appendRegime((local variable) std.array.Appender!string oo, (parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww);
if ((parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) string sparkles.test_runner.workload.WallDecomposition.noteclamp/absence/cross-thread disclosures, "; "-joined
note.(field) ulong const(string).lengthlength)
(local variable) std.array.Appender!string oo ~= " \"note\": \"" ~ string sparkles.test_runner.bench_json.jsonEscape(scope const(char)[] s) pure @safeRFC 8259 string escaping: ", \, and control characters.
jsonEscape((parameter) const(sparkles.test_runner.workload.WorkloadWindow) ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) string sparkles.test_runner.workload.WallDecomposition.noteclamp/absence/cross-thread disclosures, "; "-joined
note) ~ "\",\n";
(local variable) std.array.Appender!string oo ~= " \"error\": \"\"\n";
(local variable) std.array.Appender!string oo ~= " }";
return (local variable) std.array.Appender!string oo[];
}
@("benchJson.document.roundTrips")
@system
unittest
{
import (package) stdstd.(module) std.jsonImplements functionality to read and write JavaScript Object Notation values.
JavaScript Object Notation is a lightweight data interchange format commonly used in web services and configuration files.
It's easy for humans to read and write, and it's easy for machines to parse and generate.
Warning: While JSONValue is fine for small-scale use, at the range of hundreds of megabytes it is
known to cause and exacerbate GC problems. If you encounter problems, try replacing it with a stream parser. See
also https://forum.dlang.org/post/dzfyaxypmkdrpakmycjv@forum.dlang.org.
References
http://json.org/, https://seriot.ch/projects/parsing_json.html
Source
std/json.d
Examples
import std.conv : to;
// parse a file or string of json into a usable structure
string s = `{ "language": "D", "rating": 3.5, "code": "42" }`;
JSONValue j = parseJSON(s);
// j and j["language"] return JSONValue,
// j["language"].str returns a string
assert(j["language"].str == "D");
assert(j["rating"].floating == 3.5);
// check a type
long x;
if (const(JSONValue)* code = "code" in j)
{
if (code.type() == JSONType.integer)
x = code.integer;
else
x = to!int(code.str);
}
// create a json struct
JSONValue jj = [ "language": "D" ];
// rating doesnt exist yet, so use .object to assign
jj.object["rating"] = JSONValue(3.5);
// create an array to assign to list
jj.object["list"] = JSONValue( ["a", "b", "c"] );
// list already exists, so .object optional
jj["list"].array ~= JSONValue("D");
string jjStr = `{"language":"D","list":["a","b","c","D"],"rating":3.5}`;
assert(jj.toString == jjStr);
json : (enum) std.json.JSONTypeEnumeration of JSON types
JSONType, (alias template) parseJSON = std.json.parseJSON(T)(T json, int maxDepth = -1, JSONOptions options = JSONOptions.none) if (isSomeFiniteCharInputRange!T)Parses a serialized string and returns a tree of JSON values.
Throws: $(LREF JSONException) if string does not follow the JSON grammar or the depth exceeds the max depth,
$(LREF ConvException) if a number in the input cannot be represented by a native D type.
Params:
json = json-formatted string to parse
maxDepth = maximum depth of nesting allowed, -1 disables depth checking
options = enable decoding string representations of NaN/Inf as float values
parseJSON;
import (package) stdstd.(module) std.typeconsThis module implements a variety of type constructors, i.e., templates
that allow construction of new, useful general-purpose types.
Category Symbols Tuple isTuple Tuple tuple reverse Flags BitFlags isBitFlagEnum Flag No Yes Reference Counting borrow RefCountedAutoInitialize RefCounted refCounted SafeRefCounted safeRefCounted Memory allocation scoped Unique Code generation AutoImplement BlackHole generateAssertTrap generateEmptyFunction NotImplementedError WhiteHole Nullable apply Nullable nullable NullableRef nullableRef Proxies Proxy rebindable Rebindable unwrap wrap Types alignForSize ReplaceType ReplaceTypeUnless Ternary Typedef TypedefType UnqualRef
Source
std/typecons.d
Examples
Value tuples
alias Coord = Tuple!(int, "x", int, "y", int, "z");
Coord c;
c[1] = 1; // access by index
c.z = 1; // access by given name
assert(c == Coord(0, 1, 1));
// names can be omitted, types can be mixed
alias DictEntry = Tuple!(string, int);
auto dict = DictEntry("seven", 7);
// element types can be inferred
assert(tuple(2, 3, 4)[1] == 3);
// type inference works with names too
auto tup = tuple!("x", "y", "z")(2, 3, 4);
assert(tup.y == 3);
Rebindable references to const and immutable objects
class Widget
{
void foo() const @safe {}
}
const w1 = new Widget, w2 = new Widget;
w1.foo();
// w1 = w2 would not work; can't rebind const object
auto r = Rebindable!(const Widget)(w1);
// invoke method as if r were a Widget object
r.foo();
// rebind r to refer to another object
r = w2;
typecons : (alias struct) Nullable = std.typecons.Nullable(T)Defines a value paired with a distinctive "null" state that denotes
the absence of a value. If default constructed, a $(D
Nullable!T) object starts in the null state. Assigning it renders it
non-null. Calling nullify can nullify it again.
Practically Nullable!T stores a T and a bool.
See also:
$(LREF apply), an alternative way to use the payload.
Nullable;
import (package) sparklessparkles.(package) sparkles.test_runnertest_runner.(module) sparkles.test_runner.benchBenchmark measurement: auto-scaling iteration counts, basic robust
statistics, and an optimizer barrier.
@benchmark unittest blocks are executed by the runner's --bench`` mode.
By default the whole test body is the measured unit. To time only part of
the body (excluding setup), call benchIter inside the test:
@("sort.bench")
@benchmark @safe
unittest
{
import sparkles.test_runner.bench : benchIter, blackBox;
auto data = makeInput(); // setup — not measured
benchIter({ blackBox(data.dup.sort()); }); // measured
}
The measurement protocol follows Rust libtest's Bencher: the iteration
count per sample is doubled until a sample takes at least
BenchConfig.minSampleTime, then BenchConfig.sampleCount samples are
collected and summarized as median / median-absolute-deviation / min / max
nanoseconds per iteration.
bench : (struct) sparkles.test_runner.bench.MetricA measurement attached to a benchmark case: amount units of work per timed
iteration. Reported as a per-second rate (amount ÷ iteration-time, a
quantity of dimension unit·s⁻¹) or as a per-iteration level (as-is).
Metric, (struct) sparkles.test_runner.bench.UnitA unit of measure for a benchmark metric. A forward-compatible stand-in for
sparkles.quantities' runtime unit — today just the symbol (its identity).
Domain counts ("tweet", "frame", "req") are open-basis units minted by name;
"B"/"s" map to SI base dimensions once the quantities library lands.
Unit;
import (package) sparklessparkles.(package) sparkles.test_runnertest_runner.(module) sparkles.test_runner.perfHardware performance counters via perf_event_open(2), in pure D.
One counter group (cycles leader; instructions, branches, branch-misses,
cache-references, cache-misses, plus the page-fault software event) is
opened once and reused: a benchmark's counting pass — separate from the
wall-clock measurement — brackets only the timed body with
PERF_EVENT_IOC_ENABLE/DISABLE, so the per-iteration ioctls never pollute
the reported timings and any between() cleanup is never counted.
Counters answer why two implementations differ: IPC, cycles and
instructions per iteration, branch/cache miss rates, and the page-fault
(allocation) signature. On kernels that refuse perf_event_open
(perf_event_paranoid, seccomp) — and on platforms with no backend at
all — this degrades gracefully: PerfGroup.available is false and
callers simply omit the counter columns.
The binding is pure D over druntime's core.sys.linux.perf_event (which
carries the arch-specific syscall numbers, the perf_event_attr layout, and
a perf_event_open wrapper) plus ioctl/read/close — no ImportC, so the
module source-includes cleanly into every host package's test build.
On macOS the same PerfGroup surface is backed by
proc_pid_rusage(RUSAGE_INFO_V4) — the unprivileged XNU fixed counters:
true retired instructions and core cycles (process-wide, user+kernel, all
threads), so --perf`` renders IPC and instr/iter with the other columns
honestly absent. Everything richer is a capability ad, not a backend: kpc
is root-or-blessed with the RESTRICT_TO_KNOWN allowlist, and sampling is
Instruments/xctrace-brokered only.
perf : (struct) sparkles.test_runner.perf.PerfStatsPer-iteration counter averages of one counting pass. A field is nan when
the event could not be opened on this machine (e.g. the LLC pair was
dropped to avoid multiplexing, or the PMU exposes fewer events).
PerfStats;
(struct) sparkles.test_runner.bench.BenchStatsSummary statistics of one benchmark row, in nanoseconds per iteration. A row
with a non-empty error is a failure row (its timing fields are unset).
BenchStats (local variable) sparkles.test_runner.bench.BenchStats measuredmeasured;
(local variable) sparkles.test_runner.bench.BenchStats measuredmeasured.(field) string sparkles.test_runner.bench.BenchStats.namename = "mir-ion";
(local variable) sparkles.test_runner.bench.BenchStats measuredmeasured.(field) string[string] sparkles.test_runner.bench.BenchStats.labelsorthogonal grouping dimensions (from the case's labels)
labels = ["operation": "parse", "dataset": "twitter"];
(local variable) sparkles.test_runner.bench.BenchStats measuredmeasured.(field) ulong sparkles.test_runner.bench.BenchStats.iterationsiterations per sample
iterations = 1;
(local variable) sparkles.test_runner.bench.BenchStats measuredmeasured.(field) ulong sparkles.test_runner.bench.BenchStats.samplessamples = 42;
(local variable) sparkles.test_runner.bench.BenchStats measuredmeasured.(field) double sparkles.test_runner.bench.BenchStats.nsPerIterMediannsPerIterMedian = 3_823_300;
(local variable) sparkles.test_runner.bench.BenchStats measuredmeasured.(field) double sparkles.test_runner.bench.BenchStats.nsPerIterDeviationmedian absolute deviation
nsPerIterDeviation = 41_200;
(local variable) sparkles.test_runner.bench.BenchStats measuredmeasured.(field) double sparkles.test_runner.bench.BenchStats.nsPerIterMinnsPerIterMin = 3_615_100;
(local variable) sparkles.test_runner.bench.BenchStats measuredmeasured.(field) double sparkles.test_runner.bench.BenchStats.nsPerIterMaxnsPerIterMax = 4_891_000;
(local variable) sparkles.test_runner.bench.BenchStats measuredmeasured.(field) sparkles.test_runner.bench.Metric[] sparkles.test_runner.bench.BenchStats.metricsclient throughput / level metrics (empty = none)
metrics = [(struct) sparkles.test_runner.bench.MetricA measurement attached to a benchmark case: amount units of work per timed
iteration. Reported as a per-second rate (amount ÷ iteration-time, a
quantity of dimension unit·s⁻¹) or as a per-iteration level (as-is).
Metric((struct) sparkles.test_runner.bench.UnitA unit of measure for a benchmark metric. A forward-compatible stand-in for
sparkles.quantities' runtime unit — today just the symbol (its identity).
Domain counts ("tweet", "frame", "req") are open-basis units minted by name;
"B"/"s" map to SI base dimensions once the quantities library lands.
Unit("B"), 1000.0, (struct) sparkles.test_runner.bench.MetricA measurement attached to a benchmark case: amount units of work per timed
iteration. Reported as a per-second rate (amount ÷ iteration-time, a
quantity of dimension unit·s⁻¹) or as a per-iteration level (as-is).
Metric.(enum) sparkles.test_runner.bench.Metric.ModeHow the runner reports amount.
Mode.(enum value) sparkles.test_runner.bench.Metric.Mode.rate = 0amount ÷ iteration-time → <unit>/s
rate)];
(struct) sparkles.test_runner.perf.PerfStatsPer-iteration counter averages of one counting pass. A field is nan when
the event could not be opened on this machine (e.g. the LLC pair was
dropped to avoid multiplexing, or the PMU exposes fewer events).
PerfStats (local variable) sparkles.test_runner.perf.PerfStats pp;
(local variable) sparkles.test_runner.perf.PerfStats pp.(field) double sparkles.test_runner.perf.PerfStats.cyclesCPU cycles per iteration
cycles = 100;
(local variable) sparkles.test_runner.perf.PerfStats pp.(field) double sparkles.test_runner.perf.PerfStats.instructionsretired instructions per iteration
instructions = 200;
(local variable) sparkles.test_runner.bench.BenchStats measuredmeasured.(field) std.typecons.Nullable!(PerfStats) sparkles.test_runner.bench.BenchStats.perfhardware counters under --perf`` (empty otherwise)
perf = std.typecons.Nullable!(PerfStats) std.typecons.Nullable!(sparkles.test_runner.perf.PerfStats).opAssign!()(sparkles.test_runner.perf.PerfStats value) pure nothrow @nogc return ref @safeAssigns value to the internally-held state. If the assignment
succeeds, this becomes non-null.
p;
(struct) sparkles.test_runner.bench.BenchStatsSummary statistics of one benchmark row, in nanoseconds per iteration. A row
with a non-empty error is a failure row (its timing fields are unset).
BenchStats (local variable) sparkles.test_runner.bench.BenchStats plainplain;
(local variable) sparkles.test_runner.bench.BenchStats plainplain.(field) string sparkles.test_runner.bench.BenchStats.namename = "sum/64";
(local variable) sparkles.test_runner.bench.BenchStats plainplain.(field) ulong sparkles.test_runner.bench.BenchStats.iterationsiterations per sample
iterations = 1;
(local variable) sparkles.test_runner.bench.BenchStats plainplain.(field) ulong sparkles.test_runner.bench.BenchStats.samplessamples = 32;
(local variable) sparkles.test_runner.bench.BenchStats plainplain.(field) double sparkles.test_runner.bench.BenchStats.nsPerIterMediannsPerIterMedian = 110;
const (local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta = (struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta(date: "2026-07-10", hostname: "h", os: "linux",
arch: "x86_64", compiler: "LDC (front-end 2.111)", cpu: "cpu",
minSampleTimeMs: 5, sampleCount: 32);
const (local variable) const(std.json.JSONValue) docdoc = std.json.JSONValue std.json.parseJSON!string(string json, int maxDepth = -1, std.json.JSONOptions options = JSONOptions.none) pure @safeParses a serialized string and returns a tree of JSON values.
parseJSON(string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson([(local variable) sparkles.test_runner.bench.BenchStats measuredmeasured, (local variable) sparkles.test_runner.bench.BenchStats plainplain], (local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta));
assert((local variable) const(std.json.JSONValue) docdoc["schema"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 2);
assert((local variable) const(std.json.JSONValue) docdoc["meta"]["minSampleTimeMs"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 5);
assert((local variable) const(std.json.JSONValue) docdoc["rows"].inout(std.json.JSONValue[]) std.json.JSONValue.array() inout pure @property return ref scope @systemValue getter/setter for JSONType.array``.
Note
This is @system because of the following pattern:
auto a = &(json.array());
json.uinteger = 0; // overwrite array pointer
(*a)[0] = "world"; // segmentation fault
array.(field) ulong const(std.json.JSONValue[]).lengthlength == 2);
assert((local variable) const(std.json.JSONValue) docdoc["rows"][0]["labels"]["dataset"].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str == "twitter");
assert((local variable) const(std.json.JSONValue) docdoc["rows"][0]["metrics"]["ipc"].inout(double) std.json.JSONValue.get!double() inout const pure @property @safeA convenience getter that returns this JSONValue as the specified D type.
Note
Only numeric types, bool, string, JSONValue[string], and JSONValue[] types are accepted
get!double == 2.0);
assert("estimatedMetrics" !in (local variable) const(std.json.JSONValue) docdoc["rows"][0],
"exact counts carry no estimate list");
assert((local variable) const(std.json.JSONValue) docdoc["rows"][0]["medianNs"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 3_823_300);
assert((local variable) const(std.json.JSONValue) docdoc["rows"][1]["metrics"].inout(std.json.JSONValue[string]) std.json.JSONValue.object() inout pure @property return ref @systemValue getter/setter for unordered JSONType.object``.
Note
This is @system because of the following pattern:
auto a = &(json.object());
json.uinteger = 0; // overwrite AA pointer
(*a)["hello"] = "world"; // segmentation fault
object.(field) ulong const(std.json.JSONValue[string]).lengthlength == 0 || "ipc" !in (local variable) const(std.json.JSONValue) docdoc["rows"][1]["metrics"]);
bool (local variable) bool sawIpcsawIpc;
foreach ((parameter) const(std.json.JSONValue) colcol; (local variable) const(std.json.JSONValue) docdoc["columns"].inout(std.json.JSONValue[]) std.json.JSONValue.array() inout pure @property return ref scope @systemValue getter/setter for JSONType.array``.
Note
This is @system because of the following pattern:
auto a = &(json.array());
json.uinteger = 0; // overwrite array pointer
(*a)[0] = "world"; // segmentation fault
array)
if ((local variable) const(std.json.JSONValue) colcol["name"].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str == "ipc")
{
(local variable) bool sawIpcsawIpc = true;
assert((local variable) const(std.json.JSONValue) colcol["source"].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str == "perf");
}
assert((local variable) bool sawIpcsawIpc);
}
@("benchJson.errorRow.nullTiming")
@system
unittest
{
import (package) stdstd.(module) std.jsonImplements functionality to read and write JavaScript Object Notation values.
JavaScript Object Notation is a lightweight data interchange format commonly used in web services and configuration files.
It's easy for humans to read and write, and it's easy for machines to parse and generate.
Warning: While JSONValue is fine for small-scale use, at the range of hundreds of megabytes it is
known to cause and exacerbate GC problems. If you encounter problems, try replacing it with a stream parser. See
also https://forum.dlang.org/post/dzfyaxypmkdrpakmycjv@forum.dlang.org.
References
http://json.org/, https://seriot.ch/projects/parsing_json.html
Source
std/json.d
Examples
import std.conv : to;
// parse a file or string of json into a usable structure
string s = `{ "language": "D", "rating": 3.5, "code": "42" }`;
JSONValue j = parseJSON(s);
// j and j["language"] return JSONValue,
// j["language"].str returns a string
assert(j["language"].str == "D");
assert(j["rating"].floating == 3.5);
// check a type
long x;
if (const(JSONValue)* code = "code" in j)
{
if (code.type() == JSONType.integer)
x = code.integer;
else
x = to!int(code.str);
}
// create a json struct
JSONValue jj = [ "language": "D" ];
// rating doesnt exist yet, so use .object to assign
jj.object["rating"] = JSONValue(3.5);
// create an array to assign to list
jj.object["list"] = JSONValue( ["a", "b", "c"] );
// list already exists, so .object optional
jj["list"].array ~= JSONValue("D");
string jjStr = `{"language":"D","list":["a","b","c","D"],"rating":3.5}`;
assert(jj.toString == jjStr);
json : (enum) std.json.JSONTypeEnumeration of JSON types
JSONType, (alias template) parseJSON = std.json.parseJSON(T)(T json, int maxDepth = -1, JSONOptions options = JSONOptions.none) if (isSomeFiniteCharInputRange!T)Parses a serialized string and returns a tree of JSON values.
Throws: $(LREF JSONException) if string does not follow the JSON grammar or the depth exceeds the max depth,
$(LREF ConvException) if a number in the input cannot be represented by a native D type.
Params:
json = json-formatted string to parse
maxDepth = maximum depth of nesting allowed, -1 disables depth checking
options = enable decoding string representations of NaN/Inf as float values
parseJSON;
(struct) sparkles.test_runner.bench.BenchStatsSummary statistics of one benchmark row, in nanoseconds per iteration. A row
with a non-empty error is a failure row (its timing fields are unset).
BenchStats (local variable) sparkles.test_runner.bench.BenchStats badbad;
(local variable) sparkles.test_runner.bench.BenchStats badbad.(field) string sparkles.test_runner.bench.BenchStats.namename = "crashed";
(local variable) sparkles.test_runner.bench.BenchStats badbad.(field) string[string] sparkles.test_runner.bench.BenchStats.labelsorthogonal grouping dimensions (from the case's labels)
labels = ["dataset": "canada"];
(local variable) sparkles.test_runner.bench.BenchStats badbad.(field) string sparkles.test_runner.bench.BenchStats.errornon-empty = an error row (a case whose after reported failure)
error = "object.Exception: boom";
const (local variable) const(std.json.JSONValue) docdoc = std.json.JSONValue std.json.parseJSON!string(string json, int maxDepth = -1, std.json.JSONOptions options = JSONOptions.none) pure @safeParses a serialized string and returns a tree of JSON values.
parseJSON(string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson([(local variable) sparkles.test_runner.bench.BenchStats badbad], (struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta(date: "2026-07-10")));
const (local variable) const(std.json.JSONValue) rowrow = (local variable) const(std.json.JSONValue) docdoc["rows"][0];
assert((local variable) const(std.json.JSONValue) rowrow["error"].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str == "object.Exception: boom");
assert((local variable) const(std.json.JSONValue) rowrow["medianNs"].std.json.JSONType std.json.JSONValue.type() const pure nothrow @nogc @property @safeReturns the JSONType of the value stored in this structure.
Examples
string s = "{ \"language\": \"D\" }";
JSONValue j = parseJSON(s);
assert(j.type == JSONType.object);
assert(j["language"].type == JSONType.string);
type == (enum) std.json.JSONTypeEnumeration of JSON types
JSONType.(enum value) std.json.JSONType.null_ = cast(byte)0Indicates the type of a JSONValue.
null_);
assert((local variable) const(std.json.JSONValue) rowrow["iterations"].std.json.JSONType std.json.JSONValue.type() const pure nothrow @nogc @property @safeReturns the JSONType of the value stored in this structure.
Examples
string s = "{ \"language\": \"D\" }";
JSONValue j = parseJSON(s);
assert(j.type == JSONType.object);
assert(j["language"].type == JSONType.string);
type == (enum) std.json.JSONTypeEnumeration of JSON types
JSONType.(enum value) std.json.JSONType.null_ = cast(byte)0Indicates the type of a JSONValue.
null_);
assert((local variable) const(std.json.JSONValue) rowrow["metrics"].inout(std.json.JSONValue[string]) std.json.JSONValue.object() inout pure @property return ref @systemValue getter/setter for unordered JSONType.object``.
Note
This is @system because of the following pattern:
auto a = &(json.object());
json.uinteger = 0; // overwrite AA pointer
(*a)["hello"] = "world"; // segmentation fault
object.(field) ulong const(std.json.JSONValue[string]).lengthlength == 0);
assert((local variable) const(std.json.JSONValue) rowrow["labels"]["dataset"].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str == "canada");
}
@("benchJson.deterministic.sortedLabels")
@system
unittest
{
(struct) sparkles.test_runner.bench.BenchStatsSummary statistics of one benchmark row, in nanoseconds per iteration. A row
with a non-empty error is a failure row (its timing fields are unset).
BenchStats (local variable) sparkles.test_runner.bench.BenchStats aa, (local variable) sparkles.test_runner.bench.BenchStats bb;
(local variable) sparkles.test_runner.bench.BenchStats aa.(field) string sparkles.test_runner.bench.BenchStats.namename = (local variable) sparkles.test_runner.bench.BenchStats bb.(field) string sparkles.test_runner.bench.BenchStats.namename = "x";
(local variable) sparkles.test_runner.bench.BenchStats aa.(field) ulong sparkles.test_runner.bench.BenchStats.iterationsiterations per sample
iterations = (local variable) sparkles.test_runner.bench.BenchStats bb.(field) ulong sparkles.test_runner.bench.BenchStats.iterationsiterations per sample
iterations = 1;
// Different insertion orders must emit identical documents.
(local variable) sparkles.test_runner.bench.BenchStats aa.(field) string[string] sparkles.test_runner.bench.BenchStats.labelsorthogonal grouping dimensions (from the case's labels)
labels = ["k1": "v1", "k2": "v2"];
(local variable) sparkles.test_runner.bench.BenchStats bb.(field) string[string] sparkles.test_runner.bench.BenchStats.labelsorthogonal grouping dimensions (from the case's labels)
labels = ["k2": "v2"];
string* core.internal.newaa._d_aaGetY!(string, string, string[string], string, string, string)(ref scope string[string] aa, string key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
b.string* core.internal.newaa._d_aaGetY!(string, string, string[string], string, string, string)(ref scope string[string] aa, string key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
labels["k1"] = "v1";
const (local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta = (struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta(date: "2026-07-10");
const (local variable) const(string) oneone = string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson([(local variable) sparkles.test_runner.bench.BenchStats aa], (local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta);
assert((local variable) const(string) oneone == string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson([(local variable) sparkles.test_runner.bench.BenchStats bb], (local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta));
assert((local variable) const(string) oneone == string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson([(local variable) sparkles.test_runner.bench.BenchStats aa], (local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta), "re-emission is byte-identical");
}
@("benchJson.escaping")
@system
unittest
{
import (package) stdstd.(module) std.jsonImplements functionality to read and write JavaScript Object Notation values.
JavaScript Object Notation is a lightweight data interchange format commonly used in web services and configuration files.
It's easy for humans to read and write, and it's easy for machines to parse and generate.
Warning: While JSONValue is fine for small-scale use, at the range of hundreds of megabytes it is
known to cause and exacerbate GC problems. If you encounter problems, try replacing it with a stream parser. See
also https://forum.dlang.org/post/dzfyaxypmkdrpakmycjv@forum.dlang.org.
References
http://json.org/, https://seriot.ch/projects/parsing_json.html
Source
std/json.d
Examples
import std.conv : to;
// parse a file or string of json into a usable structure
string s = `{ "language": "D", "rating": 3.5, "code": "42" }`;
JSONValue j = parseJSON(s);
// j and j["language"] return JSONValue,
// j["language"].str returns a string
assert(j["language"].str == "D");
assert(j["rating"].floating == 3.5);
// check a type
long x;
if (const(JSONValue)* code = "code" in j)
{
if (code.type() == JSONType.integer)
x = code.integer;
else
x = to!int(code.str);
}
// create a json struct
JSONValue jj = [ "language": "D" ];
// rating doesnt exist yet, so use .object to assign
jj.object["rating"] = JSONValue(3.5);
// create an array to assign to list
jj.object["list"] = JSONValue( ["a", "b", "c"] );
// list already exists, so .object optional
jj["list"].array ~= JSONValue("D");
string jjStr = `{"language":"D","list":["a","b","c","D"],"rating":3.5}`;
assert(jj.toString == jjStr);
json : (alias template) parseJSON = std.json.parseJSON(T)(T json, int maxDepth = -1, JSONOptions options = JSONOptions.none) if (isSomeFiniteCharInputRange!T)Parses a serialized string and returns a tree of JSON values.
Throws: $(LREF JSONException) if string does not follow the JSON grammar or the depth exceeds the max depth,
$(LREF ConvException) if a number in the input cannot be represented by a native D type.
Params:
json = json-formatted string to parse
maxDepth = maximum depth of nesting allowed, -1 disables depth checking
options = enable decoding string representations of NaN/Inf as float values
parseJSON;
(struct) sparkles.test_runner.bench.BenchStatsSummary statistics of one benchmark row, in nanoseconds per iteration. A row
with a non-empty error is a failure row (its timing fields are unset).
BenchStats (local variable) sparkles.test_runner.bench.BenchStats rowrow;
(local variable) sparkles.test_runner.bench.BenchStats rowrow.(field) string sparkles.test_runner.bench.BenchStats.namename = "quote \" back \\ newline \n tab \t";
(local variable) sparkles.test_runner.bench.BenchStats rowrow.(field) ulong sparkles.test_runner.bench.BenchStats.iterationsiterations per sample
iterations = 1;
const (local variable) const(std.json.JSONValue) docdoc = std.json.JSONValue std.json.parseJSON!string(string json, int maxDepth = -1, std.json.JSONOptions options = JSONOptions.none) pure @safeParses a serialized string and returns a tree of JSON values.
parseJSON(string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson([(local variable) sparkles.test_runner.bench.BenchStats rowrow], (struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta(date: "2026-07-10")));
assert((local variable) const(std.json.JSONValue) docdoc["rows"][0]["name"].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str == (local variable) sparkles.test_runner.bench.BenchStats rowrow.(field) string sparkles.test_runner.bench.BenchStats.namename, "escaping round-trips");
}
@("benchJson.meta.collect")
@system
unittest
{
import (package) corecore.(module) core.timeModule containing core time functionality, such as Duration (which
represents a duration of time) or MonoTime (which represents a
timestamp of the system's monotonic clock).
Various functions take a string (or strings) to represent a unit of time
(e.g. convert!("days", "hours")(numDays)). The valid strings to use
with such functions are "years", "months", "weeks", "days", "hours",
"minutes", "seconds", "msecs" (milliseconds), "usecs" (microseconds),
"hnsecs" (hecto-nanoseconds - i.e. 100 ns) or some subset thereof. There
are a few functions that also allow "nsecs", but very little actually
has precision greater than hnsecs.
Symbol Description Types Duration Represents a duration of time of weeks or less (kept internally as hnsecs). (e.g. 22 days or 700 seconds). TickDuration DEPRECATED Represents a duration of time in system clock ticks, using the highest precision that the system provides. MonoTime Represents a monotonic timestamp in system clock ticks, using the highest precision that the system provides. Functions convert Generic way of converting between two time units. dur Allows constructing a Duration from the given time units with the given length. weeks days hours
minutes seconds msecs
usecs hnsecs nsecs |
Convenience aliases for dur. |
| abs | Returns the absolute value of a duration. |
From Duration
From TickDuration
From units
To Duration tickDuration.to, std,conv!Duration() dur!"msecs"(5) or 5.msecs()
| To TickDuration |
duration.to, std,conv!TickDuration() |
|
TickDuration.from!"msecs"(msecs) |
| To units |
duration.total!"days" |
tickDuration.msecs |
convert!("days", "msecs")(msecs) |
Source
core/time.d
time : msecs;
import (package) stdstd.(package) std.algorithmalgorithm.(module) std.algorithm.searchingThis is a submodule of std.algorithm.
It contains generic searching algorithms.
Function Name Description all all!"a > 0"([1, 2, 3, 4]) returns true because all elements are positive any any!"a > 0"([1, 2, -3, -4]) returns true because at least one element is positive balancedParens balancedParens("((1 + 1) / 2)", '(', ')') returns true because the string has balanced parentheses. boyerMooreFinder find("hello world", boyerMooreFinder("or")) returns "orld" using the Boyer-Moore algorithm. canFind canFind("hello world", "or") returns true. count Counts all elements or elements matching a predicate, specific element or sub-range.
count([1, 2, 1]) returns 3,
count([1, 2, 1], 1) returns 2 and
count!"a < 0"([1, -3, 0]) returns 1. |
| countUntil | countUntil(a, b) returns the number of steps taken in a to reach b; for example, countUntil("hello!", "o") returns 4. |
| commonPrefix | commonPrefix("parakeet", "parachute") returns "para". |
| endsWith | endsWith("rocks", "ks") returns true. |
| extrema | extrema([2, 1, 3, 5, 4]) returns [1, 5]. |
| find | find("hello world", "or") returns "orld" using linear search. (For binary search refer to SortedRange.) |
| findAdjacent | findAdjacent([1, 2, 3, 3, 4]) returns the subrange starting with two equal adjacent elements, i.e. [3, 3, 4]. |
| findAmong | findAmong("abcd", "qcx") returns "cd" because 'c' is among "qcx". |
| findSkip | If a = "abcde", then findSkip(a, "x") returns false and leaves a unchanged, whereas findSkip(a, "c") advances a to "de" and returns true. |
| findSplit | findSplit("abcdefg", "de") returns a tuple of three ranges "abc", "de", and "fg". |
| findSplitAfter | findSplitAfter("abcdefg", "de") returns a tuple of two ranges "abcde" and "fg". |
| findSplitBefore | findSplitBefore("abcdefg", "de") returns a tuple of two ranges "abc" and "defg". |
| minCount | minCount([2, 1, 1, 4, 1]) returns tuple(1, 3). |
| maxCount | maxCount([2, 4, 1, 4, 1]) returns tuple(4, 2). |
| minElement | Selects the minimal element of a range. minElement([3, 4, 1, 2]) returns 1. |
| maxElement | Selects the maximal element of a range. maxElement([3, 4, 1, 2]) returns 4. |
| minIndex | Index of the minimal element of a range. minIndex([3, 4, 1, 2]) returns 2. |
| maxIndex | Index of the maximal element of a range. maxIndex([3, 4, 1, 2]) returns 1. |
| minPos | minPos([2, 3, 1, 3, 4, 1]) returns the subrange [1, 3, 4, 1], i.e., positions the range at the first occurrence of its minimal element. |
| maxPos | maxPos([2, 3, 1, 3, 4, 1]) returns the subrange [4, 1], i.e., positions the range at the first occurrence of its maximal element. |
| skipOver | Assume a = "blah". Then skipOver(a, "bi") leaves a unchanged and returns false, whereas skipOver(a, "bl") advances a to refer to "ah" and returns true. |
| startsWith | startsWith("hello, world", "hello") returns true. |
| until | Lazily iterates a range until a specific value is found. |
Source
std/algorithm/searching.d
searching : (alias template) canFind = std.algorithm.searching.canFind(alias pred = "a == b")Convenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see $(LREF find).
See_Also:
$(REF among, std,algorithm,comparison) for checking a value against multiple arguments.
canFind;
const (local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta = sparkles.test_runner.bench_json.BenchMeta sparkles.test_runner.bench_json.collectBenchMeta(in sparkles.test_runner.bench.BenchConfig config) @safeCollects host/toolchain provenance and the run's effective knobs.
collectBenchMeta((struct) sparkles.test_runner.bench.BenchConfigTuning knobs of one benchmark run.
BenchConfig(minSampleTime: 2000.msecs));
assert((local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta.(field) long sparkles.test_runner.bench_json.BenchMeta.minSampleTimeMseffective per-sample/total budget (--bench-min-time)
minSampleTimeMs == 2000);
assert((local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta.(field) uint sparkles.test_runner.bench_json.BenchMeta.sampleCounteffective BenchConfig.sampleCount
sampleCount == 32);
assert((local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta.(field) string sparkles.test_runner.bench_json.BenchMeta.compilere.g. "LDC (front-end 2.111)"
compiler.bool std.algorithm.searching.canFind!().canFind!(string, string)(string haystack, scope string needle) pure nothrow @nogc @safeConvenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see find.
Examples
const arr = [0, 1, 2, 3];
assert(canFind(arr, 2));
assert(!canFind(arr, 4));
// find one of several needles
assert(arr.canFind(3, 2));
assert(arr.canFind(3, 2) == 2); // second needle found
assert(arr.canFind([1, 3], 2) == 2);
assert(canFind(arr, [1, 2], [2, 3]));
assert(canFind(arr, [1, 2], [2, 3]) == 1);
assert(canFind(arr, [1, 7], [2, 3]));
assert(canFind(arr, [1, 7], [2, 3]) == 2);
assert(!canFind(arr, [1, 3], [2, 4]));
assert(canFind(arr, [1, 3], [2, 4]) == 0);
Example using a custom predicate.
Note that the needle appears as the second argument of the predicate.
auto words = [
"apple",
"beeswax",
"cardboard"
];
assert(!canFind(words, "bees"));
assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
Search for multiple items in an array of items (search for needles in an array of haystacks)
string s1 = "aaa111aaa";
string s2 = "aaa222aaa";
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
assert(hay.canFind!(e => e.canFind("111", "222")));
canFind("front-end"));
assert((local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta.(field) string sparkles.test_runner.bench_json.BenchMeta.osos.(field) ulong const(string).lengthlength && (local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta.(field) string sparkles.test_runner.bench_json.BenchMeta.archarch.(field) ulong const(string).lengthlength);
assert((local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta.(field) string sparkles.test_runner.bench_json.BenchMeta.dateISO day, e.g. "2026-07-10"
date.(field) ulong const(string).lengthlength == 10); // ISO day
}
@("benchJson.rows.estimatedMetrics")
@system
unittest
{
import (package) stdstd.(module) std.jsonImplements functionality to read and write JavaScript Object Notation values.
JavaScript Object Notation is a lightweight data interchange format commonly used in web services and configuration files.
It's easy for humans to read and write, and it's easy for machines to parse and generate.
Warning: While JSONValue is fine for small-scale use, at the range of hundreds of megabytes it is
known to cause and exacerbate GC problems. If you encounter problems, try replacing it with a stream parser. See
also https://forum.dlang.org/post/dzfyaxypmkdrpakmycjv@forum.dlang.org.
References
http://json.org/, https://seriot.ch/projects/parsing_json.html
Source
std/json.d
Examples
import std.conv : to;
// parse a file or string of json into a usable structure
string s = `{ "language": "D", "rating": 3.5, "code": "42" }`;
JSONValue j = parseJSON(s);
// j and j["language"] return JSONValue,
// j["language"].str returns a string
assert(j["language"].str == "D");
assert(j["rating"].floating == 3.5);
// check a type
long x;
if (const(JSONValue)* code = "code" in j)
{
if (code.type() == JSONType.integer)
x = code.integer;
else
x = to!int(code.str);
}
// create a json struct
JSONValue jj = [ "language": "D" ];
// rating doesnt exist yet, so use .object to assign
jj.object["rating"] = JSONValue(3.5);
// create an array to assign to list
jj.object["list"] = JSONValue( ["a", "b", "c"] );
// list already exists, so .object optional
jj["list"].array ~= JSONValue("D");
string jjStr = `{"language":"D","list":["a","b","c","D"],"rating":3.5}`;
assert(jj.toString == jjStr);
json : (alias template) parseJSON = std.json.parseJSON(T)(T json, int maxDepth = -1, JSONOptions options = JSONOptions.none) if (isSomeFiniteCharInputRange!T)Parses a serialized string and returns a tree of JSON values.
Throws: $(LREF JSONException) if string does not follow the JSON grammar or the depth exceeds the max depth,
$(LREF ConvException) if a number in the input cannot be represented by a native D type.
Params:
json = json-formatted string to parse
maxDepth = maximum depth of nesting allowed, -1 disables depth checking
options = enable decoding string representations of NaN/Inf as float values
parseJSON;
import (package) sparklessparkles.(package) sparkles.test_runnertest_runner.(module) sparkles.test_runner.perfHardware performance counters via perf_event_open(2), in pure D.
One counter group (cycles leader; instructions, branches, branch-misses,
cache-references, cache-misses, plus the page-fault software event) is
opened once and reused: a benchmark's counting pass — separate from the
wall-clock measurement — brackets only the timed body with
PERF_EVENT_IOC_ENABLE/DISABLE, so the per-iteration ioctls never pollute
the reported timings and any between() cleanup is never counted.
Counters answer why two implementations differ: IPC, cycles and
instructions per iteration, branch/cache miss rates, and the page-fault
(allocation) signature. On kernels that refuse perf_event_open
(perf_event_paranoid, seccomp) — and on platforms with no backend at
all — this degrades gracefully: PerfGroup.available is false and
callers simply omit the counter columns.
The binding is pure D over druntime's core.sys.linux.perf_event (which
carries the arch-specific syscall numbers, the perf_event_attr layout, and
a perf_event_open wrapper) plus ioctl/read/close — no ImportC, so the
module source-includes cleanly into every host package's test build.
On macOS the same PerfGroup surface is backed by
proc_pid_rusage(RUSAGE_INFO_V4) — the unprivileged XNU fixed counters:
true retired instructions and core cycles (process-wide, user+kernel, all
threads), so --perf`` renders IPC and instr/iter with the other columns
honestly absent. Everything richer is a capability ad, not a backend: kpc
is root-or-blessed with the RESTRICT_TO_KNOWN allowlist, and sampling is
Instruments/xctrace-brokered only.
perf : (struct) sparkles.test_runner.perf.PerfStatsPer-iteration counter averages of one counting pass. A field is nan when
the event could not be opened on this machine (e.g. the LLC pair was
dropped to avoid multiplexing, or the PMU exposes fewer events).
PerfStats;
(struct) sparkles.test_runner.bench.BenchStatsSummary statistics of one benchmark row, in nanoseconds per iteration. A row
with a non-empty error is a failure row (its timing fields are unset).
BenchStats (local variable) sparkles.test_runner.bench.BenchStats rowrow;
(local variable) sparkles.test_runner.bench.BenchStats rowrow.(field) string sparkles.test_runner.bench.BenchStats.namename = "scaled";
(local variable) sparkles.test_runner.bench.BenchStats rowrow.(field) ulong sparkles.test_runner.bench.BenchStats.iterationsiterations per sample
iterations = 1;
(local variable) sparkles.test_runner.bench.BenchStats rowrow.(field) ulong sparkles.test_runner.bench.BenchStats.samplessamples = 32;
(local variable) sparkles.test_runner.bench.BenchStats rowrow.(field) double sparkles.test_runner.bench.BenchStats.nsPerIterMediannsPerIterMedian = 100;
(struct) sparkles.test_runner.perf.PerfStatsPer-iteration counter averages of one counting pass. A field is nan when
the event could not be opened on this machine (e.g. the LLC pair was
dropped to avoid multiplexing, or the PMU exposes fewer events).
PerfStats (local variable) sparkles.test_runner.perf.PerfStats pp;
(local variable) sparkles.test_runner.perf.PerfStats pp.(field) double sparkles.test_runner.perf.PerfStats.cyclesCPU cycles per iteration
cycles = 100;
(local variable) sparkles.test_runner.perf.PerfStats pp.(field) double sparkles.test_runner.perf.PerfStats.instructionsretired instructions per iteration
instructions = 200;
(local variable) sparkles.test_runner.perf.PerfStats pp.(field) double sparkles.test_runner.perf.PerfStats.scalecounter running/enabled ratio (1 = clean)
scale = 0.5; // a half-scheduled pass: values are estimates
(local variable) sparkles.test_runner.bench.BenchStats rowrow.(field) std.typecons.Nullable!(PerfStats) sparkles.test_runner.bench.BenchStats.perfhardware counters under --perf`` (empty otherwise)
perf = std.typecons.Nullable!(PerfStats) std.typecons.Nullable!(sparkles.test_runner.perf.PerfStats).opAssign!()(sparkles.test_runner.perf.PerfStats value) pure nothrow @nogc return ref @safeAssigns value to the internally-held state. If the assignment
succeeds, this becomes non-null.
p;
const (local variable) const(std.json.JSONValue) docdoc = std.json.JSONValue std.json.parseJSON!string(string json, int maxDepth = -1, std.json.JSONOptions options = JSONOptions.none) pure @safeParses a serialized string and returns a tree of JSON values.
parseJSON(string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson([(local variable) sparkles.test_runner.bench.BenchStats rowrow], (struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta(date: "2026-07-10")));
const (local variable) const(std.json.JSONValue[]) estest = (local variable) const(std.json.JSONValue) docdoc["rows"][0]["estimatedMetrics"].inout(std.json.JSONValue[]) std.json.JSONValue.array() inout pure @property return ref scope @systemValue getter/setter for JSONType.array``.
Note
This is @system because of the following pattern:
auto a = &(json.array());
json.uinteger = 0; // overwrite array pointer
(*a)[0] = "world"; // segmentation fault
array;
assert((local variable) const(std.json.JSONValue[]) estest.(field) ulong const(std.json.JSONValue[]).lengthlength > 0);
bool (local variable) bool foundIpcfoundIpc;
foreach ((parameter) const(std.json.JSONValue) ee; (local variable) const(std.json.JSONValue[]) estest)
(local variable) bool foundIpcfoundIpc |= (local variable) const(std.json.JSONValue) ee.string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str == "ipc";
assert((local variable) bool foundIpcfoundIpc, "the scaled perf cells are named");
}
@("benchJson.meta.provenance")
@system
unittest
{
import (package) stdstd.(module) std.jsonImplements functionality to read and write JavaScript Object Notation values.
JavaScript Object Notation is a lightweight data interchange format commonly used in web services and configuration files.
It's easy for humans to read and write, and it's easy for machines to parse and generate.
Warning: While JSONValue is fine for small-scale use, at the range of hundreds of megabytes it is
known to cause and exacerbate GC problems. If you encounter problems, try replacing it with a stream parser. See
also https://forum.dlang.org/post/dzfyaxypmkdrpakmycjv@forum.dlang.org.
References
http://json.org/, https://seriot.ch/projects/parsing_json.html
Source
std/json.d
Examples
import std.conv : to;
// parse a file or string of json into a usable structure
string s = `{ "language": "D", "rating": 3.5, "code": "42" }`;
JSONValue j = parseJSON(s);
// j and j["language"] return JSONValue,
// j["language"].str returns a string
assert(j["language"].str == "D");
assert(j["rating"].floating == 3.5);
// check a type
long x;
if (const(JSONValue)* code = "code" in j)
{
if (code.type() == JSONType.integer)
x = code.integer;
else
x = to!int(code.str);
}
// create a json struct
JSONValue jj = [ "language": "D" ];
// rating doesnt exist yet, so use .object to assign
jj.object["rating"] = JSONValue(3.5);
// create an array to assign to list
jj.object["list"] = JSONValue( ["a", "b", "c"] );
// list already exists, so .object optional
jj["list"].array ~= JSONValue("D");
string jjStr = `{"language":"D","list":["a","b","c","D"],"rating":3.5}`;
assert(jj.toString == jjStr);
json : (alias template) parseJSON = std.json.parseJSON(T)(T json, int maxDepth = -1, JSONOptions options = JSONOptions.none) if (isSomeFiniteCharInputRange!T)Parses a serialized string and returns a tree of JSON values.
Throws: $(LREF JSONException) if string does not follow the JSON grammar or the depth exceeds the max depth,
$(LREF ConvException) if a number in the input cannot be represented by a native D type.
Params:
json = json-formatted string to parse
maxDepth = maximum depth of nesting allowed, -1 disables depth checking
options = enable decoding string representations of NaN/Inf as float values
parseJSON;
(struct) sparkles.test_runner.bench.BenchStatsSummary statistics of one benchmark row, in nanoseconds per iteration. A row
with a non-empty error is a failure row (its timing fields are unset).
BenchStats (local variable) sparkles.test_runner.bench.BenchStats rowrow;
(local variable) sparkles.test_runner.bench.BenchStats rowrow.(field) string sparkles.test_runner.bench.BenchStats.namename = "x";
(local variable) sparkles.test_runner.bench.BenchStats rowrow.(field) ulong sparkles.test_runner.bench.BenchStats.iterationsiterations per sample
iterations = 1;
const (local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta = (struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta(date: "2026-07-12",
provenance: ["glibc malloc trim/mmap thresholds raised to 64 MiB",
"codegen: library-inline"]);
const (local variable) const(std.json.JSONValue) docdoc = std.json.JSONValue std.json.parseJSON!string(string json, int maxDepth = -1, std.json.JSONOptions options = JSONOptions.none) pure @safeParses a serialized string and returns a tree of JSON values.
parseJSON(string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson([(local variable) sparkles.test_runner.bench.BenchStats rowrow], (local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta));
const (local variable) const(std.json.JSONValue[]) pp = (local variable) const(std.json.JSONValue) docdoc["meta"]["provenance"].inout(std.json.JSONValue[]) std.json.JSONValue.array() inout pure @property return ref scope @systemValue getter/setter for JSONType.array``.
Note
This is @system because of the following pattern:
auto a = &(json.array());
json.uinteger = 0; // overwrite array pointer
(*a)[0] = "world"; // segmentation fault
array;
assert((local variable) const(std.json.JSONValue[]) pp.(field) ulong const(std.json.JSONValue[]).lengthlength == 2);
assert((local variable) const(std.json.JSONValue[]) pp[0].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str == "glibc malloc trim/mmap thresholds raised to 64 MiB");
assert((local variable) const(std.json.JSONValue[]) pp[1].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str == "codegen: library-inline");
const (local variable) const(std.json.JSONValue) barebare = std.json.JSONValue std.json.parseJSON!string(string json, int maxDepth = -1, std.json.JSONOptions options = JSONOptions.none) pure @safeParses a serialized string and returns a tree of JSON values.
parseJSON(string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson([(local variable) sparkles.test_runner.bench.BenchStats rowrow], (struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta(date: "2026-07-12")));
assert("provenance" !in (local variable) const(std.json.JSONValue) barebare["meta"], "no lines registered — no key");
}
@("benchJson.rows.countIterations")
@system
unittest
{
import (package) stdstd.(module) std.jsonImplements functionality to read and write JavaScript Object Notation values.
JavaScript Object Notation is a lightweight data interchange format commonly used in web services and configuration files.
It's easy for humans to read and write, and it's easy for machines to parse and generate.
Warning: While JSONValue is fine for small-scale use, at the range of hundreds of megabytes it is
known to cause and exacerbate GC problems. If you encounter problems, try replacing it with a stream parser. See
also https://forum.dlang.org/post/dzfyaxypmkdrpakmycjv@forum.dlang.org.
References
http://json.org/, https://seriot.ch/projects/parsing_json.html
Source
std/json.d
Examples
import std.conv : to;
// parse a file or string of json into a usable structure
string s = `{ "language": "D", "rating": 3.5, "code": "42" }`;
JSONValue j = parseJSON(s);
// j and j["language"] return JSONValue,
// j["language"].str returns a string
assert(j["language"].str == "D");
assert(j["rating"].floating == 3.5);
// check a type
long x;
if (const(JSONValue)* code = "code" in j)
{
if (code.type() == JSONType.integer)
x = code.integer;
else
x = to!int(code.str);
}
// create a json struct
JSONValue jj = [ "language": "D" ];
// rating doesnt exist yet, so use .object to assign
jj.object["rating"] = JSONValue(3.5);
// create an array to assign to list
jj.object["list"] = JSONValue( ["a", "b", "c"] );
// list already exists, so .object optional
jj["list"].array ~= JSONValue("D");
string jjStr = `{"language":"D","list":["a","b","c","D"],"rating":3.5}`;
assert(jj.toString == jjStr);
json : (alias template) parseJSON = std.json.parseJSON(T)(T json, int maxDepth = -1, JSONOptions options = JSONOptions.none) if (isSomeFiniteCharInputRange!T)Parses a serialized string and returns a tree of JSON values.
Throws: $(LREF JSONException) if string does not follow the JSON grammar or the depth exceeds the max depth,
$(LREF ConvException) if a number in the input cannot be represented by a native D type.
Params:
json = json-formatted string to parse
maxDepth = maximum depth of nesting allowed, -1 disables depth checking
options = enable decoding string representations of NaN/Inf as float values
parseJSON;
import (package) sparklessparkles.(package) sparkles.test_runnertest_runner.(module) sparkles.test_runner.perfHardware performance counters via perf_event_open(2), in pure D.
One counter group (cycles leader; instructions, branches, branch-misses,
cache-references, cache-misses, plus the page-fault software event) is
opened once and reused: a benchmark's counting pass — separate from the
wall-clock measurement — brackets only the timed body with
PERF_EVENT_IOC_ENABLE/DISABLE, so the per-iteration ioctls never pollute
the reported timings and any between() cleanup is never counted.
Counters answer why two implementations differ: IPC, cycles and
instructions per iteration, branch/cache miss rates, and the page-fault
(allocation) signature. On kernels that refuse perf_event_open
(perf_event_paranoid, seccomp) — and on platforms with no backend at
all — this degrades gracefully: PerfGroup.available is false and
callers simply omit the counter columns.
The binding is pure D over druntime's core.sys.linux.perf_event (which
carries the arch-specific syscall numbers, the perf_event_attr layout, and
a perf_event_open wrapper) plus ioctl/read/close — no ImportC, so the
module source-includes cleanly into every host package's test build.
On macOS the same PerfGroup surface is backed by
proc_pid_rusage(RUSAGE_INFO_V4) — the unprivileged XNU fixed counters:
true retired instructions and core cycles (process-wide, user+kernel, all
threads), so --perf`` renders IPC and instr/iter with the other columns
honestly absent. Everything richer is a capability ad, not a backend: kpc
is root-or-blessed with the RESTRICT_TO_KNOWN allowlist, and sampling is
Instruments/xctrace-brokered only.
perf : (struct) sparkles.test_runner.perf.PerfStatsPer-iteration counter averages of one counting pass. A field is nan when
the event could not be opened on this machine (e.g. the LLC pair was
dropped to avoid multiplexing, or the PMU exposes fewer events).
PerfStats;
(struct) sparkles.test_runner.bench.BenchStatsSummary statistics of one benchmark row, in nanoseconds per iteration. A row
with a non-empty error is a failure row (its timing fields are unset).
BenchStats (local variable) sparkles.test_runner.bench.BenchStats countedcounted;
(local variable) sparkles.test_runner.bench.BenchStats countedcounted.(field) string sparkles.test_runner.bench.BenchStats.namename = "counted";
(local variable) sparkles.test_runner.bench.BenchStats countedcounted.(field) ulong sparkles.test_runner.bench.BenchStats.iterationsiterations per sample
iterations = 1;
(struct) sparkles.test_runner.perf.PerfStatsPer-iteration counter averages of one counting pass. A field is nan when
the event could not be opened on this machine (e.g. the LLC pair was
dropped to avoid multiplexing, or the PMU exposes fewer events).
PerfStats (local variable) sparkles.test_runner.perf.PerfStats pp;
(local variable) sparkles.test_runner.perf.PerfStats pp.(field) ulong sparkles.test_runner.perf.PerfStats.iterscounting-pass iterations
iters = 7;
(local variable) sparkles.test_runner.perf.PerfStats pp.(field) double sparkles.test_runner.perf.PerfStats.cyclesCPU cycles per iteration
cycles = 100;
(local variable) sparkles.test_runner.bench.BenchStats countedcounted.(field) std.typecons.Nullable!(PerfStats) sparkles.test_runner.bench.BenchStats.perfhardware counters under --perf`` (empty otherwise)
perf = std.typecons.Nullable!(PerfStats) std.typecons.Nullable!(sparkles.test_runner.perf.PerfStats).opAssign!()(sparkles.test_runner.perf.PerfStats value) pure nothrow @nogc return ref @safeAssigns value to the internally-held state. If the assignment
succeeds, this becomes non-null.
p;
(struct) sparkles.test_runner.bench.BenchStatsSummary statistics of one benchmark row, in nanoseconds per iteration. A row
with a non-empty error is a failure row (its timing fields are unset).
BenchStats (local variable) sparkles.test_runner.bench.BenchStats uncounteduncounted;
(local variable) sparkles.test_runner.bench.BenchStats uncounteduncounted.(field) string sparkles.test_runner.bench.BenchStats.namename = "plain";
(local variable) sparkles.test_runner.bench.BenchStats uncounteduncounted.(field) ulong sparkles.test_runner.bench.BenchStats.iterationsiterations per sample
iterations = 1;
const (local variable) const(std.json.JSONValue) docdoc = std.json.JSONValue std.json.parseJSON!string(string json, int maxDepth = -1, std.json.JSONOptions options = JSONOptions.none) pure @safeParses a serialized string and returns a tree of JSON values.
parseJSON(string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson([(local variable) sparkles.test_runner.bench.BenchStats countedcounted, (local variable) sparkles.test_runner.bench.BenchStats uncounteduncounted],
(struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta(date: "2026-07-12")));
assert((local variable) const(std.json.JSONValue) docdoc["rows"][0]["countIterations"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 7);
assert("countIterations" !in (local variable) const(std.json.JSONValue) docdoc["rows"][1], "no counting pass — no key");
}
@("benchJson.windows.roundTrip")
@system
unittest
{
import (package) stdstd.(module) std.jsonImplements functionality to read and write JavaScript Object Notation values.
JavaScript Object Notation is a lightweight data interchange format commonly used in web services and configuration files.
It's easy for humans to read and write, and it's easy for machines to parse and generate.
Warning: While JSONValue is fine for small-scale use, at the range of hundreds of megabytes it is
known to cause and exacerbate GC problems. If you encounter problems, try replacing it with a stream parser. See
also https://forum.dlang.org/post/dzfyaxypmkdrpakmycjv@forum.dlang.org.
References
http://json.org/, https://seriot.ch/projects/parsing_json.html
Source
std/json.d
Examples
import std.conv : to;
// parse a file or string of json into a usable structure
string s = `{ "language": "D", "rating": 3.5, "code": "42" }`;
JSONValue j = parseJSON(s);
// j and j["language"] return JSONValue,
// j["language"].str returns a string
assert(j["language"].str == "D");
assert(j["rating"].floating == 3.5);
// check a type
long x;
if (const(JSONValue)* code = "code" in j)
{
if (code.type() == JSONType.integer)
x = code.integer;
else
x = to!int(code.str);
}
// create a json struct
JSONValue jj = [ "language": "D" ];
// rating doesnt exist yet, so use .object to assign
jj.object["rating"] = JSONValue(3.5);
// create an array to assign to list
jj.object["list"] = JSONValue( ["a", "b", "c"] );
// list already exists, so .object optional
jj["list"].array ~= JSONValue("D");
string jjStr = `{"language":"D","list":["a","b","c","D"],"rating":3.5}`;
assert(jj.toString == jjStr);
json : (enum) std.json.JSONTypeEnumeration of JSON types
JSONType, (alias template) parseJSON = std.json.parseJSON(T)(T json, int maxDepth = -1, JSONOptions options = JSONOptions.none) if (isSomeFiniteCharInputRange!T)Parses a serialized string and returns a tree of JSON values.
Throws: $(LREF JSONException) if string does not follow the JSON grammar or the depth exceeds the max depth,
$(LREF ConvException) if a number in the input cannot be represented by a native D type.
Params:
json = json-formatted string to parse
maxDepth = maximum depth of nesting allowed, -1 disables depth checking
options = enable decoding string representations of NaN/Inf as float values
parseJSON;
import (package) stdstd.(module) std.typeconsThis module implements a variety of type constructors, i.e., templates
that allow construction of new, useful general-purpose types.
Category Symbols Tuple isTuple Tuple tuple reverse Flags BitFlags isBitFlagEnum Flag No Yes Reference Counting borrow RefCountedAutoInitialize RefCounted refCounted SafeRefCounted safeRefCounted Memory allocation scoped Unique Code generation AutoImplement BlackHole generateAssertTrap generateEmptyFunction NotImplementedError WhiteHole Nullable apply Nullable nullable NullableRef nullableRef Proxies Proxy rebindable Rebindable unwrap wrap Types alignForSize ReplaceType ReplaceTypeUnless Ternary Typedef TypedefType UnqualRef
Source
std/typecons.d
Examples
Value tuples
alias Coord = Tuple!(int, "x", int, "y", int, "z");
Coord c;
c[1] = 1; // access by index
c.z = 1; // access by given name
assert(c == Coord(0, 1, 1));
// names can be omitted, types can be mixed
alias DictEntry = Tuple!(string, int);
auto dict = DictEntry("seven", 7);
// element types can be inferred
assert(tuple(2, 3, 4)[1] == 3);
// type inference works with names too
auto tup = tuple!("x", "y", "z")(2, 3, 4);
assert(tup.y == 3);
Rebindable references to const and immutable objects
class Widget
{
void foo() const @safe {}
}
const w1 = new Widget, w2 = new Widget;
w1.foo();
// w1 = w2 would not work; can't rebind const object
auto r = Rebindable!(const Widget)(w1);
// invoke method as if r were a Widget object
r.foo();
// rebind r to refer to another object
r = w2;
typecons : (alias template) nullable = std.typecons.nullable(T)(T t)Defines a value paired with a distinctive "null" state that denotes
the absence of a value. If default constructed, a $(D
Nullable!T) object starts in the null state. Assigning it renders it
non-null. Calling nullify can nullify it again.
Practically Nullable!T stores a T and a bool.
See also:
$(LREF apply), an alternative way to use the payload.
nullable;
import (package) sparklessparkles.(package) sparkles.test_runnertest_runner.(module) sparkles.test_runner.perfHardware performance counters via perf_event_open(2), in pure D.
One counter group (cycles leader; instructions, branches, branch-misses,
cache-references, cache-misses, plus the page-fault software event) is
opened once and reused: a benchmark's counting pass — separate from the
wall-clock measurement — brackets only the timed body with
PERF_EVENT_IOC_ENABLE/DISABLE, so the per-iteration ioctls never pollute
the reported timings and any between() cleanup is never counted.
Counters answer why two implementations differ: IPC, cycles and
instructions per iteration, branch/cache miss rates, and the page-fault
(allocation) signature. On kernels that refuse perf_event_open
(perf_event_paranoid, seccomp) — and on platforms with no backend at
all — this degrades gracefully: PerfGroup.available is false and
callers simply omit the counter columns.
The binding is pure D over druntime's core.sys.linux.perf_event (which
carries the arch-specific syscall numbers, the perf_event_attr layout, and
a perf_event_open wrapper) plus ioctl/read/close — no ImportC, so the
module source-includes cleanly into every host package's test build.
On macOS the same PerfGroup surface is backed by
proc_pid_rusage(RUSAGE_INFO_V4) — the unprivileged XNU fixed counters:
true retired instructions and core cycles (process-wide, user+kernel, all
threads), so --perf`` renders IPC and instr/iter with the other columns
honestly absent. Everything richer is a capability ad, not a backend: kpc
is root-or-blessed with the RESTRICT_TO_KNOWN allowlist, and sampling is
Instruments/xctrace-brokered only.
perf : (struct) sparkles.test_runner.perf.PerfStatsPer-iteration counter averages of one counting pass. A field is nan when
the event could not be opened on this machine (e.g. the LLC pair was
dropped to avoid multiplexing, or the PMU exposes fewer events).
PerfStats;
import (package) sparklessparkles.(package) sparkles.test_runnertest_runner.(module) sparkles.test_runner.syscallsIn-process syscall counting via perf_event_open tracepoints, in pure D —
strace -c without a subprocess or ptrace.
A counter group is opened over syscall tracepoints: raw_syscalls:sys_enter
(the group leader) counts every syscall, and one ``syscalls:sys_enter_<name>
counter per requested name gives the per-syscall breakdown. The tracepoint ids
come from tracefs (/sys/kernel/tracing/events/<group>/<event>/id). Counting
is kernel-side, so — like perf.d — a separate counting pass brackets each
benchmark's timed body with ENABLE/DISABLE, and the ioctls never perturb
the reported timings.
attr.inherit is set, so counters clone into every thread the process spawns
after perf_event_open — and the group opens once at bench-mode start,
before any case's setup runs, so worker pools created in untimed setup are
followed too (their syscalls aggregate into the leader's group read). Only
threads that already existed when the group opened are not followed — that
needs per-TID attach (a later refinement) or the ptrace backend the roadmap
prepares behind the same --syscalls`` flag.
Tracepoints need perf_event_paranoid <= 1; where they can't be opened — and
everywhere off Linux — the group degrades to unavailable and the columns are
simply omitted. Pure D over druntime's core.sys.linux.perf_event; no ImportC.
syscalls : (struct) sparkles.test_runner.syscalls.SyscallStatsPer-iteration syscall counts of one counting pass. total is every syscall
(raw_syscalls:sys_enter); counts[i] is the per-iteration count of the
tracepoint named named[i] (nan if that tracepoint could not be opened).
SyscallStats;
(struct) sparkles.test_runner.workload.WorkloadWindowOne measured window. Deliberately NOT BenchStats: its per-iteration
timing fields would misrepresent a single window — counter stats here are
window totals (iters == 1).
WorkloadWindow (local variable) sparkles.test_runner.workload.WorkloadWindow ww;
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) string sparkles.test_runner.workload.WorkloadWindow.namename = "ingest";
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) uint sparkles.test_runner.workload.WorkloadWindow.repstimes the window content ran inside this window
reps = 2;
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) long sparkles.test_runner.workload.WallDecomposition.wallNsthe window's wall-clock duration
wallNs = 41_235_678;
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) string sparkles.test_runner.workload.WallDecomposition.scope_"thread" (Linux) or "process"
scope_ = "thread";
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) double sparkles.test_runner.workload.WallDecomposition.onCpuUserNsrusage user time (µs resolution)
onCpuUserNs = 31_000_000;
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) double sparkles.test_runner.workload.WallDecomposition.onCpuKernelNsrusage system time
onCpuKernelNs = 4_000_000;
// runqueue stays nan (schedstat-less host) → null in the document
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) double sparkles.test_runner.workload.WallDecomposition.offCpuOtherNsclamped residual: locks, sleeps, the rest
offCpuOtherNs = 6_235_678;
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) string sparkles.test_runner.workload.WallDecomposition.noteclamp/absence/cross-thread disclosures, "; "-joined
note = "runqueue wait unattributed (schedstat unreadable) — included in other";
(struct) sparkles.test_runner.perf.PerfStatsPer-iteration counter averages of one counting pass. A field is nan when
the event could not be opened on this machine (e.g. the LLC pair was
dropped to avoid multiplexing, or the PMU exposes fewer events).
PerfStats (local variable) sparkles.test_runner.perf.PerfStats pp;
(local variable) sparkles.test_runner.perf.PerfStats pp.(field) ulong sparkles.test_runner.perf.PerfStats.iterscounting-pass iterations
iters = 1;
(local variable) sparkles.test_runner.perf.PerfStats pp.(field) double sparkles.test_runner.perf.PerfStats.instructionsretired instructions per iteration
instructions = 2.41e9;
(local variable) sparkles.test_runner.perf.PerfStats pp.(field) double sparkles.test_runner.perf.PerfStats.cyclesCPU cycles per iteration
cycles = 3.1e9;
(local variable) sparkles.test_runner.perf.PerfStats pp.(field) double sparkles.test_runner.perf.PerfStats.pageFaultspage faults per iteration
pageFaults = 12;
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) std.typecons.Nullable!(PerfStats) sparkles.test_runner.workload.WorkloadWindow.perfperf = std.typecons.Nullable!(PerfStats) std.typecons.nullable!(sparkles.test_runner.perf.PerfStats)(sparkles.test_runner.perf.PerfStats t) pure nothrow @nogc @safeDefines a value paired with a distinctive "null" state that denotes
the absence of a value. If default constructed, a Nullable!T object starts in the null state. Assigning it renders it
non-null. Calling nullify can nullify it again.
Practically Nullable!T stores a T and a bool.
See also:
apply, an alternative way to use the payload.
Examples
struct CustomerRecord
{
string name;
string address;
int customerNum;
}
Nullable!CustomerRecord getByName(string name)
{
//A bunch of hairy stuff
return Nullable!CustomerRecord.init;
}
auto queryResult = getByName("Doe, John");
if (!queryResult.isNull)
{
//Process Mr. Doe's customer record
auto address = queryResult.get.address;
auto customerNum = queryResult.get.customerNum;
//Do some things with this customer's info
}
else
{
//Add the customer to the database
}
import std.exception : assertThrown;
auto a = 42.nullable;
assert(!a.isNull);
assert(a.get == 42);
a.nullify();
assert(a.isNull);
assertThrown!Throwable(a.get);
import std.algorithm.iteration : each, joiner;
Nullable!int a = 42;
Nullable!int b;
// Add each value to an array
int[] arr;
a.each!((n) => arr ~= n);
assert(arr == [42]);
b.each!((n) => arr ~= n);
assert(arr == [42]);
// Take first value from an array of Nullables
Nullable!int[] c = new Nullable!int[](10);
c[7] = Nullable!int(42);
assert(c.joiner.front == 42);
nullable((local variable) sparkles.test_runner.perf.PerfStats pp);
(struct) sparkles.test_runner.syscalls.SyscallStatsPer-iteration syscall counts of one counting pass. total is every syscall
(raw_syscalls:sys_enter); counts[i] is the per-iteration count of the
tracepoint named named[i] (nan if that tracepoint could not be opened).
SyscallStats (local variable) sparkles.test_runner.syscalls.SyscallStats ss;
(local variable) sparkles.test_runner.syscalls.SyscallStats ss.(field) ulong sparkles.test_runner.syscalls.SyscallStats.itersiters = 1;
(local variable) sparkles.test_runner.syscalls.SyscallStats ss.(field) double sparkles.test_runner.syscalls.SyscallStats.totaltotal = 1234;
(local variable) sparkles.test_runner.syscalls.SyscallStats ss.(field) const(string)[] sparkles.test_runner.syscalls.SyscallStats.namednamed = ["read"];
(local variable) sparkles.test_runner.syscalls.SyscallStats ss.(field) double[] sparkles.test_runner.syscalls.SyscallStats.countscounts = [600.0];
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) std.typecons.Nullable!(SyscallStats) sparkles.test_runner.workload.WorkloadWindow.syscallssyscalls = std.typecons.Nullable!(SyscallStats) std.typecons.nullable!(sparkles.test_runner.syscalls.SyscallStats)(sparkles.test_runner.syscalls.SyscallStats t) pure nothrow @nogc @safeDefines a value paired with a distinctive "null" state that denotes
the absence of a value. If default constructed, a Nullable!T object starts in the null state. Assigning it renders it
non-null. Calling nullify can nullify it again.
Practically Nullable!T stores a T and a bool.
See also:
apply, an alternative way to use the payload.
Examples
struct CustomerRecord
{
string name;
string address;
int customerNum;
}
Nullable!CustomerRecord getByName(string name)
{
//A bunch of hairy stuff
return Nullable!CustomerRecord.init;
}
auto queryResult = getByName("Doe, John");
if (!queryResult.isNull)
{
//Process Mr. Doe's customer record
auto address = queryResult.get.address;
auto customerNum = queryResult.get.customerNum;
//Do some things with this customer's info
}
else
{
//Add the customer to the database
}
import std.exception : assertThrown;
auto a = 42.nullable;
assert(!a.isNull);
assert(a.get == 42);
a.nullify();
assert(a.isNull);
assertThrown!Throwable(a.get);
import std.algorithm.iteration : each, joiner;
Nullable!int a = 42;
Nullable!int b;
// Add each value to an array
int[] arr;
a.each!((n) => arr ~= n);
assert(arr == [42]);
b.each!((n) => arr ~= n);
assert(arr == [42]);
// Take first value from an array of Nullables
Nullable!int[] c = new Nullable!int[](10);
c[7] = Nullable!int(42);
assert(c.joiner.front == 42);
nullable((local variable) sparkles.test_runner.syscalls.SyscallStats ss);
(struct) sparkles.test_runner.workload.WorkloadWindowOne measured window. Deliberately NOT BenchStats: its per-iteration
timing fields would misrepresent a single window — counter stats here are
window totals (iters == 1).
WorkloadWindow (local variable) sparkles.test_runner.workload.WorkloadWindow errerr;
(local variable) sparkles.test_runner.workload.WorkloadWindow errerr.(field) string sparkles.test_runner.workload.WorkloadWindow.namename = "bad";
(local variable) sparkles.test_runner.workload.WorkloadWindow errerr.(field) uint sparkles.test_runner.workload.WorkloadWindow.repstimes the window content ran inside this window
reps = 1;
(local variable) sparkles.test_runner.workload.WorkloadWindow errerr.(field) string sparkles.test_runner.workload.WorkloadWindow.errornon-empty = error (or, with skipped, skip) row
error = "object.Exception: boom";
(struct) sparkles.test_runner.workload.WorkloadWindowOne measured window. Deliberately NOT BenchStats: its per-iteration
timing fields would misrepresent a single window — counter stats here are
window totals (iters == 1).
WorkloadWindow (local variable) sparkles.test_runner.workload.WorkloadWindow skippedskipped;
(local variable) sparkles.test_runner.workload.WorkloadWindow skippedskipped.(field) string sparkles.test_runner.workload.WorkloadWindow.namename = "skippy";
(local variable) sparkles.test_runner.workload.WorkloadWindow skippedskipped.(field) uint sparkles.test_runner.workload.WorkloadWindow.repstimes the window content ran inside this window
reps = 1;
(local variable) sparkles.test_runner.workload.WorkloadWindow skippedskipped.(field) string sparkles.test_runner.workload.WorkloadWindow.errornon-empty = error (or, with skipped, skip) row
error = "no hardware";
(local variable) sparkles.test_runner.workload.WorkloadWindow skippedskipped.(field) bool sparkles.test_runner.workload.WorkloadWindow.skippedskipped = true;
const (local variable) const(std.json.JSONValue) docdoc = std.json.JSONValue std.json.parseJSON!string(string json, int maxDepth = -1, std.json.JSONOptions options = JSONOptions.none) pure @safeParses a serialized string and returns a tree of JSON values.
parseJSON(string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson(null, (struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta(date: "2026-08-02"),
[(local variable) sparkles.test_runner.workload.WorkloadWindow ww, (local variable) sparkles.test_runner.workload.WorkloadWindow errerr, (local variable) sparkles.test_runner.workload.WorkloadWindow skippedskipped]));
assert((local variable) const(std.json.JSONValue) docdoc["schema"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 2, "windows fold into unreleased schema 2");
const (local variable) const(std.json.JSONValue) winwin = (local variable) const(std.json.JSONValue) docdoc["windows"][0];
assert((local variable) const(std.json.JSONValue) winwin["name"].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str == "ingest");
assert((local variable) const(std.json.JSONValue) winwin["reps"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 2);
assert((local variable) const(std.json.JSONValue) winwin["wallNs"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 41_235_678);
assert((local variable) const(std.json.JSONValue) winwin["scope"].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str == "thread");
assert((local variable) const(std.json.JSONValue) winwin["onCpuUserNs"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 31_000_000);
assert((local variable) const(std.json.JSONValue) winwin["offCpuRunqueueNs"].std.json.JSONType std.json.JSONValue.type() const pure nothrow @nogc @property @safeReturns the JSONType of the value stored in this structure.
Examples
string s = "{ \"language\": \"D\" }";
JSONValue j = parseJSON(s);
assert(j.type == JSONType.object);
assert(j["language"].type == JSONType.string);
type == (enum) std.json.JSONTypeEnumeration of JSON types
JSONType.(enum value) std.json.JSONType.null_ = cast(byte)0Indicates the type of a JSONValue.
null_,
"unattributable = null, exactly the table's em dash");
assert((local variable) const(std.json.JSONValue) winwin["offCpuDiskNs"].std.json.JSONType std.json.JSONValue.type() const pure nothrow @nogc @property @safeReturns the JSONType of the value stored in this structure.
Examples
string s = "{ \"language\": \"D\" }";
JSONValue j = parseJSON(s);
assert(j.type == JSONType.object);
assert(j["language"].type == JSONType.string);
type == (enum) std.json.JSONTypeEnumeration of JSON types
JSONType.(enum value) std.json.JSONType.null_ = cast(byte)0Indicates the type of a JSONValue.
null_,
"PSI is system-scoped; disk attribution lands with M8 cgroups");
assert((local variable) const(std.json.JSONValue) winwin["perf"]["instructions"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 2_410_000_000,
"integral totals render as JSON integers");
assert((local variable) const(std.json.JSONValue) winwin["perf"]["scale"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 1);
assert((local variable) const(std.json.JSONValue) winwin["syscalls"]["total"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 1234);
assert((local variable) const(std.json.JSONValue) winwin["syscalls"]["named"]["read"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 600);
assert("tier0" !in (local variable) const(std.json.JSONValue) winwin, "an absent source omits its key");
assert("raw" !in (local variable) const(std.json.JSONValue) winwin);
assert("psi" !in (local variable) const(std.json.JSONValue) winwin, "psi omits its key like every absent source");
assert((local variable) const(std.json.JSONValue) winwin["note"].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str.(field) ulong string.lengthlength > 0);
assert((local variable) const(std.json.JSONValue) winwin["error"].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str == "");
const (local variable) const(std.json.JSONValue) badbad = (local variable) const(std.json.JSONValue) docdoc["windows"][1];
assert((local variable) const(std.json.JSONValue) badbad["wallNs"].std.json.JSONType std.json.JSONValue.type() const pure nothrow @nogc @property @safeReturns the JSONType of the value stored in this structure.
Examples
string s = "{ \"language\": \"D\" }";
JSONValue j = parseJSON(s);
assert(j.type == JSONType.object);
assert(j["language"].type == JSONType.string);
type == (enum) std.json.JSONTypeEnumeration of JSON types
JSONType.(enum value) std.json.JSONType.null_ = cast(byte)0Indicates the type of a JSONValue.
null_);
// The always-present keys mirror the error-row shape: null, not absent.
assert((local variable) const(std.json.JSONValue) badbad["scope"].std.json.JSONType std.json.JSONValue.type() const pure nothrow @nogc @property @safeReturns the JSONType of the value stored in this structure.
Examples
string s = "{ \"language\": \"D\" }";
JSONValue j = parseJSON(s);
assert(j.type == JSONType.object);
assert(j["language"].type == JSONType.string);
type == (enum) std.json.JSONTypeEnumeration of JSON types
JSONType.(enum value) std.json.JSONType.null_ = cast(byte)0Indicates the type of a JSONValue.
null_);
assert((local variable) const(std.json.JSONValue) badbad["onCpuUserNs"].std.json.JSONType std.json.JSONValue.type() const pure nothrow @nogc @property @safeReturns the JSONType of the value stored in this structure.
Examples
string s = "{ \"language\": \"D\" }";
JSONValue j = parseJSON(s);
assert(j.type == JSONType.object);
assert(j["language"].type == JSONType.string);
type == (enum) std.json.JSONTypeEnumeration of JSON types
JSONType.(enum value) std.json.JSONType.null_ = cast(byte)0Indicates the type of a JSONValue.
null_);
assert((local variable) const(std.json.JSONValue) badbad["offCpuOtherNs"].std.json.JSONType std.json.JSONValue.type() const pure nothrow @nogc @property @safeReturns the JSONType of the value stored in this structure.
Examples
string s = "{ \"language\": \"D\" }";
JSONValue j = parseJSON(s);
assert(j.type == JSONType.object);
assert(j["language"].type == JSONType.string);
type == (enum) std.json.JSONTypeEnumeration of JSON types
JSONType.(enum value) std.json.JSONType.null_ = cast(byte)0Indicates the type of a JSONValue.
null_);
assert((local variable) const(std.json.JSONValue) badbad["error"].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str == "object.Exception: boom");
assert("skipped" !in (local variable) const(std.json.JSONValue) badbad);
assert((local variable) const(std.json.JSONValue) docdoc["windows"][2]["skipped"].bool std.json.JSONValue.boolean() const pure @property @safeValue getter/setter for boolean stored in JSON.
boolean);
}
@("benchJson.windows.absentKeepsDocumentByteIdentical")
@safe
unittest
{
// A run without workloads must stay byte-identical to the pre-window
// document — `windows` is a pure addition, not a schema perturbation.
(struct) sparkles.test_runner.bench.BenchStatsSummary statistics of one benchmark row, in nanoseconds per iteration. A row
with a non-empty error is a failure row (its timing fields are unset).
BenchStats (local variable) sparkles.test_runner.bench.BenchStats rowrow;
(local variable) sparkles.test_runner.bench.BenchStats rowrow.(field) string sparkles.test_runner.bench.BenchStats.namename = "r";
(local variable) sparkles.test_runner.bench.BenchStats rowrow.(field) ulong sparkles.test_runner.bench.BenchStats.iterationsiterations per sample
iterations = 1;
const (local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta = (struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta(date: "2026-08-02");
assert(string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson([(local variable) sparkles.test_runner.bench.BenchStats rowrow], (local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta) == string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson([(local variable) sparkles.test_runner.bench.BenchStats rowrow], (local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta, null));
assert(string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson(null, (local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta) == string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson(null, (local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta, null));
// And a psi-less window (a CONFIG_PSI=n host) must omit the psi key —
// asserted explicitly, not incidentally.
(struct) sparkles.test_runner.workload.WorkloadWindowOne measured window. Deliberately NOT BenchStats: its per-iteration
timing fields would misrepresent a single window — counter stats here are
window totals (iters == 1).
WorkloadWindow (local variable) sparkles.test_runner.workload.WorkloadWindow noPsinoPsi;
(local variable) sparkles.test_runner.workload.WorkloadWindow noPsinoPsi.(field) string sparkles.test_runner.workload.WorkloadWindow.namename = "w";
(local variable) sparkles.test_runner.workload.WorkloadWindow noPsinoPsi.(field) uint sparkles.test_runner.workload.WorkloadWindow.repstimes the window content ran inside this window
reps = 1;
(local variable) sparkles.test_runner.workload.WorkloadWindow noPsinoPsi.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) long sparkles.test_runner.workload.WallDecomposition.wallNsthe window's wall-clock duration
wallNs = 1;
(local variable) sparkles.test_runner.workload.WorkloadWindow noPsinoPsi.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) string sparkles.test_runner.workload.WallDecomposition.scope_"thread" (Linux) or "process"
scope_ = "thread";
import (package) stdstd.(package) std.algorithmalgorithm.(module) std.algorithm.searchingThis is a submodule of std.algorithm.
It contains generic searching algorithms.
Function Name Description all all!"a > 0"([1, 2, 3, 4]) returns true because all elements are positive any any!"a > 0"([1, 2, -3, -4]) returns true because at least one element is positive balancedParens balancedParens("((1 + 1) / 2)", '(', ')') returns true because the string has balanced parentheses. boyerMooreFinder find("hello world", boyerMooreFinder("or")) returns "orld" using the Boyer-Moore algorithm. canFind canFind("hello world", "or") returns true. count Counts all elements or elements matching a predicate, specific element or sub-range.
count([1, 2, 1]) returns 3,
count([1, 2, 1], 1) returns 2 and
count!"a < 0"([1, -3, 0]) returns 1. |
| countUntil | countUntil(a, b) returns the number of steps taken in a to reach b; for example, countUntil("hello!", "o") returns 4. |
| commonPrefix | commonPrefix("parakeet", "parachute") returns "para". |
| endsWith | endsWith("rocks", "ks") returns true. |
| extrema | extrema([2, 1, 3, 5, 4]) returns [1, 5]. |
| find | find("hello world", "or") returns "orld" using linear search. (For binary search refer to SortedRange.) |
| findAdjacent | findAdjacent([1, 2, 3, 3, 4]) returns the subrange starting with two equal adjacent elements, i.e. [3, 3, 4]. |
| findAmong | findAmong("abcd", "qcx") returns "cd" because 'c' is among "qcx". |
| findSkip | If a = "abcde", then findSkip(a, "x") returns false and leaves a unchanged, whereas findSkip(a, "c") advances a to "de" and returns true. |
| findSplit | findSplit("abcdefg", "de") returns a tuple of three ranges "abc", "de", and "fg". |
| findSplitAfter | findSplitAfter("abcdefg", "de") returns a tuple of two ranges "abcde" and "fg". |
| findSplitBefore | findSplitBefore("abcdefg", "de") returns a tuple of two ranges "abc" and "defg". |
| minCount | minCount([2, 1, 1, 4, 1]) returns tuple(1, 3). |
| maxCount | maxCount([2, 4, 1, 4, 1]) returns tuple(4, 2). |
| minElement | Selects the minimal element of a range. minElement([3, 4, 1, 2]) returns 1. |
| maxElement | Selects the maximal element of a range. maxElement([3, 4, 1, 2]) returns 4. |
| minIndex | Index of the minimal element of a range. minIndex([3, 4, 1, 2]) returns 2. |
| maxIndex | Index of the maximal element of a range. maxIndex([3, 4, 1, 2]) returns 1. |
| minPos | minPos([2, 3, 1, 3, 4, 1]) returns the subrange [1, 3, 4, 1], i.e., positions the range at the first occurrence of its minimal element. |
| maxPos | maxPos([2, 3, 1, 3, 4, 1]) returns the subrange [4, 1], i.e., positions the range at the first occurrence of its maximal element. |
| skipOver | Assume a = "blah". Then skipOver(a, "bi") leaves a unchanged and returns false, whereas skipOver(a, "bl") advances a to refer to "ah" and returns true. |
| startsWith | startsWith("hello, world", "hello") returns true. |
| until | Lazily iterates a range until a specific value is found. |
Source
std/algorithm/searching.d
searching : (alias template) canFind = std.algorithm.searching.canFind(alias pred = "a == b")Convenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see $(LREF find).
See_Also:
$(REF among, std,algorithm,comparison) for checking a value against multiple arguments.
canFind;
assert(!string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson(null, (local variable) const(sparkles.test_runner.bench_json.BenchMeta) metameta, [(local variable) sparkles.test_runner.workload.WorkloadWindow noPsinoPsi]).bool std.algorithm.searching.canFind!().canFind!(string, string)(string haystack, scope string needle) pure nothrow @nogc @safeConvenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see find.
Examples
const arr = [0, 1, 2, 3];
assert(canFind(arr, 2));
assert(!canFind(arr, 4));
// find one of several needles
assert(arr.canFind(3, 2));
assert(arr.canFind(3, 2) == 2); // second needle found
assert(arr.canFind([1, 3], 2) == 2);
assert(canFind(arr, [1, 2], [2, 3]));
assert(canFind(arr, [1, 2], [2, 3]) == 1);
assert(canFind(arr, [1, 7], [2, 3]));
assert(canFind(arr, [1, 7], [2, 3]) == 2);
assert(!canFind(arr, [1, 3], [2, 4]));
assert(canFind(arr, [1, 3], [2, 4]) == 0);
Example using a custom predicate.
Note that the needle appears as the second argument of the predicate.
auto words = [
"apple",
"beeswax",
"cardboard"
];
assert(!canFind(words, "bees"));
assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
Search for multiple items in an array of items (search for needles in an array of haystacks)
string s1 = "aaa111aaa";
string s2 = "aaa222aaa";
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
assert(hay.canFind!(e => e.canFind("111", "222")));
canFind("\"psi\""));
}
@("benchJson.windows.psiObject")
@system
unittest
{
import (package) stdstd.(module) std.jsonImplements functionality to read and write JavaScript Object Notation values.
JavaScript Object Notation is a lightweight data interchange format commonly used in web services and configuration files.
It's easy for humans to read and write, and it's easy for machines to parse and generate.
Warning: While JSONValue is fine for small-scale use, at the range of hundreds of megabytes it is
known to cause and exacerbate GC problems. If you encounter problems, try replacing it with a stream parser. See
also https://forum.dlang.org/post/dzfyaxypmkdrpakmycjv@forum.dlang.org.
References
http://json.org/, https://seriot.ch/projects/parsing_json.html
Source
std/json.d
Examples
import std.conv : to;
// parse a file or string of json into a usable structure
string s = `{ "language": "D", "rating": 3.5, "code": "42" }`;
JSONValue j = parseJSON(s);
// j and j["language"] return JSONValue,
// j["language"].str returns a string
assert(j["language"].str == "D");
assert(j["rating"].floating == 3.5);
// check a type
long x;
if (const(JSONValue)* code = "code" in j)
{
if (code.type() == JSONType.integer)
x = code.integer;
else
x = to!int(code.str);
}
// create a json struct
JSONValue jj = [ "language": "D" ];
// rating doesnt exist yet, so use .object to assign
jj.object["rating"] = JSONValue(3.5);
// create an array to assign to list
jj.object["list"] = JSONValue( ["a", "b", "c"] );
// list already exists, so .object optional
jj["list"].array ~= JSONValue("D");
string jjStr = `{"language":"D","list":["a","b","c","D"],"rating":3.5}`;
assert(jj.toString == jjStr);
json : (enum) std.json.JSONTypeEnumeration of JSON types
JSONType, (alias template) parseJSON = std.json.parseJSON(T)(T json, int maxDepth = -1, JSONOptions options = JSONOptions.none) if (isSomeFiniteCharInputRange!T)Parses a serialized string and returns a tree of JSON values.
Throws: $(LREF JSONException) if string does not follow the JSON grammar or the depth exceeds the max depth,
$(LREF ConvException) if a number in the input cannot be represented by a native D type.
Params:
json = json-formatted string to parse
maxDepth = maximum depth of nesting allowed, -1 disables depth checking
options = enable decoding string representations of NaN/Inf as float values
parseJSON;
import (package) stdstd.(module) std.typeconsThis module implements a variety of type constructors, i.e., templates
that allow construction of new, useful general-purpose types.
Category Symbols Tuple isTuple Tuple tuple reverse Flags BitFlags isBitFlagEnum Flag No Yes Reference Counting borrow RefCountedAutoInitialize RefCounted refCounted SafeRefCounted safeRefCounted Memory allocation scoped Unique Code generation AutoImplement BlackHole generateAssertTrap generateEmptyFunction NotImplementedError WhiteHole Nullable apply Nullable nullable NullableRef nullableRef Proxies Proxy rebindable Rebindable unwrap wrap Types alignForSize ReplaceType ReplaceTypeUnless Ternary Typedef TypedefType UnqualRef
Source
std/typecons.d
Examples
Value tuples
alias Coord = Tuple!(int, "x", int, "y", int, "z");
Coord c;
c[1] = 1; // access by index
c.z = 1; // access by given name
assert(c == Coord(0, 1, 1));
// names can be omitted, types can be mixed
alias DictEntry = Tuple!(string, int);
auto dict = DictEntry("seven", 7);
// element types can be inferred
assert(tuple(2, 3, 4)[1] == 3);
// type inference works with names too
auto tup = tuple!("x", "y", "z")(2, 3, 4);
assert(tup.y == 3);
Rebindable references to const and immutable objects
class Widget
{
void foo() const @safe {}
}
const w1 = new Widget, w2 = new Widget;
w1.foo();
// w1 = w2 would not work; can't rebind const object
auto r = Rebindable!(const Widget)(w1);
// invoke method as if r were a Widget object
r.foo();
// rebind r to refer to another object
r = w2;
typecons : (alias template) nullable = std.typecons.nullable(T)(T t)Defines a value paired with a distinctive "null" state that denotes
the absence of a value. If default constructed, a $(D
Nullable!T) object starts in the null state. Assigning it renders it
non-null. Calling nullify can nullify it again.
Practically Nullable!T stores a T and a bool.
See also:
$(LREF apply), an alternative way to use the payload.
nullable;
import (package) sparklessparkles.(package) sparkles.test_runnertest_runner.(module) sparkles.test_runner.workloadThe @workload`` window measurement model: one window, counter deltas.
Where @benchmark runs a body many times and reports per-iteration
statistics, a workload runs once (or a few reps) and reports what happened
across the window: every open counter source's delta between two edge
snapshots, plus a wall-clock decomposition into on-CPU time (rusage),
runqueue wait (schedstat), and a clamped residual. Sources are read
cumulatively at the edges (no per-iteration ioctl bracket, no RESET —
see sparkles.test_runner.perf_group.GroupSnapshot), so the driver's
whole-body candidate window and in-body workloadWindow calls overlap
freely in a single pass — a workload body is never re-run for counting,
because it may be expensive or non-idempotent.
Edge-snapshot nesting order (outer → inner): psi, wall clock, wall
source (rusage/schedstat), syscalls, raw, tier-0, perf — so the cycle
counters see only the body, and each tier's window contains at most the
inner tiers' edge reads (a handful of syscalls per edge, negligible at
window granularity and disclosed here rather than hidden). Psi sits
outermost — outside even the wall clock and rusage windows — so its six
file reads per edge (~20 µs) contribute zero apparatus anywhere in the
decomposition; a system-wide µs-resolution integral's own window being a
few µs wider than the wall clock is immaterial.
Decomposition honesty: only runqueue wait is a true per-cause duration
today; everything else off-CPU — locks, sleeps, disk — lands in
offCpuOtherNs, which clamps at zero and says so in note rather than
fabricating a cause. PSI stall integrals ride alongside as system-wide
diagnostics (WorkloadWindow.psi) — /proc/pressure cannot attribute to
the measured thread, so disk attribution waits for M8's cgroup scoping.
On Linux the decomposition is thread-scoped (RUSAGE_THREAD +
/proc/thread-self/schedstat — the only scoping under which
wall = onCpu + runqueue + other is arithmetically meaningful); the
process-wide reading is captured too, purely to disclose CPU burned by
other threads. Thread coverage caveats (counters follow clone inheritance,
the decomposition follows the driving thread) match the bench modes.
workload : (struct) sparkles.test_runner.workload.PsiStatsA window's PSI stall-time deltas, in ns — system-wide diagnostics
("the system accumulated this much stall concurrently with the window"),
never attribution to the measured thread (that lands with M8's
cgroup-scoped PSI). nan = line absent, edges unreadable, or a
backwards accumulator.
PsiStats;
(struct) sparkles.test_runner.workload.WorkloadWindowOne measured window. Deliberately NOT BenchStats: its per-iteration
timing fields would misrepresent a single window — counter stats here are
window totals (iters == 1).
WorkloadWindow (local variable) sparkles.test_runner.workload.WorkloadWindow ww;
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) string sparkles.test_runner.workload.WorkloadWindow.namename = "with-psi";
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) uint sparkles.test_runner.workload.WorkloadWindow.repstimes the window content ran inside this window
reps = 1;
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) long sparkles.test_runner.workload.WallDecomposition.wallNsthe window's wall-clock duration
wallNs = 10_000_000;
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) string sparkles.test_runner.workload.WallDecomposition.scope_"thread" (Linux) or "process"
scope_ = "thread";
(struct) sparkles.test_runner.workload.PsiStatsA window's PSI stall-time deltas, in ns — system-wide diagnostics
("the system accumulated this much stall concurrently with the window"),
never attribution to the measured thread (that lands with M8's
cgroup-scoped PSI). nan = line absent, edges unreadable, or a
backwards accumulator.
PsiStats (local variable) sparkles.test_runner.workload.PsiStats pp;
(local variable) sparkles.test_runner.workload.PsiStats pp.(field) double sparkles.test_runner.workload.PsiStats.ioSomeNs≥ 1 task stalled on io
ioSomeNs = 3_000_000;
(local variable) sparkles.test_runner.workload.PsiStats pp.(field) double sparkles.test_runner.workload.PsiStats.ioFullNsall non-idle tasks stalled on io
ioFullNs = 200_000;
(local variable) sparkles.test_runner.workload.PsiStats pp.(field) double sparkles.test_runner.workload.PsiStats.memSomeNsmemSomeNs = 0;
// memFullNs stays nan (absent full line) → null
(local variable) sparkles.test_runner.workload.PsiStats pp.(field) double sparkles.test_runner.workload.PsiStats.cpuSomeNscpuSomeNs = 14_000;
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) std.typecons.Nullable!(PsiStats) sparkles.test_runner.workload.WorkloadWindow.psisystem-wide stall deltas — diagnostics, not attribution
psi = std.typecons.Nullable!(PsiStats) std.typecons.nullable!(sparkles.test_runner.workload.PsiStats)(sparkles.test_runner.workload.PsiStats t) pure nothrow @nogc @safeDefines a value paired with a distinctive "null" state that denotes
the absence of a value. If default constructed, a Nullable!T object starts in the null state. Assigning it renders it
non-null. Calling nullify can nullify it again.
Practically Nullable!T stores a T and a bool.
See also:
apply, an alternative way to use the payload.
Examples
struct CustomerRecord
{
string name;
string address;
int customerNum;
}
Nullable!CustomerRecord getByName(string name)
{
//A bunch of hairy stuff
return Nullable!CustomerRecord.init;
}
auto queryResult = getByName("Doe, John");
if (!queryResult.isNull)
{
//Process Mr. Doe's customer record
auto address = queryResult.get.address;
auto customerNum = queryResult.get.customerNum;
//Do some things with this customer's info
}
else
{
//Add the customer to the database
}
import std.exception : assertThrown;
auto a = 42.nullable;
assert(!a.isNull);
assert(a.get == 42);
a.nullify();
assert(a.isNull);
assertThrown!Throwable(a.get);
import std.algorithm.iteration : each, joiner;
Nullable!int a = 42;
Nullable!int b;
// Add each value to an array
int[] arr;
a.each!((n) => arr ~= n);
assert(arr == [42]);
b.each!((n) => arr ~= n);
assert(arr == [42]);
// Take first value from an array of Nullables
Nullable!int[] c = new Nullable!int[](10);
c[7] = Nullable!int(42);
assert(c.joiner.front == 42);
nullable((local variable) sparkles.test_runner.workload.PsiStats pp);
const (local variable) const(std.json.JSONValue) docdoc = std.json.JSONValue std.json.parseJSON!string(string json, int maxDepth = -1, std.json.JSONOptions options = JSONOptions.none) pure @safeParses a serialized string and returns a tree of JSON values.
parseJSON(string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson(null, (struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta(date: "2026-08-03"), [(local variable) sparkles.test_runner.workload.WorkloadWindow ww]));
const (local variable) const(std.json.JSONValue) psipsi = (local variable) const(std.json.JSONValue) docdoc["windows"][0]["psi"];
assert((local variable) const(std.json.JSONValue) psipsi["scope"].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str == "system",
"the object self-describes its scope — M8's cgroup source will differ");
assert((local variable) const(std.json.JSONValue) psipsi["ioSomeNs"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 3_000_000);
assert((local variable) const(std.json.JSONValue) psipsi["ioFullNs"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 200_000);
assert((local variable) const(std.json.JSONValue) psipsi["memSomeNs"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 0, "a zero system delta is a true statement");
assert((local variable) const(std.json.JSONValue) psipsi["memFullNs"].std.json.JSONType std.json.JSONValue.type() const pure nothrow @nogc @property @safeReturns the JSONType of the value stored in this structure.
Examples
string s = "{ \"language\": \"D\" }";
JSONValue j = parseJSON(s);
assert(j.type == JSONType.object);
assert(j["language"].type == JSONType.string);
type == (enum) std.json.JSONTypeEnumeration of JSON types
JSONType.(enum value) std.json.JSONType.null_ = cast(byte)0Indicates the type of a JSONValue.
null_, "absent full line → null");
assert((local variable) const(std.json.JSONValue) psipsi["cpuSomeNs"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 14_000);
assert("cpuFullNs" !in (local variable) const(std.json.JSONValue) psipsi, "pinned-zero system cpu-full is not emitted");
// The decomposition slot stays honest: no attribution from system scope.
assert((local variable) const(std.json.JSONValue) docdoc["windows"][0]["offCpuDiskNs"].std.json.JSONType std.json.JSONValue.type() const pure nothrow @nogc @property @safeReturns the JSONType of the value stored in this structure.
Examples
string s = "{ \"language\": \"D\" }";
JSONValue j = parseJSON(s);
assert(j.type == JSONType.object);
assert(j["language"].type == JSONType.string);
type == (enum) std.json.JSONTypeEnumeration of JSON types
JSONType.(enum value) std.json.JSONType.null_ = cast(byte)0Indicates the type of a JSONValue.
null_);
}
@("benchJson.windows.regimeObject")
@system
unittest
{
import (package) stdstd.(package) std.algorithmalgorithm.(module) std.algorithm.searchingThis is a submodule of std.algorithm.
It contains generic searching algorithms.
Function Name Description all all!"a > 0"([1, 2, 3, 4]) returns true because all elements are positive any any!"a > 0"([1, 2, -3, -4]) returns true because at least one element is positive balancedParens balancedParens("((1 + 1) / 2)", '(', ')') returns true because the string has balanced parentheses. boyerMooreFinder find("hello world", boyerMooreFinder("or")) returns "orld" using the Boyer-Moore algorithm. canFind canFind("hello world", "or") returns true. count Counts all elements or elements matching a predicate, specific element or sub-range.
count([1, 2, 1]) returns 3,
count([1, 2, 1], 1) returns 2 and
count!"a < 0"([1, -3, 0]) returns 1. |
| countUntil | countUntil(a, b) returns the number of steps taken in a to reach b; for example, countUntil("hello!", "o") returns 4. |
| commonPrefix | commonPrefix("parakeet", "parachute") returns "para". |
| endsWith | endsWith("rocks", "ks") returns true. |
| extrema | extrema([2, 1, 3, 5, 4]) returns [1, 5]. |
| find | find("hello world", "or") returns "orld" using linear search. (For binary search refer to SortedRange.) |
| findAdjacent | findAdjacent([1, 2, 3, 3, 4]) returns the subrange starting with two equal adjacent elements, i.e. [3, 3, 4]. |
| findAmong | findAmong("abcd", "qcx") returns "cd" because 'c' is among "qcx". |
| findSkip | If a = "abcde", then findSkip(a, "x") returns false and leaves a unchanged, whereas findSkip(a, "c") advances a to "de" and returns true. |
| findSplit | findSplit("abcdefg", "de") returns a tuple of three ranges "abc", "de", and "fg". |
| findSplitAfter | findSplitAfter("abcdefg", "de") returns a tuple of two ranges "abcde" and "fg". |
| findSplitBefore | findSplitBefore("abcdefg", "de") returns a tuple of two ranges "abc" and "defg". |
| minCount | minCount([2, 1, 1, 4, 1]) returns tuple(1, 3). |
| maxCount | maxCount([2, 4, 1, 4, 1]) returns tuple(4, 2). |
| minElement | Selects the minimal element of a range. minElement([3, 4, 1, 2]) returns 1. |
| maxElement | Selects the maximal element of a range. maxElement([3, 4, 1, 2]) returns 4. |
| minIndex | Index of the minimal element of a range. minIndex([3, 4, 1, 2]) returns 2. |
| maxIndex | Index of the maximal element of a range. maxIndex([3, 4, 1, 2]) returns 1. |
| minPos | minPos([2, 3, 1, 3, 4, 1]) returns the subrange [1, 3, 4, 1], i.e., positions the range at the first occurrence of its minimal element. |
| maxPos | maxPos([2, 3, 1, 3, 4, 1]) returns the subrange [4, 1], i.e., positions the range at the first occurrence of its maximal element. |
| skipOver | Assume a = "blah". Then skipOver(a, "bi") leaves a unchanged and returns false, whereas skipOver(a, "bl") advances a to refer to "ah" and returns true. |
| startsWith | startsWith("hello, world", "hello") returns true. |
| until | Lazily iterates a range until a specific value is found. |
Source
std/algorithm/searching.d
searching : (alias template) canFind = std.algorithm.searching.canFind(alias pred = "a == b")Convenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see $(LREF find).
See_Also:
$(REF among, std,algorithm,comparison) for checking a value against multiple arguments.
canFind;
import (package) stdstd.(module) std.jsonImplements functionality to read and write JavaScript Object Notation values.
JavaScript Object Notation is a lightweight data interchange format commonly used in web services and configuration files.
It's easy for humans to read and write, and it's easy for machines to parse and generate.
Warning: While JSONValue is fine for small-scale use, at the range of hundreds of megabytes it is
known to cause and exacerbate GC problems. If you encounter problems, try replacing it with a stream parser. See
also https://forum.dlang.org/post/dzfyaxypmkdrpakmycjv@forum.dlang.org.
References
http://json.org/, https://seriot.ch/projects/parsing_json.html
Source
std/json.d
Examples
import std.conv : to;
// parse a file or string of json into a usable structure
string s = `{ "language": "D", "rating": 3.5, "code": "42" }`;
JSONValue j = parseJSON(s);
// j and j["language"] return JSONValue,
// j["language"].str returns a string
assert(j["language"].str == "D");
assert(j["rating"].floating == 3.5);
// check a type
long x;
if (const(JSONValue)* code = "code" in j)
{
if (code.type() == JSONType.integer)
x = code.integer;
else
x = to!int(code.str);
}
// create a json struct
JSONValue jj = [ "language": "D" ];
// rating doesnt exist yet, so use .object to assign
jj.object["rating"] = JSONValue(3.5);
// create an array to assign to list
jj.object["list"] = JSONValue( ["a", "b", "c"] );
// list already exists, so .object optional
jj["list"].array ~= JSONValue("D");
string jjStr = `{"language":"D","list":["a","b","c","D"],"rating":3.5}`;
assert(jj.toString == jjStr);
json : (enum) std.json.JSONTypeEnumeration of JSON types
JSONType, (alias template) parseJSON = std.json.parseJSON(T)(T json, int maxDepth = -1, JSONOptions options = JSONOptions.none) if (isSomeFiniteCharInputRange!T)Parses a serialized string and returns a tree of JSON values.
Throws: $(LREF JSONException) if string does not follow the JSON grammar or the depth exceeds the max depth,
$(LREF ConvException) if a number in the input cannot be represented by a native D type.
Params:
json = json-formatted string to parse
maxDepth = maximum depth of nesting allowed, -1 disables depth checking
options = enable decoding string representations of NaN/Inf as float values
parseJSON;
import (package) stdstd.(module) std.typeconsThis module implements a variety of type constructors, i.e., templates
that allow construction of new, useful general-purpose types.
Category Symbols Tuple isTuple Tuple tuple reverse Flags BitFlags isBitFlagEnum Flag No Yes Reference Counting borrow RefCountedAutoInitialize RefCounted refCounted SafeRefCounted safeRefCounted Memory allocation scoped Unique Code generation AutoImplement BlackHole generateAssertTrap generateEmptyFunction NotImplementedError WhiteHole Nullable apply Nullable nullable NullableRef nullableRef Proxies Proxy rebindable Rebindable unwrap wrap Types alignForSize ReplaceType ReplaceTypeUnless Ternary Typedef TypedefType UnqualRef
Source
std/typecons.d
Examples
Value tuples
alias Coord = Tuple!(int, "x", int, "y", int, "z");
Coord c;
c[1] = 1; // access by index
c.z = 1; // access by given name
assert(c == Coord(0, 1, 1));
// names can be omitted, types can be mixed
alias DictEntry = Tuple!(string, int);
auto dict = DictEntry("seven", 7);
// element types can be inferred
assert(tuple(2, 3, 4)[1] == 3);
// type inference works with names too
auto tup = tuple!("x", "y", "z")(2, 3, 4);
assert(tup.y == 3);
Rebindable references to const and immutable objects
class Widget
{
void foo() const @safe {}
}
const w1 = new Widget, w2 = new Widget;
w1.foo();
// w1 = w2 would not work; can't rebind const object
auto r = Rebindable!(const Widget)(w1);
// invoke method as if r were a Widget object
r.foo();
// rebind r to refer to another object
r = w2;
typecons : (alias template) nullable = std.typecons.nullable(T)(T t)Defines a value paired with a distinctive "null" state that denotes
the absence of a value. If default constructed, a $(D
Nullable!T) object starts in the null state. Assigning it renders it
non-null. Calling nullify can nullify it again.
Practically Nullable!T stores a T and a bool.
See also:
$(LREF apply), an alternative way to use the payload.
nullable;
import (package) sparklessparkles.(package) sparkles.test_runnertest_runner.(module) sparkles.test_runner.attributesUser-defined attributes recognized by the sparkles:test-runner unittest
runner.
Attach these to unittest blocks to opt into special handling:
import sparkles.test_runner.attributes : benchmark, betterC, ctfe;
@("SmallBuffer.append")
@betterC @safe pure nothrow @nogc
unittest { /+ also compiled & run with -betterC via `--better-c` +/ }
@("levenshtein.ctfe")
@ctfe @safe pure nothrow
unittest { /+ evaluated during compilation, not at runtime +/ }
@("SmallBuffer.append.bench")
@benchmark @safe
unittest { /+ timed with auto-scaling iterations via `--bench` +/ }
All attributes are plain marker types — the runner discovers them with
hasUDA — so annotated tests remain ordinary unittest blocks for any
other runner.
attributes : (enum) sparkles.test_runner.attributes.CacheRegimeThe page-cache regime a @workload requests for the files it names via
workloadFiles: leave the cache
alone (steadyState), preload (warm), or evict (cold). The runner
verifies the achieved regime (mmap + mincore residency) and
stamps every measured window with requested vs effective — a regime that
could not be established (tmpfs, no posix_fadvise, foreign mappings)
degrades with a reason, never silently.
steadyState is first so .init (and a bare @workload) means
"no cache manipulation".
CacheRegime;
import (package) sparklessparkles.(package) sparkles.test_runnertest_runner.(module) sparkles.test_runner.cache_regimePage-cache regime control for @workload tests: establish a declared
cache state — cold (evict), warm (preload), steadyState (leave
alone) — for the files a workload names, and verify what was
actually achieved instead of assuming it.
The mechanics: cold is posix_fadvise(POSIX_FADV_DONTNEED) per file
(preceded by fdatasync — DONTNEED silently skips dirty pages); warm
is an explicit read-through preload (never the async WILLNEED advice,
which promises nothing); verification is mmap + mincore residency,
strided by sysconf(_SC_PAGESIZE) (Apple Silicon's 16 KiB pages make
hardcoded 4 KiB wrong). The pure resolveStamp policy turns
requested + filesystem kind + measured residency into an honest
CacheRegimeStamp: a regime that could not be established downgrades
effective with a reason, and residency that cannot be trusted is
noted, never converted into a confident number.
Filesystem honesty: on tmpfs the pages ARE the file — cold is
impossible by construction. On ZFS, mincore is blind in both
directions: reads are served from the ARC without populating the Linux
page cache, so a warm-preloaded file can read 0 % resident while fully
cached, and a fadvised file reads 0 % while the ARC still holds
everything — the residency thresholds are suppressed there and the
stamp says so. /proc/sys/vm/drop_caches is deliberately never used:
it is a system-global, root-only sledgehammer that evicts every other
process's state — the per-file fadvise + verify + downgrade-note
contract is the honest scope (M8's cgroup memory.max is the scoped
successor if stronger eviction is ever needed).
cache_regime : (struct) sparkles.test_runner.cache_regime.CacheRegimeStampWhat one workloadFiles call established, attached to every window
measured after it. residentBefore/residentAfter are page-weighted
fractions across the call's files (nan = unverifiable, which is a
note, never a downgrade by itself).
CacheRegimeStamp;
(struct) sparkles.test_runner.workload.WorkloadWindowOne measured window. Deliberately NOT BenchStats: its per-iteration
timing fields would misrepresent a single window — counter stats here are
window totals (iters == 1).
WorkloadWindow (local variable) sparkles.test_runner.workload.WorkloadWindow ww;
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) string sparkles.test_runner.workload.WorkloadWindow.namename = "cold-run";
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) uint sparkles.test_runner.workload.WorkloadWindow.repstimes the window content ran inside this window
reps = 1;
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) long sparkles.test_runner.workload.WallDecomposition.wallNsthe window's wall-clock duration
wallNs = 5_000_000;
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) string sparkles.test_runner.workload.WallDecomposition.scope_"thread" (Linux) or "process"
scope_ = "thread";
(local variable) sparkles.test_runner.workload.WorkloadWindow ww.(field) std.typecons.Nullable!(CacheRegimeStamp) sparkles.test_runner.workload.WorkloadWindow.regimewhat workloadFiles established for this window
regime = std.typecons.Nullable!(CacheRegimeStamp) std.typecons.nullable!(sparkles.test_runner.cache_regime.CacheRegimeStamp)(sparkles.test_runner.cache_regime.CacheRegimeStamp t) pure nothrow @nogc @safeDefines a value paired with a distinctive "null" state that denotes
the absence of a value. If default constructed, a Nullable!T object starts in the null state. Assigning it renders it
non-null. Calling nullify can nullify it again.
Practically Nullable!T stores a T and a bool.
See also:
apply, an alternative way to use the payload.
Examples
struct CustomerRecord
{
string name;
string address;
int customerNum;
}
Nullable!CustomerRecord getByName(string name)
{
//A bunch of hairy stuff
return Nullable!CustomerRecord.init;
}
auto queryResult = getByName("Doe, John");
if (!queryResult.isNull)
{
//Process Mr. Doe's customer record
auto address = queryResult.get.address;
auto customerNum = queryResult.get.customerNum;
//Do some things with this customer's info
}
else
{
//Add the customer to the database
}
import std.exception : assertThrown;
auto a = 42.nullable;
assert(!a.isNull);
assert(a.get == 42);
a.nullify();
assert(a.isNull);
assertThrown!Throwable(a.get);
import std.algorithm.iteration : each, joiner;
Nullable!int a = 42;
Nullable!int b;
// Add each value to an array
int[] arr;
a.each!((n) => arr ~= n);
assert(arr == [42]);
b.each!((n) => arr ~= n);
assert(arr == [42]);
// Take first value from an array of Nullables
Nullable!int[] c = new Nullable!int[](10);
c[7] = Nullable!int(42);
assert(c.joiner.front == 42);
nullable((struct) sparkles.test_runner.cache_regime.CacheRegimeStampWhat one workloadFiles call established, attached to every window
measured after it. residentBefore/residentAfter are page-weighted
fractions across the call's files (nan = unverifiable, which is a
note, never a downgrade by itself).
CacheRegimeStamp(
requested: (enum) sparkles.test_runner.attributes.CacheRegimeThe page-cache regime a @workload requests for the files it names via
workloadFiles: leave the cache
alone (steadyState), preload (warm), or evict (cold). The runner
verifies the achieved regime (mmap + mincore residency) and
stamps every measured window with requested vs effective — a regime that
could not be established (tmpfs, no posix_fadvise, foreign mappings)
degrades with a reason, never silently.
steadyState is first so .init (and a bare @workload) means
"no cache manipulation".
CacheRegime.(enum value) sparkles.test_runner.attributes.CacheRegime.cold = 2cold, effective: (enum) sparkles.test_runner.attributes.CacheRegimeThe page-cache regime a @workload requests for the files it names via
workloadFiles: leave the cache
alone (steadyState), preload (warm), or evict (cold). The runner
verifies the achieved regime (mmap + mincore residency) and
stamps every measured window with requested vs effective — a regime that
could not be established (tmpfs, no posix_fadvise, foreign mappings)
degrades with a reason, never silently.
steadyState is first so .init (and a bare @workload) means
"no cache manipulation".
CacheRegime.(enum value) sparkles.test_runner.attributes.CacheRegime.steadyState = 0steadyState,
residentBefore: 1.0, residentAfter: double.(constant) double double.nan = nannan,
note: "cold impossible on tmpfs (the pages ARE the file) — ran steady-state"));
const (local variable) const(std.json.JSONValue) docdoc = std.json.JSONValue std.json.parseJSON!string(string json, int maxDepth = -1, std.json.JSONOptions options = JSONOptions.none) pure @safeParses a serialized string and returns a tree of JSON values.
parseJSON(string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson(null, (struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta(date: "2026-08-05"), [(local variable) sparkles.test_runner.workload.WorkloadWindow ww]));
const (local variable) const(std.json.JSONValue) gg = (local variable) const(std.json.JSONValue) docdoc["windows"][0]["regime"];
assert((local variable) const(std.json.JSONValue) gg["requested"].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str == "cold");
assert((local variable) const(std.json.JSONValue) gg["effective"].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str == "steadyState");
assert((local variable) const(std.json.JSONValue) gg["residentBefore"].long std.json.JSONValue.integer() const pure @property @safeValue getter/setter for JSONType.integer``.
integer == 1);
assert((local variable) const(std.json.JSONValue) gg["residentAfter"].std.json.JSONType std.json.JSONValue.type() const pure nothrow @nogc @property @safeReturns the JSONType of the value stored in this structure.
Examples
string s = "{ \"language\": \"D\" }";
JSONValue j = parseJSON(s);
assert(j.type == JSONType.object);
assert(j["language"].type == JSONType.string);
type == (enum) std.json.JSONTypeEnumeration of JSON types
JSONType.(enum value) std.json.JSONType.null_ = cast(byte)0Indicates the type of a JSONValue.
null_, "nan fraction → null");
assert((local variable) const(std.json.JSONValue) gg["note"].string std.json.JSONValue.str() const pure @property return scope @trustedValue getter/setter for JSONType.string.
str.bool std.algorithm.searching.canFind!().canFind!(string, string)(string haystack, scope string needle) pure nothrow @nogc @safeConvenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see find.
Examples
const arr = [0, 1, 2, 3];
assert(canFind(arr, 2));
assert(!canFind(arr, 4));
// find one of several needles
assert(arr.canFind(3, 2));
assert(arr.canFind(3, 2) == 2); // second needle found
assert(arr.canFind([1, 3], 2) == 2);
assert(canFind(arr, [1, 2], [2, 3]));
assert(canFind(arr, [1, 2], [2, 3]) == 1);
assert(canFind(arr, [1, 7], [2, 3]));
assert(canFind(arr, [1, 7], [2, 3]) == 2);
assert(!canFind(arr, [1, 3], [2, 4]));
assert(canFind(arr, [1, 3], [2, 4]) == 0);
Example using a custom predicate.
Note that the needle appears as the second argument of the predicate.
auto words = [
"apple",
"beeswax",
"cardboard"
];
assert(!canFind(words, "bees"));
assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
Search for multiple items in an array of items (search for needles in an array of haystacks)
string s1 = "aaa111aaa";
string s2 = "aaa222aaa";
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
assert(hay.canFind!(e => e.canFind("111", "222")));
canFind("tmpfs"));
// Stampless windows omit the key — and the whole document stays free
// of it (the byte-identity contract for regime-less runs).
(struct) sparkles.test_runner.workload.WorkloadWindowOne measured window. Deliberately NOT BenchStats: its per-iteration
timing fields would misrepresent a single window — counter stats here are
window totals (iters == 1).
WorkloadWindow (local variable) sparkles.test_runner.workload.WorkloadWindow plainplain;
(local variable) sparkles.test_runner.workload.WorkloadWindow plainplain.(field) string sparkles.test_runner.workload.WorkloadWindow.namename = "plain";
(local variable) sparkles.test_runner.workload.WorkloadWindow plainplain.(field) uint sparkles.test_runner.workload.WorkloadWindow.repstimes the window content ran inside this window
reps = 1;
(local variable) sparkles.test_runner.workload.WorkloadWindow plainplain.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) long sparkles.test_runner.workload.WallDecomposition.wallNsthe window's wall-clock duration
wallNs = 1;
(local variable) sparkles.test_runner.workload.WorkloadWindow plainplain.(field) sparkles.test_runner.workload.WallDecomposition sparkles.test_runner.workload.WorkloadWindow.wallwall.(field) string sparkles.test_runner.workload.WallDecomposition.scope_"thread" (Linux) or "process"
scope_ = "thread";
assert(!string sparkles.test_runner.bench_json.benchReportJson(in sparkles.test_runner.bench.BenchStats[] rows, in sparkles.test_runner.bench_json.BenchMeta meta, in sparkles.test_runner.workload.WorkloadWindow[] windows = null) @safeThe full report document: {schema, meta, columns, rows}, pretty-printed
with 2-space indent. rows keep measurement order (grouping/sorting are
presentation concerns; the group dimensions travel in each row's labels,
whose keys are emitted sorted). columns describe the available catalog
metrics for these rows, so metrics keys match --list-metrics names.
Schema 2 adds the optional per-row estimatedMetrics array naming the
metrics keys whose values are multiplex-scaled estimates (absent =
every metric exact), and — when @workload tests ran — a windows
sibling array of window objects: wall decomposition fields (null =
unattributable on this host, exactly the table's em dash) and one nested
per-source totals object per attached source. Window values are window
TOTALS with their own field names, deliberately never the per-iteration
metrics catalog keys — reusing those names would quietly overload
their semantics. A run without workloads emits no windows key and is
byte-identical to the pre-window document.
benchReportJson(null, (struct) sparkles.test_runner.bench_json.BenchMetaProvenance and the effective measurement knobs stamped onto a report, so a
committed baseline is self-describing (the budget it was measured under is
part of the data, not tribal knowledge).
BenchMeta(date: "2026-08-05"), [(local variable) sparkles.test_runner.workload.WorkloadWindow plainplain])
.bool std.algorithm.searching.canFind!().canFind!(string, string)(string haystack, scope string needle) pure nothrow @nogc @safeConvenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see find.
Examples
const arr = [0, 1, 2, 3];
assert(canFind(arr, 2));
assert(!canFind(arr, 4));
// find one of several needles
assert(arr.canFind(3, 2));
assert(arr.canFind(3, 2) == 2); // second needle found
assert(arr.canFind([1, 3], 2) == 2);
assert(canFind(arr, [1, 2], [2, 3]));
assert(canFind(arr, [1, 2], [2, 3]) == 1);
assert(canFind(arr, [1, 7], [2, 3]));
assert(canFind(arr, [1, 7], [2, 3]) == 2);
assert(!canFind(arr, [1, 3], [2, 4]));
assert(canFind(arr, [1, 3], [2, 4]) == 0);
Example using a custom predicate.
Note that the needle appears as the second argument of the predicate.
auto words = [
"apple",
"beeswax",
"cardboard"
];
assert(!canFind(words, "bees"));
assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
Search for multiple items in an array of items (search for needles in an array of haystacks)
string s1 = "aaa111aaa";
string s2 = "aaa222aaa";
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
assert(hay.canFind!(e => e.canFind("111", "222")));
canFind("\"regime\""));
}