relocation-join.dhover×285all
#!/usr/bin/env dub
/+ dub.sdl:
    name "autological_relocation_join"
    targetPath "build"
    dflags "-preview=in" "-preview=dip1000"
    buildType "checked" {
        buildOptions "optimize" "inline" "debugInfo"
    }
+/
/**
 * "If relocations are a join, the loader is a query engine" — executed.
 *
 * The catalog's cluster-D claim is that `ld.so` computes, at every single
 * process start, the answer to a query it has already answered identically
 * thousands of times: for each undefined symbol, which object in the search
 * scope defines it? This program implements that query over a small in-memory
 * relational model — `objects`, `needs`, `defines`, `undefined` — and prints:
 *
 *   1. The **scope order**: a breadth-first walk of `DT_NEEDED` from the
 *      executable, deduplicated on first sight. This is the ordering rule
 *      `ld.so` uses, and it is why the *shape* of the dependency graph, not
 *      just its contents, decides which definition wins.
 *   2. The **join**, resolved under first-wins interposition, with the number
 *      of scope probes each lookup cost.
 *   3. The same computation with an `LD_PRELOAD` object spliced in at the front
 *      — SELF's "`LD_PRELOAD` becomes a row" claim, shown as exactly that: one
 *      inserted tuple, no other change, different answers.
 *   4. A **cost summary** demonstrating the confounder the measurement page
 *      warns about: the work is proportional to the *object count* traversed,
 *      not to the byte size of anything.
 *   5. The identical query written as SQL and as Datalog, so the tree's
 *      "SQL or Datalog?" open question can be read rather than argued: the
 *      transitive part is one line in Datalog and a recursive CTE in SQL.
 *
 * Nothing here is a simulation of performance — it is a statement of *what is
 * being computed*. The interesting number is the probe count, because that is
 * the quantity a materialized view (`prelink`, or a resolved-address table
 * stored in the artifact) would drive to zero.
 *
 * Companions:
 *   docs/research/autological-artifacts/dynamic-linking.md
 *   docs/research/autological-artifacts/code-as-database.md
 *   docs/research/autological-artifacts/measurement.md
 *   docs/research/autological-artifacts/self-selfdb/index.md
 *
 * Run with: `dub run --single relocation-join.d`
 *
 * Portability: pure `std`, no I/O beyond stdout. Deterministic everywhere.
 */
module 
(module) autological_relocation_join

"If relocations are a join, the loader is a query engine" — executed.

The catalog's cluster-D claim is that ld.so computes, at every single process start, the answer to a query it has already answered identically thousands of times: for each undefined symbol, which object in the search scope defines it? This program implements that query over a small in-memory relational model — objects, needs, defines, undefined — and prints:

  1. The scope order: a breadth-first walk of DT_NEEDED from the executable, deduplicated on first sight. This is the ordering rule ld.so uses, and it is why the shape of the dependency graph, not just its contents, decides which definition wins.

  2. The join, resolved under first-wins interposition, with the number of scope probes each lookup cost.

  3. The same computation with an LD_PRELOAD object spliced in at the front — SELF's "LD_PRELOAD becomes a row" claim, shown as exactly that: one inserted tuple, no other change, different answers.

  4. A cost summary demonstrating the confounder the measurement page warns about: the work is proportional to the object count traversed, not to the byte size of anything.

  5. The identical query written as SQL and as Datalog, so the tree's "SQL or Datalog?" open question can be read rather than argued: the transitive part is one line in Datalog and a recursive CTE in SQL.

Nothing here is a simulation of performance — it is a statement of what is being computed. The interesting number is the probe count, because that is the quantity a materialized view (prelink, or a resolved-address table stored in the artifact) would drive to zero.

Companions

docs/research/autological-artifacts/dynamic-linking.md docs/research/autological-artifacts/code-as-database.md docs/research/autological-artifacts/measurement.md docs/research/autological-artifacts/self-selfdb/index.md

Run with: dub run --single relocation-join.d

Portability

pure std, no I/O beyond stdout. Deterministic everywhere.

autological_relocation_join
;
import
(package) std
std
.
(module) std.algorithm

This 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

@copyrightAndrei Alexandrescu 2008-.@licenseBoost License 1.0.@authorsAndrei Alexandrescu
algorithm
:
(alias template) autological_relocation_join.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.

@seeamong for checking a value against multiple arguments.
canFind
,
(alias template) autological_relocation_join.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).

