Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
27.istream.sentry.cpp
Go to the documentation of this file.
1
29#include <istream>
30#include <locale> // for ctype
31#include <streambuf> // for streambuf
32
33#include <rw_char.h> // for UserChar, UserTraits
34#include <rw_printf.h> // for rw_printf()
35#include <rw_driver.h>
36
37
119void
120memfun_info (int line, const char *cname, const char *tname, const char *fname)
121{
122 // format the ISTREAM and SENTRY environment variables w/o writing
123 // out any output
124 rw_fprintf (0,
125 "%{$ISTREAM!:@}",
126 "%{?}istream%{:}%{?}wistream"
127 "%{:}basic_istream<%s, %s>%{;}%{;}",
128 'c' == *cname && 'c' == *tname,
129 'w' == *cname && 'c' == *tname,
130 cname, tname);
131
132 rw_fprintf (0,
133 "%{$SENTRY!:@}",
134 "%{$ISTREAM}::sentry");
135
136 // pass fname through the "%{@}" directive to expand any embedded
137 // %{$XYZ} directives
138 rw_info (0, 0, line, "std::%{$SENTRY}::%{@}", fname);
139}
140
141
143template <class charT>
144struct Ctype: std::ctype<charT>
145{
146 typedef std::ctype<charT> Base;
147
148 const charT ws_; // whitespace character
149
150 std::ctype_base::mask table_ [256];
151
152 Ctype (unsigned ref, charT white)
153 : Base (ref), ws_ (white) { }
154
155 // virtuals overridden below used by ctype<wchar_t>
156 // ctype<char> uses the table() member instead
157
158 /* virtual */ bool
159 do_is (std::ctype_base::mask m, charT c) const {
160 if (m & std::ctype_base::space)
161 return ws_ == c;
162 return Base::is (m, c);
163 }
164
165 /* virtual */ const charT*
166 do_is (const charT *from, const charT *to,
167 std::ctype_base::mask *m) const {
168 return Base::is (from, to, m);
169 }
170
171 /* virtual */ const charT*
172 do_scan_is (std::ctype_base::mask m,
173 const charT *from, const charT *to) const {
174 for (; from != to && !do_is (m, *from); ++from);
175 return from;
176 }
177
178 /* virtual */ const charT*
179 do_scan_not (std::ctype_base::mask m,
180 const charT *from, const charT *to) const {
181 for (; from != to && do_is (m, *from); ++from);
182 return from;
183 }
184};
185
186
187// specialized for ctype<char>
189Ctype<char>::Ctype (unsigned ref, char white)
190 : Base (table_, false, ref), ws_ (white)
191{
192 for (unsigned i = 0; i != sizeof table_ / sizeof *table_; ++i)
193 table_ [i] = std::ctype_base::mask ();
194
195 typedef unsigned char UChar;
196
197 table_ [UChar (ws_)] = std::ctype_base::space;
198}
199
200
201template <class charT, class Traits>
202struct Streambuf: std::basic_streambuf<charT, Traits>
203{
204 typedef std::basic_streambuf<charT, Traits> Base;
205
206 int nsyncs_;
207
208 Streambuf (const charT *gbeg, const charT *gend)
209 : Base (), nsyncs_ (0) {
210 this->setg (_RWSTD_CONST_CAST (charT*, gbeg),
211 _RWSTD_CONST_CAST (charT*, gbeg),
212 _RWSTD_CONST_CAST (charT*, gend));
213 }
214
215 const charT* pubeback () const {
216 return this->eback ();
217 }
218
219 const charT* pubgptr () const {
220 return this->gptr ();
221 }
222
223 const charT* pubegptr () const {
224 return this->egptr ();
225 }
226
227 /* virtual */ int sync () {
228 ++nsyncs_;
229 return Base::sync ();
230 }
231};
232
233
234template <class charT, class Traits>
235void test_ctor (const charT*, const Traits*,
236 const char *cname, const char *tname)
237{
238 typedef std::basic_istream<charT, Traits> Istream;
239 typedef typename Istream::sentry Sentry;
240
241 memfun_info (__LINE__, cname, tname, "sentry (%{$ISTREAM}&, bool)");
242
243 const charT cbuf[] = { 'a', 'b', 'c', 'd', 'e', ' ', 'f', '\0' };
244
245 const std::ios_base::iostate states[] = {
246 std::ios_base::badbit,
247 std::ios_base::eofbit,
248 std::ios_base::failbit,
249 std::ios_base::goodbit,
250 std::ios_base::badbit | std::ios_base::eofbit,
251 std::ios_base::badbit | std::ios_base::failbit,
252 std::ios_base::eofbit | std::ios_base::failbit,
253 std::ios_base::badbit | std::ios_base::eofbit | std::ios_base::failbit
254 };
255
257 // exercise 27.6.1.1.2, p1:
258 // - is.good() is true
259 // - is.tie() is not null
260 // = the function calls is.tie().flush()
261
262 unsigned iter = 0; // iteration counter
263
264 for (unsigned i = 0; i != sizeof states / sizeof *states; ++i) {
265 for (unsigned j = 0; j != 2; ++j /* noskipws */) {
267 sb (cbuf, cbuf + sizeof cbuf / sizeof *cbuf);
268
269 Istream is (&sb);
270
271 // flush() is called iff
272 // all of the following conditions hold
273 const bool flush_called = is.good () && 0 != is.tie ();
274
275 const Sentry guard (is, 0 != j);
276
277 _RWSTD_UNUSED (guard);
278
279 rw_assert (flush_called == sb.nsyncs_, 0, __LINE__,
280 "%u. basic_istream<%s, %s>::sentry::sentry"
281 "(basic_istream &is, bool noskipws = %d); "
282 "expected to call is.flush () %d times, got %d"
283 "initial is.state () = %{Is}, is.flags() & "
284 "ios::skipws = %d",
285 iter, cname, tname, 0 != j, flush_called, sb.nsyncs_,
286 states [i], is.flags () & std::ios_base::skipws);
287
288 ++iter;
289 }
290 }
291
293 // exercise 27.6.1.1.2, p1:
294 // - is.good() is true
295 // - noskipws is zero
296 // - is.flags() & ios_base::skipws
297 // = the function extracts and discards each character as long
298 // as the next available input character c is a whitespace
299 // character.
300
301 for (unsigned i = 0; i != sizeof states / sizeof *states; ++i) {
302 for (unsigned j = 0; j != 2; ++j /* noskipws */) {
303 for (unsigned k = 0; k != 2; ++k /* ios_base::skipws */) {
304 for (charT wc = charT ('a'); wc != charT ('c'); ++wc) {
305
306 const Ctype<charT> ctp (1, wc);
307
309 sb (cbuf, cbuf + sizeof cbuf / sizeof *cbuf);
310
311 Istream is (&sb);
312
313 is.setstate (states [i]);
314
315 if (k)
316 is.setf (std::ios_base::skipws);
317 else
318 is.unsetf (std::ios_base::skipws);
319
320 const std::locale loc =
321 is.imbue (std::locale (is.getloc (), &ctp));
322
323 // imbue the previous locale into the stream
324 // buffer to verify that the sentry ctor uses
325 // the locale imbued in the stream object and
326 // not the one in the stream buffer
327 sb.pubimbue (loc);
328
329 // a whitespace character is extracted iff
330 // all of the following conditions hold
331 const bool extract =
332 is.good ()
333 && 0 == j
334 && is.flags () & std::ios_base::skipws
335 && cbuf [0] == wc;
336
337 const Sentry guard (is, 0 != j);
338
339 _RWSTD_UNUSED (guard);
340
341 rw_assert (cbuf + extract == sb.pubgptr (), 0, __LINE__,
342 "%u. %{$SENTRY}::sentry"
343 "(%{$ISTREAM} &is, bool noskipws "
344 "= %b); expected to extract %d "
345 "whitespace chars ('%c') from %{*Ac}, "
346 "extracted %u; initial is.state () = "
347 "%{Is}, is.flags() & ios::skipws = %d",
348 iter, j, extract + 0, char (wc),
349 int (sizeof (*cbuf)), cbuf,
350 sb.pubgptr () - sb.pubeback (),
351 states [i], k);
352
353 // verify that the ctor doesn't affect gcount()
354 rw_assert (0 == is.gcount (), 0, __LINE__,
355 "%u. %{$SENTRY}::sentry"
356 "(%{$ISTREAM} &is = %{*Ac}, bool noskipws "
357 "= %b); changed is.gcount() from 0 to %i",
358 iter, int (sizeof (*cbuf)), cbuf, j,
359 is.gcount ());
360
361 ++iter;
362 }
363 }
364 }
365 }
366}
367
368
370template <class charT, class Traits>
371void test_ok (const charT*, const Traits*,
372 const char *cname, const char *tname)
373{
374 typedef std::basic_istream<charT, Traits> Istream;
375 typedef typename Istream::sentry Sentry;
376
377 memfun_info (__LINE__, cname, tname, "operator bool () const");
378
379 const charT cbuf[] = { 'a', 'b', 'c', 'd', 'e', ' ', 'f', '\0' };
380
381 const std::ios_base::iostate states[] = {
382 std::ios_base::badbit,
383 std::ios_base::eofbit,
384 std::ios_base::failbit,
385 std::ios_base::goodbit,
386 std::ios_base::badbit | std::ios_base::eofbit,
387 std::ios_base::badbit | std::ios_base::failbit,
388 std::ios_base::eofbit | std::ios_base::failbit,
389 std::ios_base::badbit | std::ios_base::eofbit | std::ios_base::failbit
390 };
391
393 // exercise 27.6.1.1.2, p5:
394 // - is.good() is true
395 // - noskipws is zero
396 // - is.flags() & ios_base::skipws
397 // - the function extracts and discards each character as long
398 // as the next available input character c is a whitespace
399 // character
400 // = if, after any preparation is completed, is.good() is true,
401 // ok_ != false otherwise, ok_ == false.
402
403 unsigned iter = 0; // iteration counter
404
405 for (unsigned i = 0; i != sizeof states / sizeof *states; ++i) {
406 for (unsigned j = 0; j != 2; ++j /* noskipws */) {
407 for (unsigned k = 0; k != 2; ++k /* ios_base::skipws */) {
408 for (charT wc = charT ('a'); wc != charT ('c'); ++wc) {
409
410 const Ctype<charT> ctp (1, wc);
411
413 sb (cbuf, cbuf + sizeof cbuf / sizeof *cbuf);
414
415 Istream is (&sb);
416
417 is.setstate (states [i]);
418
419 if (k)
420 is.setf (std::ios_base::skipws);
421 else
422 is.unsetf (std::ios_base::skipws);
423
424 const std::locale loc =
425 is.imbue (std::locale (is.getloc (), &ctp));
426
427 // imbue the previous locale into the stream
428 // buffer to verify that the sentry ctor uses
429 // the locale imbued in the stream object and
430 // not the one in the stream buffer
431 sb.pubimbue (loc);
432
433 const Sentry guard (is, 0 != j);
434
435 _RWSTD_UNUSED (guard);
436
437 // verify that both are either false or true
438 const bool success = !is.good () == !guard;
439
440 rw_assert (success, 0, __LINE__,
441 "%u. %{$SENTRY}"
442 "(%{$ISTREAM} &is, bool noskipws "
443 "= %d).operator bool() == %d; initial "
444 "is.state() = %{Is}, is.flags() & "
445 "ios::skipws = %d",
446 iter, j, is.good (),
447 states [i], k);
448
449 ++iter;
450 }
451 }
452 }
453 }
454}
455
456
458static int opt_char;
459static int opt_wchar;
460static int opt_char_traits;
461static int opt_user_traits;
462
463
464static int
465run_test (int, char**)
466{
467#define TEST(what, charT, Traits) \
468 test_ ## what ((charT*)0, (Traits*)0, #charT, #Traits)
469
470 using namespace std;
471
472 if (rw_note (0 <= opt_char && 0 <= opt_char_traits, 0, __LINE__,
473 "istream::sentry tests disabled")) {
474 TEST (ctor, char, char_traits<char>);
475 TEST (ok, char, char_traits<char>);
476 }
477
478 if (rw_note (0 <= opt_char && 0 <= opt_user_traits, 0, __LINE__,
479 "basic_istream<char, UserTraits<char>::sentry "
480 "tests disabled")) {
481 TEST (ctor, char, UserTraits<char>);
482 TEST (ok, char, UserTraits<char>);
483 }
484
485#ifndef _RWSTD_NO_WCHAR_T
486
487 if (rw_note (0 <= opt_wchar && 0 <= opt_char_traits, 0, __LINE__,
488 "wistream::sentry tests disabled")) {
489 TEST (ctor, wchar_t, char_traits<wchar_t>);
490 TEST (ok, wchar_t, char_traits<wchar_t>);
491 }
492
493 if (rw_note (0 <= opt_wchar && 0 <= opt_user_traits, 0, __LINE__,
494 "basic_istream<wchar_t, UserTraits<wchar_t>::sentry "
495 "tests disabled")) {
496 TEST (ctor, wchar_t, UserTraits<wchar_t>);
497 TEST (ok, wchar_t, UserTraits<wchar_t>);
498 }
499
500#endif // _RWSTD_NO_WCHAR_T
501
502 return 0;
503
504}
505
506
508int main (int argc, char *argv[])
509{
510 return rw_test (argc, argv, __FILE__,
511 "istream.sentry",
512 0 /* no comment */,
513 run_test,
514 "|-char~ "
515 "|-wchar_t~ "
516 "|-char_traits~ "
517 "|-UserTraits~ ",
518 &opt_char,
519 &opt_wchar,
520 &opt_char_traits,
521 &opt_user_traits,
522 (void*)0 /* sentinel */);
523}
#define m
Definition 17.names.cpp:129
#define i
Definition 17.names.cpp:126
#define k
Definition 17.names.cpp:128
#define line
Definition 17.names.cpp:490
#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
int opt_wchar
int opt_char
void run_test(const ForwardIterator &dummy, T *, Predicate *pred)
std::char_traits< S > Traits
const std::ios_base::iostate states[]
void test_ctor(const charT *, const Traits *, const char *cname, const char *tname)
void test_ok(const charT *, const Traits *, const char *cname, const char *tname)
void memfun_info(int line, const char *cname, const char *tname, const char *fname)
#define TEST(what, charT, Traits)
#define main
#define _RWSTD_SPECIALIZED_CLASS
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
#define _RWSTD_CONST_CAST(T, x)
Definition _defs.h:536
Definition json.h:5363
_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
_TEST_EXPORT int rw_fprintf(rw_file *, const char *,...)
Definition printf.cpp:3397
unsigned char UChar
Definition collate.cpp:122
#define false
Definition stdbool.h:26
std::ctype_base::mask table_[256]
const charT * do_scan_is(std::ctype_base::mask m, const charT *from, const charT *to) const
std::ctype< charT > Base
const charT * do_is(const charT *from, const charT *to, std::ctype_base::mask *m) const
const charT ws_
bool do_is(std::ctype_base::mask m, charT c) const
const charT * do_scan_not(std::ctype_base::mask m, const charT *from, const charT *to) const
Ctype(unsigned ref, charT white)
const charT * pubeback() const
std::basic_streambuf< charT, Traits > Base
const charT * pubgptr() const
Streambuf(const charT *gbeg, const charT *gend)
const charT * pubegptr() const