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