@parampredicate Function to apply to each element of range@returnsAn input range that contains the filtered elements. If range is at least a forward range, the return value of filter will also be a forward range.@seeFilter (higher-order function), filterBidirectional
filter
,
(alias template) autological_relocation_join.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.

@paramfun one or more transformation functions@seeMap (higher-order function)
map
,
(alias template) autological_relocation_join.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.

@paramseed the initial value of the summation@paramr a finite input range@returnsThe sum of all the elements in the range r.
sum
;
import
(package) std
std
.
(module) std.array

Functions 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

@copyrightCopyright Andrei Alexandrescu 2008- and Jonathan M Davis 2011-.@licenseBoost License 1.0.@authorsAndrei Alexandrescu and Jonathan M Davis
array
:
(alias template) autological_relocation_join.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.

@paramr range (or aggregate with opApply function) whose elements are copied into the allocated array@returnsallocated and initialized array
array
,
(alias template) autological_relocation_join.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.

@paramror An input range of input ranges@paramsep An input range, or a single element, to join the ranges on@returnsAn array of elements@seeFor a lazy version, see joiner
join
;
import
(package) std
std
.
(module) std.conv

A 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

@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Shin Fujishiro, Adam D. Ruppe, Kenji Hara
conv
:
(alias template) autological_relocation_join.text = std.conv.text(T...)(T args) if (T.length > 0)

Convenience functions for converting one or more arguments of any type into text (the three character widths).

text
;
import
(package) std
std
.
(module) std.stdio
Category Symbols
File handles _popen File isFileHandle openNetwork stderr stdin stdout
Reading chunks lines readf readfln readln
Writing toFile write writef writefln writeln
Misc KeepTerminator LockType StdioException

Standard I/O functions that extend core.stdc.stdio. core.stdc.stdio is publically imported when importing std.stdio.

There are three layers of I/O:

  1. The lowest layer is the operating system layer. The two main schemes are Windows and Posix.

  2. C's stdio.h which unifies the two operating system schemes.

  3. std.stdio, this module, unifies the various stdio.h implementations into a high level package for D programs.

Source

std/stdio.d

@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Alex Rønne Petersen
stdio
:
(alias template) autological_relocation_join.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))

Equivalent to writef(fmt, args, '\n').

writefln
,
(alias template) autological_relocation_join.writeln = std.stdio.writeln(T...)(T args)

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
/// One shared object in the model: the `objects` table, with its columns. struct
(struct) autological_relocation_join.Object

One shared object in the model: the objects table, with its columns.

Object
{
(alias) object.string = string
string
(field) string autological_relocation_join.Object.soname
soname
;
(alias) object.string = string
string
[]
(field) string[] autological_relocation_join.Object.needs
needs
; // the DT_NEEDED edges
(alias) object.string = string
string
[]
(field) string[] autological_relocation_join.Object.defines
defines
; // exported definitions
(alias) object.string = string
string
[]
(field) string[] autological_relocation_join.Object.undefined
undefined
; // symbols this object must have resolved
} /// One resolved relocation: the join's output row. struct
(struct) autological_relocation_join.Resolution

One resolved relocation: the join's output row.

Resolution
{
(alias) object.string = string
string
(field) string autological_relocation_join.Resolution.referrer
referrer
;
(alias) object.string = string
string
(field) string autological_relocation_join.Resolution.symbol
symbol
;
(alias) object.string = string
string
(field) string autological_relocation_join.Resolution.provider
provider
; // null when unresolved
(alias) object.size_t = ulong
size_t
(field) ulong autological_relocation_join.Resolution.probes
probes
; // objects examined before the answer was found
} /++ The scope order `ld.so` builds: breadth-first over `DT_NEEDED`, first sight wins. Depth-first would produce a different order and therefore different interposition winners; the breadth-first rule is the one glibc implements, and stating it is half the point of this program — the answer to the query depends on a traversal order that lives in the loader, not in the data. +/
(alias) object.string = string
string
[]
string[] autological_relocation_join.scopeOrder(in autological_relocation_join.Object[string] world, string root, string[] preload = null) @safe

The scope order ld.so builds: breadth-first over DT_NEEDED, first sight wins.

Depth-first would produce a different order and therefore different interposition winners; the breadth-first rule is the one glibc implements, and stating it is half the point of this program — the answer to the query depends on a traversal order that lives in the loader, not in the data.

