mirror of
https://github.com/dlang/phobos.git
synced 2025-05-07 19:49:36 +03:00
Fix Issue 12556 - Add persistent byLine
This commit is contained in:
parent
a7f08aaa31
commit
22edb2ed36
1 changed files with 125 additions and 3 deletions
128
std/stdio.d
128
std/stdio.d
|
@ -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).
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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...)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue