@@ -3993,79 +3993,103 @@ enum LockType
3993
3993
3994
3994
struct LockingTextReader
3995
3995
{
3996
- private File _f;
3997
- private char _front;
3998
- private bool _hasChar;
3999
-
4000
- this (File f)
3996
+ private static struct Impl
4001
3997
{
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;
4007
4001
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
+ }
4012
4009
4013
- ~this ()
4014
- {
4015
- if (_hasChar)
4016
- ungetc(_front, cast (FILE * )_f._p.handle);
4010
+ @disable this (this );
4017
4011
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);
4021
4016
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
+ }
4027
4020
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()
4031
4028
{
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)
4036
4030
{
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 ;
4039
4041
}
4040
- _front = cast (char ) c;
4041
- _hasChar = true ;
4042
+ return false ;
4042
4043
}
4043
- return false ;
4044
- }
4045
4044
4046
- @property char front()
4047
- {
4048
- if (! _hasChar)
4045
+ @property char front()
4049
4046
{
4050
- version ( assert )
4047
+ if ( ! _hasChar )
4051
4048
{
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
+ }
4055
4059
}
4056
- else
4057
- {
4060
+ return _front;
4061
+ }
4062
+
4063
+ void popFront ()
4064
+ {
4065
+ if (! _hasChar)
4058
4066
empty;
4059
- }
4067
+ _hasChar = false ;
4060
4068
}
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);
4062
4088
}
4063
4089
4064
4090
void popFront ()
4065
4091
{
4066
- if (! _hasChar)
4067
- empty;
4068
- _hasChar = false ;
4092
+ impl.borrow! ((ref r) { r.popFront; });
4069
4093
}
4070
4094
}
4071
4095
@@ -4143,6 +4167,29 @@ struct LockingTextReader
4143
4167
fr.readf(" %s;%s;%s;%s\n " , &nom, &fam, &nam, &ot);
4144
4168
}
4145
4169
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
+
4146
4193
/**
4147
4194
* Indicates whether `T` is a file handle, i.e. the type
4148
4195
* is implicitly convertable to $(LREF File) or a pointer to a
0 commit comments