blob: 984821cb412356d7756b30bcaf25e3916e5a86a9 [file] [log] [blame]
/***********************************************************************
*
* 24.istream.iterator.cpp - test exercising [istream.iterator]
*
* $Id$
*
***********************************************************************
*
* 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 <sstream> // for stringstream
#include <iterator> // for istream_iterator
#include <cstddef> // for ptrdiff_t
#include <rw_char.h>
#include <rw_printf.h>
#include <rw_driver.h>
/***********************************************************************/
// 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 <class T, class CharT, class Traits, class Dist>
struct TempParams { ParamNames names; };
// exercise istream_iterator ctors
template <class T, class CharT, class Traits, class Dist>
void test_ctors (const TempParams<T, CharT, Traits, Dist> &params)
{
typedef std::istream_iterator<T, CharT, Traits, Dist> Iterator;
typedef std::basic_stringstream<CharT, Traits> 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<CharT, Traits> StreambufIterator;
typedef std::num_get<CharT, StreambufIterator> NumGet;
if (false == std::has_facet<NumGet>(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 <class T, class CharT, class Traits, class Dist>
void test_ops (const TempParams<T, CharT, Traits, Dist> &params,
int line,
const char *input,
T expect,
bool is_eos,
int state)
{
typedef std::istream_iterator<T, CharT, Traits, Dist> Iterator;
typedef std::basic_stringstream<CharT, Traits> StringStream;
fmtnam (params.names);
StringStream strm;
typedef std::istreambuf_iterator<CharT, Traits> StreambufIterator;
typedef std::num_get<CharT, StreambufIterator> NumGet;
if (false == std::has_facet<NumGet>(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 <class T, class CharT, class Traits, class Dist>
void test_ops (const TempParams<T, CharT, Traits, Dist> &params)
{
// 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 <class T, class CharT, class Traits, class Dist>
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<T, CharT, Traits, Dist> 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 <class CharT, class Traits, class Dist>
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<T, CharT, Traits, Dist>(id, #T, fmt, cname, trname, dname)
// cannot instantiate basic_istream<CharT>::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 <class CharT, class Traits>
void do_test (TestId id, const char *cname, const char *trname)
{
do_test<CharT, Traits, short>(id, cname, trname, "short");
do_test<CharT, Traits, std::ptrdiff_t>(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<char> Traits;
typedef UserTraits<char> 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<CharT>::operator>>(char&) on any CharT other
// than char
do_test<char, char, Traits, std::ptrdiff_t>(id, "char", "%{hhi}",
0, 0, 0);
if (0 <= opt_UserTraits)
do_test<char, char, UsrTraits, std::ptrdiff_t>(id, "char",
"%{hhi}", 0, "UserTraits<char>", "std::ptrdiff_t");
do_test<char, Traits>(id, 0, 0);
if (0 <= opt_UserTraits)
do_test<char, UsrTraits>(id, "char", "UserTraits<char>");
}
#ifndef _RWSTD_NO_WCHAR_T
if (0 <= opt_wchar_t) {
typedef std::char_traits<wchar_t> WTraits;
typedef UserTraits<wchar_t> WUsrTraits;
do_test<wchar_t, WTraits>(id, 0, 0);
if (0 <= opt_UserTraits)
do_test<wchar_t, WUsrTraits>(id, "wchar_t",
"UserTraits<wchar_t>");
}
#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 */);
}