/***************************************************************************
 *
 * 23.bitset.cpp - test exercising [lib.bitset]
 *
 * $Id: 23.bitset.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.
 *
 * Copyright 2001-2006 Rogue Wave Software.
 * 
 **************************************************************************/

#include <bitset>
#include <istream>
#include <ostream>

#include <cstdio>     // for sprintf()
#include <climits>

#include <rw_char.h>  // for UserChar
#include <rw_rand.h>  // for rw_rand()
#include <driver.h>   // for rw_test(), ...


#define NLOOPS 128

/**************************************************************************/

// sets the `n' least significant bits
std::size_t
bitmax (std::size_t n)
{
    std::size_t result = 0;
    while (n--)
        result = result << 1 | 1U;
    return result;
}

/**************************************************************************/

// fake bitset class, bit pattern represented as a character string
template <std::size_t N>
struct test_set
{
    char bits_ [N + 1];

    test_set () {
        reset ();
        bits_ [N] = '\0';   // null-terminate
    }

    _EXPLICIT test_set (unsigned long val) {
        for (std::size_t i = 0; i != N; ++i)
            set (i, !!(val & (1UL << i)));
        bits_ [N] = '\0';   // NUL-terminate
    }

    _EXPLICIT test_set (const std::bitset<N> &rhs) {
        for (std::size_t i = 0; i != N; ++i)
            set (i, rhs.test (i));
        bits_ [N] = '\0';   // NUL-terminate
    }

    // accessor function provided to work around
    // a MIPSpro 7.3.1.1 bug (PR #25682)
    const char* bits () const {
        return bits_;
    }

    test_set& random () {
        for (std::size_t i = 0; i != N; ++i)
            bits_ [i] = char ('0' + rw_rand (2U));
        return *this;
    }

    std::bitset<N> to_bitset () const {
        std::bitset<N> tmp;
        for (std::size_t i = 0; i != N; ++i)
            tmp.set (i, test (i));
        return tmp;
    }

    test_set& operator&= (const test_set &rhs) {
        for (std::size_t i = 0; i != N; ++i)
            bits_ [i] = '0' + ('1' == bits_ [i] && '1' == rhs.bits_ [i]);
        return *this;
    }

    test_set& operator|= (const test_set &rhs) {
        for (std::size_t i = 0; i != N; ++i)
            bits_ [i] = '0' + ('1' == bits_ [i] || '1' == rhs.bits_ [i]);
        return *this;
    }

    test_set& operator^= (const test_set &rhs) {
        for (std::size_t i = 0; i != N; ++i)
            bits_ [i] = '0' + !!(bits_ [i] - rhs.bits_ [i]);
        return *this;
    }

    test_set& operator<<= (std::size_t n) {
        for (std::size_t i = 0; i < N - n && i + n + 1 < N + 1; ++i)
            bits_ [i] = bits_ [i + n];
        for (std::size_t j = N - n; j != N; ++j)
            bits_ [j] = '0';
        return *this;
    }

    test_set& operator>>= (std::size_t n) {
        for (std::size_t i = N - 1; i != n - 1; --i)
            bits_ [i] = bits_ [i - n];
        for (std::size_t j = n; j != 0; )
            bits_ [--j] = '0';
        return *this;
    }

    test_set& set () {
        for (std::size_t i = 0; i != N; ++i)
            bits_ [i] = '1';
        return *this;
    }

    test_set& set (std::size_t pos, bool val) {
        bits_ [N - pos - 1] = '0' + val;
        return *this;
    }

    test_set& reset () {
        for (std::size_t i = 0; i != N; ++i)
            bits_ [i] = '0';
        return *this;
    }

    test_set& reset (std::size_t pos) {
        return bits_ [N - pos - 1] = '0', *this;
    }

    test_set operator~ () const {
        return test_set (*this).flip ();
    }

    test_set& flip () {
        for (std::size_t i = 0; i != N; ++i)
            bits_ [i] = '0' + ('0' == bits_ [i]);
        return *this;
    }

    test_set& flip (std::size_t pos) {
        bits_ [N - pos - 1] = '0' + ('0' == bits_ [N - pos - 1]);
        return *this;
    }

    std::size_t count () const {
        std::size_t n = 0;
        for (std::size_t i = 0; i != N; ++i)
            n += bits_ [i] != '0';
        return n;
    }

    bool operator== (const test_set &rhs) const {
        for (std::size_t i = 0; i != N; ++i)
            if (bits_ [i] != rhs.bits_ [i])
                return false;
        return true;
    }

    bool test (std::size_t pos) const {
        return '0' != bits_ [N - pos - 1];
    }
};

/**************************************************************************/

#ifndef _RWSTD_NO_EXPLICIT

// helper to verify that bitset ctor is explicit
// not defined since it must not be referenced if test is successful
// static commented out to prevent gcc warning: function declared
// 'static' but never defined
/* static */ void
is_explicit (const std::bitset<0>&);

struct has_implicit_ctor
{
    // NOT explicit
    has_implicit_ctor (const std::string&) { }
};

// calls to the overloaded is_explicit() resolve to the function below
static void
is_explicit (const has_implicit_ctor&) { }

#endif   // _RWSTD_NO_EXPLICIT


static void
test_synopsis (std::bitset<0>*)
{
    // prevent warnings about unreachable code
    volatile bool dummy = false;

    if (!dummy)
        return;

    typedef std::bitset<0>    Bitset;
    typedef Bitset::reference Reference;

    Bitset::reference *pr = (Bitset::reference*)0;
    _RWSTD_UNUSED (pr);

// verify that a member function is accessible and has the appropriate
// signature, including return type and exception specification
#define MEMFUN(result, name, arg_list) do {                                   \
        result (Bitset::reference::*pf) arg_list = &Bitset::reference::name;  \
        _RWSTD_UNUSED (pf);                                                   \
    } while (0)

    // exercise bitset::reference members
    MEMFUN (Reference&, operator=, (bool));
    MEMFUN (Reference&, operator=, (const Reference&));
    MEMFUN (bool, operator~, () const);
    MEMFUN (bool, operator bool, () const);
    MEMFUN (Reference&, flip, ());

    // 23.3.5.1 - verify bitset ctors
