Aliases to mutable thread-local data not allowed [testable source code]
mark
mark at qtrac.eu
Tue Mar 10 20:03:21 UTC 2020
I've managed to make a cut-down version that's < 170 LOC.
It needs to be run on Debian or a Debian-based Linux (e.g.,
Ubuntu).
Below is the full source followed by the error output.
// app.d
import std.typecons: Tuple;
void main() {
import std.stdio: writeln, writefln;
auto model = Model();
model.readPackages();
writefln("read %,d packages", model.length);
}
enum PACKAGE_DIR = "/var/lib/apt/lists";
enum PACKAGE_PATTERN = "*Packages";
alias Unit = void[0];
enum unit = Unit.init;
alias MaybeKeyValue = Tuple!(string, "key", string, "value",
bool, "ok");
struct DoneMessage {}
struct Deb {
string name;
string description;
Unit[string] tags; // set of tags
Deb dup() const {
Deb deb;
deb.name = name;
deb.description = description;
foreach (key; tags.byKey)
deb.tags[key] = unit;
return deb;
}
bool valid() {
import std.string: empty;
return !name.empty && !description.empty;
}
void clear() {
name = "";
description = "";
tags.clear;
}
}
struct Model {
import std.concurrency: Tid;
private Deb[string] debForName; // Only read once populated
size_t length() const { return debForName.length; }
void readPackages() {
import std.concurrency: receive, thisTid, spawn;
import std.file: dirEntries, FileException, SpanMode;
Tid[] tids;
try {
foreach (string filename; dirEntries(PACKAGE_DIR,
PACKAGE_PATTERN,
SpanMode.shallow))
tids ~= spawn(&readPackageFile, thisTid,
filename);
auto jobs = tids.length;
while (jobs) {
receive(
(Deb deb) { debForName[deb.name] = deb; },
(DoneMessage) { jobs--; }
);
}
} catch (FileException err) {
import std.stdio: stderr;
stderr.writeln("failed to read packages: ", err);
}
}
private void readPackageFile(Tid parentTid, string filename) {
import std.concurrency: send;
import std.file: FileException;
import std.range: enumerate;
import std.stdio: File, stderr;
try {
bool inDescription = false; // Descriptions can by
multi-line
bool inContinuation = false; // Other things can be
multi-line
Deb deb;
auto file = File(filename);
foreach(lino, line; file.byLine.enumerate(1))
readPackageLine(parentTid, filename, lino, line,
deb,
inDescription, inContinuation);
if (deb.valid)
send(parentTid, cast(immutable)deb.dup);
} catch (FileException err) {
stderr.writefln("error: %s: failed to read packages:
%s",
filename, err);
}
send(parentTid, DoneMessage());
}
private void readPackageLine(
Tid parentTid, const string filename, const int lino,
const(char[]) line, ref Deb deb, ref bool
inDescription,
ref bool inContinuation) {
import std.concurrency: send;
import std.path: baseName;
import std.stdio: stderr;
import std.string: empty, startsWith, strip;
if (strip(line).empty) {
if (deb.valid)
send(parentTid, cast(immutable)deb.dup);
else if (!deb.name.empty || !deb.description.empty ||
!deb.tags.empty)
stderr.writefln("error: %s:%,d: incomplete
package: %s",
baseName(filename), lino, deb);
deb.clear;
return;
}
if (inDescription || inContinuation) {
if (line.startsWith(' ') || line.startsWith('\t')) {
if (inDescription)
deb.description ~= line;
return;
}
inDescription = inContinuation = false;
}
immutable keyValue = maybeKeyValue(line);
if (!keyValue.ok)
inContinuation = true;
else
inDescription = populateDeb(deb, keyValue.key,
keyValue.value);
}
}
MaybeKeyValue maybeKeyValue(const(char[]) line) {
import std.string: indexOf, strip;
immutable i = line.indexOf(':');
if (i == -1)
return MaybeKeyValue("", "", false);
immutable key = strip(line[0..i]).idup;
immutable value = strip(line[i + 1..$]).idup;
return MaybeKeyValue(key, value, true);
}
bool populateDeb(ref Deb deb, const string key, const string
value) {
import std.conv: to;
switch (key) {
case "Package":
deb.name = value;
return false;
case "Description", "Npp-Description": // XXX ignore Npp-?
deb.description ~= value;
return true; // We are now in a description
case "Tag":
maybePopulateTags(deb, value);
return false;
default: return false; // Ignore "uninteresting" fields
}
}
void maybePopulateTags(ref Deb deb, const string tags) {
import std.regex: ctRegex, split;
auto rx = ctRegex!(`\s*,\s*`);
foreach (tag; tags.split(rx))
deb.tags[tag] = unit;
}
// end of app.d
Error output:
src/app.d(59,30): Error: template std.concurrency.spawn cannot
deduce function from argument types !()(void delegate(Tid
parentTid, string filename), Tid, string), candidates are:
/home/mark/opt/ldc2-1.20.0-linux-x86_64/bin/../import/std/concurrency.d(460,5): spawn(F, T...)(F fn, T args)
with F = void delegate(Tid, string),
T = (Tid, string)
must satisfy the following constraint:
isSpawnable!(F, T)
src/app.d(62,24): Error: template std.concurrency.receive cannot
deduce function from argument types !()(void delegate(Deb deb)
pure nothrow @safe, void), candidates are:
/home/mark/opt/ldc2-1.20.0-linux-x86_64/bin/../import/std/concurrency.d(673,6): receive(T...)(T ops)
/home/mark/opt/ldc2-1.20.0-linux-x86_64/bin/../import/std/variant.d(701,26): Error: cannot implicitly convert expression rhs of type immutable(Deb) to Deb
/home/mark/opt/ldc2-1.20.0-linux-x86_64/bin/../import/std/variant.d(603,17): Error: template instance std.variant.VariantN!32LU.VariantN.opAssign!(immutable(Deb)) error instantiating
/home/mark/opt/ldc2-1.20.0-linux-x86_64/bin/../import/std/concurrency.d(126,22): instantiated from here: __ctor!(immutable(Deb))
/home/mark/opt/ldc2-1.20.0-linux-x86_64/bin/../import/std/concurrency.d(656,23): instantiated from here: __ctor!(immutable(Deb))
/home/mark/opt/ldc2-1.20.0-linux-x86_64/bin/../import/std/concurrency.d(647,10): instantiated from here: _send!(immutable(Deb))
/home/mark/opt/ldc2-1.20.0-linux-x86_64/bin/../import/std/concurrency.d(626,10): instantiated from here: _send!(immutable(Deb))
src/app.d(88,21): instantiated from here:
send!(immutable(Deb))
/home/mark/opt/ldc2-1.20.0-linux-x86_64/bin/ldc2 failed with exit
code 1.
Hopefully this will help someone understand and be able to help!
More information about the Digitalmars-d-learn
mailing list