scopeOrder
(in
(struct) autological_relocation_join.Object

One shared object in the model: the objects table, with its columns.

Object
[
(alias) object.string = string
string
]
(parameter) const(autological_relocation_join.Object[string]) world
world
,
(alias) object.string = string
string
(parameter) string root
root
,
(alias) object.string = string
string
[]
(parameter) string[] preload
preload
= null) @safe
{
(alias) object.string = string
string
[]
(local variable) string[] order
order
;
bool[
(alias) object.string = string
string
]
(local variable) bool[string] seen
seen
;
void
void autological_relocation_join.scopeOrder.admit(string name) pure nothrow @safe
admit
(
(alias) object.string = string
string
(parameter) string name
name
)
{ if (
(parameter) string name
name
in
(local variable) bool[string] seen
seen
)
return;
bool* core.internal.newaa._d_aaGetY!(string, bool, bool[string], string, bool, string)(ref scope bool[string] aa, ref string key, out bool found) pure nothrow @safe

Lookup key in aa. Called only from implementation of (aakey) expressions when value is mutable.

@paramaa associative array@paramkey reference to the key value@paramfound returns whether the key was found or a new entry was added@returnsif key was in the aa, a mutable pointer to the existing value. If key was not in the aa, a mutable pointer to newly inserted value which is set to zero
seen
[
bool* core.internal.newaa._d_aaGetY!(string, bool, bool[string], string, bool, string)(ref scope bool[string] aa, ref string key, out bool found) pure nothrow @safe

Lookup key in aa. Called only from implementation of (aakey) expressions when value is mutable.

@paramaa associative array@paramkey reference to the key value@paramfound returns whether the key was found or a new entry was added@returnsif key was in the aa, a mutable pointer to the existing value. If key was not in the aa, a mutable pointer to newly inserted value which is set to zero
name
] = true;
(local variable) string[] order
order
~=
(parameter) string name
name
;
}
void autological_relocation_join.scopeOrder.admit(string name) pure nothrow @safe
admit
(
(parameter) string root
root
);
// `LD_PRELOAD` objects are admitted immediately after the executable and // before anything the executable needs — which is the whole mechanism. foreach (
(parameter) string p
p
;
(parameter) string[] preload
preload
)
void autological_relocation_join.scopeOrder.admit(string name) pure nothrow @safe
admit
(
(local variable) string p
p
);
for (
(alias) object.size_t = ulong
size_t
(local variable) ulong i
i
= 0; i < order.length; i++)
{ if (auto
(local variable) const(autological_relocation_join.Object)* o
o
=
(local variable) string[] order
order
[
(local variable) ulong i
i
] in
(parameter) const(autological_relocation_join.Object[string]) world
world
)
foreach (
(parameter) const(string) n
n
;
(local variable) const(autological_relocation_join.Object)* o
o
.
(field) string[] autological_relocation_join.Object.needs
needs
)
void autological_relocation_join.scopeOrder.admit(string name) pure nothrow @safe
admit
(
(local variable) const(string) n
n
);
} return
(local variable) string[] order
order
;
} /++ The join itself: for every undefined symbol, the first definition in scope order. `probes` counts how many objects were examined. In glibc this is a `.gnu.hash` bloom-filter test per object followed by a bucket walk on a hit; the count below is the number of objects the loader must at minimum touch, which is the quantity that scales with object count rather than with image size. +/
(struct) autological_relocation_join.Resolution

One resolved relocation: the join's output row.

Resolution
[]
autological_relocation_join.Resolution[] autological_relocation_join.resolve(in autological_relocation_join.Object[string] world, in string[] order) @safe

The join itself: for every undefined symbol, the first definition in scope order.

probes counts how many objects were examined. In glibc this is a .gnu.hash bloom-filter test per object followed by a bucket walk on a hit; the count below is the number of objects the loader must at minimum touch, which is the quantity that scales with object count rather than with image size.