#if    !defined (_RWSTD_NO_EXPLICIT) \
    && (!defined (__SUNPRO_CC) || __SUNPRO_CC > 0x530) \
    && (!defined (__GNUG__) || __GNUG__ >= 3)
    // working around a SunPro 5.2 bug (see PR #25959)

    // verify that bitset ctor is declared explicit
    is_explicit (std::string ());

#endif   // _RWSTD_NO_EXPLICIT && SunPro > 5.3

    // verify default arguments
    (void)Bitset (std::string ());
    (void)Bitset (std::string (), std::string::size_type ());

// verify that a member function is accessible and has the appropriate
// signature, including return type and exception specification
#undef MEMFUN
#define MEMFUN(result, name, arg_list) do {              \
        result (Bitset::*pf) arg_list = &Bitset::name;   \
        _RWSTD_UNUSED (pf);                              \
    } while (0)

    MEMFUN (Bitset&, operator&=, (const Bitset&));
    MEMFUN (Bitset&, operator|=, (const Bitset&));
    MEMFUN (Bitset&, operator^=, (const Bitset&));
    MEMFUN (Bitset&, operator<<=, (std::size_t));
    MEMFUN (Bitset&, operator>>=, (std::size_t));

    MEMFUN (Bitset&, set, ());
    MEMFUN (Bitset&, set, (std::size_t, bool));   // lwg issue 186
    Bitset ().set (0);   // verify default argument

    MEMFUN (Bitset&, reset, ());
    MEMFUN (Bitset&, reset, (std::size_t));
    
    MEMFUN (Bitset, operator~, () const);
    MEMFUN (Bitset&, flip, ());
    MEMFUN (Bitset&, flip, (std::size_t));

    MEMFUN (Bitset::reference, operator[], (std::size_t));
    MEMFUN (bool, operator[], (std::size_t) const);

    MEMFUN (unsigned long, to_ulong, () const);

#ifndef _RWSTD_NO_MEMBER_TEMPLATES
#  if !defined (__HP_aCC) || __HP_aCC >= 60000

     // working around HP aCC bugs PR #23312 and bug #503

#    define PARAMLIST_3(T)   T, std::char_traits<T>, std::allocator<T>
#    define PARAMLIST_2(T)   T, std::char_traits<T>

    // exercise the overloaded member template function and ordinary
    // member function to_string()
    MEMFUN (std::basic_string<PARAMLIST_3 (char) >,
            to_string<PARAMLIST_3 (char) >, (char, char) const);
    MEMFUN (std::basic_string<PARAMLIST_3 (char) >,
            to_string, (char, char) const);

#    ifndef _RWSTD_NO_WCHAR_T

    MEMFUN (std::basic_string<PARAMLIST_3 (wchar_t) >,
            to_string<PARAMLIST_3 (wchar_t) >, (wchar_t, wchar_t) const);

#    endif   // _RWSTD_NO_WCHAR_T

    MEMFUN (std::basic_string<PARAMLIST_3 (int) >,
            to_string<PARAMLIST_3 (int) >, (int, int) const);

#    undef PARAMLIST_3
#    undef PARAMLIST_2

#  endif   // !__HP_aCC || __HP_aCC >= 60000
#endif   // _RWSTD_NO_MEMBER_TEMPLATES

    MEMFUN (std::size_t, size, () const);
    MEMFUN (std::size_t, count, () const);

    MEMFUN (bool, operator==, (const Bitset&) const);
    MEMFUN (bool, operator!=, (const Bitset&) const);

    MEMFUN (bool, test, (std::size_t) const);
    MEMFUN (bool, any, () const);
    MEMFUN (bool, none, () const);
    
    MEMFUN (Bitset, operator>>, (std::size_t) const);
    MEMFUN (Bitset, operator<<, (std::size_t) const);

#define FUN(result, name, arg_list) do {  \
        result (*pf) arg_list = &name;    \
        _RWSTD_UNUSED (pf);               \
    } while (0)

#if !defined (__IBMCPP__) || __IBMCPP__ > 502
    FUN (Bitset, std::operator&, (const Bitset&, const Bitset&));
    FUN (Bitset, std::operator|, (const Bitset&, const Bitset&));
    FUN (Bitset, std::operator^, (const Bitset&, const Bitset&));

#else
    // working around xlC 5.0.2.0 bug: PR #26561

    FUN (Bitset, std::operator&,(const Bitset&,const Bitset&) _PTR_THROWS(()));
    FUN (Bitset, std::operator|,(const Bitset&,const Bitset&) _PTR_THROWS(()));
    FUN (Bitset, std::operator^,(const Bitset&,const Bitset&) _PTR_THROWS(()));
#endif    


#define PARAMLIST(T)   T, std::char_traits<T>

    FUN (std::basic_istream< PARAMLIST (char) >&, std::operator>>,
         (std::basic_istream< PARAMLIST (char) >&, Bitset&));
    FUN (std::basic_ostream< PARAMLIST (char) >&, std::operator<<,
         (std::basic_ostream< PARAMLIST (char) >&, const Bitset&));

#ifndef _RWSTD_NO_MEMBER_TEMPLATES
#  ifndef _RWSTD_NO_WCHAR_T

    FUN (std::basic_istream< PARAMLIST (wchar_t) >&, std::operator>>,
         (std::basic_istream< PARAMLIST (wchar_t) >&, Bitset&));
    FUN (std::basic_ostream< PARAMLIST (wchar_t) >&, std::operator<<,
         (std::basic_ostream< PARAMLIST (wchar_t) >&, const Bitset&));

#  endif   // _RWSTD_NO_WCHAR_T

