Take two with corrections to add z modifier to size_t arguments.

Liviu Nicoara wrote:
> I have attached a second version of the test. Please let me know if this
> addresses the points you raised.
> 
> Thanks,
> Liviu
> 
> Liviu Nicoara wrote:
> 
>>Martin Sebor wrote:
>>
>>
>>>Liviu Nicoara wrote:
>>>
>>>
>>>
>>>>I have attached my tentative porting of lib.deque.modifiers test to the
>>>>new driver. Martin, I would appreciate suggestions for improving the
>>>>sections which use ToString class (one of those uses split formatting).
>>>
>>>
>>>I don't see the class defined in the test. Did you by any chance
>>>move/copy it into your version alg_test.h?
>>
>>
>>Yes, I did. My bad, I just wanted to get your feed-back on the
>>formatting bits and I didn't think that was important. I will stick a
>>ToString in each of the tests using it.
>>
>>
>>
>>>I think the bits that use the ToString class are fine. As soon as
>>>I'm done with the extension to rw_asnprintf() to format arrays of
>>>class X (we need to rename it!) it should be straightforward to
>>>simply remove the class and pass the arrays directly to rw_assert().
>>
>>
>>Super.
>>
>>
>>
>>>Btw., the old tests were designed to avoid invoking the RW_ASSERT
>>>macro except on failure (i.e., there's usually an if (failed) { }
>>>block around it). 
>>
>>
>>I got that. I will eliminate the conditionals from now on.
>>
>>Thanks,
>>Liviu
>>
> 
> 
> 

/***************************************************************************
 *
 * 23.containers.deque.modifiers.cpp - test exercising [lib.deque.modifiers]
 *
 * $Id$
 *
 ***************************************************************************
 *
 * Copyright (c) 1994-2005 Quovadx,  Inc., acting through its  Rogue Wave
 * Software division. Licensed 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.
 * 
 **************************************************************************/

#ifdef _MSC_VER
   // silence warning C4244: 'argument' : conversion from 'T' to
   // 'const std::allocator<_TypeT>::value_type', possible loss of data
   // issued for deque::assign(InputIterator a, InputIterator b) and
   // deque::insert(iterator, InputIterator a, InputIterator b) due
   // the implicit conversion of a to size_type and b to value_type
   // required by DR 438:
   // http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#438
#  pragma warning (disable: 4244)
#endif

#include <cstdio>    // for sprintf()
#include <cstdlib>   // for free()
#include <cstring>   // for strlen()

#include <deque>

#ifndef _RWSTD_NO_REPLACEABLE_NEW_DELETE
   // disabled for MSVC since it can't reliably replace the operators
#  define DEFINE_REPLACEMENT_NEW_AND_DELETE
#endif   // _RWSTD_NO_REPLACEABLE_NEW_DELETE

#include <driver.h>
#include <printf.h>

#include <alg_test.h>
#include <rw_new.h>

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

// for convenience
typedef unsigned char UChar;

// Formatting class
template <class T>
struct ToString
{

public:

    ToString (const T* first, const T* last, 
              int pos, bool use_id = false)
            : buffer_ (0) {

        std::size_t buflen = 0;

        if (first > last) {
            rw_asnprintf (&buffer_, &buflen, "%s", "bad range");
            return;
        }

        for (const T* ptr = first; ptr != last; ++ptr) {
            char* tmp = buffer_;
            // Shoddy formatting, relying on buffer_ not being modified
            // until it has been processed (first %s in formatting string)
            rw_asnprintf (&tmp, &buflen,
                          "%s%{?}>%{;}%{?}%d:%{;}%{lc}%{?}<%{;}",
                          buffer_ ? buffer_ : "\0",
                          ptr - first == pos,    // '>'
                          use_id, ptr->id_,      // "<id>:"
                          ptr->val_,             // <val>
                          ptr - first == pos);   // '<'
            buffer_ = tmp;
        }
    }

    ~ToString () {
        if (buffer_)
            std::free (buffer_);
    }

    operator const char* () const {
        return buffer_;
    }

private:

    char* buffer_;
};

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

typedef std::deque<X, std::allocator<X> > Deque;

std::size_t new_capacity;

namespace __rw {

_RWSTD_SPECIALIZED_FUNCTION
inline Deque::size_type
__rw_new_capacity<Deque>(Deque::size_type n, const Deque*)
{
    if (n) {
        // non-zero size argument indicates a request for an increase
        // in the capacity of a deque object's dynamically sizable
        // vector of nodes
        return n * 2;
    }

    // zero size argument is a request for the initial size of a deque
    // object's dynamically sizable vector of nodes or for the size of
    // the objects's fixed-size buffer for elements
    return new_capacity;
}

}

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

enum {
    NewThrows = 0x1          /* cause operator new to throw */,
    CopyCtorThrows = 0x2     /* cause element's copy ctor to throw */,
    AssignmentThrows = 0x4   /* cause element's assignment to throw */
};

enum MemberFunction {
    Assign_n    /* deque::assign (size_type, const_reference) */,
    AssignRange /* deque::assign (InputIterator, InputIterator) */,

    Erase_1     /* deque::erase (iterator) */,
    EraseRange  /* deque::erase (iterator, iterator) */,

    Insert_1    /* deque::insert (iterator, const_reference) */,
    Insert_n    /* deque::insert (iterator, size_type, const_reference) */,
    InsertRange /* deque::insert (iterator, InputIterator, InputIterator) */
};


