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