#  if !defined (_MSC_VER) || _MSC_VER > 1300

    // MSVC is too dumb to handle bitset inserters and extractors
    // parametrized on multiple template paramenters
    FUN (std::basic_istream< PARAMLIST (int) >&, std::operator>>,
         (std::basic_istream< PARAMLIST (int) >&, Bitset&));
    FUN (std::basic_ostream< PARAMLIST (int) >&, std::operator<<,
         (std::basic_ostream< PARAMLIST (int) >&, const Bitset&));

#  endif   // !defined (_MSC_VER) || _MSC_VER > 1300
#endif   // _RWSTD_NO_MEMBER_TEMPLATES

#undef PARAMLIST

}

/**************************************************************************/

template <std::size_t N>
void test_ctors (const std::bitset<N>*)
{
    typedef unsigned long ULong;
    const ULong bmask = ULong (::bitmax (N));

    {   // bitset::bitset()
        rw_info (0, 0, __LINE__, "std::bitset<%d>::bitset()", N);

        const std::bitset<N> b;
        rw_assert (0 == b.to_ulong (), 0, __LINE__,
                   "bitset<%d>::bitset ().to_ulong() == 0, got %#lx",
                   b.to_ulong ());
    }
    
    {   // bitset::bitset (unsigned long)
        rw_info (0, 0, __LINE__, "std::bitset<%d>::bitset (unsigned long)", N);

        const std::bitset<N> b (ULONG_MAX & bmask);
        rw_assert ((ULONG_MAX & bmask) == b.to_ulong (), 0, __LINE__,
                   "bitset<%d>::bitset (%#lx).to_ulong() == 0, got %#lx",
                   N, ULONG_MAX & bmask, b.to_ulong ());
    }

    {   // bitset (const string& str, size_t pos = 0, size_t n = (size_t)-1);
        rw_info (0, 0, __LINE__, "std::bitset<%d>::bitset (string)", N);

        test_set<N> ts;
        ts.set ();

        _TRY {
            const std::bitset<N> b = std::bitset<N>(std::string (ts.bits ()));

            if (N <= sizeof (unsigned long) * CHAR_BIT)
                rw_assert (b == bmask, 0, __LINE__,
                           "bitset<%d>::bitset(string(\"%s\").to_ulong()"
                           " == %#x, got %#x", N, ts.bits (), bmask,
                           b.to_ulong ());
            else
                rw_assert (test_set<N>(b) == ts, 0, __LINE__,
                           "bitset<%d>::bitset(string(\"111...111\")"
                           " == 111...111, got %s",
                           N, test_set<N>(b).bits ());

        }
        _CATCH (...) {
            rw_assert (false,  0, __LINE__, (""));
        }
    }

    {   // bitset (const bitset<N>& rhs)
        rw_info (0, 0, __LINE__, "std::bitset<%d>::bitset (const bitset&)", N);

        const std::bitset<N> b1 (12345);
        const std::bitset<N> b2 (b1);

        rw_assert (b1.to_ulong () == b2.to_ulong (), 0, __LINE__,
                   "bitset<%d>::bitset (bitset<%d>(%#lx)).to_ulong() == %#lx,"
                   " got %#lx", N, b1.to_ulong (), b2.to_ulong ());

        rw_info (0, 0, __LINE__,
                 "std::bitset<%d>::operator=(const bitset&)", N);

        std::bitset<N> b3;
        b3 = b1;

        rw_assert (b1.to_ulong () == b3.to_ulong (), 0, __LINE__,
                   "bitset<%d>::bitset (bitset<%d>(%#lx)).to_ulong() == %#lx,"
                   " got %#lx", N, b1.to_ulong (), b3.to_ulong ());
    }
}

/**************************************************************************/

template <std::size_t N>
void stress_ctors (const std::bitset<N>*)
{
    rw_info (0, 0, __LINE__, "std::bitset<%d>::bitset (string)", N);

    const std::size_t max_mask = bitmax (N);

    for (std::size_t i = 0; i != 1000U; i++) {

        typedef unsigned long ULong;

        // exercise 23.3.5.1, p2
        const ULong n = ULong (rw_rand (0) & max_mask);
        const std::bitset<N> b1 (n);

        rw_assert (n == b1.to_ulong (), 0, __LINE__,
                   "bitset<%d>::bitset(%#lx).to_ulong() == %#lx, got %#lx",
                   N, n, n, b1.to_ulong ());

        test_set<N> ts;
        ts.random ();

        // exercise 23.3.5.1, p3
        std::bitset<N> b2 = std::bitset<N>(std::string (ts.bits ()));
        rw_assert (test_set<N>(b2) == ts, 0, __LINE__,
                   "bitset<%d>::bitset (\"%s\") got %s",
                   N, ts.bits (), b2.to_string ().c_str ());
    }
}

/**************************************************************************/