resolve
(in
(struct) autological_relocation_join.Object

One shared object in the model: the objects table, with its columns.

Object
[
(alias) object.string = string
string
]
(parameter) const(autological_relocation_join.Object[string]) world
world
, in
(alias) object.string = string
string
[]
(parameter) const(string[]) order
order
) @safe
{
(struct) autological_relocation_join.Resolution

One resolved relocation: the join's output row.

Resolution
[]
(local variable) autological_relocation_join.Resolution[] out_
out_
;
foreach (
(parameter) const(string) referrer
referrer
;
(parameter) const(string[]) order
order
)
{ const
(local variable) const(autological_relocation_join.Object*) o
o
=
(local variable) const(string) referrer
referrer
in
(parameter) const(autological_relocation_join.Object[string]) world
world
;
if (
(local variable) const(autological_relocation_join.Object*) o
o
is null)
continue; foreach (
(parameter) const(string) sym
sym
;
(local variable) const(autological_relocation_join.Object*) o
o
.
(field) string[] autological_relocation_join.Object.undefined
undefined
)
{
(alias) object.size_t = ulong
size_t
(local variable) ulong probes
probes
;
(alias) object.string = string
string
(local variable) string provider
provider
;
foreach (
(parameter) const(string) candidate
candidate
;
(parameter) const(string[]) order
order
)
{
(local variable) ulong probes
probes
++;
if (auto
(local variable) const(autological_relocation_join.Object)* c
c
=
(local variable) const(string) candidate
candidate
in
(parameter) const(autological_relocation_join.Object[string]) world
world
)
if (
(local variable) const(autological_relocation_join.Object)* c
c
.
(field) string[] autological_relocation_join.Object.defines
defines
.
bool std.algorithm.searching.canFind!().canFind!(const(string)[], string)(const(string)[] haystack, scope string needle) pure nothrow @nogc @safe

Convenience function. Like find, but only returns whether or not the search was successful.

For more information about pred see find.

Examples

const arr = [0, 1, 2, 3];
assert(canFind(arr, 2));
assert(!canFind(arr, 4));

// find one of several needles
assert(arr.canFind(3, 2));
assert(arr.canFind(3, 2) == 2); // second needle found
assert(arr.canFind([1, 3], 2) == 2);

assert(canFind(arr, [1, 2], [2, 3]));
assert(canFind(arr, [1, 2], [2, 3]) == 1);
assert(canFind(arr, [1, 7], [2, 3]));
assert(canFind(arr, [1, 7], [2, 3]) == 2);
assert(!canFind(arr, [1, 3], [2, 4]));
assert(canFind(arr, [1, 3], [2, 4]) == 0);

Example using a custom predicate. Note that the needle appears as the second argument of the predicate.

auto words = [
    "apple",
    "beeswax",
    "cardboard"
];
assert(!canFind(words, "bees"));
assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));

Search for multiple items in an array of items (search for needles in an array of haystacks)

string s1 = "aaa111aaa";
string s2 = "aaa222aaa";
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
assert(hay.canFind!(e => e.canFind("111", "222")));
@see

among for checking a value against multiple arguments.

Returns true if and only if needle can be found in range. Performs O(haystack.length) evaluations of pred.

canFind
(
(local variable) const(string) sym
sym
))
{
(local variable) string provider
provider
=
(local variable) const(string) candidate
candidate
;
break; } }
(local variable) autological_relocation_join.Resolution[] out_
out_
~=
(struct) autological_relocation_join.Resolution

One resolved relocation: the join's output row.

Resolution
(
(local variable) const(string) referrer
referrer
,
(local variable) const(string) sym
sym
,
(local variable) string provider
provider
,
(local variable) ulong probes
probes
);
} } return
(local variable) autological_relocation_join.Resolution[] out_
out_
;
} /// Prints one resolution table. void
void autological_relocation_join.printResolutions(string title, in autological_relocation_join.Resolution[] rows) @safe

Prints one resolution table.

