/*********************************************************************** * * 24.istream.iterator.cpp - test exercising [istream.iterator] * * $Id: 24.istream.iterator.cpp 648752 2008-04-16 17:01:56Z faridz $ * *********************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * ***********************************************************************/ #include // for stringstream #include // for istream_iterator #include // for ptrdiff_t #include #include #include /***********************************************************************/ // names of template parameters struct ParamNames { const char *tname; // name of the T parameter const char *tfmt; // rw_printf()-style format for T const char *cname; // name of the CharT parameter const char *trname; // name of the Traits parameter const char *dname; // name of the Distance parameter }; // format the template-id of the iterator void fmtnam (const ParamNames &pn) { // omit names of unspecified (default) template arguments const char* const id = pn.cname ? pn.trname ? pn.dname ? "<%s, %s, %s, %s>" : "<%s, %s, %s>" : "<%s, %s>" : "<%s>"; rw_fprintf (0, "%{$ITER!:@}", "istream_iterator%{@}", id, pn.tname, pn.cname, pn.trname, pn.dname); } /***********************************************************************/ // for convenience template struct TempParams { ParamNames names; }; // exercise istream_iterator ctors template void test_ctors (const TempParams ¶ms) { typedef std::istream_iterator Iterator; typedef std::basic_stringstream StringStream; const Iterator eos1; const Iterator eos2; // verify [reverse.iter], p3, i.e., that two end-of-istream // always compare equal, and that no end-of-stream iterator // compares equal to a non-end-of-stream iterator fmtnam (params.names); rw_assert (eos1 == eos2, 0, __LINE__, "%{$ITER}::istream_iterator() == %{$ITER}::istream_iterator()"); StringStream strm1; // make sure the stream object's locale contains the expected // specialization of the num_get facet (in case CharT isn't // char or wchar_t, or Traits isn't std::char_traits) typedef std::istreambuf_iterator StreambufIterator; typedef std::num_get NumGet; if (false == std::has_facet(strm1.getloc ())) { const std::locale loc (std::locale::classic (), new NumGet); strm1.imbue (loc); } // insert a couple of items into the stream, one for each iterator // below, to prevent the iterator ctor from creating an end-of-stream // iterator (in case it doesn't delay extracting a value until it's // needed) strm1 << "1 2 "; // verify [reverse.iter], p3, i.e., that two istream_iterators // constructed from the same stream always compare equal const Iterator iter1 (strm1); const Iterator iter2 (strm1); rw_assert (iter1 != eos1, 0, __LINE__, "%{$ITER}::istream_iterator(basic_istream&) != " "%{$ITER}()"); rw_assert (iter1 == iter2, 0, __LINE__, "%{$ITER}::istream_iterator(basic_istream&) == " "%{$ITER}::istream_iterator(basic_istream&)"); StringStream strm2; strm2.imbue (strm1.getloc ()); strm2 << "2 "; const Iterator iter3 (strm2); rw_assert (iter3 != eos1, 0, __LINE__, "%{$ITER}::istream_iterator(basic_istream&) != " "%{$ITER}()"); // verify that iterators into different streams compare unequal rw_assert (iter3 != iter1, 0, __LINE__, "%{$ITER}::istream_iterator(basic_istream& [@%#p]) != " "%{$ITER}::istream_iterator(basic_istream& [@%#p])", &strm2, &strm1); } /***********************************************************************/ // worker to exercise operator*() template void test_ops (const TempParams ¶ms, int line, const char *input, T expect, bool is_eos, int state) { typedef std::istream_iterator Iterator; typedef std::basic_stringstream StringStream; fmtnam (params.names); StringStream strm; typedef std::istreambuf_iterator StreambufIterator; typedef std::num_get NumGet; if (false == std::has_facet(strm.getloc ())) { const std::locale loc (std::locale::classic (), new NumGet); strm.imbue (loc); } if (input && *input) strm << input; const Iterator eos; const Iterator it (strm); rw_assert (is_eos ^ (it != eos), 0, line, "line %d: %{$ITER}::operator() != %{$ITER}()", __LINE__); if (0 == (strm.rdstate () & (strm.badbit | strm.failbit))) { // operator*() is defined only for non-eos iterators // avoid calling it on a bad or failed stream too const T val = *it; rw_assert (val == expect, 0, line, "line %d: %{$ITER}::operator*() == %{@}, got %{@}", __LINE__, params.names.tfmt, expect, params.names.tfmt, val); } rw_assert (strm.rdstate () == state, 0, line, "line %d: %{$ITER}::operator*(), rdstate() == %{Is}, got %{Is}", __LINE__, state, strm.rdstate ()); } /***********************************************************************/ // exercise operator*() template void test_ops (const TempParams ¶ms) { // const int Bad = std::ios::badbit; const int Eof = std::ios::eofbit; const int Fail = std::ios::failbit; const int Good = std::ios::goodbit; #undef TEST #define TEST(input, expect, is_eos, state) \ test_ops (params, __LINE__, input, T (expect), is_eos, state) volatile T one = T (1); volatile T zero = one - one; volatile T two = one + one; const bool is_char = sizeof (T) == sizeof (char); const bool is_signed = zero - one < zero; const bool is_exact = one / two == zero; // see LWG issue 788 // an istream_iterator object becomes an end-of-stream iterator // after a failed extraction (i.e., when the call to fail() on // the associated stream returns true) if (is_char) { // +-- controlled sequence // | +-- extracted value // | | +-- iterator equal to EOS after extraction // | | | +-- stream state after extraction // | | | | // V V V V TEST ("", '\0', true, Eof | Fail); TEST ("1", '1', false, Good); TEST ("2", '2', false, Good); } else { TEST ("", 0, true, Eof | Fail); TEST ("1", 1, false, Eof); TEST ("1 ", 1, false, Good); TEST ("+1", 1, false, Eof); TEST (" 1", 1, false, Eof); TEST (" 1 ", 1, false, Good); TEST (" +1", 1, false, Eof); TEST ("2", 2, false, Eof); TEST ("+2", 2, false, Eof); TEST (" 2", 2, false, Eof); TEST (" +2", 2, false, Eof); TEST ("99", 99, false, Eof); TEST ("+99", 99, false, Eof); TEST (" 99", 99, false, Eof); TEST (" +99", 99, false, Eof); TEST ("+", 0, true, Eof | Fail); TEST ("-", 0, true, Eof | Fail); TEST (" +", 0, true, Eof | Fail); TEST (" -", 0, true, Eof | Fail); TEST ("++", 0, true, Fail); TEST ("--", 0, true, Fail); TEST (" ++", 0, true, Fail); TEST (" --", 0, true, Fail); TEST ("*", 0, true, Fail); TEST (" *", 0, true, Fail); if (is_signed) { TEST ("-1", -1, false, Eof); TEST (" -1", -1, false, Eof); TEST ("-2", -2, false, Eof); TEST (" -2", -2, false, Eof); TEST ("-99", -99, false, Eof); TEST (" -99", -99, false, Eof); } if (is_exact) { TEST ("1.2", 1, false, Good); TEST ("2.3 ", 2, false, Good); TEST (" 3.4", 3, false, Good); TEST (" +4.", 4, false, Good); } else { TEST (".1", 0.1, false, Eof); TEST ("+.2", 0.2, false, Eof); TEST ("-.3", -0.3, false, Eof); TEST (" +.4", 0.4, false, Eof); TEST (" -.5", -0.5, false, Eof); TEST ("1..", 1.0, false, Good); TEST ("1.234", 1.234, false, Eof); TEST ("+1.235", +1.235, false, Eof); TEST ("-1.236", -1.236, false, Eof); TEST (" +1.237", +1.237, false, Eof); TEST (" -1.238", -1.238, false, Eof); TEST ("1.239e1", 1.239e1, false, Eof); TEST ("1.240e+1", 1.240e+1, false, Eof); TEST ("-1.241e+2", -1.241e+2, false, Eof); TEST ("-1.242e-3 ", -1.242e-3, false, Good); TEST ("1.3e", 0, true, Eof | Fail); TEST ("1.4e+", 0, true, Eof | Fail); TEST ("1.5e-", 0, true, Eof | Fail); TEST ("1.6e+ ", 0, true, Fail); } } } /***********************************************************************/ enum TestId { TestCtors, TestOps }; // dispatch to test_ctors to test_ops template void do_test (TestId id, const char *tname, const char *tfmt, const char *cname, const char *trname, const char *dname) { const ParamNames names = { tname, tfmt, cname, trname, dname }; const TempParams params = { names }; if (TestCtors == id) { test_ctors (params); } else if (TestOps == id) { test_ops (params); } } /***********************************************************************/ int opt_char; int opt_wchar_t; int opt_UserTraits; int opt_short; int opt_int; int opt_long; int opt_double; // exercise different specializations of T template void do_test (TestId id, const char *cname, const char *trname, const char *dname) { #undef TEST #define TEST(T, fmt) \ if (opt_ ## T) \ do_test(id, #T, fmt, cname, trname, dname) // cannot instantiate basic_istream::operator>>(char&) // for any CharT other than char // TEST (char, "%{hhi}"); TEST (short, "%hi"); TEST (int, " %i"); TEST (long, "%li"); TEST (double, "%g"); } /***********************************************************************/ // exercise different specializations of Distance template void do_test (TestId id, const char *cname, const char *trname) { do_test(id, cname, trname, "short"); do_test(id, cname, trname, 0); } /***********************************************************************/ static int run_test (int, char*[]) { static const TestId test_ids [] = { TestCtors, TestOps }; if (opt_char < 0) rw_note (0, 0, __LINE__, "tests of char specialization disabled"); if (opt_wchar_t < 0) rw_note (0, 0, __LINE__, "tests of wchar_t specialization disabled"); if (opt_UserTraits < 0) rw_note (0, 0, __LINE__, "tests of UserTraits specialization disabled"); typedef std::char_traits Traits; typedef UserTraits UsrTraits; for (unsigned i = 0; i != sizeof test_ids / sizeof *test_ids; ++i) { const TestId id = test_ids [i]; if (0 <= opt_char) { // call these helper functions directly to avoid instantiating // basic_istream::operator>>(char&) on any CharT other // than char do_test(id, "char", "%{hhi}", 0, 0, 0); if (0 <= opt_UserTraits) do_test(id, "char", "%{hhi}", 0, "UserTraits", "std::ptrdiff_t"); do_test(id, 0, 0); if (0 <= opt_UserTraits) do_test(id, "char", "UserTraits"); } #ifndef _RWSTD_NO_WCHAR_T if (0 <= opt_wchar_t) { typedef std::char_traits WTraits; typedef UserTraits WUsrTraits; do_test(id, 0, 0); if (0 <= opt_UserTraits) do_test(id, "wchar_t", "UserTraits"); } #endif // _RWSTD_NO_WCHAR_T } return 0; } /***********************************************************************/ int main (int argc, char *argv[]) { return rw_test (argc, argv, __FILE__, "lib.istream.iterator", 0 /* no comment */, run_test, "|-char~ " "|-wchar_t~ " "|-UserTraits~ " "|-short~ " "|-int~ " "|-long~ " "|-double~ ", &opt_char, &opt_wchar_t, &opt_UserTraits, &opt_short, &opt_int, &opt_long, &opt_double, (void*)0 /* sentinel */); }