template <std::size_t N>
void test_operators (const std::bitset<N>*)
{
#define TEST_OP(op) do {                                                   \
   rw_info (!i, 0, __LINE__, "std::bitset<%d>::operator" #op               \
                             "= (const bitset&)", N);                      \
                                                                           \
          test_set<N> lhs = test_set<N>().random ();                       \
    const test_set<N> rhs = test_set<N>().random ();                       \
          std::bitset<N> b_lhs = std::bitset<N>(std::string (lhs.bits ()));\
    const std::bitset<N> b_rhs = std::bitset<N>(std::string (rhs.bits ()));\
    const test_set<N> res = lhs op ## = rhs;                               \
    const std::bitset<N> b_res = b_lhs op ## = b_rhs;                      \
                                                                           \
    rw_assert (res == test_set<N>(b_res), 0, __LINE__,                     \
               "bitset<%lu>::operator" #op "= (const bitset<%lu>&):"       \
               " %s " #op " %s == %s, got %s",                             \
               N, N, lhs.bits (), rhs.bits (), res.bits (),                \
               test_set<N>(b_res).bits ());                                \
                                                                           \
    rw_info (!i, 0, __LINE__, "std::bitset<%d>::operator" #op              \
                              " (const bitset&)", N);                      \
    lhs.random ();                                                         \
    b_lhs = std::bitset<N>(std::string (lhs.bits ()));                     \
                                                                           \
    const test_set<N> res2 = lhs op ## = rhs;                              \
    const std::bitset<N> b_res2 = b_lhs op b_rhs;                          \
                                                                           \
    rw_assert (res2 == test_set<N>(b_res2), 0, __LINE__,                   \
               "bitset<%lu>::operator" #op " (const bitset<%lu>&):"        \
               " %s " #op " %s == %s, got %s",                             \
               N, N, lhs.bits (), rhs.bits (), res2.bits (),               \
               test_set<N>(b_res2).bits ());                               \
  } while (0)

    // prevent division by zero errors, also exercise shifting by
    // N bits (operation must zero out the first operand)
    // especially important is shifting bitset<N> by N bits where
    // N >= sizeof (unsigned long) * CHAR_BIT, since this operation
    // is undefined for unsigned longs but defined for bitset

    const std::size_t M = N + 1;

    for (int i = 0; i != NLOOPS; ++i) {

        // 23.3.5.2, p1 and 23.3.5.3, p1
        TEST_OP (&);
        // 23.3.5.2, p3 and 23.3.5.3, p2
        TEST_OP (|);
        // 23.3.5.2, p5 and 23.3.5.3, p3
        TEST_OP (^);

        rw_info (!i, 0, __LINE__, "std::bitset<%d>::operator<<=(size_t)", N);

        const test_set<N> ts1 = test_set<N>().random ();
        const test_set<N> ts2 = test_set<N>(ts1) <<= i % M;

        std::bitset<N> b1 = std::bitset<N> (std::string (ts1.bits ()));

        // 23.3.5.2, p7
        b1 <<= i % M;

        rw_assert (test_set<N>(b1) == ts2, 0, __LINE__,
                   "bitset<%d>::operator<<=(%lu): %s << %lu == %s, got %s",
                   N, i % M, ts1.bits (), i % M, ts2.bits (),
                   test_set<N>(b1).bits ());

        rw_info (!i, 0, __LINE__, "std::bitset<%d>::operator>>=(size_t)", N);

        const test_set<N> ts3 = test_set<N>(ts1) >>= i % M;
        std::bitset<N> b2 = std::bitset<N>(std::string (ts1.bits ()));

        // 23.3.5.2, p9
        b2 >>= i % M;

        rw_assert (test_set<N>(b2) == ts3, 0, __LINE__,
                   "bitset<%d>::operator>>=(%lu): %s >> %lu == %s, got %s",
                   N, i % M, ts1.bits (), i % M, ts3.bits (),
                   test_set<N>(b2).bits ());

        rw_info (!i, 0, __LINE__,
                 "std::bitset<%d>::operator<<=(size_t) (unused bits)", N);

        if (N) {
            b1.set (N - 1);
            std::size_t first  = b1.count ();
            std::size_t second = (b1 <<= 1).count ();
            rw_assert (!(first == second), 0, __LINE__,
                       "bitset<%lu>::operator<<=(1): "
                       "after <<= 1: expected %lu, got %lu",
                       N, first - 1, second);
        }

        rw_info (!i, 0, __LINE__,
                 "std::bitset<%d>::operator>>=(size_t) (unused bits)", N);

        if (N) {
            b2.set ();
            std::size_t first  = b2.count ();
            std::size_t second = (b2 >>= 1).count ();
            rw_assert (first - 1 == second, 0, __LINE__,
                       "bitset<%lu>::operator>>=(1): "
                       "after >>= 1: expected %lu, got %lu",
                       N, first - 1, second);
        }
    }
}

/**************************************************************************/

template <std::size_t N>
void test_other (const std::bitset<N>*)
{
    for (std::size_t i = 0; i != NLOOPS; ++i) {

        // 23.3.5.2, p23
        test_set<N> ts1;
        ts1.random ();

        test_set<N> ts2 = ~ts1;

        std::bitset<N> b1 = std::bitset<N>(std::string (ts1.bits ()));
        std::bitset<N> b2 = ~b1;

        rw_assert (ts2 == test_set<N>(b2), 0, __LINE__,
                   "bitset<%d>::operator~(): ~%s == %s, got %s",
                   N, ts1.bits (), ts2.bits (), test_set<N>(b2).bits ());

        // 23.3.5.2, p25
        b2.flip ();
        rw_assert (ts1 == test_set<N>(b2), 0, __LINE__,
                   "bitset<%d>::flip (): ~%s == %s, got %s",
                   N, ts1.bits (), ts2.bits (), test_set<N>(b2).bits ());

        // 23.3.5.2, p27
        for (std::size_t _j = 0; _j != N; ++_j)
            b2.flip (_j);

        rw_assert (ts2 == test_set<N>(b2), 0, __LINE__,
            "bitset<%d>::flip () == %s, got %s",
            N, ts2.bits (), test_set<N>(b2).bits ());

        // 23.3.5.3, p35
        rw_assert (ts2.count () == b2.count (), 0, __LINE__,
                   "bitset<%d>::count () == %d, got %d [%s]",
                   N, ts2.count (), b2.count (), test_set<N>(b2).bits());
               
        // 23.3.5.3, p37
        rw_assert (b2 == b2 && (N && !(b1 == b2) || !N && b1 == b2),
                   0, __LINE__,
                   "bitset<%d>::operator==(const bitset<%ul>&) [%s]",
                   N, N, N ? test_set<N>(b2).bits () : "<empty>");
    
        // 23.3.5.3, p38
        rw_assert ((N && b1 != b2 || !N && !(b1 != b2)) && !(b2 != b2),
                   0, __LINE__,
                   "bitset<%d>::operator!=(const bitset<%ul>&) [%s]",
                   N, N, N ? test_set<N>(b2).bits () : "<empty>");
    
        // 23.3.5.3, p42
        rw_assert (b2.count() && b2.any() || !b2.count() && !b2.any(),
                   0, __LINE__,
                   "bitset<%d>::any () [%s]",
                   N, test_set<N>(b2).bits ());

        // 23.3.5.3, p43
        rw_assert (b2.count() && !b2.none() || !b2.count() && b2.none(),
                   0, __LINE__,
                   "bitset<%d>::none () [%s]",
                   N, test_set<N>(b2).bits ());

        for (std::size_t k = 0; k != N; ++k) {
            test_set<N>    ts3 = test_set<N>(ts1) <<= k;
            std::bitset<N> b3  = b1 << k;

            rw_assert (test_set<N>(b3) == ts3,  0, __LINE__,
                       "bitset<%lu>::operator<<(%lu)", N, k);

            ts3 = test_set<N>(ts1) >>= k;
            b3  = b1 >> k;

            rw_assert (test_set<N>(b3) == ts3, 0, __LINE__,
                       "bitset<%lu>::operator>>(%lu)", N, k);
        }
    }
}