printResolutions
(
(alias) object.string = string
string
(parameter) string title
title
, in
(struct) autological_relocation_join.Resolution

One resolved relocation: the join's output row.

Resolution
[]
(parameter) const(autological_relocation_join.Resolution[]) rows
rows
) @safe
{
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(
(parameter) string title
title
);
void std.stdio.writefln!(char, string, string, string, string)(in char[] fmt, string __param_1, string __param_2, string __param_3, string __param_4) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" %-12s %-16s %-16s %s", "referrer", "symbol", "resolved to", "probes");
void std.stdio.writefln!(char, string, string, string, string)(in char[] fmt, string __param_1, string __param_2, string __param_3, string __param_4) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" %-12s %-16s %-16s %s", "------------", "----------------", "----------------", "------");
foreach (
(parameter) const(autological_relocation_join.Resolution) r
r
;
(parameter) const(autological_relocation_join.Resolution[]) rows
rows
)
void std.stdio.writefln!(char, string, string, string, const(ulong))(in char[] fmt, string __param_1, string __param_2, string __param_3, const(ulong) __param_4) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" %-12s %-16s %-16s %s",
(local variable) const(autological_relocation_join.Resolution) r
r
.
(field) string autological_relocation_join.Resolution.referrer
referrer
,
(local variable) const(autological_relocation_join.Resolution) r
r
.
(field) string autological_relocation_join.Resolution.symbol
symbol
,
(local variable) const(autological_relocation_join.Resolution) r
r
.
(field) string autological_relocation_join.Resolution.provider
provider
.
(field) ulong const(string).length
length
?
(local variable) const(autological_relocation_join.Resolution) r
r
.
(field) string autological_relocation_join.Resolution.provider
provider
: "** UNRESOLVED **",
(local variable) const(autological_relocation_join.Resolution) r
r
.
(field) ulong autological_relocation_join.Resolution.probes
probes
);
void std.stdio.writefln!(char, ulong, ulong)(in char[] fmt, ulong __param_1, ulong __param_2) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" total probes: %s across %s relocations",
(parameter) const(autological_relocation_join.Resolution[]) rows
rows
.
autological_relocation_join.printResolutions.MapResult!(__lambda_L156_C68, const(Resolution)[]) autological_relocation_join.printResolutions.map!(const(autological_relocation_join.Resolution)[])(const(autological_relocation_join.Resolution)[] r) pure nothrow @nogc @safe

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.

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" ]));
@paramfun one or more transformation functions@seeMap (higher-order function)@paramr an input range@returnsA range with each fun applied to all the elements. If there is more than one fun, the element type will be Tuple containing one element for each fun.
map
!(r => r.probes).
ulong std.algorithm.iteration.sum!(autological_relocation_join.printResolutions.MapResult!(__lambda_L156_C68, const(Resolution)[]))(autological_relocation_join.printResolutions.MapResult!(__lambda_L156_C68, const(Resolution)[]) r) pure nothrow @nogc @safe

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.

