On Thursday, 6 June 2013 at 17:28:56 UTC, Steven Schveighoffer
wrote:
On Thu, 06 Jun 2013 13:25:56 -0400, Lars T. Kyllingstad
<[email protected]> wrote:
On Thursday, 6 June 2013 at 17:13:10 UTC, Steven Schveighoffer
wrote:
On Thu, 06 Jun 2013 12:14:30 -0400, Dylan Knutson
<[email protected]> wrote:
It doesn't do any allocations that the user won't have to do
anyways. Paths have to be normalized before comparison; not
doing so isn't correct behavior. Eg, the strings `foo../bar`
!= `bar`, yet they're equivalent paths. Path encapsulates
the behavior. So it's the difference between
buildNormalizedPath(s1) == buildNormalizedPath(s2);
and
p1 == p2;
This can be done without allocations.
I know. There are a few additions that I've been planning to
make for std.path for the longest time, I just haven't found
the time to do so yet. Specifically, I want to add a couple
of functions that deal with ranges of path segments rather
than full path strings.
The first one is a lazy "path normaliser":
assert (equal(pathNormalizer(["foo", "bar", "..", "baz"]),
["foo", "bar", "baz"]));
With this, non-allocating path comparison is easy. The
verbose version of p1 == p2, which could be wrapped for
convenience, is then:
equal(pathNormalizer(pathSplitter(p1)),
pathNormalizer(pathSplitter(p2)))
You can also use filenameCmp() as a predicate to equal() to
make the comparison case-insensitive on OSes where this is
expected. Very general and composable, and easily wrappable.
Great! I'd highly suggest pathEqual which takes two ranges of
dchar and does the composition and OS-specific comparison for
you.
They don't have to be dchar if all the building blocks are
templates (as the existing ones are):
bool pathEqual(CaseSensitive cs = CaseSensitive.osDefault, C1, C2)
(const(C1)[] p1, const(C2)[] p2)
if (isSomeChar!C1 && isSomeChar!C2)
{
return equal!((a, b) => filenameCharCmp!cs(a, b) == 0)
(pathNormalizer(pathSplitter(p1)),
pathNormalizer(pathSplitter(p2)));
}