#!/usr/bin/env dub
/+ dub.sdl:
name "gen_unicode_tables"
dependency "sparkles:base" path="../../.."
dependency "sparkles:core-cli" path="../../.."
libs "curl"
+/
/**
* Generator for `sparkles.base.text.unicode_tables`.
*
* Emits East Asian Width (UAX #11), emoji variation-selector bases (UTS #51),
* and the normalization/case-fold/word-break tables needed by the bounded text
* analyzer as `@safe pure nothrow @nogc` lookup functions. Property sets use
* Phobos's `CodepointSet.toSourceCode`; sequence mappings use compact sorted
* indexes over flat immutable data arrays.
*
* Usage — regenerate the in-tree table for the pinned Unicode version:
* dub run --single gen_unicode_tables.d
*
* With no arguments it downloads the width, emoji, normalization, case-fold,
* and word-break inputs from unicode.org (via `curl`) into a temp directory,
* generates the module, and writes it back into the source tree.
* Overrides:
* --unicode-version <ver> target a different Unicode version (default below)
* --ucd-dir <dir> use local UCD files instead of downloading
* --out-file <path> write somewhere other than the in-tree module
*
* When `--ucd-dir` is given, `<dir>` must contain `EastAsianWidth.txt`,
* `emoji-variation-sequences.txt`, `UnicodeData.txt`, `CaseFolding.txt`,
* `DerivedNormalizationProps.txt`, and `WordBreakProperty.txt`.
*/
module (package) sparklessparkles.(package) sparkles.basebase.(package) sparkles.base.toolstools.(module) sparkles.base.tools.gen_unicode_tablesGenerator for sparkles.base.text.unicode_tables.
Emits East Asian Width (UAX #11), emoji variation-selector bases (UTS #51),
and the normalization/case-fold/word-break tables needed by the bounded text
analyzer as @safe pure nothrow @nogc lookup functions. Property sets use
Phobos's CodepointSet.toSourceCode; sequence mappings use compact sorted
indexes over flat immutable data arrays.
Usage — regenerate the in-tree table for the pinned Unicode version:
dub run --single gen_unicode_tables.d
With no arguments it downloads the width, emoji, normalization, case-fold,
and word-break inputs from unicode.org (via curl) into a temp directory,
generates the module, and writes it back into the source tree.
Overrides
--unicode-version <ver> target a different Unicode version (default below)
--ucd-dir <dir> use local UCD files instead of downloading
--out-file <path> write somewhere other than the in-tree module
When --ucd-dir is given, <dir> must contain EastAsianWidth.txt,
emoji-variation-sequences.txt, UnicodeData.txt, CaseFolding.txt,
DerivedNormalizationProps.txt, and WordBreakProperty.txt.
gen_unicode_tables;
import (package) stdstd.(module) std.algorithmThis package implements generic algorithms oriented towards the processing of
sequences. Sequences processed by these functions define range-based
interfaces. See also Reference on ranges and
tutorial on ranges.
Algorithms are categorized into the following submodules:
Submodule Functions
| Searching |
all
any
balancedParens
boyerMooreFinder
canFind
commonPrefix
count
countUntil
endsWith
find
findAdjacent
findAmong
findSkip
findSplit
findSplitAfter
findSplitBefore
minCount
maxCount
minElement
maxElement
minIndex
maxIndex
minPos
maxPos
skipOver
startsWith
until
|
| Comparison |
among
castSwitch
clamp
cmp
either
equal
isPermutation
isSameLength
levenshteinDistance
levenshteinDistanceAndPath
max
min
mismatch
predSwitch
|
| Iteration |
cache
cacheBidirectional
chunkBy
cumulativeFold
each
filter
filterBidirectional
fold
group
joiner
map
mean
permutations
reduce
splitWhen
splitter
substitute
sum
uniq
|
| Sorting |
completeSort
isPartitioned
isSorted
isStrictlyMonotonic
ordered
strictlyOrdered
makeIndex
merge
multiSort
nextEvenPermutation
nextPermutation
nthPermutation
partialSort
partition
partition3
schwartzSort
sort
topN
topNCopy
topNIndex
|
| Set operations (setops) |
cartesianProduct
largestPartialIntersection
largestPartialIntersectionWeighted
multiwayMerge
multiwayUnion
setDifference
setIntersection
setSymmetricDifference
|
| Mutation |
bringToFront
copy
fill
initializeAll
move
moveAll
moveSome
moveEmplace
moveEmplaceAll
moveEmplaceSome
remove
reverse
strip
stripLeft
stripRight
swap
swapRanges
uninitializedFill
|
Many functions in this package are parameterized with a predicate.
The predicate may be any suitable callable type
(a function, a delegate, a functor, or a lambda), or a
compile-time string. The string may consist of any legal D
expression that uses the symbol a (for unary functions) or the
symbols a and b (for binary functions). These names will NOT
interfere with other homonym symbols in user code because they are
evaluated in a different context. The default for all binary
comparison predicates is "a == b" for unordered operations and
"a < b" for ordered operations.
Example
int[] a = ...;
static bool greater(int a, int b)
{
return a > b;
}
sort!greater(a); // predicate as alias
sort!((a, b) => a > b)(a); // predicate as a lambda.
sort!"a > b"(a); // predicate as string
// (no ambiguity with array name)
sort(a); // no predicate, "a < b" is implicit
Source
std/algorithm/package.d
algorithm : (alias template) sparkles.base.tools.gen_unicode_tables.splitter = std.algorithm.iteration.splitter(alias pred = "a == b", Flag keepSeparators = No.keepSeparators, Range, Separator)(Range r, Separator s) if (is(typeof(binaryFun!pred(r.front, s)) : bool) && (hasSlicing!Range && hasLength!Range || isNarrowString!Range) && (is(ElementType!Range : Separator) || !(isForwardRange!Separator && (hasLength!Separator || isNarrowString!Separator))))Lazily splits a range using an element or range as a separator.
Separator ranges can be any narrow string type or sliceable range type.
Two adjacent separators are considered to surround an empty element in
the split range. Use filter!(a => !a.empty) on the result to compress
empty elements.
The predicate is passed to binaryFun and accepts
any callable function that can be executed via pred(element, s).
Note
If splitting a string on whitespace and token compression is desired,
consider using the ``splitter(r) overload.
Constraints
The predicate pred needs to accept an element of r and the
separator s.
splitter, (alias template) sparkles.base.tools.gen_unicode_tables.map = std.algorithm.iteration.map(fun...) if (fun.length >= 1)Implements the homonym function (also known as transform) present
in many languages of functional flavor. The call ``map!(fun)(range)
returns a range of which elements are obtained by applying fun(a)
left to right for all elements a in range. The original ranges are
not changed. Evaluation is done lazily.
map, (alias template) sparkles.base.tools.gen_unicode_tables.filter = std.algorithm.iteration.filter(alias predicate) if (is(typeof(unaryFun!predicate)))``filter!(predicate)(range) returns a new range containing only elements x in range for
which predicate(x) returns true.
The predicate is passed to unaryFun, and can be either a string, or
any callable that can be executed via pred(element).
filter, (alias template) sparkles.base.tools.gen_unicode_tables.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 find.
canFind, (alias template) sparkles.base.tools.gen_unicode_tables.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 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.
sort, (alias template) sparkles.base.tools.gen_unicode_tables.sum = std.algorithm.iteration.sum(R)(R r) if (isInputRange!R && !isInfinite!R && is(typeof(r.front + r.front)))Sums elements of r, which must be a finite
input range. Although
conceptually sum`(r)` is equivalent to `fold`!((a, b) => a +
b)(r, 0), sum`` uses specialized algorithms to maximize accuracy,
as follows.
If ElementType!R is a floating-point
type and R is a
random-access range with
length and slicing, then sum uses the
pairwise summation
algorithm.
If ElementType!R is a floating-point type and R is a
finite input range (but not a random-access range with slicing), then
sum uses the Kahan summation algorithm.
In all other cases, a simple element by element addition is done.
For floating point inputs, calculations are made in
spec/type, Types, real
precision for real inputs and in double precision otherwise
(Note this is a special case that deviates from fold's behavior,
which would have kept float precision for a float range).
For all other types, the calculations are done in the same type obtained
from from adding two elements of the range, which may be a different
type from the elements themselves (for example, in case of
integral promotion).
A seed may be passed to sum. Not only will this seed be used as an initial
value, but its type will override all the above, and determine the algorithm
and precision used for summation. If a seed is not passed, one is created with
the value of typeof(r.front + r.front)(0), or typeof(r.front + r.front).zero
if no constructor exists that takes an int.
Note that these specialized summing algorithms execute more primitive operations
than vanilla summation. Therefore, if in certain cases maximum speed is required
at expense of precision, one can use fold!((a, b) => a + b)(r, 0), which
is not specialized for summation.
sum, (alias template) sparkles.base.tools.gen_unicode_tables.findSplit = std.algorithm.searching.findSplit(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) if (isForwardRange!R1 && isForwardRange!R2)These functions find the first occurrence of needle in haystack and then
split haystack as follows.
findSplit returns a tuple result containing three ranges.
result[0] is the portion of haystack before needle
result[1] is the portion of
haystack that matches needle
result[2] is the portion of haystack
after the match.
If needle was not found, result[0] comprehends haystack
entirely and result[1] and result[2] are empty.
findSplitBefore returns a tuple result containing two ranges.
result[0] is the portion of haystack before needle
result[1] is the balance of haystack starting with the match.
If needle was not found, result[0]
comprehends haystack entirely and result[1] is empty.
findSplitAfter returns a tuple result containing two ranges.
result[0] is the portion of haystack up to and including the
match
result[1] is the balance of haystack starting
after the match.
If needle was not found, result[0] is empty
and result[1] is haystack.
In all cases, the concatenation of the returned ranges spans the
entire haystack.
If haystack is a random-access range, all three components of the tuple have
the same type as haystack. Otherwise, haystack must be a
forward range and
the type of result[0] (and result[1] for findSplit) is the same as
the result of takeExactly.
For more information about pred see find.
findSplit;
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) sparkles.base.tools.gen_unicode_tables.appender = std.array.appender(A)() if (isDynamicArray!A)Convenience function that returns an Appender instance,
optionally initialized with array.
appender, (alias template) sparkles.base.tools.gen_unicode_tables.join = std.array.join(RoR, R)(RoR ror, R sep) if (isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR)) && isInputRange!R && (is(immutable(ElementType!(ElementType!RoR)) == immutable(ElementType!R)) || isSomeChar!(ElementType!(ElementType!RoR)) && isSomeChar!(ElementType!R)))Eagerly concatenates all of the ranges in ror together (with the GC)
into one array using sep as the separator if present.
join, (alias template) sparkles.base.tools.gen_unicode_tables.array = std.array.array(Range)(Range r) if (isIterable!Range && !isAutodecodableString!Range && !isInfinite!Range)Allocates an array and initializes it with copies of the elements
of range r.
Narrow strings are handled as follows:
If autodecoding is turned on (default), then they are handled as a separate overload.
If autodecoding is turned off, then this is equivalent to duplicating the array.
array;
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) sparkles.base.tools.gen_unicode_tables.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:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
to;
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) sparkles.base.tools.gen_unicode_tables.mkdirRecurse = void std.file.mkdirRecurse(scope const(char)[] pathname) @safeMake directory and all parent directories as needed.
Does nothing if the directory specified by
pathname already exists.
mkdirRecurse, (alias template) sparkles.base.tools.gen_unicode_tables.readText = std.file.readText(S = string, R)(auto ref R name) if (isSomeString!S && (isSomeFiniteCharInputRange!R || is(StringTypeOf!R)))Reads 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.
readText, (alias) sparkles.base.tools.gen_unicode_tables.rmdirRecurse = void std.file.rmdirRecurse(scope const(char)[] pathname) @safeRemove directory and all of its content and subdirectories,
recursively.
rmdirRecurse, (alias) sparkles.base.tools.gen_unicode_tables.tempDir = string std.file.tempDir() @trustedReturns the path to a directory for temporary files.
On POSIX platforms, it searches through the following list of directories
and returns the first one which is found to exist:
The directory given by the TMPDIR environment variable.
The directory given by the TEMP environment variable.
The directory given by the TMP environment variable.
/tmp/
/var/tmp/
/usr/tmp/
On all platforms, tempDir returns the current working directory on failure.
The return value of the function is cached, so the procedures described
below will only be performed the first time the function is called. All
subsequent runs will return the same string, regardless of whether
environment variables and directory structures have changed in the
meantime.
The POSIX tempDir algorithm is inspired by Python's
tempfile.tempdir.
tempDir, (alias template) sparkles.base.tools.gen_unicode_tables.write = std.file.write(R)(R name, const void[] buffer) if ((isSomeFiniteCharInputRange!R || isSomeString!R) && !isConvertibleToString!R)Write buffer to file name.
Creates the file if it does not already exist.
write;
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) sparkles.base.tools.gen_unicode_tables.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.
format, (alias template) sparkles.base.tools.gen_unicode_tables.formattedRead = std.format.read.formattedRead(Range, Char, Args...)(auto ref Range r, const(Char)[] fmt, auto ref Args args)Reads an input range according to a format string and stores the read
values into its arguments.
Format specifiers with format character 'd', 'u' and 'c' can take a ''* parameter for skipping values.
The second version of formattedRead takes the format string as
template argument. In this case, it is checked for consistency at
compile-time.
Note
For backward compatibility the arguments args can be given as pointers
to that variable, but it is not recommended to do so, because this
option might be removed in the future.
formattedRead, (alias template) sparkles.base.tools.gen_unicode_tables.formattedWrite = std.format.write.formattedWrite(Writer, Char, Args...)(auto ref Writer w, scope const Char[] fmt, Args args)Converts its arguments according to a format string and writes
the result to an output range.
The second version of formattedWrite takes the format string as a
template argument. In this case, it is checked for consistency at
compile-time.
Note
In theory this function should be @nogc. But with the current
implementation there are some cases where allocations occur.
See sformat for more details.
formattedWrite;
import (package) stdstd.(package) std.netnet.(module) std.net.curlNetworking client functionality as provided by libcurl. The libcurl library must be installed on the system in order to use
this module.
Category Functions
| High level | download upload get post put del options trace connect byLine byChunk byLineAsync byChunkAsync |
| Low level | HTTP FTP SMTP |
Note
You may need to link with the curl library, e.g. by adding "libs": ["curl"]
to your dub.json file if you are using DUB.
Windows x86 note:
A DMD compatible libcurl static library can be downloaded from the dlang.org
download archive page.
This module is not available for iOS, tvOS or watchOS.
Compared to using libcurl directly, this module allows simpler client code for
common uses, requires no unsafe operations, and integrates better with the rest
of the language. Furthermore it provides range
access to protocols supported by libcurl both synchronously and asynchronously.
A high level and a low level API are available. The high level API is built
entirely on top of the low level one.
The high level API is for commonly used functionality such as HTTP/FTP get. The
byLineAsync and byChunkAsync functions asynchronously
perform the request given, outputting the fetched content into a range.
The low level API allows for streaming, setting request headers and cookies, and other advanced features.
Function Name Description
High level
| download | download("ftp.digitalmars.com/sieve.ds", "/tmp/downloaded-ftp-file") downloads file from URL to file system. |
| upload | upload("/tmp/downloaded-ftp-file", "ftp.digitalmars.com/sieve.ds"); uploads file from file system to URL. |
| get | get("dlang.org") returns a char[] containing the dlang.org web page. |
| put | put("dlang.org", "Hi") returns a char[] containing the dlang.org web page. after a HTTP PUT of "hi" |
| post | post("dlang.org", "Hi") returns a char[] containing the dlang.org web page. after a HTTP POST of "hi" |
| byLine | byLine("dlang.org") returns a range of char[] containing the dlang.org web page. |
| byChunk | byChunk("dlang.org", 10) returns a range of ubyte10 containing the dlang.org web page. |
| byLineAsync | byLineAsync("dlang.org") asynchronously returns a range of char[] containing the dlang.org web page. |
| byChunkAsync | byChunkAsync("dlang.org", 10) asynchronously returns a range of ubyte10 containing the dlang.org web page. |
Low level
| HTTP | Struct for advanced HTTP usage |
| FTP | Struct for advanced FTP usage |
| SMTP | Struct for advanced SMTP usage |
Example
import std.net.curl, std.stdio;
// Return a char[] containing the content specified by a URL
auto content = get("dlang.org");
// Post data and return a char[] containing the content specified by a URL
auto content = post("mydomain.com/here.cgi", ["name1" : "value1", "name2" : "value2"]);
// Get content of file from ftp server
auto content = get("ftp.digitalmars.com/sieve.ds");
// Post and print out content line by line. The request is done in another thread.
foreach (line; byLineAsync("dlang.org", "Post data"))
writeln(line);
// Get using a line range and proxy settings
auto client = HTTP();
client.proxy = "1.2.3.4";
foreach (line; byLine("dlang.org", client))
writeln(line);
For more control than the high level functions provide, use the low level API:
Example
import std.net.curl, std.stdio;
// GET with custom data receivers
auto http = HTTP("dlang.org");
http.onReceiveHeader =
(in char[] key, in char[] value) { writeln(key, ": ", value); };
http.onReceive = (ubyte[] data) { /+ drop +/ return data.length; };
http.perform();
First, an instance of the reference-counted HTTP struct is created. Then the
custom delegates are set. These will be called whenever the HTTP instance
receives a header and a data buffer, respectively. In this simple example, the
headers are written to stdout and the data is ignored. If the request is
stopped before it has finished then return something less than data.length from
the onReceive callback. See onReceiveHeader/onReceive for more
information. Finally, the HTTP request is performed by calling perform(), which is
synchronous.
Source
std/net/curl.d
Credits
The functionality is based on libcurl.
libcurl is licensed under an MIT/X derivative license.
curl : (alias template) sparkles.base.tools.gen_unicode_tables.download = std.net.curl.download(Conn = AutoProtocol)(const(char)[] url, string saveToPath, Conn conn = Conn()) if (isCurlConn!Conn)HTTP/FTP download to local file system.
Example
import std.net.curl;
download("https://httpbin.org/get", "/tmp/downloaded-http-file");
download, (struct) std.net.curl.HTTPHTTP client functionality.
Example
Get with custom data receivers:
import std.net.curl, std.stdio;
auto http = HTTP("https://dlang.org");
http.onReceiveHeader =
(in char[] key, in char[] value) { writeln(key ~ ": " ~ value); };
http.onReceive = (ubyte[] data) { /+ drop +/ return data.length; };
http.perform();
Put with data senders:
import std.net.curl, std.stdio;
auto http = HTTP("https://dlang.org");
auto msg = "Hello world";
http.contentLength = msg.length;
http.onSend = (void[] data)
{
auto m = cast(void[]) msg;
size_t len = m.length > data.length ? data.length : m.length;
if (len == 0) return len;
data[0 .. len] = m[0 .. len];
msg = msg[len..$];
return len;
};
http.perform();
Tracking progress:
import std.net.curl, std.stdio;
auto http = HTTP();
http.method = HTTP.Method.get;
http.url = "http://upload.wikimedia.org/wikipedia/commons/" ~
"5/53/Wikipedia-logo-en-big.png";
http.onReceive = (ubyte[] data) { return data.length; };
http.onProgress = (size_t dltotal, size_t dlnow,
size_t ultotal, size_t ulnow)
{
writeln("Progress ", dltotal, ", ", dlnow, ", ", ultotal, ", ", ulnow);
return 0;
};
http.perform();
HTTP, (class) std.net.curl.CurlExceptionException thrown on errors in std.net.curl functions.
CurlException, (enum) etc.c.curl.CurlOptionCurlOption;
import (package) stdstd.(module) std.pathThis module is used to manipulate path strings.
All functions, with the exception of expandTilde (and in some
cases absolutePath and relativePath), are pure
string manipulation functions; they don't depend on any state outside
the program, nor do they perform any actual file system actions.
This has the consequence that the module does not make any distinction
between a path that points to a directory and a path that points to a
file, and it does not know whether or not the object pointed to by the
path actually exists in the file system.
To differentiate between these cases, use isDir and
exists.
Note that on Windows, both the backslash (\) and the slash (/)
are in principle valid directory separators. This module treats them
both on equal footing, but in cases where a new separator is
added, a backslash will be used. Furthermore, the buildNormalizedPath
function will replace all slashes with backslashes on that platform.
In general, the functions in this module assume that the input paths
are well-formed. (That is, they should not contain invalid characters,
they should follow the file system's path format, etc.) The result
of calling a function on an ill-formed path is undefined. When there
is a chance that a path or a file name is invalid (for instance, when it
has been input by the user), it may sometimes be desirable to use the
isValidFilename and isValidPath functions to check
this.
Most functions do not perform any memory allocations, and if a string is
returned, it is usually a slice of an input string. If a function
allocates, this is explicitly mentioned in the documentation.
Category Functions Normalization absolutePath asAbsolutePath asNormalizedPath asRelativePath buildNormalizedPath buildPath chainPath expandTilde Partitioning baseName dirName dirSeparator driveName pathSeparator pathSplitter relativePath rootName stripDrive Validation isAbsolute isDirSeparator isRooted isValidFilename isValidPath Extension defaultExtension extension setExtension stripExtension withDefaultExtension withExtension Other filenameCharCmp filenameCmp globMatch CaseSensitive
Source
std/path.d
path : (alias template) sparkles.base.tools.gen_unicode_tables.buildNormalizedPath = std.path.buildNormalizedPath(C)(const(C[])[] paths...) if (isSomeChar!C)Performs the same task as buildPath,
while at the same time resolving current/parent directory
symbols ("." and "..") and removing superfluous
directory separators.
It will return "." if the path leads to the starting directory.
On Windows, slashes are replaced with backslashes.
Using buildNormalizedPath on null paths will always return null.
Note that this function does not resolve symbolic links.
This function always allocates memory to hold the resulting path.
Use asNormalizedPath to not allocate memory.
buildNormalizedPath, (alias template) sparkles.base.tools.gen_unicode_tables.buildPath = std.path.buildPath(Range)(scope Range segments) if (isInputRange!Range && !isInfinite!Range && isSomeString!(ElementType!Range))Combines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
buildPath, (alias template) sparkles.base.tools.gen_unicode_tables.dirName = std.path.dirName(R)(return scope R path) if (isRandomAccessRange!R && hasSlicing!R && hasLength!R && isSomeChar!(ElementType!R) && !isSomeString!R)Returns the parent directory of path. On Windows, this
includes the drive letter if present. If path is a relative path and
the parent directory is the current working directory, returns ".".
dirName;
import (package) stdstd.(module) std.processFunctions for starting and interacting with other processes, and for
working with the current process' execution environment.
Process handling
`spawnProcess` spawns a new `process`, optionally assigning it an
arbitrary set of standard input, output, and error streams.
The function returns immediately, leaving the child process to execute
in parallel with its parent. All other functions in this module that
spawn processes are built around spawnProcess.
`wait` makes the parent `process` wait for a child `process` to
terminate. In general one should always do this, to avoid
child processes becoming "zombies" when the parent process exits.
Scope guards are perfect for this – see the spawnProcess
documentation for examples. tryWait is similar to wait,
but does not block if the process has not yet terminated.
`pipeProcess` also spawns a child `process` which runs
in parallel with its parent. However, instead of taking
arbitrary streams, it automatically creates a set of
pipes that allow the parent to communicate with the child
through the child's standard input, output, and/or error streams.
This function corresponds roughly to C's popen function.
`execute` starts a new `process` and waits for it
to complete before returning. Additionally, it captures
the process' standard output and error streams and returns
the output of these as a string.
`spawnShell`, `pipeShell` and `executeShell` work like
spawnProcess, pipeProcess and execute, respectively,
except that they take a single command string and run it through
the current user's default command interpreter.
executeShell corresponds roughly to C's system function.
`kill` attempts to terminate a running `process`.
The following table compactly summarises the different process creation
functions and how they relate to each other:
Runs program directly
Runs shell command Low-level process creation spawnProcess spawnShell Automatic input/output redirection using pipes pipeProcess pipeShell Execute and wait for completion, collect output execute executeShell
Other functionality
`pipe` is used to create unidirectional pipes.
`environment` is an interface through which the current `process`'
environment variables can be read and manipulated.
`escapeShellCommand` and `escapeShellFileName` are useful
for constructing shell command lines in a portable way.
Source
std/process.d
Note
Most of the functionality in this module is not available on iOS, tvOS
and watchOS. The only functions available on those platforms are:
environment, thisProcessID and thisThreadID.
process : (alias) sparkles.base.tools.gen_unicode_tables.thisProcessID = int std.process.thisProcessID() nothrow @nogc @property @trustedReturns the process ID of the current process,
which is guaranteed to be unique on the system.
Example
writefln("Current process ID: %d", thisProcessID);
thisProcessID;
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) sparkles.base.tools.gen_unicode_tables.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
isWhite) or as specified in the second argument.
strip, (alias template) sparkles.base.tools.gen_unicode_tables.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
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, (alias template) sparkles.base.tools.gen_unicode_tables.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",
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.
lineSplitter, (alias template) sparkles.base.tools.gen_unicode_tables.outdent = std.string.outdent(S)(S str) if (isSomeString!S)Removes one level of indentation from a multi-line string.
This uniformly outdents the text as much as possible.
Whitespace-only lines are always converted to blank lines.
Does not allocate memory if it does not throw.
outdent;
import (package) stdstd.(module) std.uniThe std.uni`` module provides an implementation
of fundamental Unicode algorithms and data structures.
This doesn't include UTF encoding and decoding primitives,
see decode and encode in std.utf
for this functionality.
Category Functions Decode byCodePoint byGrapheme decodeGrapheme graphemeStride popGrapheme Comparison icmp sicmp Classification isAlpha isAlphaNum isCodepointSet isControl isFormat isGraphical isIntegralPair isMark isNonCharacter isNumber isPrivateUse isPunctuation isSpace isSurrogate isSurrogateHi isSurrogateLo isSymbol isWhite Normalization NFC NFD NFKD NormalizationForm normalize Decompose decompose decomposeHangul UnicodeDecomposition Compose compose composeJamo Sets CodepointInterval CodepointSet InversionList unicode Trie codepointSetTrie CodepointSetTrie codepointTrie CodepointTrie toTrie toDelegate Casing asCapitalized asLowerCase asUpperCase isLower isUpper toLower toLowerInPlace toUpper toUpperInPlace Utf8Matcher isUtfMatcher MatcherConcept utfMatcher Separators lineSep nelSep paraSep Building blocks allowedIn combiningClass Grapheme
All primitives listed operate on Unicode characters and
sets of characters. For functions which operate on ASCII characters
and ignore Unicode <a href="#Character">characters</a>, see std.ascii.
For definitions of Unicode <a href="#Character">character</a>, <a href="#Code point">code point</a> and other terms
used throughout this module see the <a href="#Terminology">terminology</a> section
below.
The focus of this module is the core needs of developing Unicode-aware
applications. To that effect it provides the following optimized primitives:
Character classification by category and common properties:
isAlpha, isWhite and others.
Case-insensitive string comparison (`sicmp`, `icmp`).
Converting text to any of the four normalization forms via `normalize`.
Decoding (`decodeGrapheme`) and iteration (`byGrapheme`, `graphemeStride`)
by user-perceived characters, that is by Grapheme clusters.
Decomposing and composing of individual character(s) according to canonical
or compatibility rules, see compose and decompose,
including the specific version for Hangul syllables composeJamo
and decomposeHangul.
It's recognized that an application may need further enhancements
and extensions, such as less commonly known algorithms,
or tailoring existing ones for region specific needs. To help users
with building any extra functionality beyond the core primitives,
the module provides:
`CodepointSet`, a type for easy manipulation of sets of characters.
Besides the typical set algebra it provides an unusual feature:
a D source code generator for detection of <a href="#Code point">code points</a> in this set.
This is a boon for meta-programming parser frameworks,
and is used internally to power classification in small
sets like isWhite.
A way to construct optimal packed multi-stage tables also known as a
special case of Trie.
The functions codepointTrie, codepointSetTrie
construct custom tries that map dchar to value.
The end result is a fast and predictable O(1) lookup that powers
functions like isAlpha and combiningClass,
but for user-defined data sets.
A useful technique for Unicode-aware parsers that perform
character classification of encoded <a href="#Code point">code points</a>
is to avoid unnecassary decoding at all costs.
utfMatcher provides an improvement over the usual workflow
of decode-classify-process, combining the decoding and classification
steps. By extracting necessary bits directly from encoded
<a href="#Code unit">code units</a> matchers achieve
significant performance improvements. See MatcherConcept for
the common interface of UTF matchers.
Generally useful building blocks for customized normalization:
combiningClass for querying combining class
and allowedIn for testing the Quick_Check
property of a given normalization form.
Access to a large selection of commonly used sets of <a href="#Code point">code points</a>.
<a href="#Unicode properties">Supported sets</a> include Script,
Block and General Category. The exact contents of a set can be
observed in the CLDR utility, on the
property index page
of the Unicode website.
See unicode for easy and (optionally) compile-time checked set
queries.
<h3><a id="Synopsis">Synopsis</a></h3>
import std.uni;
void main()
{
// initialize code point sets using script/block or property name
// now 'set' contains code points from both scripts.
auto set = unicode("Cyrillic") | unicode("Armenian");
// same thing but simpler and checked at compile-time
auto ascii = unicode.ASCII;
auto currency = unicode.Currency_Symbol;
// easy set ops
auto a = set & ascii;
assert(a.empty); // as it has no intersection with ascii
a = set | ascii;
auto b = currency - a; // subtract all ASCII, Cyrillic and Armenian
// some properties of code point sets
assert(b.length > 45); // 46 items in Unicode 6.1, even more in 6.2
// testing presence of a code point in a set
// is just fine, it is O(logN)
assert(!b['$']);
assert(!b['\u058F']); // Armenian dram sign
assert(b['¥']);
// building fast lookup tables, these guarantee O(1) complexity
// 1-level Trie lookup table essentially a huge bit-set ~262Kb
auto oneTrie = toTrie!1(b);
// 2-level far more compact but typically slightly slower
auto twoTrie = toTrie!2(b);
// 3-level even smaller, and a bit slower yet
auto threeTrie = toTrie!3(b);
assert(oneTrie['£']);
assert(twoTrie['£']);
assert(threeTrie['£']);
// build the trie with the most sensible trie level
// and bind it as a functor
auto cyrillicOrArmenian = toDelegate(set);
auto balance = find!(cyrillicOrArmenian)("Hello ընկեր!");
assert(balance == "ընկեր!");
// compatible with bool delegate(dchar)
bool delegate(dchar) bindIt = cyrillicOrArmenian;
// Normalization
string s = "Plain ascii (and not only), is always normalized!";
assert(s is normalize(s));// is the same string
string nonS = "A\u0308ffin"; // A ligature
auto nS = normalize(nonS); // to NFC, the W3C endorsed standard
assert(nS == "Äffin");
assert(nS != nonS);
string composed = "Äffin";
assert(normalize!NFD(composed) == "A\u0308ffin");
// to NFKD, compatibility decomposition useful for fuzzy matching/searching
assert(normalize!NFKD("2¹⁰") == "210");
}
<h3><a id="Terminology">Terminology</a></h3>
The following is a list of important Unicode notions
and definitions. Any conventions used specifically in this
module alone are marked as such. The descriptions are based on the formal
definition as found in chapter three of The Unicode Standard Core Specification.
A unit of information used for the organization,
control, or representation of textual data.
Note that:
When representing data, the nature of that data
is generally symbolic as opposed to some other
kind of data (for example, visual).
An abstract character has no concrete form
and should not be confused with a <a href="#Glyph">glyph</a>.
An abstract character does not necessarily
correspond to what a user thinks of as a “character”
and should not be confused with a Grapheme.
The abstract characters encoded (see Encoded character)
are known as Unicode abstract characters.
Abstract characters not directly
encoded by the Unicode Standard can often be
represented by the use of combining character sequences.
The decomposition of a character or character sequence
that results from recursively applying the canonical
mappings found in the Unicode Character Database
and these described in Conjoining Jamo Behavior
(section 12 of
[Unicode Conformance](http://www.unicode.org/uni2book/ch03.pdf)).
The precise definition of the Canonical composition
is the algorithm as specified in [ Unicode Conformance](http://www.unicode.org/uni2book/ch03.pdf) section 11.
Informally it's the process that does the reverse of the canonical
decomposition with the addition of certain rules
that e.g. prevent legacy characters from appearing in the composed result.
Two character sequences are said to be canonical equivalents if
their full canonical decompositions are identical.
Typically differs by context.
For the purpose of this documentation the term *character*
implies *encoded character*, that is, a code point having
an assigned abstract character (a symbolic meaning).
Any value in the Unicode codespace;
that is, the range of integers from 0 to 10FFFF (hex).
Not all code points are assigned to encoded characters.
The minimal bit combination that can represent
a unit of encoded text for processing or interchange.
Depending on the encoding this could be:
8-bit code units in the UTF-8 (`char`),
16-bit code units in the UTF-16 (`wchar`),
and 32-bit code units in the UTF-32 (`dchar`).
*Note that in UTF-32, a code unit is a code point
and is represented by the D `dchar` type.*
A character with the General Category
of Combining Mark(M).
All characters with non-zero canonical combining class
are combining characters, but the reverse is not the case:
there are combining characters with a zero combining class.
These characters are not normally used in isolation
unless they are being described. They include such characters
as accents, diacritics, Hebrew points, Arabic vowel signs,
and Indic matras.
A numerical value used by the Unicode Canonical Ordering Algorithm
to determine which sequences of combining marks are to be
considered canonically equivalent and which are not.
The decomposition of a character or character sequence that results
from recursively applying both the compatibility mappings and
the canonical mappings found in the Unicode Character Database, and those
described in Conjoining Jamo Behavior no characters
can be further decomposed.
Two character sequences are said to be compatibility
equivalents if their full compatibility decompositions are identical.
An association (or mapping)
between an abstract character and a code point.
The actual, concrete image of a glyph representation
having been rasterized or otherwise imaged onto some display surface.
A character with the property
Grapheme_Base, or any standard Korean syllable block.
Defined as the text between
grapheme boundaries as specified by Unicode Standard Annex #29,
[Unicode text segmentation](http://www.unicode.org/reports/tr29/).
Important general properties of a grapheme:
The grapheme cluster represents a horizontally segmentable
unit of text, consisting of some grapheme base (which may
consist of a Korean syllable) together with any number of
nonspacing marks applied to it.
A grapheme cluster typically starts with a grapheme base
and then extends across any subsequent sequence of nonspacing marks.
A grapheme cluster is most directly relevant to text rendering and
processes such as cursor placement and text selection in editing,
but may also be relevant to comparison and searching.
For many processes, a grapheme cluster behaves as if it was a
single character with the same properties as its grapheme base.
Effectively, nonspacing marks apply graphically to the base,
but do not change its properties.
This module defines a number of primitives that work with graphemes:
Grapheme, decodeGrapheme and graphemeStride.
All of them are using extended grapheme boundaries
as defined in the aforementioned standard annex.
A combining character with the
General Category of Nonspacing Mark (Mn) or Enclosing Mark (Me).
A combining character that is not a nonspacing mark.
<h3><a id="Normalization">Normalization</a></h3>
The concepts of <a href="#Canonical equivalent">canonical equivalent</a>
or <a href="#Compatibility equivalent">compatibility equivalent</a>
characters in the Unicode Standard make it necessary to have a full, formal
definition of equivalence for Unicode strings.
String equivalence is determined by a process called normalization,
whereby strings are converted into forms which are compared
directly for identity. This is the primary goal of the normalization process,
see the function normalize to convert into any of
the four defined forms.
A very important attribute of the Unicode Normalization Forms
is that they must remain stable between versions of the Unicode Standard.
A Unicode string normalized to a particular Unicode Normalization Form
in one version of the standard is guaranteed to remain in that Normalization
Form for implementations of future versions of the standard.
The Unicode Standard specifies four normalization forms.
Informally, two of these forms are defined by maximal decomposition
of equivalent sequences, and two of these forms are defined
by maximal composition of equivalent sequences.
Normalization Form D (NFD): The <a href="#Canonical decomposition"> canonical decomposition</a> of a character sequence.
Normalization Form KD (NFKD): The <a href="#Compatibility decomposition"> compatibility decomposition</a> of a character sequence.
Normalization Form C (NFC): The canonical composition of the
<a href="#Canonical decomposition">canonical decomposition</a>
of a coded character sequence.
Normalization Form KC (NFKC): The canonical composition
of the <a href="#Compatibility decomposition"> compatibility decomposition</a> of a character sequence
The choice of the normalization form depends on the particular use case.
NFC is the best form for general text, since it's more compatible with
strings converted from legacy encodings. NFKC is the preferred form for
identifiers, especially where there are security concerns. NFD and NFKD
are the most useful for internal processing.
<h3><a id="Construction of lookup tables">Construction of lookup tables</a></h3>
The Unicode standard describes a set of algorithms that
depend on having the ability to quickly look up various properties
of a code point. Given the codespace of about 1 million <a href="#Code point">code points</a>,
it is not a trivial task to provide a space-efficient solution for
the multitude of properties.
Common approaches such as hash-tables or binary search over
sorted code point intervals (as in InversionList) are insufficient.
Hash-tables have enormous memory footprint and binary search
over intervals is not fast enough for some heavy-duty algorithms.
The recommended solution (see Unicode Implementation Guidelines)
is using multi-stage tables that are an implementation of the
Trie data structure with integer
keys and a fixed number of stages. For the remainder of the section
this will be called a fixed trie. The following describes a particular
implementation that is aimed for the speed of access at the expense
of ideal size savings.
Taking a 2-level Trie as an example the principle of operation is as follows.
Split the number of bits in a key (code point, 21 bits) into 2 components
(e.g. 15 and 8). The first is the number of bits in the index of the trie
and the other is number of bits in each page of the trie.
The layout of the trie is then an array of size 2^^bits-of-index followed
an array of memory chunks of size 2^^bits-of-page/bits-per-element.
The number of pages is variable (but not less then 1)
unlike the number of entries in the index. The slots of the index
all have to contain a number of a page that is present. The lookup is then
just a couple of operations - slice the upper bits,
lookup an index for these, take a page at this index and use
the lower bits as an offset within this page.
Assuming that pages are laid out consequently
in one array at pages, the pseudo-code is:
auto elemsPerPage = (2 ^^ bits_per_page) / Value.sizeOfInBits;
pages[index[n >> bits_per_page]][n & (elemsPerPage - 1)];
Where if elemsPerPage is a power of 2 the whole process is
a handful of simple instructions and 2 array reads. Subsequent levels
of the trie are introduced by recursing on this notion - the index array
is treated as values. The number of bits in index is then again
split into 2 parts, with pages over 'current-index' and the new 'upper-index'.
For completeness a level 1 trie is simply an array.
The current implementation takes advantage of bit-packing values
when the range is known to be limited in advance (such as bool).
See also BitPacked for enforcing it manually.
The major size advantage however comes from the fact
that multiple identical pages on every level are merged by construction.
The process of constructing a trie is more involved and is hidden from
the user in a form of the convenience functions codepointTrie,
codepointSetTrie and the even more convenient toTrie.
In general a set or built-in AA with dchar type
can be turned into a trie. The trie object in this module
is read-only (immutable); it's effectively frozen after construction.
<h3><a id="Unicode properties">Unicode properties</a></h3>
This is a full list of Unicode properties accessible through unicode
with specific helpers per category nested within. Consult the
CLDR utility
when in doubt about the contents of a particular set.
General category sets listed below are only accessible with the
unicode shorthand accessor.
Abb. Long form
Abb. Long form Abb. Long form L Letter Cn Unassigned Po Other_Punctuation Ll Lowercase_Letter Co Private_Use Ps Open_Punctuation Lm Modifier_Letter Cs Surrogate S Symbol Lo Other_Letter N Number Sc Currency_Symbol Lt Titlecase_Letter Nd Decimal_Number Sk Modifier_Symbol Lu Uppercase_Letter Nl Letter_Number Sm Math_Symbol M Mark No Other_Number So Other_Symbol Mc Spacing_Mark P Punctuation Z Separator Me Enclosing_Mark Pc Connector_Punctuation Zl Line_Separator Mn Nonspacing_Mark Pd Dash_Punctuation Zp Paragraph_Separator C Other Pe Close_Punctuation Zs Space_Separator Cc Control Pf Final_Punctuation - Any Cf Format Pi Initial_Punctuation - ASCII
Sets for other commonly useful properties that are
accessible with unicode:
Name Name Name Alphabetic Ideographic Other_Uppercase ASCII_Hex_Digit IDS_Binary_Operator Pattern_Syntax Bidi_Control ID_Start Pattern_White_Space Cased IDS_Trinary_Operator Quotation_Mark Case_Ignorable Join_Control Radical Dash Logical_Order_Exception Soft_Dotted Default_Ignorable_Code_Point Lowercase STerm Deprecated Math Terminal_Punctuation Diacritic Noncharacter_Code_Point Unified_Ideograph Extender Other_Alphabetic Uppercase Grapheme_Base Other_Default_Ignorable_Code_Point Variation_Selector Grapheme_Extend Other_Grapheme_Extend White_Space Grapheme_Link Other_ID_Continue XID_Continue Hex_Digit Other_ID_Start XID_Start Hyphen Other_Lowercase ID_Continue Other_Math
Below is the table with block names accepted by unicode.block.
Note that the shorthand version unicode requires "In"
to be prepended to the names of blocks so as to disambiguate
scripts and blocks.
| Aegean Numbers | Ethiopic Extended | Mongolian |
| Alchemical Symbols | Ethiopic Extended-A | Musical Symbols |
| Alphabetic Presentation Forms | Ethiopic Supplement | Myanmar |
| Ancient Greek Musical Notation | General Punctuation | Myanmar Extended-A |
| Ancient Greek Numbers | Geometric Shapes | New Tai Lue |
| Ancient Symbols | Georgian | NKo |
| Arabic | Georgian Supplement | Number Forms |
| Arabic Extended-A | Glagolitic | Ogham |
| Arabic Mathematical Alphabetic Symbols | Gothic | Ol Chiki |
| Arabic Presentation Forms-A | Greek and Coptic | Old Italic |
| Arabic Presentation Forms-B | Greek Extended | Old Persian |
| Arabic Supplement | Gujarati | Old South Arabian |
| Armenian | Gurmukhi | Old Turkic |
| Arrows | Halfwidth and Fullwidth Forms | Optical Character Recognition |
| Avestan | Hangul Compatibility Jamo | Oriya |
| Balinese | Hangul Jamo | Osmanya |
| Bamum | Hangul Jamo Extended-A | Phags-pa |
| Bamum Supplement | Hangul Jamo Extended-B | Phaistos Disc |
| Basic Latin | Hangul Syllables | Phoenician |
| Batak | Hanunoo | Phonetic Extensions |
| Bengali | Hebrew | Phonetic Extensions Supplement |
| Block Elements | High Private Use Surrogates | Playing Cards |
| Bopomofo | High Surrogates | Private Use Area |
| Bopomofo Extended | Hiragana | Rejang |
| Box Drawing | Ideographic Description Characters | Rumi Numeral Symbols |
| Brahmi | Imperial Aramaic | Runic |
| Braille Patterns | Inscriptional Pahlavi | Samaritan |
| Buginese | Inscriptional Parthian | Saurashtra |
| Buhid | IPA Extensions | Sharada |
| Byzantine Musical Symbols | Javanese | Shavian |
| Carian | Kaithi | Sinhala |
| Chakma | Kana Supplement | Small Form Variants |
| Cham | Kanbun | Sora Sompeng |
| Cherokee | Kangxi Radicals | Spacing Modifier Letters |
| CJK Compatibility | Kannada | Specials |
| CJK Compatibility Forms | Katakana | Sundanese |
| CJK Compatibility Ideographs | Katakana Phonetic Extensions | Sundanese Supplement |
| CJK Compatibility Ideographs Supplement | Kayah Li | Superscripts and Subscripts |
| CJK Radicals Supplement | Kharoshthi | Supplemental Arrows-A |
| CJK Strokes | Khmer | Supplemental Arrows-B |
| CJK Symbols and Punctuation | Khmer Symbols | Supplemental Mathematical Operators |
| CJK Unified Ideographs | Lao | Supplemental Punctuation |
| CJK Unified Ideographs Extension A | Latin-1 Supplement | Supplementary Private Use Area-A |
| CJK Unified Ideographs Extension B | Latin Extended-A | Supplementary Private Use Area-B |
| CJK Unified Ideographs Extension C | Latin Extended Additional | Syloti Nagri |
| CJK Unified Ideographs Extension D | Latin Extended-B | Syriac |
| Combining Diacritical Marks | Latin Extended-C | Tagalog |
| Combining Diacritical Marks for Symbols | Latin Extended-D | Tagbanwa |
| Combining Diacritical Marks Supplement | Lepcha | Tags |
| Combining Half Marks | Letterlike Symbols | Tai Le |
| Common Indic Number Forms | Limbu | Tai Tham |
| Control Pictures | Linear B Ideograms | Tai Viet |
| Coptic | Linear B Syllabary | Tai Xuan Jing Symbols |
| Counting Rod Numerals | Lisu | Takri |
| Cuneiform | Low Surrogates | Tamil |
| Cuneiform Numbers and Punctuation | Lycian | Telugu |
| Currency Symbols | Lydian | Thaana |
| Cypriot Syllabary | Mahjong Tiles | Thai |
| Cyrillic | Malayalam | Tibetan |
| Cyrillic Extended-A | Mandaic | Tifinagh |
| Cyrillic Extended-B | Mathematical Alphanumeric Symbols | Transport And Map Symbols |
| Cyrillic Supplement | Mathematical Operators | Ugaritic |
| Deseret | Meetei Mayek | Unified Canadian Aboriginal Syllabics |
| Devanagari | Meetei Mayek Extensions | Unified Canadian Aboriginal Syllabics Extended |
| Devanagari Extended | Meroitic Cursive | Vai |
| Dingbats | Meroitic Hieroglyphs | Variation Selectors |
| Domino Tiles | Miao | Variation Selectors Supplement |
| Egyptian Hieroglyphs | Miscellaneous Mathematical Symbols-A | Vedic Extensions |
| Emoticons | Miscellaneous Mathematical Symbols-B | Vertical Forms |
| Enclosed Alphanumerics | Miscellaneous Symbols | Yijing Hexagram Symbols |
| Enclosed Alphanumeric Supplement | Miscellaneous Symbols and Arrows | Yi Radicals |
| Enclosed CJK Letters and Months | Miscellaneous Symbols And Pictographs | Yi Syllables |
| Enclosed Ideographic Supplement | Miscellaneous Technical |
| Ethiopic | Modifier Tone Letters |
Below is the table with script names accepted by unicode.script
and by the shorthand version unicode:
| Arabic | Hanunoo | Old_Italic |
| Armenian | Hebrew | Old_Persian |
| Avestan | Hiragana | Old_South_Arabian |
| Balinese | Imperial_Aramaic | Old_Turkic |
| Bamum | Inherited | Oriya |
| Batak | Inscriptional_Pahlavi | Osmanya |
| Bengali | Inscriptional_Parthian | Phags_Pa |
| Bopomofo | Javanese | Phoenician |
| Brahmi | Kaithi | Rejang |
| Braille | Kannada | Runic |
| Buginese | Katakana | Samaritan |
| Buhid | Kayah_Li | Saurashtra |
| Canadian_Aboriginal | Kharoshthi | Sharada |
| Carian | Khmer | Shavian |
| Chakma | Lao | Sinhala |
| Cham | Latin | Sora_Sompeng |
| Cherokee | Lepcha | Sundanese |
| Common | Limbu | Syloti_Nagri |
| Coptic | Linear_B | Syriac |
| Cuneiform | Lisu | Tagalog |
| Cypriot | Lycian | Tagbanwa |
| Cyrillic | Lydian | Tai_Le |
| Deseret | Malayalam | Tai_Tham |
| Devanagari | Mandaic | Tai_Viet |
| Egyptian_Hieroglyphs | Meetei_Mayek | Takri |
| Ethiopic | Meroitic_Cursive | Tamil |
| Georgian | Meroitic_Hieroglyphs | Telugu |
| Glagolitic | Miao | Thaana |
| Gothic | Mongolian | Thai |
| Greek | Myanmar | Tibetan |
| Gujarati | New_Tai_Lue | Tifinagh |
| Gurmukhi | Nko | Ugaritic |
| Han | Ogham | Vai |
| Hangul | Ol_Chiki | Yi |
Below is the table of names accepted by unicode.hangulSyllableType.
Abb. Long form L Leading_Jamo LV LV_Syllable LVT LVT_Syllable T Trailing_Jamo V Vowel_Jamo
References
ASCII Table,
Wikipedia,
The Unicode Consortium,
Unicode normalization forms,
Unicode text segmentation
Unicode Implementation Guidelines
Unicode Conformance
Trademarks
Unicode(tm) is a trademark of Unicode, Inc.
Source
std/uni/package.d
uni : (struct) std.uni.InversionList!(GcPolicy)CodepointSet, (alias) sparkles.base.tools.gen_unicode_tables.isWhite = bool std.uni.isWhite(dchar c) pure nothrow @nogc @safeWhether or not c is a Unicode whitespace .
(general Unicode category: Part of C0(tab, vertical tab, form feed,
carriage return, and linefeed characters), Zs, Zl, Zp, and NEL(U+0085))
isWhite;
import (package) sparklessparkles.(package) sparkles.basebase.(module) sparkles.base.styled_templateStyle template processing for IES (Interpolated Expression Sequences).
Provides a template syntax for applying terminal styles to IES strings:
import sparkles.base.styled_template;
int cpu = 75;
styledWriteln(i"CPU: {red $(cpu)%} Status: {green OK}");
Supported syntax:
{red text} — Apply single style
{bold.red text} — Chain multiple styles
{bold outer {red nested}} — Nested blocks (inner inherits outer)
{red text {~red normal}} — Negation with ~ removes a style
#{ — Escaped literal {
#} — Escaped literal }
styled_template : (alias template) sparkles.base.tools.gen_unicode_tables.styledWriteln = sparkles.base.styled_template.styledWriteln(Args...)(ColorDepth depth, InterpolationHeader header, Args args, InterpolationFooter footer)Write styled IES to stdout with newline.
styledWriteln, (alias template) sparkles.base.tools.gen_unicode_tables.styledWritelnErr = sparkles.base.styled_template.styledWritelnErr(Args...)(ColorDepth depth, InterpolationHeader header, Args args, InterpolationFooter footer)Write styled IES to stderr with newline.
styledWritelnErr;
import (package) sparklessparkles.(package) sparkles.core_clicore_cli.(module) sparkles.core_cli.argsargs : (struct) sparkles.core_cli.help_formatting.HelpInfoHelpInfo, (struct) sparkles.core_cli.args.uda.OptionOption, (alias template) sparkles.base.tools.gen_unicode_tables.parseCli = sparkles.core_cli.args.internal.parseCli(Cli)(string[] argv, HelpInfo helpInfo = HelpInfo.init)parseCli, (alias) sparkles.base.tools.gen_unicode_tables.reportCliError = int sparkles.core_cli.args.internal.reportCliError(in sparkles.core_cli.args.error.CliError e)Reports a failed parse and returns the exit code the program should use.
A help request is a failure in the Expected sense but a success to the
user, and carries exitCode == 0 to say so — returning this value is what
keeps --help from looking like an error to a shell.
For a program whose commands have run methods, prefer runCli,
which calls this. This is the entry point for a program that parses into a
struct and then does its own work.
reportCliError;
/// Unicode version this generator targets by default. All properties consumed
/// by the bounded analyzer, including canonical combining classes, are emitted
/// here so its behavior does not silently follow the compiler's `std.uni`.
enum (constant) string sparkles.base.tools.gen_unicode_tables.pinnedUnicodeVersion = "17.0.0"Unicode version this generator targets by default. All properties consumed
by the bounded analyzer, including canonical combining classes, are emitted
here so its behavior does not silently follow the compiler's std.uni.
pinnedUnicodeVersion = "17.0.0";
/// Base URL of the Unicode Character Database.
enum (constant) string sparkles.base.tools.gen_unicode_tables.ucdBaseUrl = "https://www.unicode.org/Public"Base URL of the Unicode Character Database.
ucdBaseUrl = "https://www.unicode.org/Public";
/// Default output: the in-tree generated module, resolved relative to this
/// source file so `dub run --single` writes straight into the work tree.
enum (constant) string sparkles.base.tools.gen_unicode_tables.defaultOutFile = __errorDefault output: the in-tree generated module, resolved relative to this
source file so dub run --single writes straight into the work tree.
defaultOutFile = __FILE_FULL_PATH__
.string std.path.dirName!(immutable(char))(return scope string path) pure nothrow @nogc @safeReturns the parent directory of path. On Windows, this
includes the drive letter if present. If path is a relative path and
the parent directory is the current working directory, returns ".".
Examples
assert(dirName("") == ".");
assert(dirName("file"w) == ".");
assert(dirName("dir/"d) == ".");
assert(dirName("dir///") == ".");
assert(dirName("dir/file"w.dup) == "dir");
assert(dirName("dir///file"d.dup) == "dir");
assert(dirName("dir/subdir/") == "dir");
assert(dirName("/dir/file"w) == "/dir");
assert(dirName("/file"d) == "/");
assert(dirName("/") == "/");
assert(dirName("///") == "/");
version (Windows)
{
assert(dirName(`dir\`) == `.`);
assert(dirName(`dir\\\`) == `.`);
assert(dirName(`dir\file`) == `dir`);
assert(dirName(`dir\\\file`) == `dir`);
assert(dirName(`dir\subdir\`) == `dir`);
assert(dirName(`\dir\file`) == `\dir`);
assert(dirName(`\file`) == `\`);
assert(dirName(`\`) == `\`);
assert(dirName(`\\\`) == `\`);
assert(dirName(`d:`) == `d:`);
assert(dirName(`d:file`) == `d:`);
assert(dirName(`d:\`) == `d:\`);
assert(dirName(`d:\file`) == `d:\`);
assert(dirName(`d:\dir\file`) == `d:\dir`);
assert(dirName(`\\server\share\dir\file`) == `\\server\share\dir`);
assert(dirName(`\\server\share\file`) == `\\server\share`);
assert(dirName(`\\server\share\`) == `\\server\share`);
assert(dirName(`\\server\share`) == `\\server\share`);
}
dirName
.string std.path.buildNormalizedPath!char(const(char[])[] paths...) pure nothrow @safePerforms the same task as buildPath,
while at the same time resolving current/parent directory
symbols ("." and "..") and removing superfluous
directory separators.
It will return "." if the path leads to the starting directory.
On Windows, slashes are replaced with backslashes.
Using buildNormalizedPath on null paths will always return null.
Note that this function does not resolve symbolic links.
This function always allocates memory to hold the resulting path.
Use asNormalizedPath to not allocate memory.
Examples
assert(buildNormalizedPath("foo", "..") == ".");
version (Posix)
{
assert(buildNormalizedPath("/foo/./bar/..//baz/") == "/foo/baz");
assert(buildNormalizedPath("../foo/.") == "../foo");
assert(buildNormalizedPath("/foo", "bar/baz/") == "/foo/bar/baz");
assert(buildNormalizedPath("/foo", "/bar/..", "baz") == "/baz");
assert(buildNormalizedPath("foo/./bar", "../../", "../baz") == "../baz");
assert(buildNormalizedPath("/foo/./bar", "../../baz") == "/baz");
}
version (Windows)
{
assert(buildNormalizedPath(`c:\foo\.\bar/..\\baz\`) == `c:\foo\baz`);
assert(buildNormalizedPath(`..\foo\.`) == `..\foo`);
assert(buildNormalizedPath(`c:\foo`, `bar\baz\`) == `c:\foo\bar\baz`);
assert(buildNormalizedPath(`c:\foo`, `bar/..`) == `c:\foo`);
assert(buildNormalizedPath(`\\server\share\foo`, `..\bar`) ==
`\\server\share\bar`);
}
buildNormalizedPath("../src/sparkles/base/text/unicode_tables.d");
struct (struct) sparkles.base.tools.gen_unicode_tables.CliParamsCliParams
{
@((struct) sparkles.core_cli.args.uda.OptionOption(`u|ucd-dir`, description: "Directory with the six documented UCD/emoji inputs. If omitted, they are downloaded from unicode.org for --unicode-version."))
(alias) object.string = stringstring (field) string sparkles.base.tools.gen_unicode_tables.CliParams.ucdDirucdDir;
@((struct) sparkles.core_cli.args.uda.OptionOption(`o|out-file`, description: "Path to write the generated module (default: the in-tree unicode_tables.d)."))
(alias) object.string = stringstring (field) string sparkles.base.tools.gen_unicode_tables.CliParams.outFileoutFile = (constant) string sparkles.base.tools.gen_unicode_tables.defaultOutFile = __errorDefault output: the in-tree generated module, resolved relative to this
source file so dub run --single writes straight into the work tree.
defaultOutFile;
@((struct) sparkles.core_cli.args.uda.OptionOption(`V|unicode-version`, description: "Unicode version to generate for."))
(alias) object.string = stringstring (field) string sparkles.base.tools.gen_unicode_tables.CliParams.unicodeVersionunicodeVersion = (constant) string sparkles.base.tools.gen_unicode_tables.pinnedUnicodeVersion = "17.0.0"Unicode version this generator targets by default. All properties consumed
by the bounded analyzer, including canonical combining classes, are emitted
here so its behavior does not silently follow the compiler's std.uni.
pinnedUnicodeVersion;
}
int int D main(string[] args)main((alias) object.string = stringstring[] (parameter) string[] argsargs)
{
auto (local variable) expected.Expected!(CliParams, CliError, Abort) parsedparsed = expected.Expected!(CliParams, CliError, Abort) sparkles.core_cli.args.internal.parseCli!(sparkles.base.tools.gen_unicode_tables.CliParams)(string[] argv, sparkles.core_cli.help_formatting.HelpInfo helpInfo = HelpInfo(null, null, null)) @systemparseCli!(struct) sparkles.base.tools.gen_unicode_tables.CliParamsCliParams(
(parameter) string[] argsargs,
(struct) sparkles.core_cli.help_formatting.HelpInfoHelpInfo(
"gen_unicode_tables",
"Generate sparkles.base.text.unicode_tables from the Unicode Character Database",
),
);
if (!(local variable) expected.Expected!(CliParams, CliError, Abort) parsedparsed)
return int sparkles.core_cli.args.internal.reportCliError(in sparkles.core_cli.args.error.CliError e)Reports a failed parse and returns the exit code the program should use.
A help request is a failure in the Expected sense but a success to the
user, and carries exitCode == 0 to say so — returning this value is what
keeps --help from looking like an error to a shell.
For a program whose commands have run methods, prefer runCli,
which calls this. This is the entry point for a program that parses into a
struct and then does its own work.
reportCliError((local variable) expected.Expected!(CliParams, CliError, Abort) parsedparsed.inout(sparkles.core_cli.args.error.CliError) expected.Expected!(sparkles.base.tools.gen_unicode_tables.CliParams, sparkles.core_cli.args.error.CliError, expected.Abort).error() inout nothrow @nogc @property ref @safeReturns the error value. May only be called when hasValue returns false.
If there is no error value, it calls hook's onAccessEmptyError.
It returns E.init when hook doesn't provide onAccessEmptyError.
error);
const (local variable) const(sparkles.base.tools.gen_unicode_tables.CliParams) clicli = (local variable) expected.Expected!(CliParams, CliError, Abort) parsedparsed.inout(sparkles.base.tools.gen_unicode_tables.CliParams) expected.Expected!(sparkles.base.tools.gen_unicode_tables.CliParams, sparkles.core_cli.args.error.CliError, expected.Abort).value!()() inout pure nothrow @nogc @property ref @safeReturns the expected value if there is one.
With default Abort hook, it asserts when there is no value.
It calls hook's onAccessEmptyValue otherwise.
It returns T.init when hook doesn't provide onAccessEmptyValue.
value;
const (local variable) const(string) verver = (local variable) const(sparkles.base.tools.gen_unicode_tables.CliParams) clicli.(field) string sparkles.base.tools.gen_unicode_tables.CliParams.unicodeVersionunicodeVersion;
const (local variable) const(string) outFileoutFile = string std.path.buildNormalizedPath!char(const(char[])[] paths...) pure nothrow @safePerforms the same task as buildPath,
while at the same time resolving current/parent directory
symbols ("." and "..") and removing superfluous
directory separators.
It will return "." if the path leads to the starting directory.
On Windows, slashes are replaced with backslashes.
Using buildNormalizedPath on null paths will always return null.
Note that this function does not resolve symbolic links.
This function always allocates memory to hold the resulting path.
Use asNormalizedPath to not allocate memory.
Examples
assert(buildNormalizedPath("foo", "..") == ".");
version (Posix)
{
assert(buildNormalizedPath("/foo/./bar/..//baz/") == "/foo/baz");
assert(buildNormalizedPath("../foo/.") == "../foo");
assert(buildNormalizedPath("/foo", "bar/baz/") == "/foo/bar/baz");
assert(buildNormalizedPath("/foo", "/bar/..", "baz") == "/baz");
assert(buildNormalizedPath("foo/./bar", "../../", "../baz") == "../baz");
assert(buildNormalizedPath("/foo/./bar", "../../baz") == "/baz");
}
version (Windows)
{
assert(buildNormalizedPath(`c:\foo\.\bar/..\\baz\`) == `c:\foo\baz`);
assert(buildNormalizedPath(`..\foo\.`) == `..\foo`);
assert(buildNormalizedPath(`c:\foo`, `bar\baz\`) == `c:\foo\bar\baz`);
assert(buildNormalizedPath(`c:\foo`, `bar/..`) == `c:\foo`);
assert(buildNormalizedPath(`\\server\share\foo`, `..\bar`) ==
`\\server\share\bar`);
}
buildNormalizedPath((local variable) const(sparkles.base.tools.gen_unicode_tables.CliParams) clicli.(field) string sparkles.base.tools.gen_unicode_tables.CliParams.outFileoutFile);
void sparkles.base.styled_template.styledWritelnErr!(core.interpolation.InterpolatedLiteral!"{dim unicode version}: {cyan ", core.interpolation.InterpolatedExpression!"ver", string, core.interpolation.InterpolatedLiteral!"}")(core.interpolation.InterpolationHeader header, core.interpolation.InterpolatedLiteral!"{dim unicode version}: {cyan " __param_1, core.interpolation.InterpolatedExpression!"ver" __param_2, string __param_3, core.interpolation.InterpolatedLiteral!"}" __param_4, core.interpolation.InterpolationFooter footer) @systemditto — defaults to ColorDepth.trueColor.
styledWritelnErr(i"{dim unicode version}: {cyan $(ver)}");
void sparkles.base.styled_template.styledWritelnErr!(core.interpolation.InterpolatedLiteral!"{dim output file}: {cyan ", core.interpolation.InterpolatedExpression!"outFile", string, core.interpolation.InterpolatedLiteral!"}")(core.interpolation.InterpolationHeader header, core.interpolation.InterpolatedLiteral!"{dim output file}: {cyan " __param_1, core.interpolation.InterpolatedExpression!"outFile" __param_2, string __param_3, core.interpolation.InterpolatedLiteral!"}" __param_4, core.interpolation.InterpolationFooter footer) @systemditto — defaults to ColorDepth.trueColor.
styledWritelnErr(i"{dim output file}: {cyan $(outFile)}");
if ((local variable) const(sparkles.base.tools.gen_unicode_tables.CliParams) clicli.(field) string sparkles.base.tools.gen_unicode_tables.CliParams.ucdDirucdDir.(field) ulong const(string).lengthlength)
void sparkles.base.styled_template.styledWritelnErr!(core.interpolation.InterpolatedLiteral!"{dim source}: {dim local} {cyan ", core.interpolation.InterpolatedExpression!"cli.ucdDir", string, core.interpolation.InterpolatedLiteral!"}")(core.interpolation.InterpolationHeader header, core.interpolation.InterpolatedLiteral!"{dim source}: {dim local} {cyan " __param_1, core.interpolation.InterpolatedExpression!"cli.ucdDir" __param_2, string __param_3, core.interpolation.InterpolatedLiteral!"}" __param_4, core.interpolation.InterpolationFooter footer) @systemditto — defaults to ColorDepth.trueColor.
styledWritelnErr(i"{dim source}: {dim local} {cyan $(cli.ucdDir)}");
else
void sparkles.base.styled_template.styledWritelnErr!(core.interpolation.InterpolatedLiteral!"{dim source}: {dim downloading from unicode.org}")(core.interpolation.InterpolationHeader header, core.interpolation.InterpolatedLiteral!"{dim source}: {dim downloading from unicode.org}" __param_1, core.interpolation.InterpolationFooter footer) @systemditto — defaults to ColorDepth.trueColor.
styledWritelnErr(i"{dim source}: {dim downloading from unicode.org}");
// Without --ucd-dir, fetch every pinned input for `ver` into a temp dir
// and remove them afterwards.
(alias) object.string = stringstring (local variable) string ucdDirucdDir = (local variable) const(sparkles.base.tools.gen_unicode_tables.CliParams) clicli.(field) string sparkles.base.tools.gen_unicode_tables.CliParams.ucdDirucdDir;
(alias) object.string = stringstring (local variable) string tmpDirtmpDir;
scope (exit) if ((local variable) string tmpDirtmpDir.(field) ulong string.lengthlength) void std.file.rmdirRecurse(scope const(char)[] pathname) @safeRemove directory and all of its content and subdirectories,
recursively.
rmdirRecurse((local variable) string tmpDirtmpDir);
if (!(local variable) string ucdDirucdDir.(field) ulong string.lengthlength)
{
(local variable) string tmpDirtmpDir = string std.file.tempDir() @trustedReturns the path to a directory for temporary files.
On POSIX platforms, it searches through the following list of directories
and returns the first one which is found to exist:
The directory given by the TMPDIR environment variable.
The directory given by the TEMP environment variable.
The directory given by the TMP environment variable.
/tmp/
/var/tmp/
/usr/tmp/
On all platforms, tempDir returns the current working directory on failure.
The return value of the function is cached, so the procedures described
below will only be performed the first time the function is called. All
subsequent runs will return the same string, regardless of whether
environment variables and directory structures have changed in the
meantime.
The POSIX tempDir algorithm is inspired by Python's
tempfile.tempdir.
Examples
import std.ascii : letters;
import std.conv : to;
import std.path : buildPath;
import std.random : randomSample;
import std.utf : byCodeUnit;
// random id with 20 letters
auto id = letters.byCodeUnit.randomSample(20).to!string;
auto myFile = tempDir.buildPath(id ~ "my_tmp_file");
scope(exit) myFile.remove;
myFile.write("hello");
assert(myFile.readText == "hello");
tempDir.string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath("gen_unicode_tables-" ~ int std.process.thisProcessID() nothrow @nogc @property @trustedReturns the process ID of the current process,
which is guaranteed to be unique on the system.
Example
writefln("Current process ID: %d", thisProcessID);
thisProcessID.string std.conv.to!string.to!int(int __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);
void std.file.mkdirRecurse(scope const(char)[] pathname) @safeMake directory and all parent directories as needed.
Does nothing if the directory specified by
pathname already exists.
Examples
import std.path : buildPath;
auto dir = deleteme ~ "dir";
scope(exit) dir.rmdirRecurse;
dir.mkdir;
assert(dir.exists);
dir.mkdirRecurse; // does nothing
// creates all parent directories as needed
auto nested = dir.buildPath("a", "b", "c");
nested.mkdirRecurse;
assert(nested.exists);
import std.exception : assertThrown;
scope(exit) deleteme.remove;
deleteme.write("a");
// cannot make directory as it's already a file
assertThrown!FileException(deleteme.mkdirRecurse);
mkdirRecurse((local variable) string tmpDirtmpDir);
void sparkles.base.tools.gen_unicode_tables.fetchUcd(string ver, string remotePath, string dest)Download a UCD input for Unicode ver into dest via libcurl
(std.net.curl). Mirrors curl -fSL: follow redirects and fail on an HTTP
error status instead of writing the error page to dest.
fetchUcd((local variable) const(string) verver, "EastAsianWidth.txt", string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath((local variable) string tmpDirtmpDir, "EastAsianWidth.txt"));
void sparkles.base.tools.gen_unicode_tables.fetchUcd(string ver, string remotePath, string dest)Download a UCD input for Unicode ver into dest via libcurl
(std.net.curl). Mirrors curl -fSL: follow redirects and fail on an HTTP
error status instead of writing the error page to dest.
fetchUcd((local variable) const(string) verver, "emoji/emoji-variation-sequences.txt",
string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath((local variable) string tmpDirtmpDir, "emoji-variation-sequences.txt"));
void sparkles.base.tools.gen_unicode_tables.fetchUcd(string ver, string remotePath, string dest)Download a UCD input for Unicode ver into dest via libcurl
(std.net.curl). Mirrors curl -fSL: follow redirects and fail on an HTTP
error status instead of writing the error page to dest.
fetchUcd((local variable) const(string) verver, "UnicodeData.txt", string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath((local variable) string tmpDirtmpDir, "UnicodeData.txt"));
void sparkles.base.tools.gen_unicode_tables.fetchUcd(string ver, string remotePath, string dest)Download a UCD input for Unicode ver into dest via libcurl
(std.net.curl). Mirrors curl -fSL: follow redirects and fail on an HTTP
error status instead of writing the error page to dest.
fetchUcd((local variable) const(string) verver, "CaseFolding.txt", string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath((local variable) string tmpDirtmpDir, "CaseFolding.txt"));
void sparkles.base.tools.gen_unicode_tables.fetchUcd(string ver, string remotePath, string dest)Download a UCD input for Unicode ver into dest via libcurl
(std.net.curl). Mirrors curl -fSL: follow redirects and fail on an HTTP
error status instead of writing the error page to dest.
fetchUcd((local variable) const(string) verver, "DerivedNormalizationProps.txt",
string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath((local variable) string tmpDirtmpDir, "DerivedNormalizationProps.txt"));
void sparkles.base.tools.gen_unicode_tables.fetchUcd(string ver, string remotePath, string dest)Download a UCD input for Unicode ver into dest via libcurl
(std.net.curl). Mirrors curl -fSL: follow redirects and fail on an HTTP
error status instead of writing the error page to dest.
fetchUcd((local variable) const(string) verver, "auxiliary/WordBreakProperty.txt",
string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath((local variable) string tmpDirtmpDir, "WordBreakProperty.txt"));
(local variable) string ucdDirucdDir = (local variable) string tmpDirtmpDir;
}
auto (local variable) string eaweaw = (local variable) string ucdDirucdDir.string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath("EastAsianWidth.txt").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;
auto (local variable) string emojiVsemojiVs = (local variable) string ucdDirucdDir.string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath("emoji-variation-sequences.txt").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;
auto (local variable) string unicodeDataunicodeData = (local variable) string ucdDirucdDir.string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath("UnicodeData.txt").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;
auto (local variable) string caseFoldingcaseFolding = (local variable) string ucdDirucdDir.string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath("CaseFolding.txt").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;
auto (local variable) string normalizationPropsnormalizationProps = (local variable) string ucdDirucdDir
.string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath("DerivedNormalizationProps.txt").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;
auto (local variable) string wordBreakwordBreak = (local variable) string ucdDirucdDir.string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath("WordBreakProperty.txt").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;
auto (local variable) std.uni.InversionList!(GcPolicy) widewide = std.uni.InversionList!(GcPolicy) sparkles.base.tools.gen_unicode_tables.parseEastAsianWidth(string text, const(string)[] wanted)Parse a UCD property file (code[..code] ; VALUE # comment) collecting the
code points whose property value is one of wanted.
parseEastAsianWidth((local variable) string eaweaw, ["W", "F"]);
auto (local variable) std.uni.InversionList!(GcPolicy) ambiguousambiguous = std.uni.InversionList!(GcPolicy) sparkles.base.tools.gen_unicode_tables.parseEastAsianWidth(string text, const(string)[] wanted)Parse a UCD property file (code[..code] ; VALUE # comment) collecting the
code points whose property value is one of wanted.
parseEastAsianWidth((local variable) string eaweaw, ["A"]);
auto (local variable) std.uni.InversionList!(GcPolicy) emojiVsBaseemojiVsBase = std.uni.InversionList!(GcPolicy) sparkles.base.tools.gen_unicode_tables.parseEmojiVsBases(string text)Parse emoji-variation-sequences.txt, collecting the base code points that
have an emoji style (… FE0F) presentation sequence — i.e. the bases VS16
promotes to emoji (width 2). Lines look like: 0023 FE0F ; emoji style; # ….
parseEmojiVsBases((local variable) string emojiVsemojiVs);
auto (local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables analysisanalysis = sparkles.base.tools.gen_unicode_tables.AnalysisTables sparkles.base.tools.gen_unicode_tables.buildAnalysisTables(string unicodeData, string caseFolding, string normalizationProps, string wordBreak)buildAnalysisTables(
(local variable) string unicodeDataunicodeData, (local variable) string caseFoldingcaseFolding, (local variable) string normalizationPropsnormalizationProps, (local variable) string wordBreakwordBreak);
void sparkles.base.styled_template.styledWritelnErr!(core.interpolation.InterpolatedLiteral!"\xe2\x84\xb9\xef\xb8\x8f {bold ", core.interpolation.InterpolatedExpression!"countCodePoints(wide)", ulong, core.interpolation.InterpolatedLiteral!"} wide")(core.interpolation.InterpolationHeader header, core.interpolation.InterpolatedLiteral!"\xe2\x84\xb9\xef\xb8\x8f {bold " __param_1, core.interpolation.InterpolatedExpression!"countCodePoints(wide)" __param_2, ulong __param_3, core.interpolation.InterpolatedLiteral!"} wide" __param_4, core.interpolation.InterpolationFooter footer) @systemditto — defaults to ColorDepth.trueColor.
styledWritelnErr(i"ℹ️ {bold $(countCodePoints(wide))} wide");
void sparkles.base.styled_template.styledWritelnErr!(core.interpolation.InterpolatedLiteral!"\xe2\x84\xb9\xef\xb8\x8f {bold ", core.interpolation.InterpolatedExpression!"countCodePoints(ambiguous)", ulong, core.interpolation.InterpolatedLiteral!"} ambiguous")(core.interpolation.InterpolationHeader header, core.interpolation.InterpolatedLiteral!"\xe2\x84\xb9\xef\xb8\x8f {bold " __param_1, core.interpolation.InterpolatedExpression!"countCodePoints(ambiguous)" __param_2, ulong __param_3, core.interpolation.InterpolatedLiteral!"} ambiguous" __param_4, core.interpolation.InterpolationFooter footer) @systemditto — defaults to ColorDepth.trueColor.
styledWritelnErr(i"ℹ️ {bold $(countCodePoints(ambiguous))} ambiguous");
void sparkles.base.styled_template.styledWritelnErr!(core.interpolation.InterpolatedLiteral!"\xe2\x84\xb9\xef\xb8\x8f {bold ", core.interpolation.InterpolatedExpression!"countCodePoints(emojiVsBase)", ulong, core.interpolation.InterpolatedLiteral!"} emoji-vs bases")(core.interpolation.InterpolationHeader header, core.interpolation.InterpolatedLiteral!"\xe2\x84\xb9\xef\xb8\x8f {bold " __param_1, core.interpolation.InterpolatedExpression!"countCodePoints(emojiVsBase)" __param_2, ulong __param_3, core.interpolation.InterpolatedLiteral!"} emoji-vs bases" __param_4, core.interpolation.InterpolationFooter footer) @systemditto — defaults to ColorDepth.trueColor.
styledWritelnErr(i"ℹ️ {bold $(countCodePoints(emojiVsBase))} emoji-vs bases");
void sparkles.base.styled_template.styledWritelnErr!(core.interpolation.InterpolatedLiteral!"\xe2\x84\xb9\xef\xb8\x8f {bold ", core.interpolation.InterpolatedExpression!"analysis.canonical.length", ulong, core.interpolation.InterpolatedLiteral!"} canonical mappings")(core.interpolation.InterpolationHeader header, core.interpolation.InterpolatedLiteral!"\xe2\x84\xb9\xef\xb8\x8f {bold " __param_1, core.interpolation.InterpolatedExpression!"analysis.canonical.length" __param_2, ulong __param_3, core.interpolation.InterpolatedLiteral!"} canonical mappings" __param_4, core.interpolation.InterpolationFooter footer) @systemditto — defaults to ColorDepth.trueColor.
styledWritelnErr(i"ℹ️ {bold $(analysis.canonical.length)} canonical mappings");
void sparkles.base.styled_template.styledWritelnErr!(core.interpolation.InterpolatedLiteral!"\xe2\x84\xb9\xef\xb8\x8f {bold ", core.interpolation.InterpolatedExpression!"analysis.compatibility.length", ulong, core.interpolation.InterpolatedLiteral!"} compatibility mappings")(core.interpolation.InterpolationHeader header, core.interpolation.InterpolatedLiteral!"\xe2\x84\xb9\xef\xb8\x8f {bold " __param_1, core.interpolation.InterpolatedExpression!"analysis.compatibility.length" __param_2, ulong __param_3, core.interpolation.InterpolatedLiteral!"} compatibility mappings" __param_4, core.interpolation.InterpolationFooter footer) @systemditto — defaults to ColorDepth.trueColor.
styledWritelnErr(i"ℹ️ {bold $(analysis.compatibility.length)} compatibility mappings");
void sparkles.base.styled_template.styledWritelnErr!(core.interpolation.InterpolatedLiteral!"\xe2\x84\xb9\xef\xb8\x8f {bold ", core.interpolation.InterpolatedExpression!"analysis.fullFold.length", ulong, core.interpolation.InterpolatedLiteral!"} full-fold mappings")(core.interpolation.InterpolationHeader header, core.interpolation.InterpolatedLiteral!"\xe2\x84\xb9\xef\xb8\x8f {bold " __param_1, core.interpolation.InterpolatedExpression!"analysis.fullFold.length" __param_2, ulong __param_3, core.interpolation.InterpolatedLiteral!"} full-fold mappings" __param_4, core.interpolation.InterpolationFooter footer) @systemditto — defaults to ColorDepth.trueColor.
styledWritelnErr(i"ℹ️ {bold $(analysis.fullFold.length)} full-fold mappings");
void std.file.write!string(string name, const(void[]) buffer) @safeWrite buffer to file name.
Creates the file if it does not already exist.
Examples
scope(exit)
{
assert(exists(deleteme));
remove(deleteme);
}
int[] a = [ 0, 1, 1, 2, 3, 5, 8 ];
write(deleteme, a); // deleteme is the name of a temporary file
const bytes = read(deleteme);
const fileInts = () @trusted { return cast(int[]) bytes; }();
assert(fileInts == a);
write((local variable) const(string) outFileoutFile, [
string sparkles.base.tools.gen_unicode_tables.header(string ver)header((local variable) const(string) verver),
(local variable) std.uni.InversionList!(GcPolicy) widewide.string std.uni.InversionList!(std.uni.GcPolicy).toSourceCode(string funcName = "") @safeGenerates string with D source code of unary function with name of
funcName taking a single dchar argument. If funcName is empty
the code is adjusted to be a lambda function.
The function generated tests if the passed
belongs to this set or not. The result is to be used with string mixin.
The intended usage area is aggressive optimization via meta programming
in parser generators and the like.
Note
Use with care for relatively small or regular sets. It
could end up being slower then just using multi-staged tables.
Example
import std.stdio;
// construct set directly from [a, b$RPAREN intervals
auto set = CodepointSet(10, 12, 45, 65, 100, 200);
writeln(set);
writeln(set.toSourceCode("func"));
The above outputs something along the lines of:
bool func(dchar ch) @safe pure nothrow @nogc
{
if (ch < 45)
{
if (ch == 10 || ch == 11) return true;
return false;
}
else if (ch < 65) return true;
else
{
if (ch < 100) return false;
if (ch < 200) return true;
return false;
}
}
toSourceCode("isEastAsianWide"),
(local variable) std.uni.InversionList!(GcPolicy) ambiguousambiguous.string std.uni.InversionList!(std.uni.GcPolicy).toSourceCode(string funcName = "") @safeGenerates string with D source code of unary function with name of
funcName taking a single dchar argument. If funcName is empty
the code is adjusted to be a lambda function.
The function generated tests if the passed
belongs to this set or not. The result is to be used with string mixin.
The intended usage area is aggressive optimization via meta programming
in parser generators and the like.
Note
Use with care for relatively small or regular sets. It
could end up being slower then just using multi-staged tables.
Example
import std.stdio;
// construct set directly from [a, b$RPAREN intervals
auto set = CodepointSet(10, 12, 45, 65, 100, 200);
writeln(set);
writeln(set.toSourceCode("func"));
The above outputs something along the lines of:
bool func(dchar ch) @safe pure nothrow @nogc
{
if (ch < 45)
{
if (ch == 10 || ch == 11) return true;
return false;
}
else if (ch < 65) return true;
else
{
if (ch < 100) return false;
if (ch < 200) return true;
return false;
}
}
toSourceCode("isEastAsianAmbiguous"),
(local variable) std.uni.InversionList!(GcPolicy) emojiVsBaseemojiVsBase.string std.uni.InversionList!(std.uni.GcPolicy).toSourceCode(string funcName = "") @safeGenerates string with D source code of unary function with name of
funcName taking a single dchar argument. If funcName is empty
the code is adjusted to be a lambda function.
The function generated tests if the passed
belongs to this set or not. The result is to be used with string mixin.
The intended usage area is aggressive optimization via meta programming
in parser generators and the like.
Note
Use with care for relatively small or regular sets. It
could end up being slower then just using multi-staged tables.
Example
import std.stdio;
// construct set directly from [a, b$RPAREN intervals
auto set = CodepointSet(10, 12, 45, 65, 100, 200);
writeln(set);
writeln(set.toSourceCode("func"));
The above outputs something along the lines of:
bool func(dchar ch) @safe pure nothrow @nogc
{
if (ch < 45)
{
if (ch == 10 || ch == 11) return true;
return false;
}
else if (ch < 65) return true;
else
{
if (ch < 100) return false;
if (ch < 200) return true;
return false;
}
}
toSourceCode("isEmojiVsBase"),
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables analysisanalysis.string sparkles.base.tools.gen_unicode_tables.AnalysisTables.toSourceCode()toSourceCode,
].string std.array.join!(string[], string)(string[] ror, string sep) pure nothrow @safeEagerly concatenates all of the ranges in ror together (with the GC)
into one array using sep as the separator if present.
join("\n"));
void sparkles.base.styled_template.styledWriteln!(core.interpolation.InterpolatedLiteral!"{green wrote} {cyan ", core.interpolation.InterpolatedExpression!"outFile", string, core.interpolation.InterpolatedLiteral!"}")(core.interpolation.InterpolationHeader header, core.interpolation.InterpolatedLiteral!"{green wrote} {cyan " __param_1, core.interpolation.InterpolatedExpression!"outFile" __param_2, string __param_3, core.interpolation.InterpolatedLiteral!"}" __param_4, core.interpolation.InterpolationFooter footer) @systemditto — defaults to ColorDepth.trueColor.
styledWriteln(i"{green wrote} {cyan $(outFile)}");
void sparkles.base.styled_template.styledWriteln!(core.interpolation.InterpolatedLiteral!"Review the diff and commit the regenerated module.")(core.interpolation.InterpolationHeader header, core.interpolation.InterpolatedLiteral!"Review the diff and commit the regenerated module." __param_1, core.interpolation.InterpolationFooter footer) @systemditto — defaults to ColorDepth.trueColor.
styledWriteln(i"Review the diff and commit the regenerated module.");
return 0;
}
/// Download a UCD input for Unicode `ver` into `dest` via libcurl
/// (`std.net.curl`). Mirrors `curl -fSL`: follow redirects and fail on an HTTP
/// error status instead of writing the error page to `dest`.
private void void sparkles.base.tools.gen_unicode_tables.fetchUcd(string ver, string remotePath, string dest)Download a UCD input for Unicode ver into dest via libcurl
(std.net.curl). Mirrors curl -fSL: follow redirects and fail on an HTTP
error status instead of writing the error page to dest.
fetchUcd((alias) object.string = stringstring (parameter) string verver, (alias) object.string = stringstring (parameter) string remotePathremotePath, (alias) object.string = stringstring (parameter) string destdest)
{
const (local variable) const(string) urlurl = (constant) string sparkles.base.tools.gen_unicode_tables.ucdBaseUrl = "https://www.unicode.org/Public"Base URL of the Unicode Character Database.
ucdBaseUrl ~ "/" ~ (parameter) string verver ~ "/ucd/" ~ (parameter) string remotePathremotePath;
void sparkles.base.styled_template.styledWritelnErr!(core.interpolation.InterpolatedLiteral!"{dim fetching} ", core.interpolation.InterpolatedExpression!"url", string)(core.interpolation.InterpolationHeader header, core.interpolation.InterpolatedLiteral!"{dim fetching} " __param_1, core.interpolation.InterpolatedExpression!"url" __param_2, string __param_3, core.interpolation.InterpolationFooter footer) @systemditto — defaults to ColorDepth.trueColor.
styledWritelnErr(i"{dim fetching} $(url)");
auto (local variable) std.net.curl.HTTP httphttp = (struct) std.net.curl.HTTPHTTP client functionality.
Example
Get with custom data receivers:
import std.net.curl, std.stdio;
auto http = HTTP("https://dlang.org");
http.onReceiveHeader =
(in char[] key, in char[] value) { writeln(key ~ ": " ~ value); };
http.onReceive = (ubyte[] data) { /+ drop +/ return data.length; };
http.perform();
Put with data senders:
import std.net.curl, std.stdio;
auto http = HTTP("https://dlang.org");
auto msg = "Hello world";
http.contentLength = msg.length;
http.onSend = (void[] data)
{
auto m = cast(void[]) msg;
size_t len = m.length > data.length ? data.length : m.length;
if (len == 0) return len;
data[0 .. len] = m[0 .. len];
msg = msg[len..$];
return len;
};
http.perform();
Tracking progress:
import std.net.curl, std.stdio;
auto http = HTTP();
http.method = HTTP.Method.get;
http.url = "http://upload.wikimedia.org/wikipedia/commons/" ~
"5/53/Wikipedia-logo-en-big.png";
http.onReceive = (ubyte[] data) { return data.length; };
http.onProgress = (size_t dltotal, size_t dlnow,
size_t ultotal, size_t ulnow)
{
writeln("Progress ", dltotal, ", ", dlnow, ", ", ultotal, ", ", ulnow);
return 0;
};
http.perform();
HTTP();
(local variable) std.net.curl.HTTP httphttp.std.net.curl.Curl std.net.curl.HTTP.Protocol!().handle() @property return refThe curl handle used by this connection.
handle.void std.net.curl.Curl.set(etc.c.curl.CurlOption option, long value)Set a long curl option.
set((enum) etc.c.curl.CurlOptionCurlOption.(enum value) etc.c.curl.CurlOption.failonerror = 45no output on http error codes >= 300
failonerror, 1L); // -f: 4xx/5xx → throw, no body
try
void std.net.curl.download!(std.net.curl.HTTP)(const(char)[] url, string saveToPath, std.net.curl.HTTP conn = opCall()) @systemHTTP/FTP download to local file system.
Example
import std.net.curl;
download("https://httpbin.org/get", "/tmp/downloaded-http-file");
download((local variable) const(string) urlurl, (parameter) string destdest, (local variable) std.net.curl.HTTP httphttp);
catch ((class) std.net.curl.CurlExceptionException thrown on errors in std.net.curl functions.
CurlException (local variable) std.net.curl.CurlException ee)
throw new (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(string std.format.format!(char, string, string)(in char[] fmt, string __param_1, string __param_2) pure @safeConverts 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.
Examples
assert(format("Here are %d %s.", 3, "apples") == "Here are 3 apples.");
assert("Increase: %7.2f %%".format(17.4285) == "Increase: 17.43 %");
format("download failed for %s:\n%s", (local variable) const(string) urlurl, (local variable) std.net.curl.CurlException ee.(field) string object.Throwable.msgA message describing the error.
msg));
}
/// Parse a UCD property file (`code[..code] ; VALUE # comment`) collecting the
/// code points whose property value is one of `wanted`.
(struct) std.uni.InversionList!(GcPolicy)CodepointSet std.uni.InversionList!(GcPolicy) sparkles.base.tools.gen_unicode_tables.parseEastAsianWidth(string text, const(string)[] wanted)Parse a UCD property file (code[..code] ; VALUE # comment) collecting the
code points whose property value is one of wanted.
parseEastAsianWidth((alias) object.string = stringstring (parameter) string texttext, const((alias) object.string = stringstring)[] (parameter) const(string)[] wantedwanted)
=> (parameter) string texttext.std.uni.InversionList!(GcPolicy) sparkles.base.tools.gen_unicode_tables.parseEastAsianWidth.ucdCodepoints!((v) => wanted.canFind(v))(string text) @systemCollect, into a CodepointSet, the leading code-point column of every data
record whose value field (the column after the first ;) satisfies
valueMatches. For each record: strip the trailing # comment, split on ;
into whitespace-trimmed fields (comment-only and blank lines collapse to one
empty field and are dropped), take the first whitespace-separated token of the
code-point column, and read it as a ..-separated hex sequence — so a bare
AAAA adds one code point, AAAA..BBBB adds the inclusive range, and the
BASE VS form (e.g. 0023 FE0F) adds just BASE.
ucdCodepoints!(v => wanted.canFind(v));
/// Parse emoji-variation-sequences.txt, collecting the base code points that
/// have an `emoji style` (… FE0F) presentation sequence — i.e. the bases VS16
/// promotes to emoji (width 2). Lines look like: `0023 FE0F ; emoji style; # …`.
(struct) std.uni.InversionList!(GcPolicy)CodepointSet std.uni.InversionList!(GcPolicy) sparkles.base.tools.gen_unicode_tables.parseEmojiVsBases(string text)Parse emoji-variation-sequences.txt, collecting the base code points that
have an emoji style (… FE0F) presentation sequence — i.e. the bases VS16
promotes to emoji (width 2). Lines look like: 0023 FE0F ; emoji style; # ….
parseEmojiVsBases((alias) object.string = stringstring (parameter) string texttext)
=> (parameter) string texttext.std.uni.InversionList!(GcPolicy) sparkles.base.tools.gen_unicode_tables.parseEmojiVsBases.ucdCodepoints!((v) => v.startsWith("emoji style"))(string text) @systemCollect, into a CodepointSet, the leading code-point column of every data
record whose value field (the column after the first ;) satisfies
valueMatches. For each record: strip the trailing # comment, split on ;
into whitespace-trimmed fields (comment-only and blank lines collapse to one
empty field and are dropped), take the first whitespace-separated token of the
code-point column, and read it as a ..-separated hex sequence — so a bare
AAAA adds one code point, AAAA..BBBB adds the inclusive range, and the
BASE VS form (e.g. 0023 FE0F) adds just BASE.
ucdCodepoints!(v => v.startsWith("emoji style"));
/// Collect, into a `CodepointSet`, the leading code-point column of every data
/// record whose value field (the column after the first `;`) satisfies
/// `valueMatches`. For each record: strip the trailing `# comment`, split on `;`
/// into whitespace-trimmed fields (comment-only and blank lines collapse to one
/// empty field and are dropped), take the first whitespace-separated token of the
/// code-point column, and read it as a `..`-separated hex sequence — so a bare
/// `AAAA` adds one code point, `AAAA..BBBB` adds the inclusive range, and the
/// `BASE VS` form (e.g. `0023 FE0F`) adds just `BASE`.
(struct) std.uni.InversionList!(GcPolicy)CodepointSet std.uni.InversionList!(GcPolicy) sparkles.base.tools.gen_unicode_tables.parseEmojiVsBases.ucdCodepoints!((v) => v.startsWith("emoji style"))(string text) @systemCollect, into a CodepointSet, the leading code-point column of every data
record whose value field (the column after the first ;) satisfies
valueMatches. For each record: strip the trailing # comment, split on ;
into whitespace-trimmed fields (comment-only and blank lines collapse to one
empty field and are dropped), take the first whitespace-separated token of the
code-point column, and read it as a ..-separated hex sequence — so a bare
AAAA adds one code point, AAAA..BBBB adds the inclusive range, and the
BASE VS form (e.g. 0023 FE0F) adds just BASE.
ucdCodepoints(alias valueMatches)((alias) object.string = stringstring (parameter) string texttext)
{
(struct) std.uni.InversionList!(GcPolicy)CodepointSet (local variable) std.uni.InversionList!(GcPolicy) setset;
foreach ((local variable) string[] fieldsfields; (parameter) string texttext
.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
.std.algorithm.iteration.MapResult!(stripComment, LineSplitter!(Flag.no, string)) std.algorithm.iteration.map!(stripComment).map!(std.string.LineSplitter!(Flag.no, string))(std.string.LineSplitter!(Flag.no, string) r) pure nothrow @nogc @safeImplements the homonym function (also known as transform) present
in many languages of functional flavor. The call ``map!(fun)(range)
returns a range of which elements are obtained by applying fun(a)
left to right for all elements a in range. The original ranges are
not changed. Evaluation is done lazily.
Examples
import std.algorithm.comparison : equal;
import std.range : chain, only;
auto squares =
chain(only(1, 2, 3, 4), only(5, 6)).map!(a => a * a);
assert(equal(squares, only(1, 4, 9, 16, 25, 36)));
Multiple functions can be passed to map. In that case, the
element type of map is a tuple containing one element for each
function.
auto sums = [2, 4, 6, 8];
auto products = [1, 4, 9, 16];
size_t i = 0;
foreach (result; [ 1, 2, 3, 4 ].map!("a + a", "a * a"))
{
assert(result[0] == sums[i]);
assert(result[1] == products[i]);
++i;
}
You may alias map with some function(s) to a symbol and use
it separately:
import std.algorithm.comparison : equal;
import std.conv : to;
alias stringize = map!(to!string);
assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));
map!string sparkles.base.tools.gen_unicode_tables.stripComment(string line)Strip a trailing # comment and surrounding whitespace from a UCD line.
findSplit("#")[0] is the text before the first #, or the whole line when
there is none.
stripComment
.sparkles.base.tools.gen_unicode_tables.parseEmojiVsBases.ucdCodepoints!((v) => v.startsWith("emoji style")).MapResult!(__lambda_L194_C15, MapResult!(stripComment, LineSplitter!(Flag.no, string))) sparkles.base.tools.gen_unicode_tables.parseEmojiVsBases.ucdCodepoints!((v) => v.startsWith("emoji style")).map!(std.algorithm.iteration.MapResult!(stripComment, LineSplitter!(Flag.no, string)))(std.algorithm.iteration.MapResult!(stripComment, LineSplitter!(Flag.no, string)) r) pure nothrow @nogc @safeImplements the homonym function (also known as transform) present
in many languages of functional flavor. The call ``map!(fun)(range)
returns a range of which elements are obtained by applying fun(a)
left to right for all elements a in range. The original ranges are
not changed. Evaluation is done lazily.
Examples
import std.algorithm.comparison : equal;
import std.range : chain, only;
auto squares =
chain(only(1, 2, 3, 4), only(5, 6)).map!(a => a * a);
assert(equal(squares, only(1, 4, 9, 16, 25, 36)));
Multiple functions can be passed to map. In that case, the
element type of map is a tuple containing one element for each
function.
auto sums = [2, 4, 6, 8];
auto products = [1, 4, 9, 16];
size_t i = 0;
foreach (result; [ 1, 2, 3, 4 ].map!("a + a", "a * a"))
{
assert(result[0] == sums[i]);
assert(result[1] == products[i]);
++i;
}
You may alias map with some function(s) to a symbol and use
it separately:
import std.algorithm.comparison : equal;
import std.conv : to;
alias stringize = map!(to!string);
assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));
map!(line => line.splitter(';').map!strip.array)
.sparkles.base.tools.gen_unicode_tables.parseEmojiVsBases.ucdCodepoints!((v) => v.startsWith("emoji style")).FilterResult!(__lambda_L195_C18, MapResult!(__lambda_L194_C15, MapResult!(stripComment, LineSplitter!(Flag.no, string)))) sparkles.base.tools.gen_unicode_tables.parseEmojiVsBases.ucdCodepoints!((v) => v.startsWith("emoji style")).filter!(sparkles.base.tools.gen_unicode_tables.parseEmojiVsBases.ucdCodepoints!((v) => v.startsWith("emoji style")).MapResult!(__lambda_L194_C15, MapResult!(stripComment, LineSplitter!(Flag.no, string))))(sparkles.base.tools.gen_unicode_tables.parseEmojiVsBases.ucdCodepoints!((v) => v.startsWith("emoji style")).MapResult!(__lambda_L194_C15, MapResult!(stripComment, LineSplitter!(Flag.no, string))) range) pure nothrow @nogc @safefilter`!(predicate)(`range`)` returns a new `range` containing only elements `x` in range`` for
which predicate(x) returns true.
The predicate is passed to unaryFun, and can be either a string, or
any callable that can be executed via pred(element).
Examples
import std.algorithm.comparison : equal;
import std.math.operations : isClose;
import std.range;
int[] arr = [ 1, 2, 3, 4, 5 ];
// Filter below 3
auto small = filter!(a => a < 3)(arr);
assert(equal(small, [ 1, 2 ]));
// Filter again, but with Uniform Function Call Syntax (UFCS)
auto sum = arr.filter!(a => a < 3);
assert(equal(sum, [ 1, 2 ]));
// In combination with chain() to span multiple ranges
int[] a = [ 3, -2, 400 ];
int[] b = [ 100, -101, 102 ];
auto r = chain(a, b).filter!(a => a > 0);
assert(equal(r, [ 3, 400, 100, 102 ]));
// Mixing convertible types is fair game, too
double[] c = [ 2.5, 3.0 ];
auto r1 = chain(c, a, b).filter!(a => cast(int) a != a);
assert(isClose(r1, [ 2.5 ]));
filter!(rec => rec.length >= 2 && valueMatches(rec[1])))
{
auto (local variable) string codecode = (local variable) string[] fieldsfields[0].std.algorithm.iteration.SplitterResult!(isWhite, string) std.algorithm.iteration.splitter!(isWhite, string)(string r) pure @safeLazily splits a range r whenever a predicate isTerminator returns true for an element.
As above, two adjacent separators are considered to surround an empty element in
the split range.
Examples
import std.ascii : isWhite;
import std.algorithm.comparison : equal;
import std.algorithm.iteration : splitter;
string str = "Hello World\t!";
assert(str.splitter!(isWhite).equal(["Hello", "World", "!"]));
import std.algorithm.comparison : equal;
import std.range.primitives : front;
assert(equal(splitter!(a => a == '|')("a|bc|def"), [ "a", "bc", "def" ]));
assert(equal(splitter!(a => a == ' ')("hello world"), [ "hello", "", "world" ]));
int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
int[][] w = [ [1, 2], [], [3], [4, 5], [] ];
assert(equal(splitter!(a => a == 0)(a), w));
a = [ 0 ];
assert(equal(splitter!(a => a == 0)(a), [ (int[]).init, (int[]).init ]));
a = [ 0, 1 ];
assert(equal(splitter!(a => a == 0)(a), [ [], [1] ]));
w = [ [0], [1], [2] ];
assert(equal(splitter!(a => a.front == 1)(w), [ [[0]], [[2]] ]));
splitter!bool std.uni.isWhite(dchar c) pure nothrow @nogc @safeWhether or not c is a Unicode whitespace .
(general Unicode category: Part of C0(tab, vertical tab, form feed,
carriage return, and linefeed characters), Zs, Zl, Zp, and NEL(U+0085))
isWhite.string std.algorithm.iteration.SplitterResult!(isWhite, string).front() pure nothrow @property @safefront;
uint[] (local variable) uint[] cpscps;
(local variable) string codecode.uint std.format.read.formattedRead!("%(%x%|..%)", string, uint[])(ref string r, ref uint[] __param_1) pure @safeReads an input range according to a format string and stores the read
values into its arguments.
Format specifiers with format character 'd', 'u' and 'c' can take a ''* parameter for skipping values.
The second version of formattedRead takes the format string as
template argument. In this case, it is checked for consistency at
compile-time.
Note
For backward compatibility the arguments args can be given as pointers
to that variable, but it is not recommended to do so, because this
option might be removed in the future.
Examples
string object;
char cmp;
int value;
assert(formattedRead("angle < 36", "%s %c %d", object, cmp, value) == 3);
assert(object == "angle");
assert(cmp == '<');
assert(value == 36);
// reading may end early:
assert(formattedRead("length >", "%s %c %d", object, cmp, value) == 2);
assert(object == "length");
assert(cmp == '>');
// value is not changed:
assert(value == 36);
The format string can be checked at compile-time:
string a;
int b;
double c;
assert("hello!124:34.5".formattedRead!"%s!%s:%s"(a, b, c) == 3);
assert(a == "hello");
assert(b == 124);
assert(c == 34.5);
Skipping values
string item;
double amount;
assert("orange: (12%) 15.25".formattedRead("%s: (%*d%%) %f", item, amount) == 2);
assert(item == "orange");
assert(amount == 15.25);
// can also be used with tuples
import std.typecons : Tuple;
Tuple!(int, float) t;
char[] line = "1 7643 2.125".dup;
formattedRead(line, "%s %*u %s", t);
assert(t[0] == 1 && t[1] == 2.125);
formattedRead!"%(%x%|..%)"((local variable) uint[] cpscps);
(local variable) std.uni.InversionList!(GcPolicy) setset.std.uni.InversionList!(GcPolicy) std.uni.InversionList!(std.uni.GcPolicy).add!()(uint a, uint b) pure nothrow ref @safeAdd an interval [a, b) to this set.
add((local variable) uint[] cpscps[0], (local variable) uint[] cpscps[$ - 1] + 1); // add takes a half-open [a, b) interval
}
return (local variable) std.uni.InversionList!(GcPolicy) setset;
}
/// Strip a trailing `# comment` and surrounding whitespace from a UCD line.
/// `findSplit("#")[0]` is the text before the first `#`, or the whole line when
/// there is none.
private (alias) object.string = stringstring string sparkles.base.tools.gen_unicode_tables.stripComment(string line)Strip a trailing # comment and surrounding whitespace from a UCD line.
findSplit("#")[0] is the text before the first #, or the whole line when
there is none.
stripComment((alias) object.string = stringstring (parameter) string lineline) => (parameter) string lineline.std.algorithm.searching.FindSplitResult!(cast(ubyte)1u, string, string, string) std.algorithm.searching.findSplit!("a == b", string, string)(string haystack, string needle) pure nothrow @nogc @safeThese functions find the first occurrence of needle in haystack and then
split haystack as follows.
findSplit returns a tuple result containing three ranges.
result[0] is the portion of haystack before needle
result[1] is the portion of
haystack that matches needle
result[2] is the portion of haystack
after the match.
If needle was not found, result[0] comprehends haystack
entirely and result[1] and result[2] are empty.
findSplitBefore returns a tuple result containing two ranges.
result[0] is the portion of haystack before needle
result[1] is the balance of haystack starting with the match.
If needle was not found, result[0]
comprehends haystack entirely and result[1] is empty.
findSplitAfter returns a tuple result containing two ranges.
result[0] is the portion of haystack up to and including the
match
result[1] is the balance of haystack starting
after the match.
If needle was not found, result[0] is empty
and result[1] is haystack.
In all cases, the concatenation of the returned ranges spans the
entire haystack.
If haystack is a random-access range, all three components of the tuple have
the same type as haystack. Otherwise, haystack must be a
forward range and
the type of result[0] (and result[1] for findSplit) is the same as
the result of takeExactly.
For more information about pred see find.
findSplit("#")[0].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;
private (alias) object.size_t = ulongsize_t ulong sparkles.base.tools.gen_unicode_tables.countCodePoints(std.uni.InversionList!(GcPolicy) set)countCodePoints((struct) std.uni.InversionList!(GcPolicy)CodepointSet (parameter) std.uni.InversionList!(GcPolicy) setset)
{
return (parameter) std.uni.InversionList!(GcPolicy) setset.std.uni.InversionList!(GcPolicy).Intervals!(uint[]) std.uni.InversionList!(std.uni.GcPolicy).byInterval() pure @property scope @safeGet range that spans all of the intervals in this InversionList.
byInterval
.sparkles.base.tools.gen_unicode_tables.countCodePoints.MapResult!(__lambda_L213_C15, Intervals!(uint[])) sparkles.base.tools.gen_unicode_tables.countCodePoints.map!(std.uni.InversionList!(GcPolicy).Intervals!(uint[]))(std.uni.InversionList!(GcPolicy).Intervals!(uint[]) r) pure nothrow @nogc @safeImplements the homonym function (also known as transform) present
in many languages of functional flavor. The call ``map!(fun)(range)
returns a range of which elements are obtained by applying fun(a)
left to right for all elements a in range. The original ranges are
not changed. Evaluation is done lazily.
Examples
import std.algorithm.comparison : equal;
import std.range : chain, only;
auto squares =
chain(only(1, 2, 3, 4), only(5, 6)).map!(a => a * a);
assert(equal(squares, only(1, 4, 9, 16, 25, 36)));
Multiple functions can be passed to map. In that case, the
element type of map is a tuple containing one element for each
function.
auto sums = [2, 4, 6, 8];
auto products = [1, 4, 9, 16];
size_t i = 0;
foreach (result; [ 1, 2, 3, 4 ].map!("a + a", "a * a"))
{
assert(result[0] == sums[i]);
assert(result[1] == products[i]);
++i;
}
You may alias map with some function(s) to a symbol and use
it separately:
import std.algorithm.comparison : equal;
import std.conv : to;
alias stringize = map!(to!string);
assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));
map!(ival => ival[1] - ival[0])
.uint std.algorithm.iteration.sum!(sparkles.base.tools.gen_unicode_tables.countCodePoints.MapResult!(__lambda_L213_C15, Intervals!(uint[])))(sparkles.base.tools.gen_unicode_tables.countCodePoints.MapResult!(__lambda_L213_C15, Intervals!(uint[])) r) pure nothrow @nogc @safeSums elements of r, which must be a finite
input range. Although
conceptually sum`(`r`)` is equivalent to `fold`!((a, b) => a +
b)(`r`, 0), sum`` uses specialized algorithms to maximize accuracy,
as follows.
If ElementType!R is a floating-point
type and R is a
random-access range with
length and slicing, then sum uses the
pairwise summation
algorithm.
If ElementType!R is a floating-point type and R is a
finite input range (but not a random-access range with slicing), then
sum uses the Kahan summation algorithm.
In all other cases, a simple element by element addition is done.
For floating point inputs, calculations are made in
spec/type, Types, real
precision for real inputs and in double precision otherwise
(Note this is a special case that deviates from fold's behavior,
which would have kept float precision for a float range).
For all other types, the calculations are done in the same type obtained
from from adding two elements of the range, which may be a different
type from the elements themselves (for example, in case of
integral promotion).
A seed may be passed to sum. Not only will this seed be used as an initial
value, but its type will override all the above, and determine the algorithm
and precision used for summation. If a seed is not passed, one is created with
the value of typeof(r.front + r.front)(0), or typeof(r.front + r.front).zero
if no constructor exists that takes an int.
Note that these specialized summing algorithms execute more primitive operations
than vanilla summation. Therefore, if in certain cases maximum speed is required
at expense of precision, one can use fold!((a, b) => a + b)(r, 0), which
is not specialized for summation.
sum;
}
private struct (struct) sparkles.base.tools.gen_unicode_tables.UcdRecordUcdRecord
{
(alias) object.string = stringstring (field) string sparkles.base.tools.gen_unicode_tables.UcdRecord.categorycategory;
bool (field) bool sparkles.base.tools.gen_unicode_tables.UcdRecord.compatibilitycompatibility;
uint[] (field) uint[] sparkles.base.tools.gen_unicode_tables.UcdRecord.decompositiondecomposition;
}
private struct (struct) sparkles.base.tools.gen_unicode_tables.SequenceMappingSequenceMapping
{
uint (field) uint sparkles.base.tools.gen_unicode_tables.SequenceMapping.codepointcodepoint;
uint[] (field) uint[] sparkles.base.tools.gen_unicode_tables.SequenceMapping.valuesvalues;
}
private struct (struct) sparkles.base.tools.gen_unicode_tables.ScalarMappingScalarMapping
{
uint (field) uint sparkles.base.tools.gen_unicode_tables.ScalarMapping.codepointcodepoint;
uint (field) uint sparkles.base.tools.gen_unicode_tables.ScalarMapping.valuevalue;
}
private struct (struct) sparkles.base.tools.gen_unicode_tables.CompositionMappingCompositionMapping
{
uint (field) uint sparkles.base.tools.gen_unicode_tables.CompositionMapping.firstfirst;
uint (field) uint sparkles.base.tools.gen_unicode_tables.CompositionMapping.secondsecond;
uint (field) uint sparkles.base.tools.gen_unicode_tables.CompositionMapping.valuevalue;
}
private struct (struct) sparkles.base.tools.gen_unicode_tables.WordBreakRangeWordBreakRange
{
uint (field) uint sparkles.base.tools.gen_unicode_tables.WordBreakRange.firstfirst;
uint (field) uint sparkles.base.tools.gen_unicode_tables.WordBreakRange.lastlast;
(alias) object.string = stringstring (field) string sparkles.base.tools.gen_unicode_tables.WordBreakRange.propertyproperty;
}
private struct (struct) sparkles.base.tools.gen_unicode_tables.AnalysisTablesAnalysisTables
{
(struct) sparkles.base.tools.gen_unicode_tables.SequenceMappingSequenceMapping[] (field) sparkles.base.tools.gen_unicode_tables.SequenceMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.canonicalcanonical;
(struct) sparkles.base.tools.gen_unicode_tables.SequenceMappingSequenceMapping[] (field) sparkles.base.tools.gen_unicode_tables.SequenceMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.compatibilitycompatibility;
(struct) sparkles.base.tools.gen_unicode_tables.SequenceMappingSequenceMapping[] (field) sparkles.base.tools.gen_unicode_tables.SequenceMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.fullFoldfullFold;
(struct) sparkles.base.tools.gen_unicode_tables.ScalarMappingScalarMapping[] (field) sparkles.base.tools.gen_unicode_tables.ScalarMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.simpleFoldsimpleFold;
(struct) sparkles.base.tools.gen_unicode_tables.CompositionMappingCompositionMapping[] (field) sparkles.base.tools.gen_unicode_tables.CompositionMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.compositionscompositions;
(struct) sparkles.base.tools.gen_unicode_tables.WordBreakRangeWordBreakRange[] (field) sparkles.base.tools.gen_unicode_tables.WordBreakRange[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.wordBreakwordBreak;
(struct) std.uni.InversionList!(GcPolicy)CodepointSet (field) std.uni.InversionList!(GcPolicy) sparkles.base.tools.gen_unicode_tables.AnalysisTables.marksmarks;
(struct) std.uni.InversionList!(GcPolicy)CodepointSet (field) std.uni.InversionList!(GcPolicy) sparkles.base.tools.gen_unicode_tables.AnalysisTables.uppercaseuppercase;
(struct) sparkles.base.tools.gen_unicode_tables.ScalarMappingScalarMapping[] (field) sparkles.base.tools.gen_unicode_tables.ScalarMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.canonicalClassescanonicalClasses;
(alias) object.string = stringstring string sparkles.base.tools.gen_unicode_tables.AnalysisTables.toSourceCode()toSourceCode()
{
return [
(constant) string sparkles.base.tools.gen_unicode_tables.analysisTypesSource = "\n/// A borrowed span inside one of the generated flat Unicode mapping arrays.\nstruct UnicodeMappingSpan\n{\n uint offset;\n ubyte length;\n}\n\nprivate struct UnicodeSequenceIndex\n{\n uint codepoint;\n uint offset;\n ubyte length;\n}\n\nprivate struct UnicodeScalarIndex\n{\n uint codepoint;\n uint value;\n}\n\nprivate UnicodeMappingSpan findUnicodeSequence(scope const(UnicodeSequenceIndex)[] index,\n dchar ch) @safe pure nothrow @nogc\n{\n size_t lo;\n size_t hi = index.length;\n while (lo < hi)\n {\n const mid = lo + (hi - lo) / 2;\n if (index[mid].codepoint < ch)\n lo = mid + 1;\n else\n hi = mid;\n }\n return lo < index.length && index[lo].codepoint == ch\n ? UnicodeMappingSpan(index[lo].offset, index[lo].length)\n : UnicodeMappingSpan.init;\n}\n\nprivate dchar findUnicodeScalar(scope const(UnicodeScalarIndex)[] index,\n dchar ch) @safe pure nothrow @nogc\n{\n size_t lo;\n size_t hi = index.length;\n while (lo < hi)\n {\n const mid = lo + (hi - lo) / 2;\n if (index[mid].codepoint < ch)\n lo = mid + 1;\n else\n hi = mid;\n }\n return lo < index.length && index[lo].codepoint == ch\n ? cast(dchar) index[lo].value : ch;\n}\n\nprivate uint findUnicodeProperty(scope const(UnicodeScalarIndex)[] index,\n dchar ch) @safe pure nothrow @nogc\n{\n size_t lo;\n size_t hi = index.length;\n while (lo < hi)\n {\n const mid = lo + (hi - lo) / 2;\n if (index[mid].codepoint < ch)\n lo = mid + 1;\n else\n hi = mid;\n }\n return lo < index.length && index[lo].codepoint == ch\n ? index[lo].value : 0;\n}\n"analysisTypesSource,
(field) std.uni.InversionList!(GcPolicy) sparkles.base.tools.gen_unicode_tables.AnalysisTables.marksmarks.string std.uni.InversionList!(std.uni.GcPolicy).toSourceCode(string funcName = "") @safeGenerates string with D source code of unary function with name of
funcName taking a single dchar argument. If funcName is empty
the code is adjusted to be a lambda function.
The function generated tests if the passed
belongs to this set or not. The result is to be used with string mixin.
The intended usage area is aggressive optimization via meta programming
in parser generators and the like.
Note
Use with care for relatively small or regular sets. It
could end up being slower then just using multi-staged tables.
Example
import std.stdio;
// construct set directly from [a, b$RPAREN intervals
auto set = CodepointSet(10, 12, 45, 65, 100, 200);
writeln(set);
writeln(set.toSourceCode("func"));
The above outputs something along the lines of:
bool func(dchar ch) @safe pure nothrow @nogc
{
if (ch < 45)
{
if (ch == 10 || ch == 11) return true;
return false;
}
else if (ch < 65) return true;
else
{
if (ch < 100) return false;
if (ch < 200) return true;
return false;
}
}
toSourceCode("isUnicodeMark"),
(field) std.uni.InversionList!(GcPolicy) sparkles.base.tools.gen_unicode_tables.AnalysisTables.uppercaseuppercase.string std.uni.InversionList!(std.uni.GcPolicy).toSourceCode(string funcName = "") @safeGenerates string with D source code of unary function with name of
funcName taking a single dchar argument. If funcName is empty
the code is adjusted to be a lambda function.
The function generated tests if the passed
belongs to this set or not. The result is to be used with string mixin.
The intended usage area is aggressive optimization via meta programming
in parser generators and the like.
Note
Use with care for relatively small or regular sets. It
could end up being slower then just using multi-staged tables.
Example
import std.stdio;
// construct set directly from [a, b$RPAREN intervals
auto set = CodepointSet(10, 12, 45, 65, 100, 200);
writeln(set);
writeln(set.toSourceCode("func"));
The above outputs something along the lines of:
bool func(dchar ch) @safe pure nothrow @nogc
{
if (ch < 45)
{
if (ch == 10 || ch == 11) return true;
return false;
}
else if (ch < 65) return true;
else
{
if (ch < 100) return false;
if (ch < 200) return true;
return false;
}
}
toSourceCode("isUnicodeUppercase"),
string sparkles.base.tools.gen_unicode_tables.scalarPropertyTableSource(string name, const(sparkles.base.tools.gen_unicode_tables.ScalarMapping)[] mappings)scalarPropertyTableSource("canonicalCombiningClass",
(field) sparkles.base.tools.gen_unicode_tables.ScalarMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.canonicalClassescanonicalClasses),
string sparkles.base.tools.gen_unicode_tables.sequenceTableSource(string name, const(sparkles.base.tools.gen_unicode_tables.SequenceMapping)[] mappings)sequenceTableSource("canonicalDecomposition", (field) sparkles.base.tools.gen_unicode_tables.SequenceMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.canonicalcanonical),
string sparkles.base.tools.gen_unicode_tables.sequenceTableSource(string name, const(sparkles.base.tools.gen_unicode_tables.SequenceMapping)[] mappings)sequenceTableSource("compatibilityDecomposition", (field) sparkles.base.tools.gen_unicode_tables.SequenceMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.compatibilitycompatibility),
string sparkles.base.tools.gen_unicode_tables.sequenceTableSource(string name, const(sparkles.base.tools.gen_unicode_tables.SequenceMapping)[] mappings)sequenceTableSource("fullCaseFold", (field) sparkles.base.tools.gen_unicode_tables.SequenceMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.fullFoldfullFold),
string sparkles.base.tools.gen_unicode_tables.scalarTableSource(string name, const(sparkles.base.tools.gen_unicode_tables.ScalarMapping)[] mappings)scalarTableSource("simpleCaseFold", (field) sparkles.base.tools.gen_unicode_tables.ScalarMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.simpleFoldsimpleFold),
string sparkles.base.tools.gen_unicode_tables.compositionTableSource(const(sparkles.base.tools.gen_unicode_tables.CompositionMapping)[] mappings)compositionTableSource((field) sparkles.base.tools.gen_unicode_tables.CompositionMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.compositionscompositions),
string sparkles.base.tools.gen_unicode_tables.wordBreakTableSource(const(sparkles.base.tools.gen_unicode_tables.WordBreakRange)[] ranges)wordBreakTableSource((field) sparkles.base.tools.gen_unicode_tables.WordBreakRange[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.wordBreakwordBreak),
].string std.array.join!(string[], string)(string[] ror, string sep) pure nothrow @safeEagerly concatenates all of the ranges in ror together (with the GC)
into one array using sep as the separator if present.
join("\n");
}
}
private (struct) sparkles.base.tools.gen_unicode_tables.AnalysisTablesAnalysisTables sparkles.base.tools.gen_unicode_tables.AnalysisTables sparkles.base.tools.gen_unicode_tables.buildAnalysisTables(string unicodeData, string caseFolding, string normalizationProps, string wordBreak)buildAnalysisTables((alias) object.string = stringstring (parameter) string unicodeDataunicodeData,
(alias) object.string = stringstring (parameter) string caseFoldingcaseFolding, (alias) object.string = stringstring (parameter) string normalizationPropsnormalizationProps, (alias) object.string = stringstring (parameter) string wordBreakwordBreak)
{
(struct) sparkles.base.tools.gen_unicode_tables.AnalysisTablesAnalysisTables (local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult;
(struct) sparkles.base.tools.gen_unicode_tables.UcdRecordUcdRecord[uint] (local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord[uint] recordsrecords;
foreach ((local variable) string lineline; (parameter) string unicodeDataunicodeData.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)
{
auto (local variable) string[] fieldsfields = (local variable) string lineline.std.algorithm.iteration.splitter!("a == b", Flag.no, string, char).Result std.algorithm.iteration.splitter!("a == b", Flag.no, string, char)(string r, char s) pure nothrow @nogc @safeLazily splits a range using an element or range as a separator.
Separator ranges can be any narrow string type or sliceable range type.
Two adjacent separators are considered to surround an empty element in
the split range. Use filter!(a => !a.empty) on the result to compress
empty elements.
The predicate is passed to binaryFun and accepts
any callable function that can be executed via pred(element, s).
Note
If splitting a string on whitespace and token compression is desired,
consider using the ``splitter(r) overload.
Constraints
The predicate pred needs to accept an element of r and the
separator s.
Examples
Basic splitting with characters and numbers.
import std.algorithm.comparison : equal;
assert("a|bc|def".splitter('|').equal([ "a", "bc", "def" ]));
int[] a = [1, 0, 2, 3, 0, 4, 5, 6];
int[][] w = [ [1], [2, 3], [4, 5, 6] ];
assert(a.splitter(0).equal(w));
Basic splitting with characters and numbers and keeping sentinels.
import std.algorithm.comparison : equal;
import std.typecons : Yes;
assert("a|bc|def".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "a", "|", "bc", "|", "def" ]));
int[] a = [1, 0, 2, 3, 0, 4, 5, 6];
int[][] w = [ [1], [0], [2, 3], [0], [4, 5, 6] ];
assert(a.splitter!("a == b", Yes.keepSeparators)(0).equal(w));
Adjacent separators.
import std.algorithm.comparison : equal;
assert("|ab|".splitter('|').equal([ "", "ab", "" ]));
assert("ab".splitter('|').equal([ "ab" ]));
assert("a|b||c".splitter('|').equal([ "a", "b", "", "c" ]));
assert("hello world".splitter(' ').equal([ "hello", "", "world" ]));
auto a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
auto w = [ [1, 2], [], [3], [4, 5], [] ];
assert(a.splitter(0).equal(w));
Adjacent separators and keeping sentinels.
import std.algorithm.comparison : equal;
import std.typecons : Yes;
assert("|ab|".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "", "|", "ab", "|", "" ]));
assert("ab".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "ab" ]));
assert("a|b||c".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "a", "|", "b", "|", "", "|", "c" ]));
assert("hello world".splitter!("a == b", Yes.keepSeparators)(' ')
.equal([ "hello", " ", "", " ", "world" ]));
auto a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
auto w = [ [1, 2], [0], [], [0], [3], [0], [4, 5], [0], [] ];
assert(a.splitter!("a == b", Yes.keepSeparators)(0).equal(w));
Empty and separator-only ranges.
import std.algorithm.comparison : equal;
import std.range : empty;
assert("".splitter('|').empty);
assert("|".splitter('|').equal([ "", "" ]));
assert("||".splitter('|').equal([ "", "", "" ]));
Empty and separator-only ranges and keeping sentinels.
import std.algorithm.comparison : equal;
import std.typecons : Yes;
import std.range : empty;
assert("".splitter!("a == b", Yes.keepSeparators)('|').empty);
assert("|".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "", "|", "" ]));
assert("||".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "", "|", "", "|", "" ]));
Use a range for splitting
import std.algorithm.comparison : equal;
assert("a=>bc=>def".splitter("=>").equal([ "a", "bc", "def" ]));
assert("a|b||c".splitter("||").equal([ "a|b", "c" ]));
assert("hello world".splitter(" ").equal([ "hello", "world" ]));
int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
int[][] w = [ [1, 2], [3, 0, 4, 5, 0] ];
assert(a.splitter([0, 0]).equal(w));
a = [ 0, 0 ];
assert(a.splitter([0, 0]).equal([ (int[]).init, (int[]).init ]));
a = [ 0, 0, 1 ];
assert(a.splitter([0, 0]).equal([ [], [1] ]));
Use a range for splitting
import std.algorithm.comparison : equal;
import std.typecons : Yes;
assert("a=>bc=>def".splitter!("a == b", Yes.keepSeparators)("=>")
.equal([ "a", "=>", "bc", "=>", "def" ]));
assert("a|b||c".splitter!("a == b", Yes.keepSeparators)("||")
.equal([ "a|b", "||", "c" ]));
assert("hello world".splitter!("a == b", Yes.keepSeparators)(" ")
.equal([ "hello", " ", "world" ]));
int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
int[][] w = [ [1, 2], [0, 0], [3, 0, 4, 5, 0] ];
assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0]).equal(w));
a = [ 0, 0 ];
assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0])
.equal([ (int[]).init, [0, 0], (int[]).init ]));
a = [ 0, 0, 1 ];
assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0])
.equal([ [], [0, 0], [1] ]));
Custom predicate functions.
import std.algorithm.comparison : equal;
import std.ascii : toLower;
assert("abXcdxef".splitter!"a.toLower == b"('x').equal(
[ "ab", "cd", "ef" ]));
auto w = [ [0], [1], [2] ];
assert(w.splitter!"a.front == b"(1).equal([ [[0]], [[2]] ]));
Custom predicate functions.
import std.algorithm.comparison : equal;
import std.typecons : Yes;
import std.ascii : toLower;
assert("abXcdxef".splitter!("a.toLower == b", Yes.keepSeparators)('x')
.equal([ "ab", "X", "cd", "x", "ef" ]));
auto w = [ [0], [1], [2] ];
assert(w.splitter!("a.front == b", Yes.keepSeparators)(1)
.equal([ [[0]], [[1]], [[2]] ]));
Leading separators, trailing separators, or no separators.
import std.algorithm.comparison : equal;
assert("|ab|".splitter('|').equal([ "", "ab", "" ]));
assert("ab".splitter('|').equal([ "ab" ]));
Leading separators, trailing separators, or no separators.
import std.algorithm.comparison : equal;
import std.typecons : Yes;
assert("|ab|".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "", "|", "ab", "|", "" ]));
assert("ab".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "ab" ]));
Splitter returns bidirectional ranges if the delimiter is a single element
import std.algorithm.comparison : equal;
import std.range : retro;
assert("a|bc|def".splitter('|').retro.equal([ "def", "bc", "a" ]));
Splitter returns bidirectional ranges if the delimiter is a single element
import std.algorithm.comparison : equal;
import std.typecons : Yes;
import std.range : retro;
assert("a|bc|def".splitter!("a == b", Yes.keepSeparators)('|')
.retro.equal([ "def", "|", "bc", "|", "a" ]));
splitter(';').string[] std.array.array!(std.algorithm.iteration.splitter!("a == b", Flag.no, string, char).Result)(std.algorithm.iteration.splitter!("a == b", Flag.no, string, char).Result r) pure @safeAllocates an array and initializes it with copies of the elements
of range r.
Narrow strings are handled as follows:
If autodecoding is turned on (default), then they are handled as a separate overload.
If autodecoding is turned off, then this is equivalent to duplicating the array.
array;
if ((local variable) string[] fieldsfields.(field) ulong string[].lengthlength < 15)
continue;
const (local variable) const(uint) cpcp = uint sparkles.base.tools.gen_unicode_tables.parseHex(string text)parseHex((local variable) string[] fieldsfields[0]);
const (local variable) const(string) categorycategory = (local variable) string[] fieldsfields[2];
const (local variable) const(uint) canonicalClasscanonicalClass = (local variable) string[] fieldsfields[3].uint std.conv.to!uint.to!string(string __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!uint;
if ((local variable) const(uint) canonicalClasscanonicalClass != 0)
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult.(field) sparkles.base.tools.gen_unicode_tables.ScalarMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.canonicalClassescanonicalClasses ~= (struct) sparkles.base.tools.gen_unicode_tables.ScalarMappingScalarMapping((local variable) const(uint) cpcp, (local variable) const(uint) canonicalClasscanonicalClass);
if ((local variable) const(string) categorycategory == "Mn" || (local variable) const(string) categorycategory == "Mc" || (local variable) const(string) categorycategory == "Me")
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult.(field) std.uni.InversionList!(GcPolicy) sparkles.base.tools.gen_unicode_tables.AnalysisTables.marksmarks.std.uni.InversionList!(GcPolicy) std.uni.InversionList!(std.uni.GcPolicy).add!()(uint a, uint b) pure nothrow ref @safeAdd an interval [a, b) to this set.
add((local variable) const(uint) cpcp, (local variable) const(uint) cpcp + 1);
if ((local variable) const(string) categorycategory == "Lu" || (local variable) const(string) categorycategory == "Lt")
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult.(field) std.uni.InversionList!(GcPolicy) sparkles.base.tools.gen_unicode_tables.AnalysisTables.uppercaseuppercase.std.uni.InversionList!(GcPolicy) std.uni.InversionList!(std.uni.GcPolicy).add!()(uint a, uint b) pure nothrow ref @safeAdd an interval [a, b) to this set.
add((local variable) const(uint) cpcp, (local variable) const(uint) cpcp + 1);
(struct) sparkles.base.tools.gen_unicode_tables.UcdRecordUcdRecord (local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord recrec;
(local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord recrec.(field) string sparkles.base.tools.gen_unicode_tables.UcdRecord.categorycategory = (local variable) const(string) categorycategory;
auto (local variable) string decompdecomp = (local variable) string[] fieldsfields[5].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;
if ((local variable) string decompdecomp.(field) ulong string.lengthlength)
{
auto (local variable) string[] piecespieces = (local variable) string decompdecomp.std.algorithm.iteration.splitter!string.Result std.algorithm.iteration.splitter!string(string s) pure @safeLazily splits the character-based range s into words, using whitespace as the
delimiter.
This function is character-range specific and, contrary to
``splitter!(std.uni.isWhite), runs of whitespace will be merged together
(no empty tokens will be produced).
Examples
import std.algorithm.comparison : equal;
auto a = " a bcd ef gh ";
assert(equal(splitter(a), ["a", "bcd", "ef", "gh"][]));
splitter.string[] std.array.array!(std.algorithm.iteration.splitter!string.Result)(std.algorithm.iteration.splitter!string.Result r) pure @safeAllocates an array and initializes it with copies of the elements
of range r.
Narrow strings are handled as follows:
If autodecoding is turned on (default), then they are handled as a separate overload.
If autodecoding is turned off, then this is equivalent to duplicating the array.
array;
(alias) object.size_t = ulongsize_t (local variable) ulong firstfirst;
if ((local variable) string[] piecespieces[0].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("<"))
{
(local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord recrec.(field) bool sparkles.base.tools.gen_unicode_tables.UcdRecord.compatibilitycompatibility = true;
(local variable) ulong firstfirst = 1;
}
foreach ((parameter) string piecepiece; (local variable) string[] piecespieces[(local variable) ulong firstfirst .. $])
(local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord recrec.(field) uint[] sparkles.base.tools.gen_unicode_tables.UcdRecord.decompositiondecomposition ~= uint sparkles.base.tools.gen_unicode_tables.parseHex(string text)parseHex((local variable) string piecepiece);
}
if ((local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord recrec.(field) uint[] sparkles.base.tools.gen_unicode_tables.UcdRecord.decompositiondecomposition.(field) ulong uint[].lengthlength)
sparkles.base.tools.gen_unicode_tables.UcdRecord* core.internal.newaa._d_aaGetY!(uint, sparkles.base.tools.gen_unicode_tables.UcdRecord, sparkles.base.tools.gen_unicode_tables.UcdRecord[uint], uint, sparkles.base.tools.gen_unicode_tables.UcdRecord, const(uint))(ref scope sparkles.base.tools.gen_unicode_tables.UcdRecord[uint] aa, ref const(uint) key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
records[sparkles.base.tools.gen_unicode_tables.UcdRecord* core.internal.newaa._d_aaGetY!(uint, sparkles.base.tools.gen_unicode_tables.UcdRecord, sparkles.base.tools.gen_unicode_tables.UcdRecord[uint], uint, sparkles.base.tools.gen_unicode_tables.UcdRecord, const(uint))(ref scope sparkles.base.tools.gen_unicode_tables.UcdRecord[uint] aa, ref const(uint) key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
cp] = (local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord recrec;
}
uint[][uint] (local variable) uint[][uint] canonicalMemocanonicalMemo;
uint[][uint] (local variable) uint[][uint] compatibilityMemocompatibilityMemo;
foreach (int core.internal.newaa._d_aaApply2!(uint, sparkles.base.tools.gen_unicode_tables.UcdRecord, int delegate(ref uint, ref sparkles.base.tools.gen_unicode_tables.UcdRecord) @system)(inout(sparkles.base.tools.gen_unicode_tables.UcdRecord[uint]) a, int delegate(ref uint, ref sparkles.base.tools.gen_unicode_tables.UcdRecord) @system dg) @systemforeach opApply over all key/value pairs
Note
emulated by the compiler during CTFE
cp, (parameter) sparkles.base.tools.gen_unicode_tables.UcdRecord recrec; (local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord[uint] recordsrecords)
{
auto (local variable) uint[] canonicalcanonical = uint[] sparkles.base.tools.gen_unicode_tables.expandDecomposition(uint cp, bool compatibility, ref sparkles.base.tools.gen_unicode_tables.UcdRecord[uint] records, ref uint[][uint] memo)expandDecomposition(
(local variable) uint cpcp, false, (local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord[uint] recordsrecords, (local variable) uint[][uint] canonicalMemocanonicalMemo);
if ((local variable) uint[] canonicalcanonical.(field) ulong uint[].lengthlength != 1 || (local variable) uint[] canonicalcanonical[0] != (local variable) uint cpcp)
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult.(field) sparkles.base.tools.gen_unicode_tables.SequenceMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.canonicalcanonical ~= (struct) sparkles.base.tools.gen_unicode_tables.SequenceMappingSequenceMapping((local variable) uint cpcp, (local variable) uint[] canonicalcanonical);
auto (local variable) uint[] compatibilitycompatibility = uint[] sparkles.base.tools.gen_unicode_tables.expandDecomposition(uint cp, bool compatibility, ref sparkles.base.tools.gen_unicode_tables.UcdRecord[uint] records, ref uint[][uint] memo)expandDecomposition(
(local variable) uint cpcp, true, (local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord[uint] recordsrecords, (local variable) uint[][uint] compatibilityMemocompatibilityMemo);
if ((local variable) uint[] compatibilitycompatibility.(field) ulong uint[].lengthlength != 1 || (local variable) uint[] compatibilitycompatibility[0] != (local variable) uint cpcp)
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult.(field) sparkles.base.tools.gen_unicode_tables.SequenceMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.compatibilitycompatibility ~= (struct) sparkles.base.tools.gen_unicode_tables.SequenceMappingSequenceMapping((local variable) uint cpcp, (local variable) uint[] compatibilitycompatibility);
}
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult.(field) sparkles.base.tools.gen_unicode_tables.SequenceMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.canonicalcanonical.sparkles.base.tools.gen_unicode_tables.buildAnalysisTables.SortedRange!(SequenceMapping[], __lambda_L334_C28, SortedRangeOptions.assumeSorted) sparkles.base.tools.gen_unicode_tables.buildAnalysisTables.sort!((a, b) => a.codepoint < b.codepoint, SwapStrategy.unstable, sparkles.base.tools.gen_unicode_tables.SequenceMapping[])(sparkles.base.tools.gen_unicode_tables.SequenceMapping[] 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!((a, b) => a.codepoint < b.codepoint);
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult.(field) sparkles.base.tools.gen_unicode_tables.SequenceMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.compatibilitycompatibility.sparkles.base.tools.gen_unicode_tables.buildAnalysisTables.SortedRange!(SequenceMapping[], __lambda_L335_C32, SortedRangeOptions.assumeSorted) sparkles.base.tools.gen_unicode_tables.buildAnalysisTables.sort!((a, b) => a.codepoint < b.codepoint, SwapStrategy.unstable, sparkles.base.tools.gen_unicode_tables.SequenceMapping[])(sparkles.base.tools.gen_unicode_tables.SequenceMapping[] 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!((a, b) => a.codepoint < b.codepoint);
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult.(field) sparkles.base.tools.gen_unicode_tables.ScalarMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.canonicalClassescanonicalClasses.sparkles.base.tools.gen_unicode_tables.buildAnalysisTables.SortedRange!(ScalarMapping[], __lambda_L336_C35, SortedRangeOptions.assumeSorted) sparkles.base.tools.gen_unicode_tables.buildAnalysisTables.sort!((a, b) => a.codepoint < b.codepoint, SwapStrategy.unstable, sparkles.base.tools.gen_unicode_tables.ScalarMapping[])(sparkles.base.tools.gen_unicode_tables.ScalarMapping[] 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!((a, b) => a.codepoint < b.codepoint);
auto (local variable) std.uni.InversionList!(GcPolicy) exclusionsexclusions = (parameter) string normalizationPropsnormalizationProps.std.uni.InversionList!(GcPolicy) sparkles.base.tools.gen_unicode_tables.buildAnalysisTables.ucdCodepoints!((value) => value == "Full_Composition_Exclusion")(string text) @systemCollect, into a CodepointSet, the leading code-point column of every data
record whose value field (the column after the first ;) satisfies
valueMatches. For each record: strip the trailing # comment, split on ;
into whitespace-trimmed fields (comment-only and blank lines collapse to one
empty field and are dropped), take the first whitespace-separated token of the
code-point column, and read it as a ..-separated hex sequence — so a bare
AAAA adds one code point, AAAA..BBBB adds the inclusive range, and the
BASE VS form (e.g. 0023 FE0F) adds just BASE.
ucdCodepoints!(
value => value == "Full_Composition_Exclusion");
foreach (int core.internal.newaa._d_aaApply2!(uint, sparkles.base.tools.gen_unicode_tables.UcdRecord, int delegate(ref uint, ref sparkles.base.tools.gen_unicode_tables.UcdRecord) pure nothrow @safe)(inout(sparkles.base.tools.gen_unicode_tables.UcdRecord[uint]) a, int delegate(ref uint, ref sparkles.base.tools.gen_unicode_tables.UcdRecord) pure nothrow @safe dg) pure nothrow @safeforeach opApply over all key/value pairs
Note
emulated by the compiler during CTFE
cp, (parameter) sparkles.base.tools.gen_unicode_tables.UcdRecord recrec; (local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord[uint] recordsrecords)
{
if (!(local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord recrec.(field) bool sparkles.base.tools.gen_unicode_tables.UcdRecord.compatibilitycompatibility && (local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord recrec.(field) uint[] sparkles.base.tools.gen_unicode_tables.UcdRecord.decompositiondecomposition.(field) ulong uint[].lengthlength == 2
&& !((local variable) uint cpcp in (local variable) std.uni.InversionList!(GcPolicy) exclusionsexclusions))
{
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult.(field) sparkles.base.tools.gen_unicode_tables.CompositionMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.compositionscompositions ~= (struct) sparkles.base.tools.gen_unicode_tables.CompositionMappingCompositionMapping(
(local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord recrec.(field) uint[] sparkles.base.tools.gen_unicode_tables.UcdRecord.decompositiondecomposition[0], (local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord recrec.(field) uint[] sparkles.base.tools.gen_unicode_tables.UcdRecord.decompositiondecomposition[1], (local variable) uint cpcp);
}
}
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult.(field) sparkles.base.tools.gen_unicode_tables.CompositionMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.compositionscompositions.sparkles.base.tools.gen_unicode_tables.buildAnalysisTables.SortedRange!(CompositionMapping[], __lambda_L349_C31, SortedRangeOptions.assumeSorted) sparkles.base.tools.gen_unicode_tables.buildAnalysisTables.sort!((a, b)
{
return a.first != b.first ? a.first < b.first : a.second < b.second;
}
, SwapStrategy.unstable, sparkles.base.tools.gen_unicode_tables.CompositionMapping[])(sparkles.base.tools.gen_unicode_tables.CompositionMapping[] 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!((a, b) {
return a.first != b.first ? a.first < b.first : a.second < b.second;
});
(struct) sparkles.base.tools.gen_unicode_tables.SequenceMappingSequenceMapping[uint] (local variable) sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint] simplesimple;
(struct) sparkles.base.tools.gen_unicode_tables.SequenceMappingSequenceMapping[uint] (local variable) sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint] fullfull;
foreach ((local variable) string rawLinerawLine; (parameter) string caseFoldingcaseFolding.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)
{
auto (local variable) string lineline = string sparkles.base.tools.gen_unicode_tables.stripComment(string line)Strip a trailing # comment and surrounding whitespace from a UCD line.
findSplit("#")[0] is the text before the first #, or the whole line when
there is none.
stripComment((local variable) string rawLinerawLine);
if (!(local variable) string lineline.(field) ulong string.lengthlength)
continue;
auto (local variable) string[] fieldsfields = (local variable) string lineline.std.algorithm.iteration.splitter!("a == b", Flag.no, string, char).Result std.algorithm.iteration.splitter!("a == b", Flag.no, string, char)(string r, char s) pure nothrow @nogc @safeLazily splits a range using an element or range as a separator.
Separator ranges can be any narrow string type or sliceable range type.
Two adjacent separators are considered to surround an empty element in
the split range. Use filter!(a => !a.empty) on the result to compress
empty elements.
The predicate is passed to binaryFun and accepts
any callable function that can be executed via pred(element, s).
Note
If splitting a string on whitespace and token compression is desired,
consider using the ``splitter(r) overload.
Constraints
The predicate pred needs to accept an element of r and the
separator s.
Examples
Basic splitting with characters and numbers.
import std.algorithm.comparison : equal;
assert("a|bc|def".splitter('|').equal([ "a", "bc", "def" ]));
int[] a = [1, 0, 2, 3, 0, 4, 5, 6];
int[][] w = [ [1], [2, 3], [4, 5, 6] ];
assert(a.splitter(0).equal(w));
Basic splitting with characters and numbers and keeping sentinels.
import std.algorithm.comparison : equal;
import std.typecons : Yes;
assert("a|bc|def".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "a", "|", "bc", "|", "def" ]));
int[] a = [1, 0, 2, 3, 0, 4, 5, 6];
int[][] w = [ [1], [0], [2, 3], [0], [4, 5, 6] ];
assert(a.splitter!("a == b", Yes.keepSeparators)(0).equal(w));
Adjacent separators.
import std.algorithm.comparison : equal;
assert("|ab|".splitter('|').equal([ "", "ab", "" ]));
assert("ab".splitter('|').equal([ "ab" ]));
assert("a|b||c".splitter('|').equal([ "a", "b", "", "c" ]));
assert("hello world".splitter(' ').equal([ "hello", "", "world" ]));
auto a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
auto w = [ [1, 2], [], [3], [4, 5], [] ];
assert(a.splitter(0).equal(w));
Adjacent separators and keeping sentinels.
import std.algorithm.comparison : equal;
import std.typecons : Yes;
assert("|ab|".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "", "|", "ab", "|", "" ]));
assert("ab".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "ab" ]));
assert("a|b||c".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "a", "|", "b", "|", "", "|", "c" ]));
assert("hello world".splitter!("a == b", Yes.keepSeparators)(' ')
.equal([ "hello", " ", "", " ", "world" ]));
auto a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
auto w = [ [1, 2], [0], [], [0], [3], [0], [4, 5], [0], [] ];
assert(a.splitter!("a == b", Yes.keepSeparators)(0).equal(w));
Empty and separator-only ranges.
import std.algorithm.comparison : equal;
import std.range : empty;
assert("".splitter('|').empty);
assert("|".splitter('|').equal([ "", "" ]));
assert("||".splitter('|').equal([ "", "", "" ]));
Empty and separator-only ranges and keeping sentinels.
import std.algorithm.comparison : equal;
import std.typecons : Yes;
import std.range : empty;
assert("".splitter!("a == b", Yes.keepSeparators)('|').empty);
assert("|".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "", "|", "" ]));
assert("||".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "", "|", "", "|", "" ]));
Use a range for splitting
import std.algorithm.comparison : equal;
assert("a=>bc=>def".splitter("=>").equal([ "a", "bc", "def" ]));
assert("a|b||c".splitter("||").equal([ "a|b", "c" ]));
assert("hello world".splitter(" ").equal([ "hello", "world" ]));
int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
int[][] w = [ [1, 2], [3, 0, 4, 5, 0] ];
assert(a.splitter([0, 0]).equal(w));
a = [ 0, 0 ];
assert(a.splitter([0, 0]).equal([ (int[]).init, (int[]).init ]));
a = [ 0, 0, 1 ];
assert(a.splitter([0, 0]).equal([ [], [1] ]));
Use a range for splitting
import std.algorithm.comparison : equal;
import std.typecons : Yes;
assert("a=>bc=>def".splitter!("a == b", Yes.keepSeparators)("=>")
.equal([ "a", "=>", "bc", "=>", "def" ]));
assert("a|b||c".splitter!("a == b", Yes.keepSeparators)("||")
.equal([ "a|b", "||", "c" ]));
assert("hello world".splitter!("a == b", Yes.keepSeparators)(" ")
.equal([ "hello", " ", "world" ]));
int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
int[][] w = [ [1, 2], [0, 0], [3, 0, 4, 5, 0] ];
assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0]).equal(w));
a = [ 0, 0 ];
assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0])
.equal([ (int[]).init, [0, 0], (int[]).init ]));
a = [ 0, 0, 1 ];
assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0])
.equal([ [], [0, 0], [1] ]));
Custom predicate functions.
import std.algorithm.comparison : equal;
import std.ascii : toLower;
assert("abXcdxef".splitter!"a.toLower == b"('x').equal(
[ "ab", "cd", "ef" ]));
auto w = [ [0], [1], [2] ];
assert(w.splitter!"a.front == b"(1).equal([ [[0]], [[2]] ]));
Custom predicate functions.
import std.algorithm.comparison : equal;
import std.typecons : Yes;
import std.ascii : toLower;
assert("abXcdxef".splitter!("a.toLower == b", Yes.keepSeparators)('x')
.equal([ "ab", "X", "cd", "x", "ef" ]));
auto w = [ [0], [1], [2] ];
assert(w.splitter!("a.front == b", Yes.keepSeparators)(1)
.equal([ [[0]], [[1]], [[2]] ]));
Leading separators, trailing separators, or no separators.
import std.algorithm.comparison : equal;
assert("|ab|".splitter('|').equal([ "", "ab", "" ]));
assert("ab".splitter('|').equal([ "ab" ]));
Leading separators, trailing separators, or no separators.
import std.algorithm.comparison : equal;
import std.typecons : Yes;
assert("|ab|".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "", "|", "ab", "|", "" ]));
assert("ab".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "ab" ]));
Splitter returns bidirectional ranges if the delimiter is a single element
import std.algorithm.comparison : equal;
import std.range : retro;
assert("a|bc|def".splitter('|').retro.equal([ "def", "bc", "a" ]));
Splitter returns bidirectional ranges if the delimiter is a single element
import std.algorithm.comparison : equal;
import std.typecons : Yes;
import std.range : retro;
assert("a|bc|def".splitter!("a == b", Yes.keepSeparators)('|')
.retro.equal([ "def", "|", "bc", "|", "a" ]));
splitter(';').std.algorithm.iteration.MapResult!(strip, Result) std.algorithm.iteration.map!(strip).map!(std.algorithm.iteration.splitter!("a == b", Flag.no, string, char).Result)(std.algorithm.iteration.splitter!("a == b", Flag.no, string, char).Result r) pure nothrow @nogc @safeImplements the homonym function (also known as transform) present
in many languages of functional flavor. The call ``map!(fun)(range)
returns a range of which elements are obtained by applying fun(a)
left to right for all elements a in range. The original ranges are
not changed. Evaluation is done lazily.
Examples
import std.algorithm.comparison : equal;
import std.range : chain, only;
auto squares =
chain(only(1, 2, 3, 4), only(5, 6)).map!(a => a * a);
assert(equal(squares, only(1, 4, 9, 16, 25, 36)));
Multiple functions can be passed to map. In that case, the
element type of map is a tuple containing one element for each
function.
auto sums = [2, 4, 6, 8];
auto products = [1, 4, 9, 16];
size_t i = 0;
foreach (result; [ 1, 2, 3, 4 ].map!("a + a", "a * a"))
{
assert(result[0] == sums[i]);
assert(result[1] == products[i]);
++i;
}
You may alias map with some function(s) to a symbol and use
it separately:
import std.algorithm.comparison : equal;
import std.conv : to;
alias stringize = map!(to!string);
assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));
map!(template) 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
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.string[] std.array.array!(std.algorithm.iteration.MapResult!(strip, Result))(std.algorithm.iteration.MapResult!(strip, Result) r) pure @safeAllocates an array and initializes it with copies of the elements
of range r.
Narrow strings are handled as follows:
If autodecoding is turned on (default), then they are handled as a separate overload.
If autodecoding is turned off, then this is equivalent to duplicating the array.
array;
if ((local variable) string[] fieldsfields.(field) ulong string[].lengthlength < 3)
continue;
const (local variable) const(uint) cpcp = uint sparkles.base.tools.gen_unicode_tables.parseHex(string text)parseHex((local variable) string[] fieldsfields[0]);
uint[] (local variable) uint[] valuesvalues;
foreach ((local variable) string piecepiece; (local variable) string[] fieldsfields[2].std.algorithm.iteration.splitter!string.Result std.algorithm.iteration.splitter!string(string s) pure @safeLazily splits the character-based range s into words, using whitespace as the
delimiter.
This function is character-range specific and, contrary to
``splitter!(std.uni.isWhite), runs of whitespace will be merged together
(no empty tokens will be produced).
Examples
import std.algorithm.comparison : equal;
auto a = " a bcd ef gh ";
assert(equal(splitter(a), ["a", "bcd", "ef", "gh"][]));
splitter)
(local variable) uint[] valuesvalues ~= uint sparkles.base.tools.gen_unicode_tables.parseHex(string text)parseHex((local variable) string piecepiece);
switch ((local variable) string[] fieldsfields[1])
{
case "C":
sparkles.base.tools.gen_unicode_tables.SequenceMapping* core.internal.newaa._d_aaGetY!(uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint], uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, const(uint))(ref scope sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint] aa, ref const(uint) key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
simple[sparkles.base.tools.gen_unicode_tables.SequenceMapping* core.internal.newaa._d_aaGetY!(uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint], uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, const(uint))(ref scope sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint] aa, ref const(uint) key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
cp] = (struct) sparkles.base.tools.gen_unicode_tables.SequenceMappingSequenceMapping((local variable) const(uint) cpcp, (local variable) uint[] valuesvalues);
sparkles.base.tools.gen_unicode_tables.SequenceMapping* core.internal.newaa._d_aaGetY!(uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint], uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, const(uint))(ref scope sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint] aa, ref const(uint) key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
full[sparkles.base.tools.gen_unicode_tables.SequenceMapping* core.internal.newaa._d_aaGetY!(uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint], uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, const(uint))(ref scope sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint] aa, ref const(uint) key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
cp] = (struct) sparkles.base.tools.gen_unicode_tables.SequenceMappingSequenceMapping((local variable) const(uint) cpcp, (local variable) uint[] valuesvalues);
break;
case "S":
sparkles.base.tools.gen_unicode_tables.SequenceMapping* core.internal.newaa._d_aaGetY!(uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint], uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, const(uint))(ref scope sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint] aa, ref const(uint) key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
simple[sparkles.base.tools.gen_unicode_tables.SequenceMapping* core.internal.newaa._d_aaGetY!(uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint], uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, const(uint))(ref scope sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint] aa, ref const(uint) key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
cp] = (struct) sparkles.base.tools.gen_unicode_tables.SequenceMappingSequenceMapping((local variable) const(uint) cpcp, (local variable) uint[] valuesvalues);
break;
case "F":
sparkles.base.tools.gen_unicode_tables.SequenceMapping* core.internal.newaa._d_aaGetY!(uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint], uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, const(uint))(ref scope sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint] aa, ref const(uint) key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
full[sparkles.base.tools.gen_unicode_tables.SequenceMapping* core.internal.newaa._d_aaGetY!(uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint], uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, const(uint))(ref scope sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint] aa, ref const(uint) key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
cp] = (struct) sparkles.base.tools.gen_unicode_tables.SequenceMappingSequenceMapping((local variable) const(uint) cpcp, (local variable) uint[] valuesvalues);
break;
default: // Turkic mappings are locale-specific and live in an adapter.
break;
}
}
foreach (int core.internal.newaa._d_aaApply2!(uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, int delegate(ref uint, ref sparkles.base.tools.gen_unicode_tables.SequenceMapping) pure nothrow @safe)(inout(sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint]) a, int delegate(ref uint, ref sparkles.base.tools.gen_unicode_tables.SequenceMapping) pure nothrow @safe dg) pure nothrow @safeforeach opApply over all key/value pairs
Note
emulated by the compiler during CTFE
cp, (parameter) sparkles.base.tools.gen_unicode_tables.SequenceMapping mappingmapping; (local variable) sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint] simplesimple)
{
if ((local variable) sparkles.base.tools.gen_unicode_tables.SequenceMapping mappingmapping.(field) uint[] sparkles.base.tools.gen_unicode_tables.SequenceMapping.valuesvalues.(field) ulong uint[].lengthlength == 1 && (local variable) sparkles.base.tools.gen_unicode_tables.SequenceMapping mappingmapping.(field) uint[] sparkles.base.tools.gen_unicode_tables.SequenceMapping.valuesvalues[0] != (local variable) uint cpcp)
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult.(field) sparkles.base.tools.gen_unicode_tables.ScalarMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.simpleFoldsimpleFold ~= (struct) sparkles.base.tools.gen_unicode_tables.ScalarMappingScalarMapping((local variable) uint cpcp, (local variable) sparkles.base.tools.gen_unicode_tables.SequenceMapping mappingmapping.(field) uint[] sparkles.base.tools.gen_unicode_tables.SequenceMapping.valuesvalues[0]);
}
foreach (int core.internal.newaa._d_aaApply2!(uint, sparkles.base.tools.gen_unicode_tables.SequenceMapping, int delegate(ref uint, ref sparkles.base.tools.gen_unicode_tables.SequenceMapping) pure nothrow @safe)(inout(sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint]) a, int delegate(ref uint, ref sparkles.base.tools.gen_unicode_tables.SequenceMapping) pure nothrow @safe dg) pure nothrow @safeforeach opApply over all key/value pairs
Note
emulated by the compiler during CTFE
cp, (parameter) sparkles.base.tools.gen_unicode_tables.SequenceMapping mappingmapping; (local variable) sparkles.base.tools.gen_unicode_tables.SequenceMapping[uint] fullfull)
{
if ((local variable) sparkles.base.tools.gen_unicode_tables.SequenceMapping mappingmapping.(field) uint[] sparkles.base.tools.gen_unicode_tables.SequenceMapping.valuesvalues.(field) ulong uint[].lengthlength != 1 || (local variable) sparkles.base.tools.gen_unicode_tables.SequenceMapping mappingmapping.(field) uint[] sparkles.base.tools.gen_unicode_tables.SequenceMapping.valuesvalues[0] != (local variable) uint cpcp)
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult.(field) sparkles.base.tools.gen_unicode_tables.SequenceMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.fullFoldfullFold ~= (local variable) sparkles.base.tools.gen_unicode_tables.SequenceMapping mappingmapping;
}
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult.(field) sparkles.base.tools.gen_unicode_tables.ScalarMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.simpleFoldsimpleFold.sparkles.base.tools.gen_unicode_tables.buildAnalysisTables.SortedRange!(ScalarMapping[], __lambda_L393_C29, SortedRangeOptions.assumeSorted) sparkles.base.tools.gen_unicode_tables.buildAnalysisTables.sort!((a, b) => a.codepoint < b.codepoint, SwapStrategy.unstable, sparkles.base.tools.gen_unicode_tables.ScalarMapping[])(sparkles.base.tools.gen_unicode_tables.ScalarMapping[] 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!((a, b) => a.codepoint < b.codepoint);
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult.(field) sparkles.base.tools.gen_unicode_tables.SequenceMapping[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.fullFoldfullFold.sparkles.base.tools.gen_unicode_tables.buildAnalysisTables.SortedRange!(SequenceMapping[], __lambda_L394_C27, SortedRangeOptions.assumeSorted) sparkles.base.tools.gen_unicode_tables.buildAnalysisTables.sort!((a, b) => a.codepoint < b.codepoint, SwapStrategy.unstable, sparkles.base.tools.gen_unicode_tables.SequenceMapping[])(sparkles.base.tools.gen_unicode_tables.SequenceMapping[] 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!((a, b) => a.codepoint < b.codepoint);
foreach ((local variable) string rawLinerawLine; (parameter) string wordBreakwordBreak.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)
{
auto (local variable) string lineline = string sparkles.base.tools.gen_unicode_tables.stripComment(string line)Strip a trailing # comment and surrounding whitespace from a UCD line.
findSplit("#")[0] is the text before the first #, or the whole line when
there is none.
stripComment((local variable) string rawLinerawLine);
if (!(local variable) string lineline.(field) ulong string.lengthlength)
continue;
auto (local variable) string[] fieldsfields = (local variable) string lineline.std.algorithm.iteration.splitter!("a == b", Flag.no, string, char).Result std.algorithm.iteration.splitter!("a == b", Flag.no, string, char)(string r, char s) pure nothrow @nogc @safeLazily splits a range using an element or range as a separator.
Separator ranges can be any narrow string type or sliceable range type.
Two adjacent separators are considered to surround an empty element in
the split range. Use filter!(a => !a.empty) on the result to compress
empty elements.
The predicate is passed to binaryFun and accepts
any callable function that can be executed via pred(element, s).
Note
If splitting a string on whitespace and token compression is desired,
consider using the ``splitter(r) overload.
Constraints
The predicate pred needs to accept an element of r and the
separator s.
Examples
Basic splitting with characters and numbers.
import std.algorithm.comparison : equal;
assert("a|bc|def".splitter('|').equal([ "a", "bc", "def" ]));
int[] a = [1, 0, 2, 3, 0, 4, 5, 6];
int[][] w = [ [1], [2, 3], [4, 5, 6] ];
assert(a.splitter(0).equal(w));
Basic splitting with characters and numbers and keeping sentinels.
import std.algorithm.comparison : equal;
import std.typecons : Yes;
assert("a|bc|def".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "a", "|", "bc", "|", "def" ]));
int[] a = [1, 0, 2, 3, 0, 4, 5, 6];
int[][] w = [ [1], [0], [2, 3], [0], [4, 5, 6] ];
assert(a.splitter!("a == b", Yes.keepSeparators)(0).equal(w));
Adjacent separators.
import std.algorithm.comparison : equal;
assert("|ab|".splitter('|').equal([ "", "ab", "" ]));
assert("ab".splitter('|').equal([ "ab" ]));
assert("a|b||c".splitter('|').equal([ "a", "b", "", "c" ]));
assert("hello world".splitter(' ').equal([ "hello", "", "world" ]));
auto a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
auto w = [ [1, 2], [], [3], [4, 5], [] ];
assert(a.splitter(0).equal(w));
Adjacent separators and keeping sentinels.
import std.algorithm.comparison : equal;
import std.typecons : Yes;
assert("|ab|".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "", "|", "ab", "|", "" ]));
assert("ab".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "ab" ]));
assert("a|b||c".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "a", "|", "b", "|", "", "|", "c" ]));
assert("hello world".splitter!("a == b", Yes.keepSeparators)(' ')
.equal([ "hello", " ", "", " ", "world" ]));
auto a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
auto w = [ [1, 2], [0], [], [0], [3], [0], [4, 5], [0], [] ];
assert(a.splitter!("a == b", Yes.keepSeparators)(0).equal(w));
Empty and separator-only ranges.
import std.algorithm.comparison : equal;
import std.range : empty;
assert("".splitter('|').empty);
assert("|".splitter('|').equal([ "", "" ]));
assert("||".splitter('|').equal([ "", "", "" ]));
Empty and separator-only ranges and keeping sentinels.
import std.algorithm.comparison : equal;
import std.typecons : Yes;
import std.range : empty;
assert("".splitter!("a == b", Yes.keepSeparators)('|').empty);
assert("|".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "", "|", "" ]));
assert("||".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "", "|", "", "|", "" ]));
Use a range for splitting
import std.algorithm.comparison : equal;
assert("a=>bc=>def".splitter("=>").equal([ "a", "bc", "def" ]));
assert("a|b||c".splitter("||").equal([ "a|b", "c" ]));
assert("hello world".splitter(" ").equal([ "hello", "world" ]));
int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
int[][] w = [ [1, 2], [3, 0, 4, 5, 0] ];
assert(a.splitter([0, 0]).equal(w));
a = [ 0, 0 ];
assert(a.splitter([0, 0]).equal([ (int[]).init, (int[]).init ]));
a = [ 0, 0, 1 ];
assert(a.splitter([0, 0]).equal([ [], [1] ]));
Use a range for splitting
import std.algorithm.comparison : equal;
import std.typecons : Yes;
assert("a=>bc=>def".splitter!("a == b", Yes.keepSeparators)("=>")
.equal([ "a", "=>", "bc", "=>", "def" ]));
assert("a|b||c".splitter!("a == b", Yes.keepSeparators)("||")
.equal([ "a|b", "||", "c" ]));
assert("hello world".splitter!("a == b", Yes.keepSeparators)(" ")
.equal([ "hello", " ", "world" ]));
int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
int[][] w = [ [1, 2], [0, 0], [3, 0, 4, 5, 0] ];
assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0]).equal(w));
a = [ 0, 0 ];
assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0])
.equal([ (int[]).init, [0, 0], (int[]).init ]));
a = [ 0, 0, 1 ];
assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0])
.equal([ [], [0, 0], [1] ]));
Custom predicate functions.
import std.algorithm.comparison : equal;
import std.ascii : toLower;
assert("abXcdxef".splitter!"a.toLower == b"('x').equal(
[ "ab", "cd", "ef" ]));
auto w = [ [0], [1], [2] ];
assert(w.splitter!"a.front == b"(1).equal([ [[0]], [[2]] ]));
Custom predicate functions.
import std.algorithm.comparison : equal;
import std.typecons : Yes;
import std.ascii : toLower;
assert("abXcdxef".splitter!("a.toLower == b", Yes.keepSeparators)('x')
.equal([ "ab", "X", "cd", "x", "ef" ]));
auto w = [ [0], [1], [2] ];
assert(w.splitter!("a.front == b", Yes.keepSeparators)(1)
.equal([ [[0]], [[1]], [[2]] ]));
Leading separators, trailing separators, or no separators.
import std.algorithm.comparison : equal;
assert("|ab|".splitter('|').equal([ "", "ab", "" ]));
assert("ab".splitter('|').equal([ "ab" ]));
Leading separators, trailing separators, or no separators.
import std.algorithm.comparison : equal;
import std.typecons : Yes;
assert("|ab|".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "", "|", "ab", "|", "" ]));
assert("ab".splitter!("a == b", Yes.keepSeparators)('|')
.equal([ "ab" ]));
Splitter returns bidirectional ranges if the delimiter is a single element
import std.algorithm.comparison : equal;
import std.range : retro;
assert("a|bc|def".splitter('|').retro.equal([ "def", "bc", "a" ]));
Splitter returns bidirectional ranges if the delimiter is a single element
import std.algorithm.comparison : equal;
import std.typecons : Yes;
import std.range : retro;
assert("a|bc|def".splitter!("a == b", Yes.keepSeparators)('|')
.retro.equal([ "def", "|", "bc", "|", "a" ]));
splitter(';').std.algorithm.iteration.MapResult!(strip, Result) std.algorithm.iteration.map!(strip).map!(std.algorithm.iteration.splitter!("a == b", Flag.no, string, char).Result)(std.algorithm.iteration.splitter!("a == b", Flag.no, string, char).Result r) pure nothrow @nogc @safeImplements the homonym function (also known as transform) present
in many languages of functional flavor. The call ``map!(fun)(range)
returns a range of which elements are obtained by applying fun(a)
left to right for all elements a in range. The original ranges are
not changed. Evaluation is done lazily.
Examples
import std.algorithm.comparison : equal;
import std.range : chain, only;
auto squares =
chain(only(1, 2, 3, 4), only(5, 6)).map!(a => a * a);
assert(equal(squares, only(1, 4, 9, 16, 25, 36)));
Multiple functions can be passed to map. In that case, the
element type of map is a tuple containing one element for each
function.
auto sums = [2, 4, 6, 8];
auto products = [1, 4, 9, 16];
size_t i = 0;
foreach (result; [ 1, 2, 3, 4 ].map!("a + a", "a * a"))
{
assert(result[0] == sums[i]);
assert(result[1] == products[i]);
++i;
}
You may alias map with some function(s) to a symbol and use
it separately:
import std.algorithm.comparison : equal;
import std.conv : to;
alias stringize = map!(to!string);
assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));
map!(template) 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
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.string[] std.array.array!(std.algorithm.iteration.MapResult!(strip, Result))(std.algorithm.iteration.MapResult!(strip, Result) r) pure @safeAllocates an array and initializes it with copies of the elements
of range r.
Narrow strings are handled as follows:
If autodecoding is turned on (default), then they are handled as a separate overload.
If autodecoding is turned off, then this is equivalent to duplicating the array.
array;
if ((local variable) string[] fieldsfields.(field) ulong string[].lengthlength < 2)
continue;
auto (local variable) string[] boundsbounds = (local variable) string[] fieldsfields[0].std.algorithm.iteration.splitter!("a == b", Flag.no, string, string).Result std.algorithm.iteration.splitter!("a == b", Flag.no, string, string)(string r, string s) pure nothrow @nogc @safeSplitter returns bidirectional ranges if the delimiter is a single element
splitter("..").string[] std.array.array!(std.algorithm.iteration.splitter!("a == b", Flag.no, string, string).Result)(std.algorithm.iteration.splitter!("a == b", Flag.no, string, string).Result r) pure nothrow @safeAllocates an array and initializes it with copies of the elements
of range r.
Narrow strings are handled as follows:
If autodecoding is turned on (default), then they are handled as a separate overload.
If autodecoding is turned off, then this is equivalent to duplicating the array.
array;
const (local variable) const(uint) firstfirst = uint sparkles.base.tools.gen_unicode_tables.parseHex(string text)parseHex((local variable) string[] boundsbounds[0]);
const (local variable) const(uint) lastlast = (local variable) string[] boundsbounds.(field) ulong string[].lengthlength == 2 ? uint sparkles.base.tools.gen_unicode_tables.parseHex(string text)parseHex((local variable) string[] boundsbounds[1]) : (local variable) const(uint) firstfirst;
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult.(field) sparkles.base.tools.gen_unicode_tables.WordBreakRange[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.wordBreakwordBreak ~= (struct) sparkles.base.tools.gen_unicode_tables.WordBreakRangeWordBreakRange((local variable) const(uint) firstfirst, (local variable) const(uint) lastlast, (local variable) string[] fieldsfields[1]);
}
(local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult.(field) sparkles.base.tools.gen_unicode_tables.WordBreakRange[] sparkles.base.tools.gen_unicode_tables.AnalysisTables.wordBreakwordBreak.sparkles.base.tools.gen_unicode_tables.buildAnalysisTables.SortedRange!(WordBreakRange[], __lambda_L409_C28, SortedRangeOptions.assumeSorted) sparkles.base.tools.gen_unicode_tables.buildAnalysisTables.sort!((a, b) => a.first < b.first, SwapStrategy.unstable, sparkles.base.tools.gen_unicode_tables.WordBreakRange[])(sparkles.base.tools.gen_unicode_tables.WordBreakRange[] 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!((a, b) => a.first < b.first);
return (local variable) sparkles.base.tools.gen_unicode_tables.AnalysisTables resultresult;
}
private uint[] uint[] sparkles.base.tools.gen_unicode_tables.expandDecomposition(uint cp, bool compatibility, ref sparkles.base.tools.gen_unicode_tables.UcdRecord[uint] records, ref uint[][uint] memo)expandDecomposition(uint (parameter) uint cpcp, bool (parameter) bool compatibilitycompatibility,
ref (struct) sparkles.base.tools.gen_unicode_tables.UcdRecordUcdRecord[uint] (parameter) sparkles.base.tools.gen_unicode_tables.UcdRecord[uint] recordsrecords, ref uint[][uint] (parameter) uint[][uint] memomemo)
{
if (auto (local variable) uint[]* cachedcached = (parameter) uint cpcp in (parameter) uint[][uint] memomemo)
return *(local variable) uint[]* cachedcached;
auto (local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord* recordrecord = (parameter) uint cpcp in (parameter) sparkles.base.tools.gen_unicode_tables.UcdRecord[uint] recordsrecords;
if ((local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord* recordrecord is null || !(local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord* recordrecord.(field) uint[] sparkles.base.tools.gen_unicode_tables.UcdRecord.decompositiondecomposition.(field) ulong uint[].lengthlength
|| (!(parameter) bool compatibilitycompatibility && (local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord* recordrecord.(field) bool sparkles.base.tools.gen_unicode_tables.UcdRecord.compatibilitycompatibility))
{
auto (local variable) uint[] identityidentity = [(parameter) uint cpcp];
uint[]* core.internal.newaa._d_aaGetY!(uint, uint[], uint[][uint], uint, uint[], uint)(ref scope uint[][uint] aa, ref uint key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
memo[uint[]* core.internal.newaa._d_aaGetY!(uint, uint[], uint[][uint], uint, uint[], uint)(ref scope uint[][uint] aa, ref uint key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
cp] = (local variable) uint[] identityidentity;
return (local variable) uint[] identityidentity;
}
uint[] (local variable) uint[] expandedexpanded;
foreach ((parameter) uint partpart; (local variable) sparkles.base.tools.gen_unicode_tables.UcdRecord* recordrecord.(field) uint[] sparkles.base.tools.gen_unicode_tables.UcdRecord.decompositiondecomposition)
(local variable) uint[] expandedexpanded ~= uint[] sparkles.base.tools.gen_unicode_tables.expandDecomposition(uint cp, bool compatibility, ref sparkles.base.tools.gen_unicode_tables.UcdRecord[uint] records, ref uint[][uint] memo)expandDecomposition((local variable) uint partpart, (parameter) bool compatibilitycompatibility, (parameter) sparkles.base.tools.gen_unicode_tables.UcdRecord[uint] recordsrecords, (parameter) uint[][uint] memomemo);
uint[]* core.internal.newaa._d_aaGetY!(uint, uint[], uint[][uint], uint, uint[], uint)(ref scope uint[][uint] aa, ref uint key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
memo[uint[]* core.internal.newaa._d_aaGetY!(uint, uint[], uint[][uint], uint, uint[], uint)(ref scope uint[][uint] aa, ref uint key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
cp] = (local variable) uint[] expandedexpanded;
return (local variable) uint[] expandedexpanded;
}
private uint uint sparkles.base.tools.gen_unicode_tables.parseHex(string text)parseHex((alias) object.string = stringstring (parameter) string texttext)
{
uint (local variable) uint valuevalue;
(parameter) string texttext.uint std.format.read.formattedRead!("%x", string, uint)(ref string r, ref uint __param_1) pure @safeReads an input range according to a format string and stores the read
values into its arguments.
Format specifiers with format character 'd', 'u' and 'c' can take a ''* parameter for skipping values.
The second version of formattedRead takes the format string as
template argument. In this case, it is checked for consistency at
compile-time.
Note
For backward compatibility the arguments args can be given as pointers
to that variable, but it is not recommended to do so, because this
option might be removed in the future.
Examples
string object;
char cmp;
int value;
assert(formattedRead("angle < 36", "%s %c %d", object, cmp, value) == 3);
assert(object == "angle");
assert(cmp == '<');
assert(value == 36);
// reading may end early:
assert(formattedRead("length >", "%s %c %d", object, cmp, value) == 2);
assert(object == "length");
assert(cmp == '>');
// value is not changed:
assert(value == 36);
The format string can be checked at compile-time:
string a;
int b;
double c;
assert("hello!124:34.5".formattedRead!"%s!%s:%s"(a, b, c) == 3);
assert(a == "hello");
assert(b == 124);
assert(c == 34.5);
Skipping values
string item;
double amount;
assert("orange: (12%) 15.25".formattedRead("%s: (%*d%%) %f", item, amount) == 2);
assert(item == "orange");
assert(amount == 15.25);
// can also be used with tuples
import std.typecons : Tuple;
Tuple!(int, float) t;
char[] line = "1 7643 2.125".dup;
formattedRead(line, "%s %*u %s", t);
assert(t[0] == 1 && t[1] == 2.125);
formattedRead!"%x"((local variable) uint valuevalue);
return (local variable) uint valuevalue;
}
private enum (constant) string sparkles.base.tools.gen_unicode_tables.analysisTypesSource = "\n/// A borrowed span inside one of the generated flat Unicode mapping arrays.\nstruct UnicodeMappingSpan\n{\n uint offset;\n ubyte length;\n}\n\nprivate struct UnicodeSequenceIndex\n{\n uint codepoint;\n uint offset;\n ubyte length;\n}\n\nprivate struct UnicodeScalarIndex\n{\n uint codepoint;\n uint value;\n}\n\nprivate UnicodeMappingSpan findUnicodeSequence(scope const(UnicodeSequenceIndex)[] index,\n dchar ch) @safe pure nothrow @nogc\n{\n size_t lo;\n size_t hi = index.length;\n while (lo < hi)\n {\n const mid = lo + (hi - lo) / 2;\n if (index[mid].codepoint < ch)\n lo = mid + 1;\n else\n hi = mid;\n }\n return lo < index.length && index[lo].codepoint == ch\n ? UnicodeMappingSpan(index[lo].offset, index[lo].length)\n : UnicodeMappingSpan.init;\n}\n\nprivate dchar findUnicodeScalar(scope const(UnicodeScalarIndex)[] index,\n dchar ch) @safe pure nothrow @nogc\n{\n size_t lo;\n size_t hi = index.length;\n while (lo < hi)\n {\n const mid = lo + (hi - lo) / 2;\n if (index[mid].codepoint < ch)\n lo = mid + 1;\n else\n hi = mid;\n }\n return lo < index.length && index[lo].codepoint == ch\n ? cast(dchar) index[lo].value : ch;\n}\n\nprivate uint findUnicodeProperty(scope const(UnicodeScalarIndex)[] index,\n dchar ch) @safe pure nothrow @nogc\n{\n size_t lo;\n size_t hi = index.length;\n while (lo < hi)\n {\n const mid = lo + (hi - lo) / 2;\n if (index[mid].codepoint < ch)\n lo = mid + 1;\n else\n hi = mid;\n }\n return lo < index.length && index[lo].codepoint == ch\n ? index[lo].value : 0;\n}\n"analysisTypesSource = q{
/// A borrowed span inside one of the generated flat Unicode mapping arrays.
struct UnicodeMappingSpan
{
uint offset;
ubyte length;
}
private struct UnicodeSequenceIndex
{
uint codepoint;
uint offset;
ubyte length;
}
private struct UnicodeScalarIndex
{
uint codepoint;
uint value;
}
private UnicodeMappingSpan findUnicodeSequence(scope const(UnicodeSequenceIndex)[] index,
dchar ch) @safe pure nothrow @nogc
{
size_t lo;
size_t hi = index.length;
while (lo < hi)
{
const mid = lo + (hi - lo) / 2;
if (index[mid].codepoint < ch)
lo = mid + 1;
else
hi = mid;
}
return lo < index.length && index[lo].codepoint == ch
? UnicodeMappingSpan(index[lo].offset, index[lo].length)
: UnicodeMappingSpan.init;
}
private dchar findUnicodeScalar(scope const(UnicodeScalarIndex)[] index,
dchar ch) @safe pure nothrow @nogc
{
size_t lo;
size_t hi = index.length;
while (lo < hi)
{
const mid = lo + (hi - lo) / 2;
if (index[mid].codepoint < ch)
lo = mid + 1;
else
hi = mid;
}
return lo < index.length && index[lo].codepoint == ch
? cast(dchar) index[lo].value : ch;
}
private uint findUnicodeProperty(scope const(UnicodeScalarIndex)[] index,
dchar ch) @safe pure nothrow @nogc
{
size_t lo;
size_t hi = index.length;
while (lo < hi)
{
const mid = lo + (hi - lo) / 2;
if (index[mid].codepoint < ch)
lo = mid + 1;
else
hi = mid;
}
return lo < index.length && index[lo].codepoint == ch
? index[lo].value : 0;
}
};
private (alias) object.string = stringstring string sparkles.base.tools.gen_unicode_tables.sequenceTableSource(string name, const(sparkles.base.tools.gen_unicode_tables.SequenceMapping)[] mappings)sequenceTableSource((alias) object.string = stringstring (parameter) string namename,
const((struct) sparkles.base.tools.gen_unicode_tables.SequenceMappingSequenceMapping)[] (parameter) const(sparkles.base.tools.gen_unicode_tables.SequenceMapping)[] mappingsmappings)
{
auto (local variable) std.array.Appender!string datadata = 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;
auto (local variable) std.array.Appender!string indexindex = 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;
uint (local variable) uint offsetoffset;
(local variable) std.array.Appender!string datadata.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put("private immutable uint[] " ~ (parameter) string namename ~ "Data = [\n ");
(local variable) std.array.Appender!string indexindex.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put("private immutable UnicodeSequenceIndex[] " ~ (parameter) string namename
~ "Index = [\n");
(alias) object.size_t = ulongsize_t (local variable) ulong columncolumn;
foreach ((parameter) const(sparkles.base.tools.gen_unicode_tables.SequenceMapping) mappingmapping; (parameter) const(sparkles.base.tools.gen_unicode_tables.SequenceMapping)[] mappingsmappings)
{
(local variable) std.array.Appender!string indexindex.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put(string std.format.format!(char, const(uint), uint, ulong)(in char[] fmt, const(uint) __param_1, uint __param_2, ulong __param_3) pure @safeConverts 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.
Examples
assert(format("Here are %d %s.", 3, "apples") == "Here are 3 apples.");
assert("Increase: %7.2f %%".format(17.4285) == "Increase: 17.43 %");
format(" UnicodeSequenceIndex(0x%X, %s, %s),\n",
(local variable) const(sparkles.base.tools.gen_unicode_tables.SequenceMapping) mappingmapping.(field) uint sparkles.base.tools.gen_unicode_tables.SequenceMapping.codepointcodepoint, (local variable) uint offsetoffset, (local variable) const(sparkles.base.tools.gen_unicode_tables.SequenceMapping) mappingmapping.(field) uint[] sparkles.base.tools.gen_unicode_tables.SequenceMapping.valuesvalues.(field) ulong const(uint[]).lengthlength));
foreach ((parameter) const(uint) valuevalue; (local variable) const(sparkles.base.tools.gen_unicode_tables.SequenceMapping) mappingmapping.(field) uint[] sparkles.base.tools.gen_unicode_tables.SequenceMapping.valuesvalues)
{
if ((local variable) ulong columncolumn != 0)
(local variable) std.array.Appender!string datadata.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put((local variable) ulong columncolumn % 10 == 0 ? "\n " : " ");
(local variable) std.array.Appender!string datadata.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put(string std.format.format!(char, const(uint))(in char[] fmt, const(uint) __param_1) pure @safeConverts 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.
Examples
assert(format("Here are %d %s.", 3, "apples") == "Here are 3 apples.");
assert("Increase: %7.2f %%".format(17.4285) == "Increase: 17.43 %");
format("0x%X,", (local variable) const(uint) valuevalue));
++(local variable) ulong columncolumn;
}
(local variable) uint offsetoffset += (local variable) const(sparkles.base.tools.gen_unicode_tables.SequenceMapping) mappingmapping.(field) uint[] sparkles.base.tools.gen_unicode_tables.SequenceMapping.valuesvalues.(field) ulong const(uint[]).lengthlength.uint std.conv.to!uint.to!ulong(ulong __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!uint;
}
(local variable) std.array.Appender!string datadata.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put("\n];\n");
(local variable) std.array.Appender!string indexindex.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put("];\n");
return (local variable) std.array.Appender!string datadata.string std.array.Appender!string.data() inout pure nothrow @nogc @property @safeUse opSlice() from now on.
data ~ (local variable) std.array.Appender!string indexindex.string std.array.Appender!string.data() inout pure nothrow @nogc @property @safeUse opSlice() from now on.
data ~ string std.format.format!(char, string)(in char[] fmt, string __param_1) pure @safeConverts 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.
Examples
assert(format("Here are %d %s.", 3, "apples") == "Here are 3 apples.");
assert("Increase: %7.2f %%".format(17.4285) == "Increase: 17.43 %");
format(q{
UnicodeMappingSpan %1$s(dchar ch) @safe pure nothrow @nogc
{
return findUnicodeSequence(%1$sIndex, ch);
}
dchar %1$sValue(size_t offset) @safe pure nothrow @nogc
{
return cast(dchar) %1$sData[offset];
}
}, (parameter) string namename);
}
private (alias) object.string = stringstring string sparkles.base.tools.gen_unicode_tables.scalarTableSource(string name, const(sparkles.base.tools.gen_unicode_tables.ScalarMapping)[] mappings)scalarTableSource((alias) object.string = stringstring (parameter) string namename, const((struct) sparkles.base.tools.gen_unicode_tables.ScalarMappingScalarMapping)[] (parameter) const(sparkles.base.tools.gen_unicode_tables.ScalarMapping)[] mappingsmappings)
{
auto (local variable) std.array.Appender!string sourcesource = 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 sourcesource.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put("private immutable UnicodeScalarIndex[] " ~ (parameter) string namename ~ "Index = [\n");
foreach ((parameter) const(sparkles.base.tools.gen_unicode_tables.ScalarMapping) mappingmapping; (parameter) const(sparkles.base.tools.gen_unicode_tables.ScalarMapping)[] mappingsmappings)
(local variable) std.array.Appender!string sourcesource.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put(string std.format.format!(char, const(uint), const(uint))(in char[] fmt, const(uint) __param_1, const(uint) __param_2) pure @safeConverts 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.
Examples
assert(format("Here are %d %s.", 3, "apples") == "Here are 3 apples.");
assert("Increase: %7.2f %%".format(17.4285) == "Increase: 17.43 %");
format(" UnicodeScalarIndex(0x%X, 0x%X),\n",
(local variable) const(sparkles.base.tools.gen_unicode_tables.ScalarMapping) mappingmapping.(field) uint sparkles.base.tools.gen_unicode_tables.ScalarMapping.codepointcodepoint, (local variable) const(sparkles.base.tools.gen_unicode_tables.ScalarMapping) mappingmapping.(field) uint sparkles.base.tools.gen_unicode_tables.ScalarMapping.valuevalue));
(local variable) std.array.Appender!string sourcesource.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put("];\n");
(local variable) std.array.Appender!string sourcesource.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put(string std.format.format!(char, string)(in char[] fmt, string __param_1) pure @safeConverts 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.
Examples
assert(format("Here are %d %s.", 3, "apples") == "Here are 3 apples.");
assert("Increase: %7.2f %%".format(17.4285) == "Increase: 17.43 %");
format(q{
dchar %1$s(dchar ch) @safe pure nothrow @nogc
{
return findUnicodeScalar(%1$sIndex, ch);
}
}, (parameter) string namename));
return (local variable) std.array.Appender!string sourcesource.string std.array.Appender!string.data() inout pure nothrow @nogc @property @safeUse opSlice() from now on.
data;
}
private (alias) object.string = stringstring string sparkles.base.tools.gen_unicode_tables.scalarPropertyTableSource(string name, const(sparkles.base.tools.gen_unicode_tables.ScalarMapping)[] mappings)scalarPropertyTableSource((alias) object.string = stringstring (parameter) string namename,
const((struct) sparkles.base.tools.gen_unicode_tables.ScalarMappingScalarMapping)[] (parameter) const(sparkles.base.tools.gen_unicode_tables.ScalarMapping)[] mappingsmappings)
{
auto (local variable) std.array.Appender!string sourcesource = 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 sourcesource.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put("private immutable UnicodeScalarIndex[] " ~ (parameter) string namename
~ "Index = [\n");
foreach ((parameter) const(sparkles.base.tools.gen_unicode_tables.ScalarMapping) mappingmapping; (parameter) const(sparkles.base.tools.gen_unicode_tables.ScalarMapping)[] mappingsmappings)
(local variable) std.array.Appender!string sourcesource.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put(string std.format.format!(char, const(uint), const(uint))(in char[] fmt, const(uint) __param_1, const(uint) __param_2) pure @safeConverts 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.
Examples
assert(format("Here are %d %s.", 3, "apples") == "Here are 3 apples.");
assert("Increase: %7.2f %%".format(17.4285) == "Increase: 17.43 %");
format(" UnicodeScalarIndex(0x%X, 0x%X),\n",
(local variable) const(sparkles.base.tools.gen_unicode_tables.ScalarMapping) mappingmapping.(field) uint sparkles.base.tools.gen_unicode_tables.ScalarMapping.codepointcodepoint, (local variable) const(sparkles.base.tools.gen_unicode_tables.ScalarMapping) mappingmapping.(field) uint sparkles.base.tools.gen_unicode_tables.ScalarMapping.valuevalue));
(local variable) std.array.Appender!string sourcesource.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put("];\n");
(local variable) std.array.Appender!string sourcesource.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put(string std.format.format!(char, string)(in char[] fmt, string __param_1) pure @safeConverts 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.
Examples
assert(format("Here are %d %s.", 3, "apples") == "Here are 3 apples.");
assert("Increase: %7.2f %%".format(17.4285) == "Increase: 17.43 %");
format(q{
ubyte %1$s(dchar ch) @safe pure nothrow @nogc
{
return cast(ubyte) findUnicodeProperty(%1$sIndex, ch);
}
}, (parameter) string namename));
return (local variable) std.array.Appender!string sourcesource.string std.array.Appender!string.data() inout pure nothrow @nogc @property @safeUse opSlice() from now on.
data;
}
private (alias) object.string = stringstring string sparkles.base.tools.gen_unicode_tables.compositionTableSource(const(sparkles.base.tools.gen_unicode_tables.CompositionMapping)[] mappings)compositionTableSource(const((struct) sparkles.base.tools.gen_unicode_tables.CompositionMappingCompositionMapping)[] (parameter) const(sparkles.base.tools.gen_unicode_tables.CompositionMapping)[] mappingsmappings)
{
auto (local variable) std.array.Appender!string sourcesource = 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 sourcesource.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put(q{
private struct UnicodeComposition
{
ulong key;
uint value;
}
private immutable UnicodeComposition[] unicodeCompositions = [
});
foreach ((parameter) const(sparkles.base.tools.gen_unicode_tables.CompositionMapping) mappingmapping; (parameter) const(sparkles.base.tools.gen_unicode_tables.CompositionMapping)[] mappingsmappings)
{
const (local variable) const(ulong) keykey = (cast(ulong) (local variable) const(sparkles.base.tools.gen_unicode_tables.CompositionMapping) mappingmapping.(field) uint sparkles.base.tools.gen_unicode_tables.CompositionMapping.firstfirst << 21) | (local variable) const(sparkles.base.tools.gen_unicode_tables.CompositionMapping) mappingmapping.(field) uint sparkles.base.tools.gen_unicode_tables.CompositionMapping.secondsecond;
(local variable) std.array.Appender!string sourcesource.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put(string std.format.format!(char, const(ulong), const(uint))(in char[] fmt, const(ulong) __param_1, const(uint) __param_2) pure @safeConverts 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.
Examples
assert(format("Here are %d %s.", 3, "apples") == "Here are 3 apples.");
assert("Increase: %7.2f %%".format(17.4285) == "Increase: 17.43 %");
format(" UnicodeComposition(0x%X, 0x%X),\n",
(local variable) const(ulong) keykey, (local variable) const(sparkles.base.tools.gen_unicode_tables.CompositionMapping) mappingmapping.(field) uint sparkles.base.tools.gen_unicode_tables.CompositionMapping.valuevalue));
}
(local variable) std.array.Appender!string sourcesource.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put(q{];
dchar canonicalComposition(dchar first, dchar second)
@safe pure nothrow @nogc
{
const key = (cast(ulong) first << 21) | cast(uint) second;
size_t lo;
size_t hi = unicodeCompositions.length;
while (lo < hi)
{
const mid = lo + (hi - lo) / 2;
if (unicodeCompositions[mid].key < key)
lo = mid + 1;
else
hi = mid;
}
return lo < unicodeCompositions.length && unicodeCompositions[lo].key == key
? cast(dchar) unicodeCompositions[lo].value : dchar.init;
}
});
return (local variable) std.array.Appender!string sourcesource.string std.array.Appender!string.data() inout pure nothrow @nogc @property @safeUse opSlice() from now on.
data;
}
private (alias) object.string = stringstring string sparkles.base.tools.gen_unicode_tables.wordBreakMember(string property)wordBreakMember((alias) object.string = stringstring (parameter) string propertyproperty)
{
switch ((parameter) string propertyproperty)
{
case "CR": return "cr";
case "LF": return "lf";
case "Newline": return "newline";
case "Extend": return "extend";
case "ZWJ": return "zwj";
case "Regional_Indicator": return "regionalIndicator";
case "Format": return "format";
case "Katakana": return "katakana";
case "Hebrew_Letter": return "hebrewLetter";
case "ALetter": return "aLetter";
case "Single_Quote": return "singleQuote";
case "Double_Quote": return "doubleQuote";
case "MidNumLet": return "midNumLet";
case "MidLetter": return "midLetter";
case "MidNum": return "midNum";
case "Numeric": return "numeric";
case "ExtendNumLet": return "extendNumLet";
case "WSegSpace": return "wSegSpace";
default: return "other";
}
}
private (alias) object.string = stringstring string sparkles.base.tools.gen_unicode_tables.wordBreakTableSource(const(sparkles.base.tools.gen_unicode_tables.WordBreakRange)[] ranges)wordBreakTableSource(const((struct) sparkles.base.tools.gen_unicode_tables.WordBreakRangeWordBreakRange)[] (parameter) const(sparkles.base.tools.gen_unicode_tables.WordBreakRange)[] rangesranges)
{
auto (local variable) std.array.Appender!string sourcesource = 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 sourcesource.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put(q{
enum WordBreakClass : ubyte
{
other, cr, lf, newline, extend, zwj, regionalIndicator, format,
katakana, hebrewLetter, aLetter, singleQuote, doubleQuote,
midNumLet, midLetter, midNum, numeric, extendNumLet, wSegSpace,
}
private struct WordBreakRange
{
uint first;
uint last;
WordBreakClass kind;
}
private immutable WordBreakRange[] wordBreakRanges = [
});
foreach ((parameter) const(sparkles.base.tools.gen_unicode_tables.WordBreakRange) rangerange; (parameter) const(sparkles.base.tools.gen_unicode_tables.WordBreakRange)[] rangesranges)
(local variable) std.array.Appender!string sourcesource.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put(string std.format.format!(char, const(uint), const(uint), string)(in char[] fmt, const(uint) __param_1, const(uint) __param_2, string __param_3) pure @safeConverts 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.
Examples
assert(format("Here are %d %s.", 3, "apples") == "Here are 3 apples.");
assert("Increase: %7.2f %%".format(17.4285) == "Increase: 17.43 %");
format(" WordBreakRange(0x%X, 0x%X, WordBreakClass.%s),\n",
(local variable) const(sparkles.base.tools.gen_unicode_tables.WordBreakRange) rangerange.(field) uint sparkles.base.tools.gen_unicode_tables.WordBreakRange.firstfirst, (local variable) const(sparkles.base.tools.gen_unicode_tables.WordBreakRange) rangerange.(field) uint sparkles.base.tools.gen_unicode_tables.WordBreakRange.lastlast, string sparkles.base.tools.gen_unicode_tables.wordBreakMember(string property)wordBreakMember((local variable) const(sparkles.base.tools.gen_unicode_tables.WordBreakRange) rangerange.(field) string sparkles.base.tools.gen_unicode_tables.WordBreakRange.propertyproperty)));
(local variable) std.array.Appender!string sourcesource.void std.array.Appender!string.put!string(string items) pure nothrow @safeAppends an entire range to the managed array. Performs encoding for
char elements if A is a differently typed char array.
put(q{];
WordBreakClass wordBreakClass(dchar ch) @safe pure nothrow @nogc
{
size_t lo;
size_t hi = wordBreakRanges.length;
while (lo < hi)
{
const mid = lo + (hi - lo) / 2;
if (wordBreakRanges[mid].last < ch)
lo = mid + 1;
else
hi = mid;
}
return lo < wordBreakRanges.length
&& wordBreakRanges[lo].first <= ch
? wordBreakRanges[lo].kind : WordBreakClass.other;
}
});
return (local variable) std.array.Appender!string sourcesource.string std.array.Appender!string.data() inout pure nothrow @nogc @property @safeUse opSlice() from now on.
data;
}
private (alias) object.string = stringstring string sparkles.base.tools.gen_unicode_tables.header(string ver)header((alias) object.string = stringstring (parameter) string verver)
{
return string std.format.format!(char, string)(in char[] fmt, string __param_1) pure @safeConverts 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.
Examples
assert(format("Here are %d %s.", 3, "apples") == "Here are 3 apples.");
assert("Increase: %7.2f %%".format(17.4285) == "Increase: 17.43 %");
format(`
// Generated by libs/base/tools/gen_unicode_tables.d — DO NOT EDIT.
//
// Unicode %s width, emoji, normalization, folding, combining-class,
// and word-break properties used by sparkles' text primitives.
// Regenerate by running ./libs/base/tools/gen_unicode_tables.d.
module sparkles.base.text.unicode_tables;
`.string std.string.outdent!string(string str) pure @safeRemoves one level of indentation from a multi-line string.
This uniformly outdents the text as much as possible.
Whitespace-only lines are always converted to blank lines.
Does not allocate memory if it does not throw.
Examples
enum pretty = q{
import std.stdio;
void main() {
writeln("Hello");
}
}.outdent();
enum ugly = q{
import std.stdio;
void main() {
writeln("Hello");
}
};
assert(pretty == ugly);
outdent[1 .. $], (parameter) string verver);
}