// causes operator new, deque element's copy ctor, or assignment operator
// to throw an exception and iterates as long as the member function exits
// by throwing an exception; verifies that the exception had no effects
// on the container
template <class Iterator>
void exception_loop (int             line /* line number in caller*/,
                     MemberFunction  mfun /* deque member function */,
                     const char     *fcall /* function call string */,
                     int             exceptions /* enabled exceptions */,
                     Deque          &deq /* container to call function on */,
                     const Deque::iterator &it /* iterator into container */,
                     int             n /* number of elements or offset */,
                     const X        *x /* pointer to an element or 0 */,
                     const Iterator &first /* beginning of range */,
                     const Iterator &last /* end of range to insert */,
                     int            *n_copy /* number of copy ctors */,
                     int            *n_asgn /* number of assignments */)
{
    std::size_t throw_after = 0;

    // get the initial size of the container and its begin() iterator
    // to detect illegal changes after an exception (i.e., violations
    // if the strong exception guarantee)
    const std::size_t           size  = deq.size ();
    const Deque::const_iterator begin = deq.begin ();
    const Deque::const_iterator end   = deq.end ();

#ifdef DEFINE_REPLACEMENT_NEW_AND_DELETE

    rwt_free_store* const pst = rwt_get_free_store (0);

#endif   // DEFINE_REPLACEMENT_NEW_AND_DELETE

    // repeatedly call the specified member function until it returns
    // without throwing an exception
    for ( ; ; ) {

        // detect objects constructed but not destroyed after an exception
        std::size_t x_count = X::count_;

        _RWSTD_ASSERT (n_copy);
        _RWSTD_ASSERT (n_asgn);

        *n_copy = X::n_total_copy_ctor_;
        *n_asgn = X::n_total_op_assign_;

#ifndef _RWSTD_NO_EXCEPTIONS

        // iterate for `n=throw_after' starting at the next call to operator
        // new, forcing each call to throw an exception, until the insertion
        // finally succeeds (i.e, no exception is thrown)

#  ifdef DEFINE_REPLACEMENT_NEW_AND_DELETE

        if (exceptions & NewThrows) {
            *pst->throw_at_calls_ [0] = pst->new_calls_ [0] + throw_after + 1;
        }

#  endif   // DEFINE_REPLACEMENT_NEW_AND_DELETE

        if (exceptions & CopyCtorThrows) {
            X::copy_ctor_throw_count_ = X::n_total_copy_ctor_ + throw_after;
        }

        if (exceptions & AssignmentThrows) {
            X::op_assign_throw_count_ = X::n_total_op_assign_ + throw_after;
        }

#endif   // _RWSTD_NO_EXCEPTIONS

        _TRY {

            switch (mfun) {
            case Assign_n:
                _RWSTD_ASSERT (x);
                deq.assign (n, *x);
                break;
            case AssignRange:
                deq.assign (first, last);
                break;

            case Erase_1:
                deq.erase (it);
                break;
            case EraseRange: {
                const Deque::iterator erase_end (it + n);
                deq.erase (it, erase_end);
                break;
            }

            case Insert_1:
                _RWSTD_ASSERT (x);
                deq.insert (it, *x);
                break;
            case Insert_n:
                _RWSTD_ASSERT (x);
                deq.insert (it, n, *x);
                break;
            case InsertRange:
                deq.insert (it, first, last);
                break;
            }
        }
        _CATCH (...) {

            // verify that an exception thrown from the member function
            // didn't cause a change in the state of the container

            rw_assert (deq.size () == size, 0, line,
                       "line %d: %s: size unexpectedly changed "
                       "from %zu to %zu after an exception",
                       __LINE__, fcall, size, deq.size ());
            
            rw_assert (deq.begin () == begin, 0, line,
                       "line %d: %s: begin() unexpectedly "
                       "changed after an exception by %d",
                       __LINE__, fcall, deq.begin () - begin);

            rw_assert (deq.end () == end, 0, line,
                       "line %d: %s: end() unexpectedly "
                       "changed after an exception by %d",
                       __LINE__, fcall, deq.end () - end);
            

            // count the number of objects to detect leaks
            x_count = X::count_ - x_count;
            rw_assert (x_count == deq.size () - size, 0, line,
                       "line %d: %s: leaked %zu objects after an exception",
                       __LINE__, fcall, x_count - (deq.size () - size));
            
            if (exceptions) {

                // increment to allow this call to operator new to succeed
                // and force the next one to fail, and try to insert again
                ++throw_after;
            }
            else
                break;

            continue;
        }

        // count the number of objects to detect leaks
        x_count = X::count_ - x_count;
        rw_assert (x_count == deq.size () - size, 0, line,
                   "line %d: %s: leaked %zu objects "
                   "after a successful insertion",
                   __LINE__, fcall, x_count - (deq.size () - size));

        break;
    }

#ifdef DEFINE_REPLACEMENT_NEW_AND_DELETE

    // disable exceptions from replacement operator new
    *pst->throw_at_calls_ [0] = _RWSTD_SIZE_MAX;

#endif   // DEFINE_REPLACEMENT_NEW_AND_DELETE

    X::copy_ctor_throw_count_ = 0;
    X::op_assign_throw_count_ = 0;

    // compute the number of calls to X copy ctor and assignment operator
    // and set `n_copy' and `n_assgn' to the value of the result
    *n_copy = X::n_total_copy_ctor_ - *n_copy;
    *n_asgn = X::n_total_op_assign_ - *n_asgn;
}


// used to determine whether insert() can or cannot use
// an algorithm optimized for BidirectionalIterators
bool is_bidirectional (std::input_iterator_tag) { return false; }
bool is_bidirectional (std::bidirectional_iterator_tag) { return true; }

// returns the number of invocations of the assignment operators
// for a call to deque::insert(iterator, InputIterator, InputIterator)
// (the value depends on the iterator category)
template <class Iterator>
std::size_t insert_assignments (Iterator it,
                                int nelems,
                                std::size_t off,
                                std::size_t seqlen,
                                std::size_t inslen)
{
    if (is_bidirectional (_RWSTD_ITERATOR_CATEGORY (Iterator, it)))
        return 0 == nelems ? 0 : off < seqlen - off ? off : seqlen - off;

    if (0 < nelems)
        --nelems;

    if (0 == nelems || 0 == inslen)
        return 0;

    // compute the number of assignments done
    // to insert the first element in the sequence
    const std::size_t first = off < seqlen - off ? off : seqlen - off;

    // recursively compute the numner of assignments
    // for the rest of the elements in the sequence
    const std::size_t rest =
        insert_assignments (it, nelems, off + 1, seqlen + 1, inslen - 1);

    return first + rest;
}