/**************************************************************************/

template <std::size_t N>
void stress_count (const std::bitset<N>*)
{
    rw_info (0, 0, __LINE__, "std::bitset<%lu>::count()", N);

    for (std::size_t i = 0; i != N; i++) {
        std::bitset<N> b;

        for (std::size_t j = 0; j != i; j++)
            b.set (j);

        rw_assert (b.count () == i,  0, __LINE__,
                   "%lu. std::bitset<%lu>::count()", i, N);
    }
}

/**************************************************************************/

template <std::size_t N>
void test_elem_access (const std::bitset<N>*)
{
    rw_info (0, 0, __LINE__, "std::bitset<%lu>::test(size_t)", N);
    rw_info (0, 0, __LINE__, "std::bitset<%lu>::operator[](size_t)", N);
    rw_info (0, 0, __LINE__, "std::bitset<%lu>::operator[](size_t) const", N);

    for (std::size_t i = 0; i != NLOOPS; ++i) {

        const test_set<N> ts = test_set<N>().random ();
        std::bitset<N>    b  = std::bitset<N>(std::string (ts.bits ()));

        for (std::size_t _j = 0; _j != N; ++_j) {
            // 23.3.5.2, p39
            rw_assert (b.test (_j) == ts.test (_j), 0, __LINE__,
                       "bitset<%lu>::test (%lu): %s",
                       N, _j, test_set<N>(b).bits ());

            // 23.3.5.2, p??: see lwg issue 11
            rw_assert (b [_j] == ts.test (_j), 0, __LINE__,
                       "bitset<%lu>::operator[](%lu): %s",
                       N, _j, test_set<N>(b).bits ());

            // 23.3.5.2, p??: see lwg issue 11
            rw_assert (((const std::bitset<N>&)b) [_j] == ts.test (_j),
                       0, __LINE__,
                       "bitset<%lu>::operator[](%lu) const: %s",
                       N, _j, test_set<N>(b).bits ());

            // exercise std::bitset<N>::reference
            _TYPENAME std::bitset<N>::reference r = b [_j];

            // std::bitset<N>::reference::flip()
            r.flip ();
            rw_assert (r == !ts.test (_j), 0, __LINE__,
                       "bitset<%lu>::reference::flip()", N);

            // std::bitset<N>::reference::operator~()
            bool toggled = ~r;
            rw_assert (toggled == ts.test (_j), 0, __LINE__,
                       "bitset<%lu>::reference::operator~()", N);

            // std::bitset<N>::reference::operator=(bool)
            r = toggled;
            rw_assert (r == ts.test (_j) && b.test (_j) == ts.test (_j),
                       0, __LINE__,
                       "bitset<%lu>::reference::operator=(bool)", N);
        }
    }
}


/**************************************************************************/

_RWSTD_NAMESPACE (std) {

_RWSTD_SPECIALIZED_CLASS
struct char_traits<UserChar>: UserTraits<UserChar> { };

}   // namespace std


const char* type_name (char) { return "char"; }

#ifndef _RWSTD_NO_WCHAR_T
const char* type_name (wchar_t) { return "wchar_t"; }
#endif   // _RWSTD_NO_WCHAR_T

const char* type_name (const UserChar&)
{
    return "UserChar";
}

template <class charT>
const char* traits_name (const std::char_traits<charT>*)
{
    static char name [64];
    std::sprintf (name, "std::char_traits<%s>", type_name (charT ()));
    return name;
}

const char* traits_name (const UserTraits<UserChar>*)
{
    return "UserTraits";
}

template <class charT>
struct MyAlloc: std::allocator<charT> { };

template <class charT>
const char* alloc_name (const std::allocator<charT>&)
{
    static char name [64];
    std::sprintf (name, "std::allocator<%s>", type_name (charT ()));
    return name;
}

template <class charT>
const char* alloc_name (const MyAlloc<charT>&)
{
    static char name [64];
    std::sprintf (name, "MyAlloc<%s>", type_name (charT ()));
    return name;
}

template <class charT>
charT& assign (charT &lhs, char rhs)
{
    return lhs = rhs;
}

UserChar& assign (UserChar &lhs, char rhs)
{
    lhs.c = _RWSTD_STATIC_CAST (unsigned char, rhs);

    return lhs;
}

// compare two strings, return the offset of the first mismatch
// or -1 when the strings are equal
template <class charT>
int compare (const charT str[], const char s[], const char bits [2])
{
    const char* const beg = s;

    for ( ; *s; ++s, ++str) {

        if (*str != bits ['1' == *s])
            return int (s - beg);
    }

    return *str ? s - beg : -1;
}

// compare two strings, return the offset of the first mismatch
// or -1 when the strings are equal
int compare (const UserChar str[], const char s[], const char bits [2])
{
    const char* const beg = s;

    for (; *s; ++s, ++str) {

        if (char (str->c) != bits ['1' == *s])
            return int (s - beg);
    }

    return str->c ? s - beg : -1;
}


#ifndef _RWSTD_NO_MEMBER_TEMPLATES

