Search code examples
memory-managementdheap-memory

High-Performant Safe and Pure Construction of Path


I'm trying to implement a variant of buildPath that is performant (minimal heap-activity) and @safe and pure.

My try so far is

/** Returns: Path to $(D this) File. */
string path() @property @safe const pure {
    const Dir[] parents;
    // collect parenting Dirs
    auto currParent = parent;
    size_t pathLength = 0; // returned path length
    while (currParent !is null) {
        if (currParent !is parent) {
            pathLength += 1;
        }
        pathLength += currParent.name.length;
        parents ~= currParent;
        currParent = parent.parent;
    }

    // build path
    auto path_ = new char[pathLength];
    size_t i = 0;
    foreach (currParent_; parents) {
        const parentName = currParent_.name;
        if (i != 0) {
            path_[++i] = '/';
        }
        path_[i .. parentName.length] = parentName[];
        i += parentName.length;
    }
    return path;
}

But it doesn't compile because of problems with constness on parents and currParent.

/home/per/Work/justd/fs.d(408): Error: cannot modify const expression parents
/home/per/Work/justd/fs.d(409): Error: cannot modify const expression currParent

If I make path() @trusted and non-const instead of @safe const and parents non-const the code compiles which may be acceptable but definitely not pretty.

Is it possible to declare a mutable array of const class Dir-references (parents) and a mutable reference to a const object (pathSlow)? If so that would solve this issue in an elegant way.

Note that path() is a member function of a file system tree structure where each node contains a reference to a instance to class Dir.


Solution

  • Sounds like you want to use

    const(Dir)[] parents;
    

    If Dir is a class, it won't let you do a const reference that can be reassigned (I think this is intended to be changed at some point, there was a pull request for a while, not sure what the current status is), but you can kinda hack around it by making a little array:

    const(Dir)[1] pathSlow;
    

    then refer to it as pathSlow[0].