template <class Iterator>
int test_insert (int line, int exceptions,
                 const Iterator &dummy, int nelems,
                 const char *seq, std::size_t seqlen, std::size_t off, 
                 const char *ins, std::size_t inslen, 
                 const char *res, std::size_t reslen)
{
    int nfailed = 0;

    const X* const xseq = X::from_char (seq, seqlen);
          X* const xins = X::from_char (ins, inslen);

    Deque deq = seqlen ? Deque (xseq, xseq + seqlen) : Deque ();

    // offset must be valid
    _RWSTD_ASSERT (off <= deq.size ());
    const Deque::iterator iter = deq.begin () + off;

    // only insert() at either end of the container is exception safe
    // insertions into the middle of the container are not (i.e., the
    // container may grow or may even become inconsistent)
    if (off && off < deq.size ())
        exceptions = 0;

    // Format arrayS of X's
    ToString<X> seqstr (xseq, xseq + seqlen, -1);
    ToString<X> insstr (xins, xins + inslen, -1);

    // format a string describing the function call being exercised
    // (used in diagnostic output below)
    char* buffer = 0;
    std::size_t len = 0;

    rw_asnprintf (&buffer, &len, "deque(%s).insert("
                  "%{?}begin(), %{;}%{?}end (), %{:}begin () + %zd%{;}%{;}"
                  "%{?}%d)%{:}%{?}%s)%{:}%d, %d)%{;}%{;}",
                  (const char*)seqstr, 0 == off, seqlen == off, off,
                  nelems == -2, *ins, nelems == -1, 
                  (const char*)insstr, nelems, *ins);
    
    int n_copy = X::n_total_copy_ctor_;
    int n_asgn = X::n_total_op_assign_;

    if (-2 == nelems) {   // insert(iterator, const_reference)

        exception_loop (line, Insert_1, buffer, exceptions,
                        deq, iter, nelems, xins, dummy, dummy,
                        &n_copy, &n_asgn);

    }
    else if (-1 == nelems) {   // insert(iterator, Iterator, Iterator)

        if (inslen > 1)
            exceptions = 0;

        const Iterator first =
            make_iter (xins, xins, xins + inslen, dummy);

        const Iterator last =
            make_iter (xins + inslen, xins, xins + inslen, dummy);

        exception_loop (line, InsertRange, buffer, exceptions,
                        deq, iter, nelems, 0, first, last,
                        &n_copy, &n_asgn);

    }
    else {   // insert(iterator, size_type, const_reference)

        if (nelems > 1)
            exceptions = 0;

        exception_loop (line, Insert_n, buffer, exceptions,
                        deq, iter, nelems, xins, dummy, dummy,
                        &n_copy, &n_asgn);

    }

    // verify the expected size of the deque after insertion
    rw_assert (deq.size () == reslen || ++nfailed == 0, __FILE__, line,
               "line %d: %s: size == %zu, got %zu\n",
               __LINE__, buffer, reslen, deq.size ());

    // verify the expected contents of the deque after insertion
    const Deque::const_iterator resbeg = deq.begin ();
    const Deque::const_iterator resend = deq.end ();

    for (Deque::const_iterator it = resbeg; it != resend; ++it) {
        if ((*it).val_ != UChar (res [it - resbeg])) {

            char* const got = new char [deq.size () + 1];

            for (Deque::const_iterator i = resbeg; i != resend; ++i) {
                got [i - resbeg] = char ((*i).val_);
            }

            got [deq.size ()] = '\0';

            ++nfailed;
            rw_assert (false, __FILE__, line,
                       "line %d: %s: expected %s, got %s\n",
                       __LINE__, buffer, res, got);

            delete[] got;
            break;
        }
    }

    // verify the complexity of the operation in terms of the number
    // of calls to the copy ctor and assignment operator on value_type
    const std::size_t expect_copy = nelems < 0 ? inslen : nelems;

    rw_assert (n_copy == int (expect_copy) || ++nfailed == 0, 
               __FILE__, line,
               "line %d: %s: expected %zu invocations "
               "of X::X(const X&), got %d\n",
               __LINE__, buffer, expect_copy, n_copy);

    // compute the number of calls to the assignment operator
    const std::size_t expect_asgn =
        insert_assignments (dummy, nelems, off, seqlen, inslen);

    rw_assert (n_asgn == int (expect_asgn) || ++nfailed == 0, 
               __FILE__, line,
               "line %d: %s: expected %zu invocations "
               "of X::operator=(const X&), got %d\n",
               __LINE__, buffer, expect_asgn, n_asgn);

    // Free buffer storage
    std::free (buffer);

    delete[] xins;
    delete[] xseq;

    return 0 != nfailed;
}

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