// call the bitset<N>::to_string() member function template,
// explicitly specifying all three template arguments,
// and 2, 1, or 0 of the two default function arguments
template <std::size_t N, class charT, class Traits, class Alloc>
std::basic_string<charT, Traits, Alloc>
bitset_to_string_3 (const std::bitset<N> &bs, int nfargs,
                    charT zero, charT one,
                    std::basic_string<charT, Traits, Alloc>*)
{
    // invoke to_string with the number of function arguments specified
    switch (nfargs) {
    case 1:
        return bs.template to_string<charT, Traits, Alloc>(zero);
    case 0:
        return bs.template to_string<charT, Traits, Alloc>();
    }

    return bs.template to_string<charT, Traits, Alloc>(zero, one);
}

template <std::size_t N, class Traits, class Alloc>
std::basic_string<UserChar, Traits, Alloc>
bitset_to_string_3 (const std::bitset<N> &bs, int nfargs,
                    UserChar zero, UserChar one,
                    std::basic_string<UserChar, Traits, Alloc>*)
{
    // UserChar digits zero and one
    static const UserChar dig[] = { { 0, '0' }, { 0, '1' } };

    // invoke to_string with the number of function arguments specified
    switch (nfargs) {
    case 1:
        return bs.template to_string<UserChar, Traits, Alloc>(zero, dig [1]);
    case 0:
        return bs.template to_string<UserChar, Traits, Alloc>(dig [0], dig [1]);
    }

    return bs.template to_string<UserChar, Traits, Alloc>(zero, one);
}

// call the bitset<N>::to_string() member function template,
// explicitly specifying two of the three template arguments,
// and 2, 1, or 0 of the two default function arguments
template <std::size_t N, class charT, class Traits>
std::basic_string<charT, Traits, std::allocator<charT> >
bitset_to_string_2 (const std::bitset<N> &bs, int nfargs,
                    charT zero, charT one,
                    std::basic_string<charT, Traits,
                                      std::allocator<charT> >*)
{
    // invoke to_string with the number of function arguments specified
    switch (nfargs) {
    case 1:
        return bs.template to_string<charT, Traits>(zero);
    case 0:
        return bs.template to_string<charT, Traits>();
    }

    return bs.template to_string<charT, Traits>(zero, one);
}

template <std::size_t N, class Traits>
std::basic_string<UserChar, Traits, std::allocator<UserChar> >
bitset_to_string_2 (const std::bitset<N> &bs, int nfargs,
                    UserChar zero, UserChar one,
                    std::basic_string<UserChar, Traits,
                                      std::allocator<UserChar> >*)
{
    static const UserChar dig[] = { { 0, '0' }, { 0, '1' } };

    // invoke to_string with the number of function arguments specified
    switch (nfargs) {
    case 1:
        return bs.template to_string<UserChar, Traits>(zero, dig [1]);
    case 0:
        return bs.template to_string<UserChar, Traits>(dig [0], dig [1]);
    }

    return bs.template to_string<UserChar, Traits>(zero, one);
}

// call the bitset<N>::to_string() member function template,
// explicitly specifying one of the three template arguments,
// and 2, 1, or 0 of the two default function arguments
template <std::size_t N, class charT>
std::basic_string<charT, std::char_traits<charT>, std::allocator<charT> >
bitset_to_string_1 (const std::bitset<N> &bs, int nfargs,
                    charT zero, charT one,
                    std::basic_string<charT,
                                      std::char_traits<charT>,
                                      std::allocator<charT> >*)
{
    // invoke to_string with the number of function arguments specified
    switch (nfargs) {
    case 1:
        return bs.template to_string<charT>(zero);
    case 0:
        return bs.template to_string<charT>();
    }

    return bs.template to_string<charT>(zero, one);
}

template <std::size_t N>
std::basic_string<UserChar, std::char_traits<UserChar>,
                  std::allocator<UserChar> >
bitset_to_string_1 (const std::bitset<N> &bs, int nfargs,
                    UserChar zero, UserChar one,
                    std::basic_string<UserChar,
                                      std::char_traits<UserChar>,
                                      std::allocator<UserChar> >*)
{
    // UserChar digits zero and one
    static const UserChar dig[] = { { 0, '0' }, { 0, '1' } };

    // invoke to_string with the number of function arguments specified
    switch (nfargs) {
    case 1:
        return bs.template to_string<UserChar>(zero, dig [1]);
    case 0:
        return bs.template to_string<UserChar>(dig [0], dig [1]);
    }

    return bs.template to_string<UserChar>(zero, one);
}

#endif   // _RWSTD_NO_MEMBER_TEMPLATES


// call the bitset<N>::to_string() ordinary member function,
// explicitly specifying none of the three template arguments,
// and 2, 1, or 0 of the two default function arguments
template <std::size_t N>
std::basic_string<char, std::char_traits<char>, std::allocator<char> >
bitset_to_string_0 (const std::bitset<N> &bs, int nfargs,
                    char zero, char one,
                    std::basic_string<char, std::char_traits<char>,
                                      std::allocator<char> >*)
{
    // invoke to_string with the number of function arguments specified
    switch (nfargs) {
    case 1:
        return bs.to_string (zero);
    case 0:
        return bs.to_string ();
    }

    return bs.to_string (zero, one);
}


inline char to_char (char ch) { return ch; }
inline char to_char (UserChar ch) { return ch.c; }

#ifndef _RWSTD_NO_WCHAR_T
inline char to_char (wchar_t ch) { return char (ch); }
#endif   // _RWSTD_NO_WCHAR_T


// convert a basic_string object to a tempstr object for diagnostics
template <class charT, class Traits, class Alloc>
std::string narrow_string (const std::basic_string<charT, Traits, Alloc> &str)
{
    std::string res;

    for (std::size_t i = 0; i != str.size (); ++i)
        res += to_char (str [i]);

    return res;
}

#define TO_STR(s)   narrow_string (s).c_str ()