@paramseed the initial value of the summation@paramr a finite input range@returnsThe sum of all the elements in the range r.
sum
,
(parameter) const(autological_relocation_join.Resolution[]) rows
rows
.
(field) ulong const(autological_relocation_join.Resolution[]).length
length
);
void std.stdio.writeln!()() @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
} int
int D main()
main
()
{ // A small but realistic graph: an application over a TLS library and a // logging library that both want `malloc`, plus a diamond on libc. const
(struct) autological_relocation_join.Object

One shared object in the model: the objects table, with its columns.

Object
[]
(local variable) const(autological_relocation_join.Object[]) catalog
catalog
= [
(struct) autological_relocation_join.Object

One shared object in the model: the objects table, with its columns.

Object
("app", ["libssl.so", "liblog.so"], ["main"], ["SSL_connect", "log_write", "malloc"]),
(struct) autological_relocation_join.Object

One shared object in the model: the objects table, with its columns.

Object
("libssl.so", ["libcrypto.so", "libc.so.6"], ["SSL_connect"], ["EVP_encrypt", "malloc"]),
(struct) autological_relocation_join.Object

One shared object in the model: the objects table, with its columns.

Object
("liblog.so", ["libc.so.6"], ["log_write"], ["malloc", "fprintf"]),
(struct) autological_relocation_join.Object

One shared object in the model: the objects table, with its columns.

Object
("libcrypto.so", ["libc.so.6"], ["EVP_encrypt"], ["malloc"]),
(struct) autological_relocation_join.Object

One shared object in the model: the objects table, with its columns.

Object
("libc.so.6", [], ["malloc", "free", "fprintf"], []),
// Present in the store but not reachable: it defines `malloc` too.
(struct) autological_relocation_join.Object

One shared object in the model: the objects table, with its columns.

Object
("libjemalloc.so", ["libc.so.6"], ["malloc", "free"], []),
];
(struct) autological_relocation_join.Object

One shared object in the model: the objects table, with its columns.

Object
[
(alias) object.string = string
string
]
(local variable) autological_relocation_join.Object[string] world
world
;
foreach (
(parameter) const(autological_relocation_join.Object) o
o
;
(local variable) const(autological_relocation_join.Object[]) catalog
catalog
)
autological_relocation_join.Object* core.internal.newaa._d_aaGetY!(string, autological_relocation_join.Object, autological_relocation_join.Object[string], string, autological_relocation_join.Object, const(string))(ref scope autological_relocation_join.Object[string] aa, ref const(string) key, out bool found) pure nothrow @safe

Lookup key in aa. Called only from implementation of (aakey) expressions when value is mutable.

@paramaa associative array@paramkey reference to the key value@paramfound returns whether the key was found or a new entry was added@returnsif key was in the aa, a mutable pointer to the existing value. If key was not in the aa, a mutable pointer to newly inserted value which is set to zero
world
[
autological_relocation_join.Object* core.internal.newaa._d_aaGetY!(string, autological_relocation_join.Object, autological_relocation_join.Object[string], string, autological_relocation_join.Object, const(string))(ref scope autological_relocation_join.Object[string] aa, ref const(string) key, out bool found) pure nothrow @safe

Lookup key in aa. Called only from implementation of (aakey) expressions when value is mutable.

@paramaa associative array@paramkey reference to the key value@paramfound returns whether the key was found or a new entry was added@returnsif key was in the aa, a mutable pointer to the existing value. If key was not in the aa, a mutable pointer to newly inserted value which is set to zero
o
.
autological_relocation_join.Object* core.internal.newaa._d_aaGetY!(string, autological_relocation_join.Object, autological_relocation_join.Object[string], string, autological_relocation_join.Object, const(string))(ref scope autological_relocation_join.Object[string] aa, ref const(string) key, out bool found) pure nothrow @safe

Lookup key in aa. Called only from implementation of (aakey) expressions when value is mutable.

@paramaa associative array@paramkey reference to the key value@paramfound returns whether the key was found or a new entry was added@returnsif key was in the aa, a mutable pointer to the existing value. If key was not in the aa, a mutable pointer to newly inserted value which is set to zero
soname
] =
(struct) autological_relocation_join.Object

One shared object in the model: the objects table, with its columns.

Object
(
(local variable) const(autological_relocation_join.Object) o
o
.
(field) string autological_relocation_join.Object.soname
soname
,
(local variable) const(autological_relocation_join.Object) o
o
.
(field) string[] autological_relocation_join.Object.needs
needs
.
string[] object.dup!string(const(string)[] a) pure nothrow @property @safe
dup
,
(local variable) const(autological_relocation_join.Object) o
o
.
(field) string[] autological_relocation_join.Object.defines
defines
.
string[] object.dup!string(const(string)[] a) pure nothrow @property @safe
dup
,
(local variable) const(autological_relocation_join.Object) o
o
.
(field) string[] autological_relocation_join.Object.undefined
undefined
.
string[] object.dup!string(const(string)[] a) pure nothrow @property @safe
dup
);
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("The `objects` table (soname, |needs|, |defines|, |undefined|):");
void std.stdio.writeln!()() @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
foreach (
(parameter) const(autological_relocation_join.Object) o
o
;
(local variable) const(autological_relocation_join.Object[]) catalog
catalog
)
void std.stdio.writefln!(char, string, ulong, ulong, ulong, string)(in char[] fmt, string __param_1, ulong __param_2, ulong __param_3, ulong __param_4, string __param_5) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" %-16s needs=%-2s defines=%-2s undefined=%-2s needs: %s",
(local variable) const(autological_relocation_join.Object) o
o
.
(field) string autological_relocation_join.Object.soname
soname
,
(local variable) const(autological_relocation_join.Object) o
o
.
(field) string[] autological_relocation_join.Object.needs
needs
.
(field) ulong const(string[]).length
length
,
(local variable) const(autological_relocation_join.Object) o
o
.
(field) string[] autological_relocation_join.Object.defines
defines
.
(field) ulong const(string[]).length
length
,
(local variable) const(autological_relocation_join.Object) o
o
.
(field) string[] autological_relocation_join.Object.undefined
undefined
.
(field) ulong const(string[]).length
length
,
(local variable) const(autological_relocation_join.Object) o
o
.
(field) string[] autological_relocation_join.Object.needs
needs
.
(field) ulong const(string[]).length
length
?
(local variable) const(autological_relocation_join.Object) o
o
.
(field) string[] autological_relocation_join.Object.needs
needs
.
string std.array.join!(const(string)[], string)(const(string)[] ror, string sep) pure nothrow @safe

Eagerly concatenates all of the ranges in ror together (with the GC) into one array using sep as the separator if present.

@paramror An input range of input ranges@paramsep An input range, or a single element, to join the ranges on@returnsAn array of elements@seeFor a lazy version, see joiner
join
(", ") : "-");
void std.stdio.writeln!()() @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
const
(local variable) const(string[]) plain
plain
=
string[] autological_relocation_join.scopeOrder(in autological_relocation_join.Object[string] world, string root, string[] preload = null) @safe