template <class Iterator>
void test_insert_range (const Iterator &it, const char* itname)
{
    rw_info (0, 0 ,0, 
             "std::deque<X>::insert(iterator, %s, %s)", itname, itname);

    static int nfailed;

#undef TEST
#define TEST(seq, off, ins, res)                        \
    nfailed += test_insert (__LINE__, -1,               \
                            it, -1,                     \
                            seq, sizeof seq - 1,        \
                            std::size_t (off),          \
                            ins, sizeof ins - 1,        \
                            res, sizeof res - 1)

    //    +---------------------------------------- seq
    //    |      +--------------------------------- off
    //    |      |   +----------------------------- ins
    //    |      |   |      +---------------------- res
    //    |      |   |      |
    //    v      v   v      v
    TEST ("",    +0, "",    "");
    TEST ("",    +0, "a",   "a");
    TEST ("",    +0, "ab",  "ab");
    TEST ("",    +0, "abc", "abc");
    TEST ("a",   +0, "",    "a");
    TEST ("b",   +0, "a",   "ab");
    TEST ("c",   +0, "ab",  "abc");
    TEST ("cd",  +0, "ab",  "abcd");
    TEST ("def", +0, "abc", "abcdef");

    TEST ("a",   +1, "",    "a");
    TEST ("a",   +1, "b",   "ab");
    TEST ("a",   +1, "bc",  "abc");
    TEST ("a",   +1, "bcd", "abcd");

    TEST ("ab",  +1, "",    "ab");
    TEST ("ac",  +1, "b",   "abc");
    TEST ("acd", +1, "b",   "abcd");

    TEST ("ab",  +2, "",    "ab");
    TEST ("ab",  +2, "c",   "abc");
    TEST ("ab",  +2, "cd",  "abcd");

    TEST ("abc", +2, "",    "abc");
    TEST ("abd", +2, "c",   "abcd");
    TEST ("abe", +2, "cd",  "abcde");
    TEST ("abf", +2, "cde", "abcdef");

    TEST ("abc", +3, "",    "abc");
    TEST ("abc", +3, "d",   "abcd");
    TEST ("abc", +3, "de",  "abcde");
    TEST ("abc", +3, "def", "abcdef");
    

#define UPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define LOWER "abcdefghijklmnopqrstuvwxyz"

    TEST (UPPER,  +0, LOWER, "" LOWER "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    TEST (UPPER,  +1, LOWER, "A" LOWER "BCDEFGHIJKLMNOPQRSTUVWXYZ");
    TEST (UPPER,  +2, LOWER, "AB" LOWER "CDEFGHIJKLMNOPQRSTUVWXYZ");
    TEST (UPPER,  +3, LOWER, "ABC" LOWER "DEFGHIJKLMNOPQRSTUVWXYZ");
    TEST (UPPER,  +4, LOWER, "ABCD" LOWER "EFGHIJKLMNOPQRSTUVWXYZ");
    TEST (UPPER,  +5, LOWER, "ABCDE" LOWER "FGHIJKLMNOPQRSTUVWXYZ");
    TEST (UPPER,  +6, LOWER, "ABCDEF" LOWER "GHIJKLMNOPQRSTUVWXYZ");
    TEST (UPPER,  +7, LOWER, "ABCDEFG" LOWER "HIJKLMNOPQRSTUVWXYZ");
    TEST (UPPER,  +8, LOWER, "ABCDEFGH" LOWER "IJKLMNOPQRSTUVWXYZ");
    TEST (UPPER,  +9, LOWER, "ABCDEFGHI" LOWER "JKLMNOPQRSTUVWXYZ");
    TEST (UPPER, +10, LOWER, "ABCDEFGHIJ" LOWER "KLMNOPQRSTUVWXYZ");
    TEST (UPPER, +11, LOWER, "ABCDEFGHIJK" LOWER "LMNOPQRSTUVWXYZ");
    TEST (UPPER, +12, LOWER, "ABCDEFGHIJKL" LOWER "MNOPQRSTUVWXYZ");
    TEST (UPPER, +13, LOWER, "ABCDEFGHIJKLM" LOWER "NOPQRSTUVWXYZ");
    TEST (UPPER, +14, LOWER, "ABCDEFGHIJKLMN" LOWER "OPQRSTUVWXYZ");
    TEST (UPPER, +15, LOWER, "ABCDEFGHIJKLMNO" LOWER "PQRSTUVWXYZ");
    TEST (UPPER, +16, LOWER, "ABCDEFGHIJKLMNOP" LOWER "QRSTUVWXYZ");
    TEST (UPPER, +17, LOWER, "ABCDEFGHIJKLMNOPQ" LOWER "RSTUVWXYZ");
    TEST (UPPER, +18, LOWER, "ABCDEFGHIJKLMNOPQR" LOWER "STUVWXYZ");
    TEST (UPPER, +19, LOWER, "ABCDEFGHIJKLMNOPQRS" LOWER "TUVWXYZ");
    TEST (UPPER, +20, LOWER, "ABCDEFGHIJKLMNOPQRST" LOWER "UVWXYZ");
    TEST (UPPER, +21, LOWER, "ABCDEFGHIJKLMNOPQRSTU" LOWER "VWXYZ");
    TEST (UPPER, +22, LOWER, "ABCDEFGHIJKLMNOPQRSTUV" LOWER "WXYZ");
    TEST (UPPER, +23, LOWER, "ABCDEFGHIJKLMNOPQRSTUVW" LOWER "XYZ");
    TEST (UPPER, +24, LOWER, "ABCDEFGHIJKLMNOPQRSTUVWX" LOWER "YZ");
    TEST (UPPER, +25, LOWER, "ABCDEFGHIJKLMNOPQRSTUVWXY" LOWER "Z");
    TEST (UPPER, +26, LOWER, "ABCDEFGHIJKLMNOPQRSTUVWXYZ" LOWER "");

    if (!nfailed)
        rw_assert (true, 0, __LINE__, "");
}

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

template <class T, class IntType>
void test_insert_int_range (const T&, const IntType&,
                            const char* t_name, const char* int_name)
{
    rw_info (0, 0, 0, 
             "std::deque<%s>::insert(iterator, %s, %s)", 
             t_name, int_name, int_name);

    std::deque<T> d;

    typename std::deque<T>::iterator it = d.begin ();

    // deque<T>::insert(iterator, size_type, const_reference)

    d.insert (it, IntType (1), IntType (0));

    rw_assert (1 == d.size (), 0, __LINE__,
               "deque<%s>::insert(begin(), %s = 1, %s = 0); size() == 1,"
               " got %zu", t_name, int_name, int_name, d.size ());

    it = d.begin ();
    ++it;

    d.insert (it, IntType (3), IntType (2));

    rw_assert (4 == d.size (), 0, __LINE__,
               "deque<%s>::insert(begin() + 1, %s = 3, %s = 2); size() == 4,"
               " got %zu", t_name, int_name, int_name, d.size ());

    it = d.begin ();
    ++it;

    d.insert (it, IntType (2), IntType (1));

    rw_assert (6 == d.size (), 0, __LINE__,
               "deque<%s>::insert(begin() + 1, %s = 2, %s = 1); size() == 6,"
               " got %zu", t_name, int_name, int_name, d.size ());
}

template <class T>
void test_insert_int_range (const T &dummy, const char* tname)
{
    test_insert_int_range (dummy, (signed char)0, tname, "signed char");
    test_insert_int_range (dummy, (unsigned char)0, tname, "unsigned char");
    test_insert_int_range (dummy, short (), tname, "short");
    test_insert_int_range (dummy, (unsigned short)0, tname, "unsigned short");
    test_insert_int_range (dummy, int (), tname, "int");
    test_insert_int_range (dummy, (unsigned int)0, tname, "unsigned int");
    test_insert_int_range (dummy, long (), tname, "long");
    test_insert_int_range (dummy, (unsigned long)0, tname, "unsigned long");

#ifdef _RWSTD_LONG_LONG

    test_insert_int_range (dummy, (_RWSTD_LONG_LONG)0, 
                           tname, "long long");
    test_insert_int_range (dummy, (unsigned _RWSTD_LONG_LONG)0, 
                           tname, "unsigned long long");

#endif   // _RWSTD_LONG_LONG

}

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

void test_insert ()
{
    //////////////////////////////////////////////////////////////////
    // exercise deque::insert(iterator, const_reference)

    rw_info (0, 0, 0, "std::deque<X>::insert(iterator, const_reference)");

    int nfailed = 0;

#undef TEST
#define TEST(seq, off, ins, res) do {                   \
      const char insseq [] = { ins, '\0' };             \
      nfailed += test_insert (__LINE__, -1,             \
                              (X*)0, -2,                \
                              seq, sizeof seq - 1,      \
                              std::size_t (off),        \
                              insseq, 1,                \
                              res, sizeof res - 1);     \
    } while (0)

    //    +------------------- original sequence
    //    |       +----------- insertion offset
    //    |       |    +------ element to insert
    //    |       |    |   +-- resulting sequence
    //    |       |    |   |
    //    V       V    V   V
    TEST ("",     +0, 'a', "a");
    TEST ("b",    +0, 'a', "ab");
    TEST ("bc",   +0, 'a', "abc");
    TEST ("bcd",  +0, 'a', "abcd");
    TEST ("bcde", +0, 'a', "abcde");

    TEST ("a",    +1, 'b', "ab");
    TEST ("ac",   +1, 'b', "abc");
    TEST ("acd",  +1, 'b', "abcd");
    TEST ("acde", +1, 'b', "abcde");

    TEST ("ab",   +2, 'c', "abc");
    TEST ("abd",  +2, 'c', "abcd");
    TEST ("abde", +2, 'c', "abcde");

    TEST ("abc",  +3, 'd', "abcd");
    TEST ("abce", +3, 'd', "abcde");

    TEST ("abcd", +4, 'e', "abcde");

#define A_to_B "AB"
#define A_to_C "ABC"
#define A_to_D "ABCD"
#define A_to_E "ABCDE"
#define A_to_F "ABCDEF"
#define A_to_G "ABCDEFG"
#define A_to_H "ABCDEFGH"
#define A_to_I "ABCDEFGHI"
#define A_to_J "ABCDEFGHIJ"
#define A_to_K "ABCDEFGHIJK"
#define A_to_L "ABCDEFGHIJKL"
#define A_to_M "ABCDEFGHIJKLM"
#define A_to_N "ABCDEFGHIJKLMN"
#define A_to_O "ABCDEFGHIJKLMNO"
#define A_to_P "ABCDEFGHIJKLMNOP"
#define A_to_Q "ABCDEFGHIJKLMNOPQ"
#define A_to_R "ABCDEFGHIJKLMNOPQR"
#define A_to_S "ABCDEFGHIJKLMNOPQRS"
#define A_to_T "ABCDEFGHIJKLMNOPQRST"
#define A_to_U "ABCDEFGHIJKLMNOPQRSTU"
#define A_to_V "ABCDEFGHIJKLMNOPQRSTUV"
#define A_to_W "ABCDEFGHIJKLMNOPQRSTUVW"
#define A_to_X "ABCDEFGHIJKLMNOPQRSTUVWX"
#define A_to_Y "ABCDEFGHIJKLMNOPQRSTUVWXY"
#define A_to_Z "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define B_to_Z "BCDEFGHIJKLMNOPQRSTUVWXYZ"
#define C_to_Z "CDEFGHIJKLMNOPQRSTUVWXYZ"
#define D_to_Z "DEFGHIJKLMNOPQRSTUVWXYZ"
#define E_to_Z "EFGHIJKLMNOPQRSTUVWXYZ"
#define F_to_Z "FGHIJKLMNOPQRSTUVWXYZ"
#define G_to_Z "GHIJKLMNOPQRSTUVWXYZ"
#define H_to_Z "HIJKLMNOPQRSTUVWXYZ"
#define I_to_Z "IJKLMNOPQRSTUVWXYZ"
#define J_to_Z "JKLMNOPQRSTUVWXYZ"
#define K_to_Z "KLMNOPQRSTUVWXYZ"
#define L_to_Z "LMNOPQRSTUVWXYZ"
#define M_to_Z "MNOPQRSTUVWXYZ"
#define N_to_Z "NOPQRSTUVWXYZ"
#define O_to_Z "OPQRSTUVWXYZ"
#define P_to_Z "PQRSTUVWXYZ"
#define Q_to_Z "QRSTUVWXYZ"
#define R_to_Z "RSTUVWXYZ"
#define S_to_Z "STUVWXYZ"
#define T_to_Z "TUVWXYZ"
#define U_to_Z "UVWXYZ"
#define V_to_Z "VWXYZ"
#define W_to_Z "WXYZ"
#define X_to_Z "XYZ"
#define Y_to_Z "YZ"

    TEST (A_to_Z, + 0, '^', ""     "^" A_to_Z);
    TEST (A_to_Z, + 1, '^', "A"    "^" B_to_Z);
    TEST (A_to_Z, + 2, '^', A_to_B "^" C_to_Z);
    TEST (A_to_Z, + 3, '^', A_to_C "^" D_to_Z);
    TEST (A_to_Z, + 4, '^', A_to_D "^" E_to_Z);
    TEST (A_to_Z, + 5, '^', A_to_E "^" F_to_Z);
    TEST (A_to_Z, + 6, '^', A_to_F "^" G_to_Z);
    TEST (A_to_Z, + 7, '^', A_to_G "^" H_to_Z);
    TEST (A_to_Z, + 8, '^', A_to_H "^" I_to_Z);
    TEST (A_to_Z, + 9, '^', A_to_I "^" J_to_Z);
    TEST (A_to_Z, +10, '^', A_to_J "^" K_to_Z);
    TEST (A_to_Z, +11, '^', A_to_K "^" L_to_Z);
    TEST (A_to_Z, +12, '^', A_to_L "^" M_to_Z);
    TEST (A_to_Z, +13, '^', A_to_M "^" N_to_Z);
    TEST (A_to_Z, +14, '^', A_to_N "^" O_to_Z);
    TEST (A_to_Z, +15, '^', A_to_O "^" P_to_Z);
    TEST (A_to_Z, +16, '^', A_to_P "^" Q_to_Z);
    TEST (A_to_Z, +17, '^', A_to_Q "^" R_to_Z);
    TEST (A_to_Z, +18, '^', A_to_R "^" S_to_Z);
    TEST (A_to_Z, +19, '^', A_to_S "^" T_to_Z);
    TEST (A_to_Z, +20, '^', A_to_T "^" U_to_Z);
    TEST (A_to_Z, +21, '^', A_to_U "^" V_to_Z);
    TEST (A_to_Z, +22, '^', A_to_V "^" W_to_Z);
    TEST (A_to_Z, +23, '^', A_to_W "^" X_to_Z);
    TEST (A_to_Z, +24, '^', A_to_X "^" Y_to_Z);
    TEST (A_to_Z, +25, '^', A_to_Y "^" "Z");
    TEST (A_to_Z, +26, '^', A_to_Z "^" "");

    if (!nfailed)
        rw_assert (true, 0, __LINE__, (""));

    //////////////////////////////////////////////////////////////////
    // exercise deque::insert(iterator, size_type, const_reference)

    rw_info (0, 0, 0, 
             "std::deque<X>::insert(iterator, size_type, "
             "const_reference)");

    nfailed = 0;


#undef TEST
#define TEST(seq, off, n, ins, res) do {                \
      const char insseq [] = { ins, '\0' };             \
      nfailed += test_insert (__LINE__, -1,             \
                              (X*)0, n,                 \
                              seq, sizeof seq - 1,      \
                              std::size_t (off),        \
                              insseq, 1,                \
                              res, sizeof res - 1);     \
    } while (0)
    
    TEST ("",     +0, 0, 'a', "");
    TEST ("",     +0, 1, 'a', "a");
    TEST ("",     +0, 2, 'b', "bb");
    TEST ("",     +0, 3, 'c', "ccc");

    TEST ("a",    +0, 0, 'a', "a");
    TEST ("b",    +0, 1, 'a', "ab");
    TEST ("b",    +0, 2, 'a', "aab");
    TEST ("b",    +0, 3, 'a', "aaab");

    TEST ("ab",   +1, 0, 'b', "ab");
    TEST ("ac",   +1, 1, 'b', "abc");
    TEST ("ac",   +1, 2, 'b', "abbc");
    TEST ("ac",   +1, 3, 'b', "abbbc");

    TEST ("abcd", +2, 0, 'c', "abcd");
    TEST ("abde", +2, 1, 'c', "abcde");
    TEST ("abde", +2, 2, 'c', "abccde");
    TEST ("abde", +2, 3, 'c', "abcccde");

    if (!nfailed)
        rw_assert (true, 0, __LINE__, (""));

    //////////////////////////////////////////////////////////////////
    // exercise deque::insert(iterator, InputIterator, InputIterator)

    rw_info (0, 0, 0, 
             "template <class InputIterator> std::deque<X>::"
             "insert(iterator, InputIterator, InputIterator)");

    test_insert_range (InputIter<X>(0, 0, 0), "InputIter<X>");
    test_insert_range (FwdIter<X>(), "FwdIter<X>");
    test_insert_range (BidirIter<X>(), "BidirIter<X>");
    test_insert_range (RandomAccessIter<X>(), "RandomAccessIter<X>");

    //////////////////////////////////////////////////////////////////
    // exercise deque::insert(iterator, int, int)

    rw_info (0, 0, 0, 
             "template <class IntType> "
             "std::deque<IntType>::"
             "insert(iterator, IntType, IntType)");

    test_insert_int_range ((signed char)0, "signed char");
    test_insert_int_range ((unsigned char)0, "unsigned char");
    test_insert_int_range (short (), "short");
    test_insert_int_range ((unsigned short)0, "unsigned short");
    test_insert_int_range (int (), "int");
    test_insert_int_range ((unsigned int)0, "unsigned int");
    test_insert_int_range (long (), "long");
    test_insert_int_range ((unsigned long)0, "unsigned long");

