32b604d5b15a2812e7bda9a0f2474af0eaff9678
[gcc.git] / libstdc++-v3 / testsuite / 27_io / basic_istream / ignore / char / 94749.cc
1 // Copyright (C) 2020 Free Software Foundation, Inc.
2 //
3 // This file is part of the GNU ISO C++ Library. This library is free
4 // software; you can redistribute it and/or modify it under the
5 // terms of the GNU General Public License as published by the
6 // Free Software Foundation; either version 3, or (at your option)
7 // any later version.
8
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13
14 // You should have received a copy of the GNU General Public License along
15 // with this library; see the file COPYING3. If not see
16 // <http://www.gnu.org/licenses/>.
17
18 // { dg-do run }
19 // { dg-options "-DSIMULATOR_TEST" { target simulator } }
20
21 // PR libstdc++/94749
22 // basic_istream::ignore(n, c) discards n+1 if next character is equal to c.
23
24 #include <sstream>
25 #include <limits>
26 #include <testsuite_hooks.h>
27
28 typedef char C;
29
30 void
31 test01()
32 {
33 std::basic_istringstream<C> s(" + -");
34 s.ignore(1, '+');
35 VERIFY( s.gcount() == 1 );
36 VERIFY( s.get() == '+' );
37 s.ignore(3, '-');
38 VERIFY( s.gcount() == 3 );
39 VERIFY( s.get() == '-' );
40 }
41
42 void
43 test02()
44 {
45 std::basic_istringstream<C> s(".+...-");
46 s.ignore(1, '+');
47 VERIFY( s.gcount() == 1 );
48 VERIFY( s.get() == '+' );
49 s.ignore(3, '-');
50 VERIFY( s.gcount() == 3 );
51 VERIFY( s.get() == '-' );
52 }
53
54 void
55 test03()
56 {
57 std::basic_istringstream<C, __gnu_cxx::char_traits<C> > s(" + -");
58 s.ignore(1, '+');
59 VERIFY( s.gcount() == 1 );
60 VERIFY( s.get() == '+' );
61 s.ignore(3, '-');
62 VERIFY( s.gcount() == 3 );
63 VERIFY( s.get() == '-' );
64 }
65
66 void
67 test04()
68 {
69 std::basic_istringstream<C, __gnu_cxx::char_traits<C> > s(".+...-");
70 s.ignore(1, '+');
71 VERIFY( s.gcount() == 1 );
72 VERIFY( s.get() == '+' );
73 s.ignore(3, '-');
74 VERIFY( s.gcount() == 3 );
75 VERIFY( s.get() == '-' );
76 }
77
78 // The original fix for PR libstdc++/94749 failed to discard the delimiter
79 // if it occurred after numeric_limits<streamsize>::max() had been seen.
80 // This streambuf will keep filling the get area with zero bytes until
81 // almost numeric_limits<streamsize>::max() characters have been read,
82 // and then return one more buffer that has "123" at its end.
83 template<typename T>
84 struct buff : std::basic_streambuf<typename T::char_type, T>
85 {
86 typedef typename T::char_type char_type;
87 typedef typename T::int_type int_type;
88 typedef std::streamsize streamsize;
89 typedef std::numeric_limits<streamsize> limits;
90
91 buff() : count(0), buf() { }
92
93 int_type underflow()
94 {
95 // Number of characters left until we overflow the counter
96 const streamsize headroom = limits::max() - count;
97
98 if (headroom == 0)
99 return T::eof();
100
101 if (bufsz < headroom)
102 {
103 this->setg(buf, buf, buf + bufsz);
104 count += bufsz;
105 }
106 else
107 {
108 // write "123" across the 2GB boundary
109 buf[headroom-1] = '1';
110 buf[headroom+0] = '2';
111 buf[headroom+1] = '3';
112 this->setg(buf, buf, buf + headroom + 2);
113 count = limits::max();
114 }
115
116 return buf[0];
117 }
118
119 streamsize count;
120
121 static const streamsize bufsz = 2048 << limits::digits10;
122 char_type buf[bufsz + 2];
123 };
124
125 void
126 test05()
127 {
128 // Not possible to overflow 64-bit streamsize in reasonable time.
129 if (std::numeric_limits<std::streamsize>::digits > 32)
130 return;
131
132 typedef std::char_traits<C> T;
133
134 std::basic_istream<C, T> in(new buff<T>);
135
136 in.ignore(std::numeric_limits<std::streamsize>::max(), '1');
137 VERIFY(in.good());
138 VERIFY(in.gcount() == std::numeric_limits<std::streamsize>::max());
139 VERIFY(in.get() == '2');
140 VERIFY(in.get() == '3');
141 VERIFY(in.get() == T::eof());
142
143 delete in.rdbuf(new buff<T>);
144
145 in.ignore(std::numeric_limits<std::streamsize>::max(), '2');
146 VERIFY(in.good());
147 // The standard doesn't say what gcount() should return in this case:
148 VERIFY(in.gcount() == std::numeric_limits<std::streamsize>::max());
149 VERIFY(in.get() == '3');
150 VERIFY(in.get() == T::eof());
151
152 delete in.rdbuf(new buff<T>);
153
154 in.ignore(std::numeric_limits<std::streamsize>::max(), '3');
155 VERIFY(in.good());
156 // The standard doesn't say what gcount() should return in this case:
157 VERIFY(in.gcount() == std::numeric_limits<std::streamsize>::max());
158 VERIFY(in.get() == T::eof());
159
160 delete in.rdbuf(new buff<T>);
161
162 in.ignore(std::numeric_limits<std::streamsize>::max(), '4');
163 VERIFY(in.eof());
164 // The standard doesn't say what gcount() should return in this case:
165 VERIFY(in.gcount() == std::numeric_limits<std::streamsize>::max());
166 VERIFY(in.get() == T::eof());
167
168 delete in.rdbuf(nullptr);
169 }
170
171 void
172 test06()
173 {
174 if (std::numeric_limits<std::streamsize>::digits > 32)
175 return;
176
177 typedef __gnu_cxx::char_traits<C> T;
178
179 std::basic_istream<C, T> in(new buff<T>);
180
181 in.ignore(std::numeric_limits<std::streamsize>::max(), '1');
182 VERIFY(in.good());
183 VERIFY(in.gcount() == std::numeric_limits<std::streamsize>::max());
184 VERIFY(in.get() == '2');
185 VERIFY(in.get() == '3');
186 VERIFY(in.get() == T::eof());
187
188 delete in.rdbuf(new buff<T>);
189
190 in.ignore(std::numeric_limits<std::streamsize>::max(), '2');
191 VERIFY(in.good());
192 // The standard doesn't say what gcount() should return in this case:
193 VERIFY(in.gcount() == std::numeric_limits<std::streamsize>::max());
194 VERIFY(in.get() == '3');
195 VERIFY(in.get() == T::eof());
196
197 delete in.rdbuf(new buff<T>);
198
199 in.ignore(std::numeric_limits<std::streamsize>::max(), '3');
200 VERIFY(in.good());
201 // The standard doesn't say what gcount() should return in this case:
202 VERIFY(in.gcount() == std::numeric_limits<std::streamsize>::max());
203 VERIFY(in.get() == T::eof());
204
205 delete in.rdbuf(new buff<T>);
206
207 in.ignore(std::numeric_limits<std::streamsize>::max(), '4');
208 VERIFY(in.eof());
209 // The standard doesn't say what gcount() should return in this case:
210 VERIFY(in.gcount() == std::numeric_limits<std::streamsize>::max());
211 VERIFY(in.get() == T::eof());
212
213 delete in.rdbuf(nullptr);
214 }
215
216 int
217 main()
218 {
219 test01();
220 test02();
221 test03();
222 test04();
223 test05();
224 #ifndef SIMULATOR_TEST
225 test06();
226 #endif
227 }