Skip to content
40 changes: 28 additions & 12 deletions std/file.d
Original file line number Diff line number Diff line change
Expand Up @@ -4626,7 +4626,8 @@ enum SpanMode
["animals", "plants"]));
}

private struct DirIteratorImpl
private struct DirIteratorImpl(alias pred = (scope ref DirEntry entry) => true)
if (__traits(compiles, { DirEntry entry; bool _ = pred(entry); }))
{
@safe:
SpanMode _mode;
Expand Down Expand Up @@ -4712,7 +4713,7 @@ private struct DirIteratorImpl
return false;
}
_cur = DirEntry(_stack[$-1].dirpath, findinfo);
return true;
return pred(_cur);
}

void popDirStack() @trusted
Expand All @@ -4730,6 +4731,8 @@ private struct DirIteratorImpl

bool mayStepIn()
{
if (!pred(_cur))
return false;
return _followSymlink ? _cur.isDir : _cur.isDir && !_cur.isSymlink;
}
}
Expand Down Expand Up @@ -4766,7 +4769,7 @@ private struct DirIteratorImpl
core.stdc.string.strcmp(&fdata.d_name[0], ".."))
{
_cur = DirEntry(_stack[$-1].dirpath, fdata);
return true;
return pred(_cur);
}
}

Expand All @@ -4789,6 +4792,8 @@ private struct DirIteratorImpl

bool mayStepIn()
{
if (!pred(_cur))
return false;
return _followSymlink ? _cur.isDir : attrIsDir(_cur.linkAttributes);
}
}
Expand Down Expand Up @@ -4834,7 +4839,7 @@ private struct DirIteratorImpl

void popFront()
{
switch (_mode)
final switch (_mode)
{
case SpanMode.depth:
if (next())
Expand Down Expand Up @@ -4862,7 +4867,7 @@ private struct DirIteratorImpl
else
while (!empty && !next()){}
break;
default:
case SpanMode.shallow:
next();
}
}
Expand All @@ -4873,16 +4878,17 @@ private struct DirIteratorImpl
}
}

struct _DirIterator(alias pred = (scope ref DirEntry entry) => true, bool useDIP1000)
if (__traits(compiles, { DirEntry entry; bool _ = pred(entry); }))
// Must be a template, because the destructor is unsafe or safe depending on
// whether `-preview=dip1000` is in use. Otherwise, linking errors would
// result.
struct _DirIterator(bool useDIP1000)
{
static assert(useDIP1000 == dip1000Enabled,
"Please don't override useDIP1000 to disagree with compiler switch.");

private:
SafeRefCounted!(DirIteratorImpl, RefCountedAutoInitialize.no) impl;
SafeRefCounted!(DirIteratorImpl!(pred), RefCountedAutoInitialize.no) impl;

this(string pathname, SpanMode mode, bool followSymlink) @trusted
{
Expand All @@ -4896,7 +4902,7 @@ public:

// This has the client code to automatically use and link to the correct
// template instance
alias DirIterator = _DirIterator!dip1000Enabled;
alias DirIterator = _DirIterator!((scope ref DirEntry entry) => true, dip1000Enabled);

/++
Returns an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
Expand Down Expand Up @@ -5005,10 +5011,11 @@ scan("");

// For some reason, doing the same alias-to-a-template trick as with DirIterator
// does not work here.
auto dirEntries(bool useDIP1000 = dip1000Enabled)
auto dirEntries(alias pred = (scope ref DirEntry entry) => true, bool useDIP1000 = dip1000Enabled)
(string path, SpanMode mode, bool followSymlink = true)
if (__traits(compiles, { DirEntry entry; bool _ = pred(entry); }))
{
return _DirIterator!useDIP1000(path, mode, followSymlink);
return _DirIterator!(pred, useDIP1000)(path, mode, followSymlink);
}

/// Duplicate functionality of D1's `std.file.listdir()`:
Expand Down Expand Up @@ -5108,15 +5115,16 @@ auto dirEntries(bool useDIP1000 = dip1000Enabled)
}

/// Ditto
auto dirEntries(bool useDIP1000 = dip1000Enabled)
auto dirEntries(alias pred = (scope ref DirEntry entry) => true, bool useDIP1000 = dip1000Enabled)
(string path, string pattern, SpanMode mode,
bool followSymlink = true)
if (__traits(compiles, { DirEntry entry; bool _ = pred(entry); }))
{
import std.algorithm.iteration : filter;
import std.path : globMatch, baseName;

bool f(DirEntry de) { return globMatch(baseName(de.name), pattern); }
return filter!f(_DirIterator!useDIP1000(path, mode, followSymlink));
return filter!f(_DirIterator!(pred, useDIP1000)(path, mode, followSymlink));
}

@safe unittest
Expand Down Expand Up @@ -5221,6 +5229,14 @@ auto dirEntries(bool useDIP1000 = dip1000Enabled)
sort(result);

assert(equal(files, result));

foreach (const spanMode; [EnumMembers!(SpanMode)]) {
import std.algorithm : endsWith;
auto result2 = dirEntries!((scope ref DirEntry entry) => entry.name.endsWith("Hello World"))(dir, spanMode).map!((return a) => a.name.normalize()).array();
import std.stdio;
writeln(result2);
assert(result2.length == 1);
}
}

// https://issues.dlang.org/show_bug.cgi?id=21250
Expand Down
Loading