#ifdef _RWSTD_LONG_LONG

    test_insert_int_range ((_RWSTD_LONG_LONG)0, "long long");
    test_insert_int_range ((unsigned _RWSTD_LONG_LONG)0, "unsigned long long");

#endif   // _RWSTD_LONG_LONG

}

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

template <class Iterator>
int test_assign (int line, int exceptions,
                 const Iterator &dummy, int nelems,
                 const char *seq, std::size_t seqlen,
                 const char *asn, std::size_t asnlen,
                 const char *res, std::size_t reslen)
{
    int nfailed = 0;

    const X* const xseq = X::from_char (seq, seqlen);
          X* const xasn = X::from_char (asn, asnlen);

    Deque deq = seqlen ? Deque (xseq, xseq + seqlen) : Deque ();

    // Format array of X
    ToString<X> seqstr (xseq, xseq + seqlen, -1);
    ToString<X> asnstr (xasn, xasn + asnlen, -1);

    // format a string describing the function call being exercised
    // (used in diagnostic output below)
    char* buffer = 0;
    std::size_t len = 0;

    rw_asnprintf (&buffer, &len, 
                  "deque(%s).assign("
                  "%{?}%s)%{:}%d, %d)%{;}", 
                  (const char*)seqstr, nelems < 0, 
                  (const char*)asnstr, nelems, *asn);

    int n_copy = X::n_total_copy_ctor_;
    int n_asgn = X::n_total_op_assign_;

    // create a dummy deque iterator to pass to exception_loop
    // (the object will not be used by the functiuon)
    const Deque::iterator dummy_it = deq.begin ();

    if (nelems < 0) {   // assign(Iterator, Iterator)

        if (asnlen > 1)
            exceptions = 0;

        const Iterator first =
            make_iter (xasn, xasn, xasn + asnlen, dummy);

        const Iterator last =
            make_iter (xasn + asnlen, xasn, xasn + asnlen, dummy);

        exception_loop (line, AssignRange, buffer, exceptions,
                        deq, dummy_it, nelems, 0, first, last,
                        &n_copy, &n_asgn);
    }
    else {   // assign(size_type, const_reference)
        if (nelems > 1)
            exceptions = 0;

        exception_loop (line, Assign_n, buffer, exceptions,
                        deq, dummy_it, nelems, xasn, dummy, dummy,
                        &n_copy, &n_asgn);
    }

    // verify the expected size of the deque after assignment
    rw_assert (deq.size () == reslen || ++nfailed == 0, 0, line,
               "line %d: %s: size == %zu, got %zu\n",
               __LINE__, buffer, reslen, deq.size ());

    // verify the expected contents of the deque after assignment
    const Deque::const_iterator resbeg = deq.begin ();
    const Deque::const_iterator resend = deq.end ();

    for (Deque::const_iterator it = resbeg; it != resend; ++it) {

        const Deque::size_type inx = it - resbeg;

        _RWSTD_ASSERT (inx < deq.size ());

        if ((*it).val_ != UChar (res [inx])) {

            char* const got = new char [deq.size () + 1];

            for (Deque::const_iterator i = resbeg; i != resend; ++i) {

                const Deque::size_type inx_2 = i - resbeg;

                _RWSTD_ASSERT (inx_2 < deq.size ());

                got [inx_2] = char ((*i).val_);
            }

            got [deq.size ()] = '\0';

            ++nfailed;
            rw_assert (false, 0, line,
                       "line %d: %s: expected %s, got %s\n",
                       __LINE__, buffer, res, got);

            delete[] got;
            break;
        }
    }

    // set asnlen to the number of elements assigned to the container
    if (0 <= nelems)
        asnlen = std::size_t (nelems);

    // verify the complexity of the operation in terms of the number
    // of calls to the copy ctor and assignment operator on value_type

    // the number of invocations of the copy ctor and the assignment
    // operator depends on whether the implementation of assign()
    // strictly follows the requirements in 23.2.1.1, p7 or p8 and
    // destroys the existing elements before inserting the new ones,
    // or whether it assigns the new elements over the existing ones

#ifndef _RWSTD_NO_EXT_DEQUE_ASSIGN_IN_PLACE
    const std::size_t expect_copy = seqlen < asnlen ? asnlen - seqlen : 0;
    const std::size_t expect_asgn = asnlen < seqlen ? asnlen : seqlen;
#else   // if defined (_RWSTD_NO_EXT_DEQUE_ASSIGN_IN_PLACE)
    const std::size_t expect_copy = asnlen;
    const std::size_t expect_asgn = 0;
#endif   // _RWSTD_NO_EXT_DEQUE_ASSIGN_IN_PLACE

    rw_assert (n_copy == int (expect_copy) || ++nfailed == 0, 0, line,
               "line %d: %s: expected %zu invocations "
               "of X::X(const X&), got %d\n",
               __LINE__, buffer, expect_copy, n_copy);

    rw_assert (n_asgn == int (expect_asgn) || ++nfailed == 0, 0, line,
               "line %d: %s: expected %zu invocations "
               "of X::operator=(const X&), got %d\n",
               __LINE__, buffer, expect_asgn, n_asgn);

    // Free buffer storage
    std::free (buffer);

    delete[] xasn;
    delete[] xseq;

    return 0 != nfailed;
}

