Skip to content

Commit

Permalink
Fix Issue 12556 - Add persistent byLine
Browse files Browse the repository at this point in the history
  • Loading branch information
ntrel committed Apr 14, 2014
1 parent a7f08aa commit 22edb2e
Showing 1 changed file with 125 additions and 3 deletions.
128 changes: 125 additions & 3 deletions std/stdio.d
Expand Up @@ -1658,7 +1658,8 @@ may throw $(D StdioException) on I/O error.
Note:
Each $(D front) will not persist after $(D
popFront) is called, so the caller must copy its contents (e.g. by
calling $(D to!string)) if retention is needed.
calling $(D to!string)) if retention is needed. Alternatively use
$(LREF byLineCopy) instead.
Params:
Char = Character type for each line, defaulting to $(D char).
Expand Down Expand Up @@ -1720,6 +1721,118 @@ the contents may well have changed).
return ByLine!(Char, Terminator)(this, keepTerminator, terminator);
}

private struct ByLineCopy(Char, Terminator)
{
private:
import std.typecons;

/* Ref-counting stops the source range's ByLineCopyImpl
* from getting out of sync after the range is copied, e.g.
* when accessing range.front, then using std.range.take,
* then accessing range.front again. */
alias Impl = RefCounted!(ByLineCopyImpl!(Char, Terminator),
RefCountedAutoInitialize.no);
Impl impl;

public:
this(File f, KeepTerminator kt, Terminator terminator)
{
impl = Impl(f, kt, terminator);
}

@property bool empty()
{
return impl.refCountedPayload.empty;
}

@property immutable(Char)[] front()
{
return impl.refCountedPayload.front;
}

void popFront()
{
impl.refCountedPayload.popFront();
}
}

private struct ByLineCopyImpl(Char, Terminator)
{
ByLineImpl!(Char, Terminator) impl;
bool gotFront;
immutable(Char)[] line;

public:
this(File f, KeepTerminator kt, Terminator terminator)
{
impl = ByLineImpl!(Char, Terminator)(f, kt, terminator);
}

@property bool empty()
{
return impl.empty;
}

@property front()
{
if (!gotFront)
line = impl.front.idup;
return line;
}

void popFront()
{
impl.popFront();
gotFront = false;
}
}

/**
Returns an input range set up to read from the file handle one line
at a time. Each line will be newly allocated.
The element type for the range will be $(D immutable(Char)[]). Range
primitives may throw $(D StdioException) on I/O error.
Params:
Char = Character type for each line, defaulting to $(D char).
keepTerminator = Use $(D KeepTerminator.yes) to include the
terminator at the end of each line.
terminator = Line separator ($(D '\n') by default).
Example:
----
import std.algorithm, std.stdio;
// Print sorted lines of a file.
void main()
{
auto sortedLines = File("file.txt") // Open for reading
.byLineCopy() // Read persistent lines
.array() // into an array
.sort(); // then sort them
foreach (line; sortedLines)
writeln(line);
}
----
See_Also:
$(XREF file,readText)
*/
auto byLineCopy(Terminator = char, Char = char)
(KeepTerminator keepTerminator = KeepTerminator.no,
Terminator terminator = '\n')
if (isScalarType!Terminator)
{
return ByLineCopy!(Char, Terminator)(this, keepTerminator, terminator);
}

/// ditto
auto byLineCopy(Terminator, Char = char)
(KeepTerminator keepTerminator, Terminator terminator)
if (is(Unqual!(ElementEncodingType!Terminator) == Char))
{
return ByLineCopy!(Char, Terminator)(this, keepTerminator, terminator);
}

unittest
{
static import std.file;
Expand All @@ -1740,7 +1853,7 @@ the contents may well have changed).
f.detach();
assert(!f.isOpen);

void test(Terminator)(string txt, string[] witness,
void test(Terminator)(string txt, in string[] witness,
KeepTerminator kt, Terminator term, bool popFirstLine = false)
{
import std.conv : text;
Expand All @@ -1767,8 +1880,11 @@ the contents may well have changed).
assert(i == witness.length, text(i, " != ", witness.length));

// Issue 11830
auto walkedLength = File(deleteme).byLine.walkLength;
auto walkedLength = File(deleteme).byLine(kt, term).walkLength;
assert(walkedLength == witness.length, text(walkedLength, " != ", witness.length));

// test persistent lines
assert(File(deleteme).byLineCopy(kt, term).array.sort() == witness.dup.sort());
}

KeepTerminator kt = KeepTerminator.no;
Expand Down Expand Up @@ -1832,6 +1948,12 @@ the contents may well have changed).
file.detach();
assert(!file.isOpen);
}

unittest
{
static assert(is(typeof(File("").byLine.front) == char[]));
static assert(is(typeof(File("").byLineCopy.front) == string));
}

template byRecord(Fields...)
{
Expand Down

0 comments on commit 22edb2e

Please sign in to comment.