The scope order ld.so builds: breadth-first over DT_NEEDED, first sight wins.

Depth-first would produce a different order and therefore different interposition winners; the breadth-first rule is the one glibc implements, and stating it is half the point of this program — the answer to the query depends on a traversal order that lives in the loader, not in the data.

scopeOrder
(
(local variable) autological_relocation_join.Object[string] world
world
, "app");
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("Scope order (breadth-first over DT_NEEDED from `app`): %s",
(local variable) const(string[]) plain
plain
.
string std.array.join!(const(string)[], string)(const(string)[] ror, string sep) pure nothrow @safe

Eagerly concatenates all of the ranges in ror together (with the GC) into one array using sep as the separator if present.

@paramror An input range of input ranges@paramsep An input range, or a single element, to join the ranges on@returnsAn array of elements@seeFor a lazy version, see joiner
join
(" -> "));
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" `libjemalloc.so` is in the store but not in scope — unreachable objects");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" do not participate in the join, which is exactly a WHERE clause.");
void std.stdio.writeln!()() @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
const
(local variable) const(autological_relocation_join.Resolution[]) before
before
=
autological_relocation_join.Resolution[] autological_relocation_join.resolve(in autological_relocation_join.Object[string] world, in string[] order) @safe

The join itself: for every undefined symbol, the first definition in scope order.

probes counts how many objects were examined. In glibc this is a .gnu.hash bloom-filter test per object followed by a bucket walk on a hit; the count below is the number of objects the loader must at minimum touch, which is the quantity that scales with object count rather than with image size.

resolve
(
(local variable) autological_relocation_join.Object[string] world
world
,
(local variable) const(string[]) plain
plain
);
void autological_relocation_join.printResolutions(string title, in autological_relocation_join.Resolution[] rows) @safe

Prints one resolution table.

printResolutions
("Resolutions, no preload:",
(local variable) const(autological_relocation_join.Resolution[]) before
before
);
// One inserted row, at one position. const
(local variable) const(string[]) preloaded
preloaded
=
string[] autological_relocation_join.scopeOrder(in autological_relocation_join.Object[string] world, string root, string[] preload = null) @safe

The scope order ld.so builds: breadth-first over DT_NEEDED, first sight wins.

Depth-first would produce a different order and therefore different interposition winners; the breadth-first rule is the one glibc implements, and stating it is half the point of this program — the answer to the query depends on a traversal order that lives in the loader, not in the data.

scopeOrder
(
(local variable) autological_relocation_join.Object[string] world
world
, "app", ["libjemalloc.so"]);
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("Scope order with LD_PRELOAD=libjemalloc.so: %s",
(local variable) const(string[]) preloaded
preloaded
.
string std.array.join!(const(string)[], string)(const(string)[] ror, string sep) pure nothrow @safe

Eagerly concatenates all of the ranges in ror together (with the GC) into one array using sep as the separator if present.

@paramror An input range of input ranges@paramsep An input range, or a single element, to join the ranges on@returnsAn array of elements@seeFor a lazy version, see joiner
join
(" -> "));
void std.stdio.writeln!()() @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
const
(local variable) const(autological_relocation_join.Resolution[]) after
after
=
autological_relocation_join.Resolution[] autological_relocation_join.resolve(in autological_relocation_join.Object[string] world, in string[] order) @safe

The join itself: for every undefined symbol, the first definition in scope order.

probes counts how many objects were examined. In glibc this is a .gnu.hash bloom-filter test per object followed by a bucket walk on a hit; the count below is the number of objects the loader must at minimum touch, which is the quantity that scales with object count rather than with image size.

resolve
(
(local variable) autological_relocation_join.Object[string] world
world
,
(local variable) const(string[]) preloaded
preloaded
);
void autological_relocation_join.printResolutions(string title, in autological_relocation_join.Resolution[] rows) @safe

Prints one resolution table.