template <class Iterator>
void test_assign_range (const Iterator &it, const char* itname)
{
    rw_info (0, 0, 0, "std::deque<X>::assign(%s, %s)", itname, itname);

    static int nfailed;

    static const char seq[] = "abcdefghijklmnopqrstuvwxyz";
    static const char asn[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    for (std::size_t i = 0; i != sizeof seq - 1; ++i) {
        for (std::size_t j = 0; j != sizeof asn - 1; ++j) {

            nfailed += test_assign (__LINE__, 0,
                                    it, -1, seq, i, asn, j, asn, j);
        }
    }

    if (!nfailed)
        rw_assert (true, 0, __LINE__, " ");
}


void test_assign ()
{
    int nfailed = 0;

    //////////////////////////////////////////////////////////////////
    // exercise
    //   deque::assign(size_type, const_reference)

    rw_info (0, 0, 0, "std::deque<X>::assign(size_type, const_reference)");

    static const char seq[] = "abcdefghijklmnopqrstuvwxyz";
    static const char res[] = "AAAAAAAAAAAAAAAAAAAAAAAAAA";

    for (std::size_t i = 0; i != sizeof seq - 1; ++i) {
        for (std::size_t j = 0; j != sizeof seq - 1; ++j) {

            nfailed += test_assign (__LINE__, -1, (X*)0,
                                    int (j), seq, i, res, 1U, res, j);
        }
    }

    if (!nfailed)
        rw_assert (true, 0, __LINE__, " ");

    //////////////////////////////////////////////////////////////////
    // exercise
    //   template <class InputIterator>
    //   deque::assign(InputIterator, InputIterator)

    rw_info (0, 0, 0, 
             "template <class InputIterator> "
             "std::deque<X>::assign(InputIterator, InputIterator)");

    test_assign_range (InputIter<X>(0, 0, 0), "InputIter<X>");
    test_assign_range (FwdIter<X>(), "FwdIter<X>");
    test_assign_range (BidirIter<X>(), "BidirIter<X>");
    test_assign_range (RandomAccessIter<X>(), "RandomAccessIter<X>");
}

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

int test_erase (int line,
                const char *seq, std::size_t seqlen,
                std::size_t begoff, std::size_t len,
                const char *res, std::size_t reslen)
{
    int nfailed = 0;

    const X* const xseq = X::from_char (seq, seqlen);

    Deque deq = seqlen ? Deque (xseq, xseq + seqlen) : Deque ();

    const Deque::iterator start = deq.begin () + begoff;

    // Format array of X
    ToString<X> seqstr (xseq, xseq + seqlen, -1);

    // Format a string describing the function call being exercised
    // (used in diagnostic output below); use a large enough buffer
    // because we cannot format in one single shot.
    char buffer [1024U];

    rw_snprintfa (buffer, 1024U,
                  "deque(%s).erase(%{?}end()%{:}"
                  "%{?}begin () + %zu%{:}begin ()%{;}%{;}",
                  (const char*)seqstr, begoff == deq.size (),
                  begoff, begoff);
        
    int n_copy = X::n_total_copy_ctor_;
    int n_asgn = X::n_total_op_assign_;

    if (std::size_t (-1) == len) {   // erase(iterator)

        exception_loop (line, Erase_1, buffer, 0,
                        deq, start, 1, 0, (X*)0, (X*)0,
                        &n_copy, &n_asgn);
    }
    else {   // assign(size_type, const_reference)

        const Deque::iterator end = start + len;

        rw_snprintfa (buffer + std::strlen (buffer), 
                      1024U - std::strlen (buffer),
                      "%{?})%{:}%{?}, end ())%{:}%{?}, begin ())"
                      "%{:}begin () + %zi%{;}%{;}%{;}",
                      std::size_t (-1) == len,
                      end == deq.end (),
                      end == deq.begin (),
                      end - deq.begin ());
        
        exception_loop (line, EraseRange, buffer, 0,
                        deq, start, len, 0, (X*)0, (X*)0,
                        &n_copy, &n_asgn);

    }

    // verify the expected size of the deque after erasure
    rw_assert (deq.size () == reslen || ++nfailed == 0, 0, line,
               "line %d: %s: size == %zu, got %zu\n",
               __LINE__, buffer, reslen, deq.size ());

    // verify the expected contents of the deque after assignment
    const Deque::const_iterator resbeg = deq.begin ();
    const Deque::const_iterator resend = deq.end ();

    for (Deque::const_iterator it = resbeg; it != resend; ++it) {
        if ((*it).val_ != UChar (res [it - resbeg])) {

            char* const got = new char [deq.size () + 1];

            for (Deque::const_iterator i = resbeg; i != resend; ++i) {
                got [i - resbeg] = char ((*i).val_);
            }

            got [deq.size ()] = '\0';

            ++nfailed;
            rw_assert (false, 0, line,
                       "line %d: %s: expected %s, got %s\n",
                       __LINE__, buffer, res, got);

            delete[] got;
            break;
        }
    }

#if 0
    // set asnlen to the number of elements assigned to the container
    if (0 <= nelems)
        asnlen = std::size_t (nelems);

    // verify the complexity of the operation in terms of the number
    // of calls to the copy ctor and assignment operator on value_type

    // the number of invocations of the copy ctor and the assignment
    // operator depends on whether the implementation of assign()
    // strictly follows the requirements in 23.2.1.1, p7 or p8 and
    // destroys the existing elements before inserting the new ones,
    // or whether it assigns the new elements over the existing ones

#ifndef _RWSTD_NO_EXT_DEQUE_ASSIGN_IN_PLACE
    const std::size_t expect_copy = seqlen < asnlen ? asnlen - seqlen : 0;
    const std::size_t expect_asgn = asnlen < seqlen ? asnlen : seqlen;
#else   // if defined (_RWSTD_NO_EXT_DEQUE_ASSIGN_IN_PLACE)
    const std::size_t expect_copy = asnlen;
    const std::size_t expect_asgn = 0;
#endif   // _RWSTD_NO_EXT_DEQUE_ASSIGN_IN_PLACE

    rw_assert (n_copy == int (expect_copy) || ++nfailed == 0, 0, line,
               "line %d: %s: expected %zu invocations "
               "of X::X(const X&), got %d\n",
               __LINE__, buffer, expect_copy, n_copy);

    rw_assert (n_asgn == int (expect_asgn) || ++nfailed == 0, 0, line,
               "line %d: %s: expected %zu invocations "
               "of X::operator=(const X&), got %d\n",
               __LINE__, buffer, expect_asgn, n_asgn);
#endif

    delete[] xseq;

    return 0 != nfailed;
}

void test_erase ()
{
    int nfailed = 0;

    //////////////////////////////////////////////////////////////////
    // exercise deque::erase(iterator)

    rw_info (0, 0, 0, "std::deque<X>::erase(iterator)");

#undef TEST
#define TEST(seq, off, res) do {                        \
      nfailed += test_erase (__LINE__,                  \
                             seq, sizeof seq - 1,       \
                             std::size_t (off),         \
                             std::size_t (-1),          \
                             res, sizeof res - 1);      \
    } while (0)

    TEST ("a", 0, "");

    TEST ("ab", 0, "b");
    TEST ("ab", 1, "a");

    TEST ("abc", 0, "bc");
    TEST ("abc", 1, "ac");
    TEST ("abc", 2, "ab");

    TEST ("abcd", 0, "bcd");
    TEST ("abcd", 1, "acd");
    TEST ("abcd", 2, "abd");
    TEST ("abcd", 3, "abc");

    TEST ("abcde", 0, "bcde");
    TEST ("abcde", 1, "acde");
    TEST ("abcde", 2, "abde");
    TEST ("abcde", 3, "abce");
    TEST ("abcde", 4, "abcd");

    TEST ("abcdef", 0, "bcdef");
    TEST ("abcdef", 1, "acdef");
    TEST ("abcdef", 2, "abdef");
    TEST ("abcdef", 3, "abcef");
    TEST ("abcdef", 4, "abcdf");
    TEST ("abcdef", 5, "abcde");

    TEST ("abcdefg", 0, "bcdefg");
    TEST ("abcdefg", 1, "acdefg");
    TEST ("abcdefg", 2, "abdefg");
    TEST ("abcdefg", 3, "abcefg");
    TEST ("abcdefg", 4, "abcdfg");
    TEST ("abcdefg", 5, "abcdeg");
    TEST ("abcdefg", 6, "abcdef");

    TEST ("abcdefgh", 0, "bcdefgh");
    TEST ("abcdefgh", 1, "acdefgh");
    TEST ("abcdefgh", 2, "abdefgh");
    TEST ("abcdefgh", 3, "abcefgh");
    TEST ("abcdefgh", 4, "abcdfgh");
    TEST ("abcdefgh", 5, "abcdegh");
    TEST ("abcdefgh", 6, "abcdefh");
    TEST ("abcdefgh", 7, "abcdefg");

    //////////////////////////////////////////////////////////////////
    // exercise deque::erase(iterator, iterator)

    rw_info (0, 0, 0, "std::deque<X>::erase(iterator, iterator)");
}

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

