@@ -3993,79 +3993,103 @@ enum LockType
39933993
39943994struct LockingTextReader
39953995{
3996- private File _f;
3997- private char _front;
3998- private bool _hasChar;
3999-
4000- this (File f)
3996+ private static struct Impl
40013997 {
4002- import std.exception : enforce;
4003- enforce(f.isOpen, " LockingTextReader: File must be open" );
4004- _f = f;
4005- _FLOCK(_f._p.handle);
4006- }
3998+ private File _f;
3999+ private char _front;
4000+ private bool _hasChar;
40074001
4008- this (this )
4009- {
4010- _FLOCK(_f._p.handle);
4011- }
4002+ this (File f)
4003+ {
4004+ import std.exception : enforce;
4005+ enforce(f.isOpen, " LockingTextReader: File must be open" );
4006+ _f = f;
4007+ _FLOCK(_f._p.handle);
4008+ }
40124009
4013- ~this ()
4014- {
4015- if (_hasChar)
4016- ungetc(_front, cast (FILE * )_f._p.handle);
4010+ @disable this (this );
40174011
4018- // File locking has its own reference count
4019- if (_f.isOpen) _FUNLOCK(_f._p.handle);
4020- }
4012+ ~this ()
4013+ {
4014+ if (_hasChar)
4015+ ungetc(_front, cast (FILE * )_f._p.handle);
40214016
4022- void opAssign (LockingTextReader r)
4023- {
4024- import std.algorithm.mutation : swap;
4025- swap(this , r);
4026- }
4017+ // File locking has its own reference count
4018+ if (_f.isOpen) _FUNLOCK(_f._p.handle);
4019+ }
40274020
4028- @property bool empty()
4029- {
4030- if (! _hasChar)
4021+ void opAssign (typeof (this ) r)
4022+ {
4023+ import std.algorithm.mutation : swap;
4024+ swap(this , r);
4025+ }
4026+
4027+ @property bool empty()
40314028 {
4032- if (! _f.isOpen || _f.eof)
4033- return true ;
4034- immutable int c = _FGETC(cast (_iobuf* ) _f._p.handle);
4035- if (c == EOF )
4029+ if (! _hasChar)
40364030 {
4037- .destroy (_f);
4038- return true ;
4031+ if (! _f.isOpen || _f.eof)
4032+ return true ;
4033+ immutable int c = _FGETC(cast (_iobuf* ) _f._p.handle);
4034+ if (c == EOF )
4035+ {
4036+ .destroy (_f);
4037+ return true ;
4038+ }
4039+ _front = cast (char ) c;
4040+ _hasChar = true ;
40394041 }
4040- _front = cast (char ) c;
4041- _hasChar = true ;
4042+ return false ;
40424043 }
4043- return false ;
4044- }
40454044
4046- @property char front()
4047- {
4048- if (! _hasChar)
4045+ @property char front()
40494046 {
4050- version ( assert )
4047+ if ( ! _hasChar )
40514048 {
4052- import core.exception : RangeError;
4053- if (empty)
4054- throw new RangeError();
4049+ version (assert )
4050+ {
4051+ import core.exception : RangeError;
4052+ if (empty)
4053+ throw new RangeError();
4054+ }
4055+ else
4056+ {
4057+ empty;
4058+ }
40554059 }
4056- else
4057- {
4060+ return _front;
4061+ }
4062+
4063+ void popFront ()
4064+ {
4065+ if (! _hasChar)
40584066 empty;
4059- }
4067+ _hasChar = false ;
40604068 }
4061- return _front;
4069+ }
4070+
4071+ import std.typecons : SafeRefCounted, borrow;
4072+
4073+ private SafeRefCounted! Impl impl;
4074+
4075+ this (File f)
4076+ {
4077+ impl = SafeRefCounted! Impl(f);
4078+ }
4079+
4080+ @property bool empty()
4081+ {
4082+ return impl.borrow! ((ref r) => r.empty);
4083+ }
4084+
4085+ @property char front()
4086+ {
4087+ return impl.borrow! ((ref r) => r.front);
40624088 }
40634089
40644090 void popFront ()
40654091 {
4066- if (! _hasChar)
4067- empty;
4068- _hasChar = false ;
4092+ impl.borrow! ((ref r) { r.popFront; });
40694093 }
40704094}
40714095
@@ -4143,6 +4167,29 @@ struct LockingTextReader
41434167 fr.readf(" %s;%s;%s;%s\n " , &nom, &fam, &nam, &ot);
41444168}
41454169
4170+ // https://issues.dlang.org/show_bug.cgi?id=24165
4171+ @system unittest
4172+ {
4173+ // @system due to readf
4174+ static import std.file ;
4175+ import std.algorithm.iteration : joiner, map;
4176+ import std.algorithm.searching : canFind;
4177+ import std.array : array;
4178+ import std.utf : byChar;
4179+
4180+ string content = " -hello" ;
4181+ auto deleteme = testFilename();
4182+ std.file.write (deleteme, content);
4183+ scope (exit) std.file.remove (deleteme);
4184+ File f = File (deleteme);
4185+ int n;
4186+ try f.readf(" %d" , n);
4187+ catch (Exception e) {}
4188+ // Data read must match what was written
4189+ char [] result = f.byLine(Yes.keepTerminator).map! byChar.joiner.array;
4190+ assert (content.canFind(result));
4191+ }
4192+
41464193/**
41474194 * Indicates whether `T` is a file handle, i.e. the type
41484195 * is implicitly convertable to $(LREF File) or a pointer to a
0 commit comments