Aliases to mutable thread-local data not allowed [testable source code]
mark
mark at qtrac.eu
Wed Mar 11 09:29:54 UTC 2020
Hi Simen,
I think you must have done something else but didn't mention to
get it to compile. I did the exact changes you said and it
wouldn't compile. Here's what I get with changes mentioned below
(with new full source):
/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(89,17): instantiated from here:
send!(immutable(Deb))
/home/mark/opt/ldc2-1.20.0-linux-x86_64/bin/ldc2 failed with exit
code 1.
Here is a modified version that names the DoneMessage variable
and makes readPackageFile and readPackageLine into functions.
Instead of making them static, I just took them outside the
struct: after all, they never access struct member data. I also
now use ownerTid.
// 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]; // These two lines allow me to use AAs as
sets
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, spawn;
import std.file: dirEntries, FileException, SpanMode;
Tid[] tids;
try {
foreach (string filename; dirEntries(PACKAGE_DIR,
PACKAGE_PATTERN,
SpanMode.shallow))
tids ~= spawn(&readPackageFile, filename);
auto jobs = tids.length;
while (jobs) {
receive(
(Deb deb) { debForName[deb.name] = deb; },
(DoneMessage m) { jobs--; }
);
}
} catch (FileException err) {
import std.stdio: stderr;
stderr.writeln("failed to read packages: ", err);
}
}
}
void readPackageFile(string filename) {
import std.concurrency: ownerTid, 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(filename, lino, line, deb,
inDescription,
inContinuation);
if (deb.valid)
send(ownerTid, cast(immutable)deb.dup);
} catch (FileException err) {
stderr.writefln("error: %s: failed to read packages: %s",
filename, err);
}
send(ownerTid, DoneMessage());
}
void readPackageLine(const string filename, const int lino,
const(char[]) line, ref Deb deb,
ref bool inDescription, ref bool
inContinuation) {
import std.concurrency: ownerTid, send;
import std.path: baseName;
import std.stdio: stderr;
import std.string: empty, startsWith, strip;
if (strip(line).empty) {
if (deb.valid)
send(ownerTid, 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;
}
More information about the Digitalmars-d-learn
mailing list