#ifndef _RWSTD_NO_INLINE_MEMBER_TEMPLATES
#  ifndef _RWSTD_NO_EXPLICIT
#    if !defined (_MSC_VER) || _MSC_VER > 1200

struct DR_438
{
    static bool cast_used;

    DR_438 () { }

    explicit DR_438 (std::size_t) { cast_used = true; }

    template <class T> DR_438 (T) { }
};

bool DR_438::cast_used;

#    else   // if MSVC <= 6.0
       // avoid an MSVC 6.0 ICE on this code
#      define NO_DR_438_TEST "this version of MSVC is too broken"
#    endif   // !MSVC || MSVC > 6.0
#  else
#    define NO_DR_438_TEST "_RWSTD_NO_EXPLICIT #defined"
#  endif   // _RWSTD_NO_EXPLICIT
#  else
#    define NO_DR_438_TEST   "_RWSTD_NO_INLINE_MEMBER_TEMPLATES #defined"
#endif   // _RWSTD_NO_INLINE_MEMBER_TEMPLATES


void test_dr_438 ()
{
    //////////////////////////////////////////////////////////////////
    // exercise the resolution of DR 438:
    //////////////////////////////////////////////////////////////////
    //
    // For every sequence defined in clause [lib.containers]
    // and in clause [lib.strings]:

    // *  If the constructor
    //
    //    template <class InputIterator>
    //    X (InputIterator f, InputIterator l,
    //       const allocator_type& a = allocator_type())
    //
    //    is called with a type InputIterator that does not qualify
    //    as an input iterator, then the constructor will behave
    //    as if the overloaded constructor:
    //
    //    X (size_type, const value_type& = value_type(),
    //       const allocator_type& = allocator_type())
    //
    //    were called instead, with the arguments static_cast<size_type>(f),
    //    l and a, respectively.
    //
    // *  If the member functions of the forms:
    //
    //    template <class InputIterator>       // such as insert()
    //    rt fx1(iterator p, InputIterator f, InputIterator l);
    //
    //    template <class InputIterator>       // such as append(), assign()
    //    rt fx2(InputIterator f, InputIterator l);
    //
    //    template <class InputIterator>        // such as replace()
    //    rt fx3(iterator i1, iterator i2, InputIterator f, InputIterator l);
    //
    //    are called with a type InputIterator that does not qualify
    //    as an input iterator, then these functions will behave
    //    as if the overloaded member functions:
    //
    //    rt fx1(iterator, size_type, const value_type&);
    //
    //    rt fx2(size_type, const value_type&);
    //
    //    rt fx3(iterator, iterator, size_type, const value_type&);
    //
    //    were called instead, with the same arguments.
    //
    // In the previous paragraph the alternative binding will fail
    // if f is not implicitly convertible to X::size_type or
    // if l is not implicitly convertible to X::value_type.
    //
    // The extent to which an implementation determines that a type
    // cannot be an input iterator is unspecified, except that
    // as a minimum integral types shall not qualify as input iterators.
    //////////////////////////////////////////////////////////////////

    rw_info (0, 0, 0, "resolution of DR 438");

#ifndef NO_DR_438_TEST

    std::deque<DR_438, std::allocator<DR_438> > dq;

    dq.assign (1, 2);

    rw_assert (!DR_438::cast_used, 0, __LINE__,
               "deque::assign(InputIterator, InputIterator)"
               "with [ InputIterator = <integral type> ] unexpectedly "
               "used explicit argument conversion");
    
    dq.insert (dq.begin (), 1, 2);

    rw_assert (!DR_438::cast_used, 0, __LINE__,
               "deque::insert(iterator, InputIterator, InputIterator) "
               "with [ InputIterator = <integral type> ] unexpectedly "
               "used explicit argument conversion");
#else   // if defined (NO_DR_438_TEST)

    rw_warning (0, 0, __LINE__, "%s; skipping test", NO_DR_438_TEST);

#endif   // NO_DR_438_TEST

}

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

int run_test (int, char**)
{
    test_dr_438 ();

    static const std::size_t caps[] = {
        2, 3, 4, 5, 16, 32
    };

    for (std::size_t i = 0; i != sizeof caps / sizeof *caps; ++i) {

        new_capacity = caps [i];

        rw_info (0, 0, 0, 
                 "__rw::__rw_new_capacity<std::deque<X> >(0) = %zu",
                 _RW::__rw_new_capacity (0, (Deque*)0));

        test_assign ();

        test_erase ();

        test_insert ();
    }

    return 0;
}

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

int main (int argc, char** argv)
{
    return rw_test (argc, argv, __FILE__,
                    "lib.deque.modifiers",
                    0 /* no comment */, run_test,
                    0 /* co command line options */);
}

Reply via email to