// convert an ordinary string to a tempstr object for diagnostics
// using the binary digits specified by `bits'
std::string to_string (const char *str, const char bits [2])
{
    std::string res;

    std::size_t i;

    for (i = 0; str [i]; ++i)
        res += bits ['1' == str [i]];

    return res;
}


template <std::size_t N, class charT, class Traits, class Alloc>
void test_to_string (std::bitset<N>*, charT*, Traits*, Alloc*,
                     bool nontemplate_done)
{
    static const char* const cname = type_name (charT ());
    static const char* const tname = traits_name ((Traits*)0);
    static const char* const aname = alloc_name (Alloc ());

    rw_info (0, 0, __LINE__,
             "std::bitset<%lu>::to_string<%s, %s, %s >()",
             N, cname, tname, aname);

    test_set<N> ts;

    ts.random ();

    const std::bitset<N> bs = ts.to_bitset ();

    charT zero;
    charT one;

    assign (zero, 'o');
    assign (one, 'x');

    int pos;

#ifndef _RWSTD_NO_MEMBER_TEMPLATES

    ////////////////////////////////////////////////////////////////////////
    // exercise the overload of the to_string() member function template
    // that takes all three template parameters different from char,
    // char_traits<char>, and allocator<char>

    typedef std::basic_string<charT, Traits, Alloc> String3;

    String3 str3;

    // specify none of the two function arguments (exercise defaults
    // or the respective overloads)
    str3 = bitset_to_string_3 (bs, 0, zero, one, (String3*)0);
    pos  = compare (str3.data (), ts.bits (), "01");

    rw_assert (-1 == pos, 0, __LINE__,
               "bitset<%lu>::to_string () == \"%s\", got \"%s\": "
               "mismatch at bit %d",
               N, ts.bits (), TO_STR (str3), pos);


    // specify one of the two function arguments (exercise the default
    // or the respective overload)
    rw_info (0, 0, __LINE__,
             "std::bitset<%lu>::to_string<%s, %s, %s >(\"%s\")",
             N, cname, tname, aname, cname);

    str3 = bitset_to_string_3 (bs, 1, zero, one, (String3*)0);
    pos  = compare (str3.data (), ts.bits (), "o1");

    rw_assert (-1 == pos, 0, __LINE__,
               "bitset<%lu>::to_string ('o') == %s, got %s: "
               "mismatch at bit %d", N,
               to_string (ts.bits (), "o1").c_str (),
               TO_STR (str3), pos);


    // specify both of the two function arguments
    rw_info (0, 0, __LINE__,
             "std::bitset<%lu>::to_string<%s, %s, %s >(%s, %s)",
             N, cname, tname, aname, cname, cname);

    str3 = bitset_to_string_3 (bs, 2, zero, one, (String3*)0);
    pos  = compare (str3.data (), ts.bits (), "ox");

    rw_assert (-1 == pos, 0, __LINE__,
               "bitset<%lu>::to_string ('o', 'x') == %s, got %s: "
               "mismatch at bit %d", N,
               to_string (ts.bits (), "ox").c_str (),
               TO_STR (str3), pos);


    ////////////////////////////////////////////////////////////////////////
    // exercise the overload of the to_string() member function template
    // that takes the first two template parameters different from char,
    // and char_traits<char>
    rw_info (0, 0, __LINE__, "std::bitset<%lu>::to_string<%s, %s >()",
             N, cname, tname);

    typedef std::allocator<charT>                        CharTAlloc;
    typedef std::basic_string<charT, Traits, CharTAlloc> String2;

    String2 str2;

    // specify none of the two function arguments (exercise defaults
    // or the respective overloads)
    str2 = bitset_to_string_2 (bs, 0, zero, one, (String2*)0);
    pos  = compare (str2.data (), ts.bits (), "01");

    rw_assert (-1 == pos, 0, __LINE__,
               "bitset<%lu>::to_string () == %s, got %s: mismatch at bit %d",
               N, ts.bits (), TO_STR (str2), pos);


    // specify one of the two function arguments (exercise the default
    // or the respective overload)
    rw_info (0, 0, __LINE__,
             "std::bitset<%lu>::to_string<%s, %s >(%s)",
             N, cname, tname, cname);

    str2 = bitset_to_string_2 (bs, 1, zero, one, (String2*)0);
    pos  = compare (str2.data (), ts.bits (), "o1");

    rw_assert (-1 == pos, 0, __LINE__,
               "bitset<%lu>::to_string ('o') == %s, got %s: "
               "mismatch at bit %d", N,
               to_string (ts.bits (), "o1").c_str (),
               TO_STR (str2), pos);


    // specify both of the two function arguments
    rw_info (0, 0, __LINE__,
             "std::bitset<%lu>::to_string<%s, %s >(%s, %s)",
             N, cname, tname, cname, cname);

    str2 = bitset_to_string_2 (bs, 2, zero, one, (String2*)0);
    pos  = compare (str2.data (), ts.bits (), "ox");

    rw_assert (-1 == pos, 0, __LINE__,
               "bitset<%lu>::to_string ('o', 'x') == %s, got %s: "
               "mismatch at bit %d", N,
               to_string (ts.bits (), "ox").c_str (),
               TO_STR (str2), pos);


    ////////////////////////////////////////////////////////////////////////
    // exercise the overload of the to_string() member function template
    // that takes the first template parameter different from char
    rw_info (0, 0, __LINE__, "std::bitset<%lu>::to_string<%s>()",
             N, cname);

    typedef std::char_traits<charT>                          CharTraits;
    typedef std::basic_string<charT, CharTraits, CharTAlloc> String1;

    String1 str1;

    // specify none of the two function arguments (exercise defaults
    // or the respective overloads)
    str1 = bitset_to_string_1 (bs, 0, zero, one, (String1*)0);
    pos  = compare (str1.data (), ts.bits (), "01");

    rw_assert (-1 == pos, 0, __LINE__,
               "bitset<%lu>::to_string () == %s, got %s: mismatch at bit %d",
               N, ts.bits (), TO_STR (str1), pos);


    // specify one of the two function arguments (exercise the default
    // or the respective overload)
    rw_info (0, 0, __LINE__, "std::bitset<%lu>::to_string<%s>(%s)",
             N, cname, cname);

    str1 = bitset_to_string_1 (bs, 1, zero, one, (String1*)0);
    pos  = compare (str1.data (), ts.bits (), "o1");

    rw_assert (-1 == pos, 0, __LINE__,
               "bitset<%lu>::to_string ('o') == %s, got %s: "
               "mismatch at bit %d", N,
               to_string (ts.bits (), "o1").c_str (),
               TO_STR (str1), pos);


    // specify both of the two function arguments
    rw_info (0, 0, __LINE__,
             "std::bitset<%lu>::to_string<%s>(%s, %s)",
             N, cname, cname, cname);

    str1 = bitset_to_string_1 (bs, 2, zero, one, (String1*)0);
    pos  = compare (str1.data (), ts.bits (), "ox");

    rw_assert (-1 == pos, 0, __LINE__,
               "bitset<%lu>::to_string ('o', 'x') == %s, got %s: "
               "mismatch at bit %d", N,
               to_string (ts.bits (), "ox").c_str (),
               TO_STR (str1), pos);

#endif   // _RWSTD_NO_MEMBER_TEMPLATES


    ////////////////////////////////////////////////////////////////////////
    // exercise the non-template overload of the to_string() member

    if (nontemplate_done)
        return;

    rw_info (0, 0, __LINE__, "std::bitset<%lu>::to_string ()", N);

    typedef std::string String0;

    String0 str0;

    // specify none of the two function arguments (exercise defaults
    // or the respective overloads)
    str0 = bitset_to_string_0 (bs, 0, 'o', 'x', (String0*)0);
    pos  = compare (str0.data (), ts.bits (), "01");

    rw_assert (-1 == pos, 0, __LINE__,
               "bitset<%lu>::to_string () == %s, got %s: mismatch at bit %d",
               N, ts.bits (), str0.c_str (), pos);


    // specify one of the two function arguments (exercise the default
    // or the respective overload)
    rw_info (0, 0, __LINE__, "std::bitset<%lu>::to_string (char)", N);

    str0 = bitset_to_string_0 (bs, 1, 'o', 'x', (String0*)0);
    pos  = compare (str0.data (), ts.bits (), "o1");

    rw_assert (-1 == pos, 0, __LINE__,
               "bitset<%lu>::to_string ('o') == %s, got %s: "
               "mismatch at bit %d", N,
               to_string (ts.bits (), "o1").c_str (),
               str0.c_str (), pos);


    // specify both of the two function arguments
    rw_info (0, 0, __LINE__, "std::bitset<%lu>::to_string (char, char)", N);

    str0 = bitset_to_string_0 (bs, 2, 'o', 'x', (String0*)0);
    pos  = compare (str0.data (), ts.bits (), "ox");

    rw_assert (-1 == pos, 0, __LINE__,
               "bitset<%lu>::to_string ('o', 'x') == %s, got %s: "
               "mismatch at bit %d", N,
               to_string (ts.bits (), "ox").c_str (),
               str0.c_str (), pos);
}


