mirror of
https://github.com/dlang/phobos.git
synced 2025-05-08 20:19:43 +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:
|
Note:
|
||||||
Each $(D front) will not persist after $(D
|
Each $(D front) will not persist after $(D
|
||||||
popFront) is called, so the caller must copy its contents (e.g. by
|
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:
|
Params:
|
||||||
Char = Character type for each line, defaulting to $(D char).
|
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);
|
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
|
unittest
|
||||||
{
|
{
|
||||||
static import std.file;
|
static import std.file;
|
||||||
|
@ -1740,7 +1853,7 @@ the contents may well have changed).
|
||||||
f.detach();
|
f.detach();
|
||||||
assert(!f.isOpen);
|
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)
|
KeepTerminator kt, Terminator term, bool popFirstLine = false)
|
||||||
{
|
{
|
||||||
import std.conv : text;
|
import std.conv : text;
|
||||||
|
@ -1767,8 +1880,11 @@ the contents may well have changed).
|
||||||
assert(i == witness.length, text(i, " != ", witness.length));
|
assert(i == witness.length, text(i, " != ", witness.length));
|
||||||
|
|
||||||
// Issue 11830
|
// Issue 11830
|
||||||
auto walkedLength = File(deleteme).byLine.walkLength;
|
auto walkedLength = File(deleteme).byLine(kt, term).walkLength;
|
||||||
assert(walkedLength == witness.length, text(walkedLength, " != ", witness.length));
|
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;
|
KeepTerminator kt = KeepTerminator.no;
|
||||||
|
@ -1833,6 +1949,12 @@ the contents may well have changed).
|
||||||
assert(!file.isOpen);
|
assert(!file.isOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
static assert(is(typeof(File("").byLine.front) == char[]));
|
||||||
|
static assert(is(typeof(File("").byLineCopy.front) == string));
|
||||||
|
}
|
||||||
|
|
||||||
template byRecord(Fields...)
|
template byRecord(Fields...)
|
||||||
{
|
{
|
||||||
ByRecord!(Fields) byRecord(string format)
|
ByRecord!(Fields) byRecord(string format)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue