Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
27.istream.manip.cpp
Go to the documentation of this file.
1
29#include <cstddef>
30#include <istream>
31
32#include <rw_driver.h>
33
34
51template <class charT>
52struct Ctype: std::ctype<charT>
53{
54 typedef std::ctype<charT> Base;
55
56 const charT ws_; // whitespace character
57
58 std::ctype_base::mask table_ [256];
59
60 Ctype (std::size_t ref, charT white)
61 : Base (ref), ws_ (white) { }
62
63 // used by ctype<wchar_t>
64 /* virtual */ bool
65 do_is (std::ctype_base::mask m, charT c) const {
66 if (m & std::ctype_base::space)
67 return ws_ == c;
68 return Base::is (m, c);
69 }
70
71 // not used by the test, defined only to silence compiler warnings
72 // about the overload above hiding the base function overloaded below
73 /* virtual */ const charT*
74 do_is (const charT *lo, const charT *hi, std::ctype_base::mask *m) const {
75 return Base::do_is (lo, hi, m);
76 }
77};
78
79
80// specialized for ctype<char>
82Ctype<char>::Ctype (std::size_t ref, char white)
83 : Base (table_, false, ref), ws_ (white)
84{
85 for (std::size_t i = 0; i != sizeof table_ / sizeof *table_; ++i)
86 table_ [i] = std::ctype_base::mask ();
87
88 typedef unsigned char UChar;
89
90 table_ [UChar (ws_)] = std::ctype_base::space;
91}
92
93
94// user-defined Traits type exercises the ability to instantiate
95// std::ws and any supporting templates on types other than the
96// default std::char_traits<charT>
97template <class charT>
98struct UserTraits: std::char_traits<charT> { };
99
100
101template <class charT, class Traits>
102struct Streambuf: std::basic_streambuf<charT, Traits>
103{
104 typedef std::basic_streambuf<charT, Traits> Base;
105
106 typedef typename Base::traits_type traits_type;
107 typedef typename Base::int_type int_type;
108
109 int nsyncs_; // number of calls to sync()
110
111 // overflow() will return eof () after extracting this many chars
113
114 // overflow() will throw am exception after extracting this many chars
116
117 const charT *end_; // the end of the buffer (future eback())
118
119 Streambuf (const charT *gbeg, const charT *gend)
120 : Base (),
121 nsyncs_ (0),
122 fail_after_ (-1), // never fail
123 throw_after_ (-1), // never throw
124 end_ (gend) {
125 this->setg (_RWSTD_CONST_CAST (charT*, gbeg),
126 _RWSTD_CONST_CAST (charT*, gbeg),
127 _RWSTD_CONST_CAST (charT*, gbeg));
128 }
129
130 const charT* pubeback () const {
131 return this->eback ();
132 }
133
134 const charT* pubgptr () const {
135 return this->gptr ();
136 }
137
138 const charT* pubegptr () const {
139 return this->egptr ();
140 }
141
142 /* virtual */ int sync () {
143 ++nsyncs_;
144 return Base::sync ();
145 }
146
147 /* virtual */ int_type underflow () {
148 if (this->gptr () == end_)
149 return traits_type::eof ();
150
151 if (throw_after_ == this->gptr () - this->eback ()) {
152
153#ifndef _RWSTD_NO_EXCEPTIONS
154
155 throw throw_after_;
156
157#else // if defined (_RWSTD_NO_EXCEPTIONS)
158
159 return traits_type::eof ();
160
161#endif // _RWSTD_NO_EXCEPTIONS
162
163 }
164
165 if (fail_after_ == this->gptr () - this->eback ())
166 return traits_type::eof ();
167
168 this->setg (this->eback (), this->gptr (), this->gptr () + 1);
169 return traits_type::to_int_type (*this->gptr ());
170 }
171};
172
173
175template <class charT, class Traits>
176void
177test_ws (const Traits* /* dummy */,
178 const char *cname,
179 const char *tname,
180 std::size_t iter,
181 const charT *cbuf,
182 std::size_t cbuf_size,
183 std::ios_base::iostate state,
184 std::size_t j,
185 bool skipws,
186 charT white)
187{
188 typedef std::basic_istream<charT, Traits> Istream;
189 typedef typename Istream::sentry Sentry;
190
191 // construct a ctype object that treats `wc' as the only
192 // whitespace character
193 const Ctype<charT> ctp (1, white);
194
195 // construct a stream buffer object and initialize its read sequence
196 // with the character buffer
197 Streambuf<charT, Traits> sb (cbuf, cbuf + cbuf_size - 1);
198
199 // set err_after to the number of successful extractions from
200 // the stream; subsequent extraction will cause an error
201 const std::size_t err_after = j % (cbuf_size - 1);
202 const char *err_type;
203
204 if (j < cbuf_size - 1) {
205 // have the stream buffer object's underflow() fail (by throwing
206 // an exception if possible) after j characters have been extracted
207 // (this object calls underflow() for every char)
208 sb.throw_after_ = int (err_after);
209 err_type = "threw";
210 }
211 else {
212 // have the stream buffer object's underflow() fail by returning
213 // eof after j characters have been extracted (this object calls
214 // underflow() for every char)
215 sb.fail_after_ = int (err_after);
216 err_type = "returned EOF";
217 }
218
219 // construct an istream object and initialize it with the user
220 // defined streambuf object
221 Istream is (&sb);
222
223 // set the stream object's initial state
224 is.setstate (state);
225
226 // set or clear the skipws bit
227 if (skipws)
228 is.setf (std::ios_base::skipws);
229 else
230 is.unsetf (std::ios_base::skipws);
231
232 // construct a locale object containing the user-defined ctype object
233 const std::locale loc = is.imbue (std::locale (is.getloc (), &ctp));
234
235 // imbue the previous locale into the stream buffer to verify that
236 // the ws manipulator uses the locale imbued in the stream object
237 // and not the one in the stream buffer
238 sb.pubimbue (loc);
239
240 // the number of extracted whitespace characters expected to
241 // be reported by gcount() must equal the number of successful
242 // extractions computed by the the stream buffer overridden
243 // underflow member function
244 const int extract = is.good () && white == cbuf [0] ? int (err_after) : 0;
245
246#ifndef _RWSTD_NO_EXCEPTIONS
247
248 bool caught = false;
249
250 // on every other iteration set badbit in exceptions to check
251 // that the thrown object is propagated by the function
252 if (err_after % 2 && !is.bad ())
253 is.exceptions (std::ios_base::badbit);
254
255 try {
256 std::ws (is);
257 }
258 catch (int) {
259 caught = true;
260 }
261 catch (...) {
262
263 caught = true;
264
265 rw_assert (false, 0, __LINE__,
266 "%u. std::ws (basic_istream<%s, %s >&);"
267 " threw exception of unexpected type",
268 iter, cname, tname);
269 }
270
272 // verify that the function propagates exceptions thrown from the
273 // streambuf object only when badbit is set in the stream object's
274 // exceptions()
275
276 rw_assert (!(caught && !(err_after % 2)), 0, __LINE__,
277 "%u. std::ws (basic_istream<%s, %s>&);"
278 " unexpectedly propagated exception",
279 iter, cname, tname);
280
281#else // if defined (_RWSTD_NO_EXCEPTIONS)
282
283 std::ws (is);
284
285#endif // _RWSTD_NO_EXCEPTIONS
286
288 // verify that the expected number of whitespace characters have
289 // been extracted from the stream
290
291 rw_assert (cbuf + extract == sb.pubgptr (), 0, __LINE__,
292 "%u. std::ws (basic_istream<%s, %s>&);"
293 " expected to extract %d "
294 "whitespace chars ('%c') from %{*Ac}, "
295 "extracted %u; initial rdstate() = %{Is}, "
296 "is.flags() & ios::skipws = %d, "
297 "underflow %s at extraction %u",
298 iter, cname, tname, extract, (char)(white),
299 int (sizeof *cbuf), cbuf,
300 sb.pubgptr () - sb.pubeback (), state,
301 skipws, err_type, err_after);
302
304 // verify that gcount() value not affected (27.6.1.4 p1)
305
306 rw_assert (0 == is.gcount (), 0, __LINE__,
307 "%u. std::ws (basic_istream<%s, %s >&)."
308 "gcount() == %d, got %d; whitespace is"
309 " '%c', input is %{*Ac}, initial rdstate() = %{Is}, "
310 "flags() & ios::skipws = %d,"
311 " underflow %s at extraction %u",
312 iter, cname, tname, extract, is.gcount (),
313 (char)(white), int (sizeof *cbuf), cbuf, state,
314 skipws, err_type, err_after);
315
317 // verify the state of the stream object after the function call
318
319 // expected stream state after the function call is unchanged
320 // (i.e., the initial stream state), // except...
321 std::ios_base::iostate expect_state = state;
322
323 if (state) {
324 // lwg 419
325 expect_state |= std::ios_base::failbit;
326 }
327 else if (white == cbuf [0] || !err_after) {
328
329#ifndef _RWSTD_NO_EXCEPTIONS
330
331 // ...when any whitespace characters are extracted, or the
332 // first character on the stream is peeked at, even if it's
333 // not a space, and an exception is thrown during input,
334 // badbit should be set, otherwise eofbit (bot not failbit)
335 // should be set
336 if (j < cbuf_size - 1)
337 expect_state = std::ios_base::badbit;
338 else
339 expect_state = std::ios_base::eofbit;
340
341#else // if defined (_RWSTD_NO_EXCEPTIONS)
342
343 expect_state = std::ios_base::eofbit;
344
345#endif // _RWSTD_NO_EXCEPTIONS
346 }
347
348 rw_assert (is.rdstate () == expect_state, 0, __LINE__,
349 "%u. std::ws (basic_istream<%s, %s >&)."
350 "rdstate() == %{Is}, got %{Is}; "
351 "extracting whitespace ('%c') from %{*Ac}, "
352 "extracted %u; initial is.rdstate() = %{Is}, "
353 "is.flags() & ios::skipws = %d, underflow %s "
354 "at extraction %u",
355 iter, cname, tname,
356 expect_state, is.rdstate(),
357 (char)(white), int (sizeof *cbuf), cbuf,
358 sb.pubgptr () - sb.pubeback (), state,
359 skipws, err_type, err_after);
360}
361
362
365template <class charT, class Traits>
366void test_ws (charT*, Traits*, const char *cname, const char *tname)
367{
368 rw_info (0, 0, __LINE__, "std::basic_istream<%s, %s>& "
369 "std::ws (std::basic_istream<%1$s, %2$s>&)",
370 cname, tname);
371
372 const charT cbuf[] = { 'a', 'a', 'a', '\0' };
373 const std::size_t cbuf_size = sizeof cbuf / sizeof *cbuf;
374
375 const std::ios_base::iostate states[] = {
376 std::ios_base::badbit,
377 std::ios_base::eofbit,
378 std::ios_base::failbit,
379 std::ios_base::goodbit,
380 std::ios_base::badbit | std::ios_base::eofbit,
381 std::ios_base::badbit | std::ios_base::failbit,
382 std::ios_base::eofbit | std::ios_base::failbit,
383 std::ios_base::badbit | std::ios_base::eofbit | std::ios_base::failbit
384 };
385
386 const std::size_t nstates = sizeof states / sizeof *states;
387
388 {
389 // exercise 27.6.1.4, p1
390
391 std::size_t iter = 0; // iteration counter
392
393 // iterate over all possible settings of the stream state
394 for (std::size_t i = 0; i != nstates; ++i) {
395
396 // iterate twice over all characters in the character buffer,
397 // once to trigger an exception at each iteration (except
398 // the last one), and then again to have underflow() fail
399 // by returning EOF at each iteration (except the last one)
400 for (std::size_t j = 0; j != 2 * cbuf_size - 1; ++j) {
401
402 // iterate over the ios_base::skipws setting
403 for (std::size_t k = 0; k != 2; ++k /* skipws */) {
404
405 // iterate over two whitespace characters
406 for (charT wc = charT ('a'); wc != charT ('c'); ++wc) {
407
408 test_ws ((Traits*)0, cname, tname, iter,
409 cbuf, cbuf_size, states [i], j, !!k, wc);
410
411 ++iter;
412 }
413 }
414 }
415 }
416 }
417}
418
419
421static int opt_char;
422static int opt_wchar;
423static int opt_char_traits;
424static int opt_user_traits;
425
426
427static int
428run_test (int, char**)
429{
430#define TEST(charT, Traits) \
431 test_ws ((charT*)0, (Traits*)0, #charT, #Traits)
432
433 if (rw_note (0 <= opt_char && 0 <= opt_char_traits, 0, __LINE__,
434 "ws (basic_istream<char, char_traits<char>>) disabled"))
435 TEST (char, std::char_traits<char>);
436
437 if (rw_note (0 <= opt_char && 0 <= opt_user_traits, 0, __LINE__,
438 "ws (basic_istream<char, UserTraits<char>>) disabled"))
439 TEST (char, UserTraits<char>);
440
441#ifndef _RWSTD_NO_WCHAR_T
442
443 if (rw_note (0 <= opt_wchar && 0 <= opt_char_traits, 0, __LINE__,
444 "ws (basic_istream<wchar_t, char_traits<wchar_t>>) disabled"))
445 TEST (wchar_t, std::char_traits<wchar_t>);
446
447 if (rw_note (0 <= opt_wchar && 0 <= opt_user_traits, 0, __LINE__,
448 "ws (basic_istream<wchar_t, UserTraits<wchar_t>>) disabled"))
449 TEST (wchar_t, UserTraits<wchar_t>);
450
451#endif // _RWSTD_NO_WCHAR_T
452
453 return 0;
454}
455
456
458int main (int argc, char *argv[])
459{
460 return rw_test (argc, argv, __FILE__,
461 "istream.manip",
462 0 /* no comment */,
463 run_test,
464 "|-char~ "
465 "|-wchar_t~ "
466 "|-char_traits~ "
467 "|-UserTraits~ ",
468 &opt_char,
469 &opt_wchar,
470 &opt_char_traits,
471 &opt_user_traits,
472 (void*)0 /* sentinel */);
473}
#define m
Definition 17.names.cpp:129
#define i
Definition 17.names.cpp:126
#define k
Definition 17.names.cpp:128
#define loc
Definition 17.names.cpp:492
#define sb
Definition 17.names.cpp:542
#define j
Definition 17.names.cpp:127
#define c
Definition 17.names.cpp:111
#define charT
Definition 17.names.cpp:456
#define skipws
int opt_wchar
int opt_char
void run_test(const ForwardIterator &dummy, T *, Predicate *pred)
std::char_traits< S > Traits
#define TEST(charT, Traits)
void test_ws(const Traits *, const char *cname, const char *tname, std::size_t iter, const charT *cbuf, std::size_t cbuf_size, std::ios_base::iostate state, std::size_t j, bool skipws, charT white)
const std::ios_base::iostate states[]
const unsigned nstates
#define main
#define _RWSTD_SPECIALIZED_CLASS
int caught
#define _RWSTD_CONST_CAST(T, x)
Definition _defs.h:536
_TEST_EXPORT int rw_test(int argc, char *argv[], const char *filename, const char *clause, const char *comment, int(*testfun)(int, char **), const char *optspec,...)
_TEST_EXPORT int rw_info(int, const char *, int, const char *,...)
Definition driver.cpp:1681
_TEST_EXPORT int rw_note(int, const char *, int, const char *,...)
Definition driver.cpp:1664
_TEST_EXPORT int rw_assert(int, const char *, int, const char *,...)
Definition driver.cpp:1630
unsigned char UChar
Definition collate.cpp:122
#define false
Definition stdbool.h:26
std::ctype_base::mask table_[256]
const charT * do_is(const charT *lo, const charT *hi, std::ctype_base::mask *m) const
std::ctype< charT > Base
const charT ws_
bool do_is(std::ctype_base::mask m, charT c) const
Ctype(std::size_t ref, charT white)
const charT * end_
const charT * pubeback() const
Base::int_type int_type
std::basic_streambuf< charT, Traits > Base
const charT * pubgptr() const
int_type underflow()
Streambuf(const charT *gbeg, const charT *gend)
Base::traits_type traits_type
const charT * pubegptr() const