template <std::size_t N>
void test_to_string (const std::bitset<N>*)
{
    test_to_string ((std::bitset<N>*)0,
                    (char*)0,
                    (std::char_traits<char>*)0,
                    (std::allocator<char>*)0,
                    false);

#ifndef _RWSTD_NO_WCHAR_T

    test_to_string ((std::bitset<N>*)0,
                    (wchar_t*)0,
                    (std::char_traits<wchar_t>*)0,
                    (std::allocator<wchar_t>*)0,
                    true);

#endif   // _RWSTD_NO_WCHAR_T

    test_to_string ((std::bitset<N>*)0,
                    (UserChar*)0,
                    (UserTraits<UserChar>*)0,
                    (std::allocator<UserChar>*)0,
                    true);
}

/**************************************************************************/

template <std::size_t N>
void run_test (const std::bitset<N>*)
{
    test_ctors ((std::bitset<N>*)0);
    stress_ctors ((std::bitset<N>*)0);
    test_elem_access ((std::bitset<N>*)0);
    test_operators ((std::bitset<N>*)0);
    test_other ((std::bitset<N>*)0);
    stress_count ((std::bitset<N>*)0);

    test_to_string ((std::bitset<N>*)0);
}

/**************************************************************************/

static int
run_test (int, char**)
{
    test_synopsis ((std::bitset<0>*)0);

#define  DO_TEST(N)   run_test ((std::bitset<N>*)0)

    DO_TEST (   0);   // interesting case
    DO_TEST (   1);   // interesting case
    DO_TEST (   2);
    DO_TEST (  31);
    DO_TEST (  32);   // interesting case
    DO_TEST (  33);   // interesting case
    DO_TEST (  34);
    DO_TEST (  63);
    DO_TEST (  64);   // interesting case
    DO_TEST (  65);   // interesting case
    DO_TEST (  66);

    DO_TEST ( 123);

    DO_TEST ( 127);   // interesting case
    DO_TEST ( 128);   // interesting case
    DO_TEST ( 129);
    DO_TEST ( 130);
    DO_TEST ( 255);
    DO_TEST ( 256);   // interesting case

#if !defined(_MSC_VER) || _MSC_VER != 1300
    // FIXME: MSVC 514 can't compile bitset<257>!
    DO_TEST ( 257);   // interesting case
#endif

    DO_TEST ( 258);   // interesting case
    DO_TEST ( 333);

    return 0;
}

/**************************************************************************/

int main (int argc, char *argv[])
{
    // TODO: add command line options to control tested functionality
    return rw_test (argc, argv, __FILE__,
                    "lib.bitset",
                    0 /* no comment */,
                    run_test,
                    "",
                    (void*)0   /* sentinel */);
}