printResolutions
("Resolutions, libjemalloc.so preloaded:",
(local variable) const(autological_relocation_join.Resolution[]) after
after
);
// The diff is the argument: one tuple changed the answer to N queries.
(alias) object.size_t = ulong
size_t
(local variable) ulong changed
changed
;
foreach (
(parameter) ulong i
i
,
(parameter) const(autological_relocation_join.Resolution) r
r
;
(local variable) const(autological_relocation_join.Resolution[]) before
before
)
if (
(local variable) ulong i
i
<
(local variable) const(autological_relocation_join.Resolution[]) after
after
.
(field) ulong const(autological_relocation_join.Resolution[]).length
length
&&
(local variable) const(autological_relocation_join.Resolution[]) after
after
[
(local variable) ulong i
i
].
(field) string autological_relocation_join.Resolution.provider
provider
!=
(local variable) const(autological_relocation_join.Resolution) r
r
.
(field) string autological_relocation_join.Resolution.provider
provider
)
(local variable) ulong changed
changed
++;
void std.stdio.writefln!(char, ulong, ulong)(in char[] fmt, ulong __param_1, ulong __param_2) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("LD_PRELOAD inserted ONE row into the scope relation and changed %s of %s",
(local variable) ulong changed
changed
,
(local variable) const(autological_relocation_join.Resolution[]) before
before
.
(field) ulong const(autological_relocation_join.Resolution[]).length
length
);
void std.stdio.writefln!char(in char[] fmt) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("resolutions. Nothing about any object's bytes changed. This is why SELF");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("can model `LD_PRELOAD` as a row rather than as an environment variable.");
void std.stdio.writeln!()() @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
void std.stdio.writefln!(char, ulong, ulong, ulong)(in char[] fmt, ulong __param_1, ulong __param_2, ulong __param_3) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("Cost: %s probes for %s relocations over %s objects in scope.",
(local variable) const(autological_relocation_join.Resolution[]) before
before
.
autological_relocation_join.main.MapResult!(__lambda_L214_C21, const(Resolution)[]) autological_relocation_join.main.map!(const(autological_relocation_join.Resolution)[])(const(autological_relocation_join.Resolution)[] r) pure nothrow @nogc @safe

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.

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" ]));
@paramfun one or more transformation functions@seeMap (higher-order function)@paramr an input range@returnsA range with each fun applied to all the elements. If there is more than one fun, the element type will be Tuple containing one element for each fun.
map
!(r => r.probes).
ulong std.algorithm.iteration.sum!(autological_relocation_join.main.MapResult!(__lambda_L214_C21, const(Resolution)[]))(autological_relocation_join.main.MapResult!(__lambda_L214_C21, const(Resolution)[]) r) pure nothrow @nogc @safe

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.

@paramseed the initial value of the summation@paramr a finite input range@returnsThe sum of all the elements in the range r.
sum
,
(local variable) const(autological_relocation_join.Resolution[]) before
before
.
(field) ulong const(autological_relocation_join.Resolution[]).length
length
,
(local variable) const(string[]) plain
plain
.
(field) ulong const(string[]).length
length
);
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" Every process start recomputes this. The probe count grows with the");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" number of objects, not with how large they are — which is the confounder");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" that makes a naive ELF-vs-SELF startup comparison meaningless unless the");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" object count is held fixed.");
void std.stdio.writeln!()() @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("The same query, two ways:");
void std.stdio.writeln!()() @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" -- SQL: the transitive part needs a recursive CTE, and the");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" -- first-wins rule needs a window function over a traversal order");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" -- the query itself has to reconstruct.");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" WITH RECURSIVE scope(obj, depth) AS (");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" SELECT 'app', 0");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" UNION");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" SELECT n.needed, s.depth + 1 FROM needs n JOIN scope s ON n.obj = s.obj");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" )");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" SELECT u.obj, u.sym, MIN(s.depth), d.obj");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" FROM undefined u JOIN scope s JOIN defines d");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" ON d.obj = s.obj AND d.sym = u.sym");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" GROUP BY u.obj, u.sym;");
void std.stdio.writeln!()() @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" % Datalog: the transitive closure is one rule, and it terminates by");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" % construction under semi-naive evaluation.");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" scope(\"app\").");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" scope(N) :- scope(O), needs(O, N).");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" resolves(U, S, D) :- undefined(U, S), scope(D), defines(D, S).");
void std.stdio.writeln!()() @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" Both compute the reachable set. Only the Datalog version says nothing");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" about *how*, which is why every code-as-a-database system that must");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" express reachability picked it. See ../code-as-database.md.");
return 0; }