blob: c4d82a33bdb74630183962d96146a44fcc2b68c4 [file] [log] [blame]
/***************************************************************************
*
* 23.vector.modifiers.cpp - test exercising [lib.vector.modifiers]
*
* $Id$
*
***************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* Copyright 2006 Rogue Wave Software.
*
**************************************************************************/
#include <memory> // for placement operator new()
#include <vector> // for vector
#include <cstddef> // for size_t
#include <rw_printf.h>
#include <rw_alg_test.h>
#include <rw_value.h> // for UserClass
#include <rw_driver.h>
#ifndef _RWSTD_NO_REPLACEABLE_NEW_DELETE
// disabled for compilers such as IBM VAC++ or MSVC
// that can't reliably replace the operators
# include <rw_new.h>
#endif // _RWSTD_NO_REPLACEABLE_NEW_DELETE
/**************************************************************************/
static unsigned rw_opt_nloops;
static int rw_opt_no_input_iter;
static int rw_opt_no_forward_iter;
static int rw_opt_no_bidir_iter;
static int rw_opt_no_random_iter;
static int rw_opt_no_insert;
static int rw_opt_no_insert_range;
static int rw_opt_no_insert_at_end;
static int rw_opt_no_complexity;
static int rw_opt_no_push_back;
/**************************************************************************/
typedef std::vector<UserClass, std::allocator<UserClass> > Vector;
Vector::size_type new_capacity;
namespace __rw {
_RWSTD_SPECIALIZED_FUNCTION
inline Vector::size_type
__rw_new_capacity<Vector>(Vector::size_type n, const Vector*)
{
if (n)
return n * 2;
return new_capacity;
}
}
/**************************************************************************/
// used to determine whether insert() can or cannot use
// an algorithm optimized for ForwardIterators
bool is_forward_category (std::input_iterator_tag) { return false; }
bool is_forward_category (std::forward_iterator_tag) { return true; }
template <class Iterator>
bool is_forward (const Iterator &it)
{
_RWSTD_UNUSED (it);
return is_forward_category (_RWSTD_ITERATOR_CATEGORY (Iterator, it));
}
// exercises the exception safety of each tested function by successively
// forcing operator new to thow a bad_alloc exception at each iteration
// of the loop until the call succeeds (i.e., until no exception is
// thrown)
template <class Iterator>
void exception_loop (int line, const char *fcall, bool capchg,
Vector &vec, const Vector::iterator &it,
int n, const UserClass *x,
const Iterator &first, const Iterator &last,
std::size_t *n_copy, std::size_t *n_asgn)
{
std::size_t throw_after = 0;
const std::size_t size = vec.size ();
const std::size_t capacity = vec.capacity ();
const Vector::const_iterator begin = vec.begin ();
#ifndef _RWSTD_NO_REPLACEABLE_NEW_DELETE
rwt_free_store* const pst = rwt_get_free_store (0);
#endif // _RWSTD_NO_REPLACEABLE_NEW_DELETE
// 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)
for ( ; ; ) {
*n_copy = UserClass::n_total_copy_ctor_;
*n_asgn = UserClass::n_total_op_assign_;
#ifndef _RWSTD_NO_EXCEPTIONS
// detect objects constructed but not destroyed after an exception
const std::size_t count = UserClass::count_;
# ifndef _RWSTD_NO_REPLACEABLE_NEW_DELETE
// disable out of memory exceptions before copying iterators
// (InputIter ctors may dynamically allocate memory)
*pst->throw_at_calls_ [0] = std::size_t (-1);
# endif // _RWSTD_NO_REPLACEABLE_NEW_DELETE
#endif // _RWSTD_NO_EXCEPTIONS
// create "deep" copies of the iterators to thwart
// InpuIter's multi-pass detection
const Iterator beg = copy_iter (first, (UserClass*)0);
const Iterator end = copy_iter (last, (UserClass*)0);
#ifndef _RWSTD_NO_EXCEPTIONS
# ifndef _RWSTD_NO_REPLACEABLE_NEW_DELETE
*pst->throw_at_calls_ [0] = pst->new_calls_ [0] + throw_after + 1;
# endif // _RWSTD_NO_REPLACEABLE_NEW_DELETE
#endif // _RWSTD_NO_EXCEPTIONS
_TRY {
if (-2 == n) {
vec.insert (it, *x);
}
else if (-1 == n) {
#ifndef _RWSTD_NO_EXT_VECTOR_INSERT_IN_PLACE
# ifndef _RWSTD_NO_REPLACEABLE_NEW_DELETE
// disable exceptions if Iterator is not at least
// a ForwardIterator since the extension doesn't
// provide the strong exception safety guarantee
// required in 23.2.4.3, p1
if (!is_forward (beg)) {
*pst->throw_at_calls_ [0] = std::size_t (-1);
}
# endif //_RWSTD_NO_REPLACEABLE_NEW_DELETE
#endif // _RWSTD_NO_EXT_VECTOR_INSERT_IN_PLACE
vec.insert (it, beg, end);
}
else {
vec.insert (it, n, *x);
}
break;
}
_CATCH (...) {
#ifndef _RWSTD_NO_EXCEPTIONS
// verify that an exception thrown during allocation
// doesn't cause a change in the state of the vector
rw_assert (vec.size () == size, 0, line,
"line %d: %s: size unexpectedly changed "
"from %zu to %zu after an exception",
__LINE__, fcall, size, vec.size ());
rw_assert (vec.capacity () == capacity, 0, line,
"line %d: %s: capacity unexpectedly "
"changed from %zu to %zu after an exception",
__LINE__, fcall, capacity, vec.capacity ());
rw_assert (vec.begin () == begin, 0, line,
"line %d: %s: begin() unexpectedly "
"changed from after an exception by %d",
__LINE__, fcall, vec.begin () - begin);
rw_assert (count == UserClass::count_, 0, line,
"line %d: %s: leaked %d objects "
"after an exception",
__LINE__, fcall, UserClass::count_ - count);
// increment to allow this call to operator new to succeed
// and force the next one to fail, and try to insert again
++throw_after;
#endif // _RWSTD_NO_EXCEPTIONS
} // catch
} // for
#ifndef _RWSTD_NO_EXCEPTIONS
# ifndef _RWSTD_NO_REPLACEABLE_NEW_DELETE
// verify that if exceptions are enabled and when capacity changes
// at least one exception is thrown
rw_assert ( *pst->throw_at_calls_ [0] == std::size_t (-1)
|| !capchg
|| throw_after,
0, line,
"line %d: %s: failed to throw an expected exception",
__LINE__, fcall);
// commented out: just because capacity doesn't change doesn't mean
// that no exception is thrown (e.g., if the function dynamically
// allocates temporary storage)
//
// rw_assert (capchg || !throw_after,
// 0, line,
// "line %d: %s: unexpectedly threw an exception",
// __LINE__, fcall);
# endif // _RWSTD_NO_REPLACEABLE_NEW_DELETE
#else // if defined (_RWSTD_NO_EXCEPTIONS)
_RWSTD_UNUSED (t);
_RWSTD_UNUSED (line);
_RWSTD_UNUSED (fcall);
_RWSTD_UNUSED (capchg);
_RWSTD_UNUSED (size);
_RWSTD_UNUSED (capacity);
_RWSTD_UNUSED (throw_after);
#endif // _RWSTD_NO_EXCEPTIONS
#ifndef _RWSTD_NO_REPLACEABLE_NEW_DELETE
*pst->throw_at_calls_ [0] = std::size_t (-1);
#endif // _RWSTD_NO_REPLACEABLE_NEW_DELETE
// compute the number of calls to UserClass copy ctor
// and assignment operator
*n_copy = UserClass::n_total_copy_ctor_ - *n_copy;
*n_asgn = UserClass::n_total_op_assign_ - *n_asgn;
}
/**************************************************************************/
template <class Iterator>
void test_insert (int line, // line number of call site
const Iterator &dummy, // unused dummy iterator
int n, // number of elements to insert
// or the special values -1 and -2
const char *seq, // initial container contents
std::size_t seqlen, // initial container size
std::size_t seqcap, // initial container capacity
int off, // offset at which to insert
const char *ins, // inserted sequence
std::size_t inslen, // length of inserted sequence
const char *res, // resulting sequence
std::size_t reslen /* length of resulting sequence */)
{
// create arrays of `seqlen' and `inslen' elements of type UserClass
// initialized from the sequences `seq' and `ins', respectively
const UserClass* const xseq = UserClass::from_char (seq, seqlen);
UserClass* const xins = UserClass::from_char (ins, inslen);
// construct a std::vector from the sequence of elements
Vector vec = seqlen ? Vector (xseq, xseq + seqlen) : Vector ();
// set the capacity of the container (if specified)
if (std::size_t (-1) == seqcap)
seqcap = vec.capacity ();
else
vec.reserve (seqcap);
// create an iterator pointing `off' past the beginning of the vector
const Vector::iterator it = vec.begin () + off;
char* fcall = 0;
std::size_t len = 0;
// format a string describing the function call being tested
// (used in diagnostic messages, if any, below)
rw_asnprintf (&fcall, &len, "vector(\"%{X=*.*}\").insert("
"%{?}begin()%{:}%{?}end()%{:}begin() + %zu%{;}%{;}, "
"%{?}%d%{:}%{?}\"%{X=*.*}\"%{:}%d, %d%{;}%{;})",
int (seqlen), -1, xseq,
0 == off, int (seqlen) == off, off,
n == -2, *ins, n == -1,
int (inslen), -1, xins, n, *ins);
// 23.2.4.3, p1
// Notes: Causes reallocation if the new size is greater than
// the old capacity. If no reallocation happens, all the iterators
// and references before the insertion point remain valid.
// If an exception is thrown other than by the copy constructor
// an assignment operator of T there are no effects.
// determine whether the insertion must or must not change capacity
const bool capchg = seqlen + (n < 0 ? inslen : n) > seqcap;
std::size_t n_copy = UserClass::n_total_copy_ctor_;
std::size_t n_asgn = UserClass::n_total_op_assign_;
if (-2 == n) {
exception_loop (line, fcall, capchg,
vec, it, n, xins, dummy, dummy,
&n_copy, &n_asgn);
}
else if (-1 == n) {
const Iterator first =
make_iter (xins, xins, xins + inslen, dummy);
const Iterator last =
make_iter (xins + inslen, xins, xins + inslen, dummy);
exception_loop (line, fcall, capchg,
vec, it, n, 0, first, last,
&n_copy, &n_asgn);
}
else /* if (n != -2 && n != -1) */ {
// n must be in the range [-2, INT_MAX]
_RWSTD_ASSERT (n >= 0);
exception_loop (line, fcall, capchg,
vec, it, n, xins, dummy, dummy,
&n_copy, &n_asgn);
}
// verify the expected size of the vector after insertion
rw_assert (vec.size () == reslen, 0, line,
"line %d: %s: size == %zu, got %zu",
__LINE__, fcall, reslen, vec.size ());
// verify the expected change in capacity of the vactor
rw_assert (capchg == (vec.capacity () != seqcap),
0, line, "line %d: %s: capacity %c = %zu, got %zu",
__LINE__, fcall, capchg ? '!' : '=', seqcap, vec.capacity ());
// verify the expected contents of the vector after insertion
const Vector::const_pointer resbeg = vec.size () ? &*vec.begin () : 0;
const Vector::const_pointer resend = resbeg + vec.size ();
for (Vector::const_pointer ptr = resbeg; ptr != resend; ++ptr) {
typedef unsigned char UChar;
if (ptr->data_.val_ != UChar (res [ptr - resbeg])) {
char* const got = new char [vec.size () + 1];
for (Vector::const_pointer p = resbeg; p != resend; ++p) {
got [p - resbeg] = char (p->data_.val_);
}
got [vec.size ()] = '\0';
rw_assert (0, 0, line,
"line %d: %s: expected %{#s}, got %{#s}",
__LINE__, fcall, res, got);
delete [] got;
break;
}
}
// 23.2.4.3, p2
// Complexity:
// -- If first and last are forward iterators, bidirectional iterators,
// or random access iterators, the complexity is linear in the number
// of elements in the range [first, last) plus the distance to
// the end of the vector.
// -- If they are input iterators, the complexity is proportional
// to the number of elements in the range [first, last) times
// the distance to the end of the vector.
// verify the complexity of the operation in terms of the number
// of calls to the copy ctor and assignment operator on value_type
// note that the complexity requirement imposes an upper bound on
// the number of operations and implementations are allowed to do
// better (see 17.3.1.3, p5)
std::size_t expect_copy; // expected number of copy ctor calls
std::size_t expect_asgn; // expected number of assignments
if (is_forward (dummy)) {
// ForwardIterator or better
if (capchg) {
// when the insertion causes a change in capacity
// (i.e., reallocation), the number of copy ctor
// invocations is equal to the size of the resulting
// sequence; no assignment operators are invoked
expect_copy = reslen;
expect_asgn = 0;
}
else {
// when no change in capacity occurs the number of copy
// ctor invocations is equal to the number of elements
// between the end of the inserted range and the end of
// the original sequence
// the number of assignments is equal to the distance
// from the point of insertion to the end of the original
// sequence
expect_copy = n < 0 ? inslen : n;
expect_asgn = n && inslen ? reslen - off : 0;
}
}
else {
// InputIterator
expect_copy = n_copy;
expect_asgn = n_asgn;
// don't bother testing the complexity of the functions with
// InputIterators, the standard's messed up (see issue 247
// and the indirectly related issue 406)
}
rw_assert (expect_copy >= n_copy,
0, line,
"line %d: %s: expected at most %zu "
"invocation(s) of UserClass::UserClass(const UserClass&), "
"got %zu", __LINE__, fcall, expect_copy, n_copy);
rw_assert (expect_asgn >= n_asgn,
0, line,
"line %d: %s: expected at most %zu invocation(s) "
"of UserClass::operator=(const UserClass&), got %zu",
__LINE__, fcall, expect_asgn, n_asgn);
delete [] xins;
delete [] _RWSTD_CONST_CAST (UserClass*, xseq);
}
/**************************************************************************/
void test_insert ()
{
//////////////////////////////////////////////////////////////////
// exercise vector::insert(iterator, const_reference)
rw_info (0, 0, 0,
"std::vector<UserClass>::insert(iterator, const_reference)");
#undef TEST
#define TEST(seq, seqcap, off, ins, res) do { \
const char insseq [] = { ins, '\0' }; \
test_insert (__LINE__, (UserClass*)0, -2, \
seq, sizeof seq - 1, \
std::size_t (seqcap), off, \
insseq, 1, \
res, sizeof res - 1); \
} while (0)
// +----------------------- initial container contents
// | +--------------- initial container capacity
// | | +----------- offset at which to insert
// | | | +------ element to insert
// | | | | +-- resulting sequence
// | | | | |
// V V V V V
TEST ("", -1, +0, 'a', "a");
TEST ("b", -1, +0, 'a', "ab");
TEST ("bc", -1, +0, 'a', "abc");
TEST ("bcd", -1, +0, 'a', "abcd");
TEST ("bcde", -1, +0, 'a', "abcde");
TEST ("a", -1, +1, 'b', "ab");
TEST ("ac", -1, +1, 'b', "abc");
TEST ("acd", -1, +1, 'b', "abcd");
TEST ("acde", -1, +1, 'b', "abcde");
TEST ("ab", -1, +2, 'c', "abc");
TEST ("abd", -1, +2, 'c', "abcd");
TEST ("abde", -1, +2, 'c', "abcde");
TEST ("abc", -1, +3, 'd', "abcd");
TEST ("abce", -1, +3, 'd', "abcde");
TEST ("abcd", -1, +4, 'e', "abcde");
//////////////////////////////////////////////////////////////////
// exercise vector::insert(iterator, size_type, const_reference)
rw_info (0, 0, 0,
"std::vector<UserClass>::insert(iterator, "
"size_type, const_reference)");
#undef TEST
#define TEST(seq, seqcap, off, n, ins, res) do { \
const char insseq [] = { ins, '\0' }; \
test_insert (__LINE__, (UserClass*)0, n, \
seq, sizeof seq - 1, \
std::size_t (seqcap), off, \
insseq, 1, \
res, sizeof res - 1); \
} while (0)
// +-------------------------- initial container contents
// | +------------------ initial container capacity
// | | +-------------- offset at which to insert
// | | | +---------- number of elements to insert
// | | | | +------ element value to insert
// | | | | | +-- resulting sequence
// | | | | | |
// V V V V V V
TEST ("", -1, +0, 0, 'a', "");
TEST ("", -1, +0, 1, 'a', "a");
TEST ("", -1, +0, 2, 'b', "bb");
TEST ("", -1, +0, 3, 'c', "ccc");
TEST ("a", -1, +0, 0, 'a', "a");
TEST ("b", -1, +0, 1, 'a', "ab");
TEST ("b", -1, +0, 2, 'a', "aab");
TEST ("b", -1, +0, 3, 'a', "aaab");
TEST ("ab", -1, +1, 0, 'b', "ab");
TEST ("ac", -1, +1, 1, 'b', "abc");
TEST ("ac", -1, +1, 2, 'b', "abbc");
TEST ("ac", -1, +1, 3, 'b', "abbbc");
TEST ("abcd", -1, +2, 0, 'c', "abcd");
TEST ("abde", -1, +2, 1, 'c', "abcde");
TEST ("abde", -1, +2, 2, 'c', "abccde");
TEST ("abde", -1, +2, 3, 'c', "abcccde");
}
/**************************************************************************/
template <class Iterator>
void test_insert_range (const Iterator &dummy)
{
static const char* const itname = type_name (dummy, (UserClass*)0);
rw_info (0, 0, 0,
"std::vector<UserClass>::insert(iterator, %s, %s)",
itname, itname);
#undef TEST
#define TEST(seq, seqcap, off, ins, res) \
test_insert (__LINE__, dummy, -1, \
seq, sizeof seq - 1, \
std::size_t (seqcap), off, \
ins, sizeof ins - 1, \
res, sizeof res - 1)
// +-------------------------------------------- seq(uence)
// | +------------------------------------- seqcap(acity)
// | | +--------------------------------- off(set of insertion)
// | | | +----------------------------- ins(erted sequence)
// | | | | +---------------------- res(ulting sequence)
// | | | | |
// v v v v v
TEST ("", -1, +0, "", "");
TEST ("", -1, +0, "a", "a");
TEST ("", -1, +0, "ab", "ab");
TEST ("", -1, +0, "abc", "abc");
TEST ("A", -1, +0, "", "A");
TEST ("B", -1, +0, "a", "aB");
TEST ("C", -1, +0, "ab", "abC");
TEST ("D", -1, +0, "abc", "abcD");
TEST ("AB", -1, +0, "", "AB");
TEST ("AB", -1, +0, "c", "cAB");
TEST ("AB", -1, +0, "cd", "cdAB");
TEST ("AB", -1, +0, "cde", "cdeAB");
TEST ("A", -1, +1, "", "A");
TEST ("A", -1, +1, "b", "Ab");
TEST ("A", -1, +1, "bc", "Abc");
TEST ("A", -1, +1, "bcd", "Abcd");
TEST ("AB", -1, +1, "", "AB");
TEST ("AC", -1, +1, "b", "AbC");
TEST ("AD", -1, +1, "bc", "AbcD");
TEST ("AE", -1, +1, "bcd", "AbcdE");
TEST ("AB", -1, +2, "", "AB");
TEST ("AB", -1, +2, "c", "ABc");
TEST ("AB", -1, +2, "cd", "ABcd");
TEST ("AB", -1, +2, "cde", "ABcde");
TEST ("ABC", -1, +2, "", "ABC");
TEST ("ABD", -1, +2, "c", "ABcD");
TEST ("ABE", -1, +2, "cd", "ABcdE");
TEST ("ABF", -1, +2, "cde", "ABcdeF");
TEST ("ABC", -1, +3, "", "ABC");
TEST ("ABC", -1, +3, "d", "ABCd");
TEST ("ABC", -1, +3, "de", "ABCde");
TEST ("ABC", -1, +3, "def", "ABCdef");
#define UPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define LOWER "abcdefghijklmnopqrstuvwxyz"
TEST ("", -1, +0, LOWER, LOWER);
TEST ("A", -1, +0, LOWER, LOWER "A");
TEST ("A", -1, +1, LOWER, "A" LOWER);
TEST ("AB", -1, +0, LOWER, LOWER "AB");
TEST ("AB", -1, +1, LOWER, "A" LOWER "B");
TEST ("AB", -1, +2, LOWER, "AB" LOWER);
TEST ("ABC", -1, +0, LOWER, LOWER "ABC");
TEST ("ABC", -1, +1, LOWER, "A" LOWER "BC");
TEST ("ABC", -1, +2, LOWER, "AB" LOWER "C");
TEST ("ABC", -1, +3, LOWER, "ABC" LOWER);
TEST (UPPER, -1, +0, "!", "!ABCDEFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +1, "!", "A!BCDEFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +2, "!", "AB!CDEFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +3, "!", "ABC!DEFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +9, "!", "ABCDEFGHI!JKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +25, "!", "ABCDEFGHIJKLMNOPQRSTUVWXY!Z");
TEST (UPPER, -1, +26, "!", "ABCDEFGHIJKLMNOPQRSTUVWXYZ!");
TEST (UPPER, -1, +0, "12", "12ABCDEFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +1, "12", "A12BCDEFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +2, "12", "AB12CDEFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +3, "12", "ABC12DEFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +9, "12", "ABCDEFGHI12JKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +25, "12", "ABCDEFGHIJKLMNOPQRSTUVWXY12Z");
TEST (UPPER, -1, +26, "12", "ABCDEFGHIJKLMNOPQRSTUVWXYZ12");
TEST (UPPER, -1, +0, "123", "123ABCDEFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +1, "123", "A123BCDEFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +2, "123", "AB123CDEFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +3, "123", "ABC123DEFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +9, "123", "ABCDEFGHI123JKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +25, "123", "ABCDEFGHIJKLMNOPQRSTUVWXY123Z");
TEST (UPPER, -1, +26, "123", "ABCDEFGHIJKLMNOPQRSTUVWXYZ123");
TEST (UPPER, -1, +0, LOWER, "" LOWER "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +1, LOWER, "A" LOWER "BCDEFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +2, LOWER, "AB" LOWER "CDEFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +3, LOWER, "ABC" LOWER "DEFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +4, LOWER, "ABCD" LOWER "EFGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +5, LOWER, "ABCDE" LOWER "FGHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +6, LOWER, "ABCDEF" LOWER "GHIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +7, LOWER, "ABCDEFG" LOWER "HIJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +8, LOWER, "ABCDEFGH" LOWER "IJKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +9, LOWER, "ABCDEFGHI" LOWER "JKLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +10, LOWER, "ABCDEFGHIJ" LOWER "KLMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +11, LOWER, "ABCDEFGHIJK" LOWER "LMNOPQRSTUVWXYZ");
TEST (UPPER, -1, +12, LOWER, "ABCDEFGHIJKL" LOWER "MNOPQRSTUVWXYZ");
TEST (UPPER, -1, +13, LOWER, "ABCDEFGHIJKLM" LOWER "NOPQRSTUVWXYZ");
TEST (UPPER, -1, +14, LOWER, "ABCDEFGHIJKLMN" LOWER "OPQRSTUVWXYZ");
TEST (UPPER, -1, +15, LOWER, "ABCDEFGHIJKLMNO" LOWER "PQRSTUVWXYZ");
TEST (UPPER, -1, +16, LOWER, "ABCDEFGHIJKLMNOP" LOWER "QRSTUVWXYZ");
TEST (UPPER, -1, +17, LOWER, "ABCDEFGHIJKLMNOPQ" LOWER "RSTUVWXYZ");
TEST (UPPER, -1, +18, LOWER, "ABCDEFGHIJKLMNOPQR" LOWER "STUVWXYZ");
TEST (UPPER, -1, +19, LOWER, "ABCDEFGHIJKLMNOPQRS" LOWER "TUVWXYZ");
TEST (UPPER, -1, +20, LOWER, "ABCDEFGHIJKLMNOPQRST" LOWER "UVWXYZ");
TEST (UPPER, -1, +21, LOWER, "ABCDEFGHIJKLMNOPQRSTU" LOWER "VWXYZ");
TEST (UPPER, -1, +22, LOWER, "ABCDEFGHIJKLMNOPQRSTUV" LOWER "WXYZ");
TEST (UPPER, -1, +23, LOWER, "ABCDEFGHIJKLMNOPQRSTUVW" LOWER "XYZ");
TEST (UPPER, -1, +24, LOWER, "ABCDEFGHIJKLMNOPQRSTUVWX" LOWER "YZ");
TEST (UPPER, -1, +25, LOWER, "ABCDEFGHIJKLMNOPQRSTUVWXY" LOWER "Z");
TEST (UPPER, -1, +26, LOWER, "ABCDEFGHIJKLMNOPQRSTUVWXYZ" LOWER "");
}
/**************************************************************************/
void test_insert_at_end ()
{
//////////////////////////////////////////////////////////////////
// exercise vector::insert() at the end of the container and
// verify that the functions perform in amortized constant time
// (see also PR #30615)
rw_info (0, 0, 0,
"std::vector<UserClass>::insert (end(), const_reference)");
typedef Vector::size_type size_type;
Vector v;
size_type nextcap = 0;
// iterate to grow vector excactly 8 times
for (int i = 0; i != 8; ++i) {
// count the number of copy ctor and assignment operator invocations
std::size_t n_copy;
std::size_t n_asgn;
// compute the next (non-zero) capacity of the container
nextcap = _RW::__rw_new_capacity (nextcap + 1, (Vector*)0);
// insert elements at the end of the container until its size
// reaches its capacity, verifying that each of the insertions
// performed in (amortized) constant time
while (v.size () < nextcap) {
n_copy = UserClass::n_total_copy_ctor_;
n_asgn = UserClass::n_total_op_assign_;
v.insert (v.end (), Vector::value_type ());
rw_assert (nextcap >= v.capacity (), 0, __LINE__,
"vector<UserClass>::insert (end(), value_type()); "
"capacity == %zu, got %zu after %zu insertions",
nextcap, v.capacity (), v.size ());
if (nextcap < v.capacity ()) break;
// compute the number of copy ctor and assignment operator calls
n_copy = UserClass::n_total_copy_ctor_ - n_copy;
n_asgn = UserClass::n_total_op_assign_ - n_asgn;
// verify that the copy ctor was invoked exactly once
rw_assert (1U == n_copy, 0, __LINE__,
"vector<UserClass>::insert (end(), value_type()); "
"expected 1 invocation of the copy ctor, got %zu",
n_copy);
// verify that the assignment operator was not invoked
rw_assert (n_asgn == 0, 0, __LINE__,
"vector<UserClass>::insert (end(), value_type()); "
"expected 0 invocations of the assignment "
"operator, got %zu", n_asgn);
}
// inserting the next element must reallocate
v.insert (v.end (), Vector::value_type ());
rw_assert (v.capacity () > nextcap, 0, __LINE__,
"vector<UserClass>::insert (end(), value_type()); "
"capacity > %zu, got %zu after %zu insertions",
nextcap, v.capacity (), v.size ());
}
}
/**************************************************************************/
// exercise vector<>::insert() and vector::erase()
// focus on the complexity of the function
void test_complexity ()
{
rw_info (0, 0, 0, "std::vector<UserClass>::insert(iterator, "
"const_reference)");
rw_info (0, 0, 0, "std::ector<UserClass>::insert(iterator, size_type, "
"const_reference)");
rw_info (0, 0, 0, "template <class InputIterator> "
"std::vector<UserClass>::insert"
"(iterator, InputIterator, InputIterator)");
rw_info (0, 0, 0, "std::vector<UserClass>::erase(iterator)");
rw_info (0, 0, 0, "std::vector<UserClass>::erase(iterator, iterator)");
typedef std::vector<UserClass, std::allocator<UserClass> > Vector;
typedef Vector::iterator VectorIter;
typedef Vector::size_type VectorSize;
bool success = true;
Vector v0;
Vector v1;
Vector v2;
VectorIter it = v0.begin ();
VectorIter it1 = v1.begin ();
VectorIter it2 = v2.begin ();
VectorSize i;
for (i = 0; i < rw_opt_nloops; i++) {
// initialize the current size, capacity and begin iterator variables
VectorSize v0_size = v0.size ();
VectorSize v0_cap = v0.capacity ();
VectorIter v0_beg = v0.begin ();
UserClass val;
// reset the UserClass totals
UserClass::reset_totals ();
// inseert val into the vector
it = v0.insert (it, val);
// 23.2.4.3, p1: causes reallocation if the new size
// is greater than the old capacity
rw_assert (v0_cap <= v0.size () || v0_beg == v0.begin (),
0, __LINE__,
"vector<UserClass>::insert(iterator, const_reference) "
"invalidated iterators w/o reallocation");
// make sure that the vector is now one element larger
rw_assert (v0.size () == v0_size + 1,
0, __LINE__,
"vector<UserClass>::insert(iterator, const_reference); "
"new size = %zu, expected %zu", v0.size (), v0_size + 1);
// make sure that the returned iterator points to the new value
rw_assert (*it == val,
0, __LINE__,
"vector<UserClass>::insert(iterator, const_reference); "
"returned iterator doesn't point at inserted value");
// 23.2.4.3, p2: the complexity is linear in the number of elements
// in the range [first, last) plus the distance to the
// end of the vector.
if(v0.begin () != v0_beg) {
rw_assert ((VectorSize)UserClass::n_total_copy_ctor_ == v0.size (),
0, __LINE__,
"vector<UserClass>::insert() - fails complexity "
"copy_ctor called %zu; size = %zu",
UserClass::n_total_copy_ctor_, v0.size ());
}
else {
rw_assert ( (UserClass::n_total_copy_ctor_
+ UserClass::n_total_op_assign_)
== std::size_t (v0.end() - it),
0, __LINE__,
"vector<UserClass>::insert(iterator, const_reference) - "
"fails complexity copy_ctor and assign called "
"%zu correct = %zu", UserClass::n_total_copy_ctor_ +
UserClass::n_total_op_assign_, (v0.end() - it));
}
// every 5 loops erase 'it'
if (i % 5) {
it1 = it;
Vector::value_type next_val;
// if we are not at the end of the vector then increment it1 and
// if we are still not at the end then set next_val = *it1
// because when we erase it, that will be the value it should
// point to
if (it != v0.end () && ++it1 != v0.end())
next_val = *it1;
VectorSize num_left = v0.end () - it - 1;
VectorSize X_count = UserClass::count_;
v0_size = v0.size ();
// reset the totals for the complexity test
UserClass::reset_totals ();
it = v0.erase (it);
// make sure only one element was erased
rw_assert (v0.size () != v0_size - 1, 0, __LINE__,
"vector<UserClass>::erase(iterator); new size = %zu, "
"expected %zu", v0.size (), v0_size - 1);
// if we were not at the end of the vector then *it should be
// next_val
rw_assert (it == v0.end () || *it == next_val, 0, __LINE__,
"vector<UserClass>::erase(iterator); "
"returned iterator doesn't point at next value ");
// 23.2.4.2, p4: The assignment operator of UserClass should be
// called the number of times equal to the number of
// elements in the vector after the erased elements.
rw_assert ((VectorSize)UserClass::n_total_op_assign_ != num_left,
0, __LINE__,
"vector<UserClass>::erase(iterator) - fails "
"complexity assign called %zu correct = %zu",
UserClass::n_total_op_assign_, num_left);
// 23.2.4.2, p4: The destructor of UserClass should be called
// the number of times equal to the number of
// elements erased
rw_assert ((VectorSize)X_count - UserClass::count_ == 1,
0, __LINE__,
"vector<UserClass>::erase(iterator) - "
"fails complexity destructor called %zu "
"correct = %zu", X_count - UserClass::count_ , 1);
}
// Don't always insert at the beginning
if (i % 2 && it != v0.end ())
it++;
}
// now lets test nultiple insert and erase functions
for (i = 0; i < rw_opt_nloops; i++) {
VectorSize v1_size = v1.size ();
VectorSize v1_cap = v1.capacity ();
VectorIter v1_beg = v1.begin ();
UserClass val;
UserClass::reset_totals ();
// insert `i' copies of `val' in the middle
VectorSize offset = (v1.size () ? (i / 2) % v1.size () : 0);
it1 = v1.begin () + offset;
v1.insert (it1, i, val);
// since insert doesn't return the next position after the
//inserted elements we will calculate this ourself
it1 = v1.begin () + offset + i;
// 23.2.4.3, p1: causes reallocation if the new size
// is greater than the old capacity
rw_assert (v1_cap <= v1.size () || v1_beg == v1.begin (),
0, __LINE__,
"vector<UserClass>::insert(iterator, const_reference) "
"invalidated iterators w/o reallocation");
// make sure that the vector increased in size by the correct number
rw_assert (v1.size () == v1_size + i,
0, __LINE__,
"vector<UserClass>::insert(iterator, const_reference); "
"new size = %zu, expected %zu", v1.size (), v1_size + i);
// 23.2.4.3, p2: the complexity is linear in the number of elements
// in the range [first, last) plus the distance to the
// end of the vector.
if (v1.begin () != v1_beg) {
rw_assert ((VectorSize)UserClass::n_total_copy_ctor_ == v1.size (),
0, __LINE__,
"vector<UserClass>::insert(iterator, const_reference) - "
"fails complexity copy_ctor called %zu size =%zu",
UserClass::n_total_copy_ctor_, v1.size());
}
else {
rw_assert ( i + (v1.end() - it1)
== (VectorSize)(UserClass::n_total_copy_ctor_ +
UserClass::n_total_op_assign_),
0, __LINE__,
"vector<UserClass>::insert(iterator, const_reference) - "
"fails complexity copy_ctor and assign "
"called %zu correct = %zu",
UserClass::n_total_copy_ctor_ +
UserClass::n_total_op_assign_,
(v1.end() - it1));
}
VectorSize old_size = v1.size();
UserClass new_val;
Vector::value_type expected_val =
v1.size () ? *(v1.begin () + (v1.size () / 2)) : new_val;
UserClass::reset_totals ();
// set up some variable that will keep track of how many we are going
// to erase, how many are left after the last element we are erasing
// and what the current number of Xs are in existance.
VectorSize num_destroy = v1.size () / 2;
VectorSize num_left =
v1.end () - (v1.begin () + (v1.size () / 2));
VectorSize X_count = UserClass::count_;
it1 = v1.erase(v1.begin (), v1.begin () + (v1.size () / 2));
// make sure the correct number of elements were erased
rw_assert (v1.size () == old_size - (old_size / 2),
0, __LINE__,
"vector<UserClass>::erase(iterator, iterator); "
"new size = %zu, expected %zu", v1.size (),
old_size - (old_size / 2));
// if there is at least one element left then make sure that it1 now
// points to the expected next element in the vector.
rw_assert (v1.size () == 0 || *it1 == expected_val,
0, __LINE__,
"vector<UserClass>::erase(iterator, iterator); "
"returned iterator doesn't point at next value ");
// 23.2.4.2, p4: The assignment operator of UserClass should be called
// the number of times equal to the number of elements
// in the vector after the erased elements.
rw_assert ((VectorSize)UserClass::n_total_op_assign_ == num_left,
0, __LINE__,
"vector<UserClass>::erase(iterator, iterator) - fails "
"complexity assign called %zu correct = %zu",
UserClass::n_total_op_assign_, num_left);
// 23.2.4.2, p4: The destructor of UserClass should be called the number
// of times equal to the number of elements erased
rw_assert (X_count - UserClass::count_ == num_destroy,
0, __LINE__,
"vector<UserClass>::erase(iterator, iterator) - fails "
"complexity destructor called %zu correct = %zu",
X_count - UserClass::count_ , num_destroy);
}
#if !defined (_MSC_VER) || _MSC_VER >= 1300
v0.clear ();
for (i = 0; i < rw_opt_nloops; i++) {
VectorSize v2_size = v2.size ();
VectorSize v2_cap = v2.capacity ();
VectorIter v2_beg = v2.begin ();
UserClass val;
v0.insert (v0.begin(), val);
// 23.2.4.3, p1: causes reallocation if the new size
// is greater than the old capacity
rw_assert (v2_cap <= v2.size () || v2_beg == v2.begin (),
0, __LINE__,
"vector<UserClass>::insert(iterator, const_reference) "
"invalidated iterators w/o reallocation");
UserClass::reset_totals ();
v2.insert(v2.begin(), v0.begin(), v0.end());
if (v2.begin () != v2_beg)
rw_assert ((VectorSize)UserClass::n_total_copy_ctor_ == v2.size (),
0, __LINE__,
"vector<UserClass>::insert(iterator, const_reference) - "
"fails complexity copy_ctor called %zu size =%zu",
UserClass::n_total_copy_ctor_, v2.size());
else {
rw_assert ( (VectorSize)(UserClass::n_total_copy_ctor_
+ UserClass::n_total_op_assign_)
== v0.size () + (v2.end() - (v2.begin() + v0.size())),
0, __LINE__,
"vector<UserClass>::insert(iterator, const_reference) - "
"fails complexity copy_ctor and assign called "
"%zu correct = %zu",
UserClass::n_total_copy_ctor_ +
UserClass::n_total_op_assign_,
v0.size() + (v2.end() - (v2.begin() + v0.size())));
}
rw_assert (v2.size () == v2_size + v0.size (),
0, __LINE__,
"vector<UserClass>::insert(iterator, const_reference); "
"new size = %zu, expected %zu", v2.size (),
v2_size + v0.size ());
VectorSize old_size = v2.size();
VectorIter expected_it = v2.begin () + (v2.size () / 2) ;
Vector::value_type expected_val = *expected_it;
UserClass::reset_totals ();
VectorSize num_destroy = v2.size () / 2;
VectorSize num_left =
v2.end () - (v2.begin () + (v2.size () / 2));
VectorSize X_count = UserClass::count_;
it2 = v2.erase(v2.begin (), v2.begin () + (v2.size () / 2));
rw_assert (v2.size () == v2_size + v0.size() - (old_size / 2),
0, __LINE__,
"vector<UserClass>::erase(iterator, iterator); "
"new size = %zu, expected %zu",
v2.size (), v2_size + i - (old_size / 2));
rw_assert (v2.size () == 0 || *it2 == expected_val,
0, __LINE__,
"vector<UserClass>::erase(iterator, iterator); "
"returned iterator doesn't point at next value ");
rw_assert ((VectorSize)UserClass::n_total_op_assign_ == num_left,
0, __LINE__,
"vector<UserClass>::erase(iterator, iterator) - "
"fails complexity assign called %zu correct = %zu",
UserClass::n_total_op_assign_, num_left);
rw_assert (X_count - UserClass::count_ == num_destroy,
0, __LINE__,
"vector<UserClass>::erase(iterator, iterator) - "
"fails complexity destructor called %zu correct = %zu",
X_count - UserClass::count_ , num_destroy);
}
#endif // !defined (_MSC_VER) || _MSC_VER >= 1300
rw_assert (success, 0, __LINE__, "vector<UserClass>::insert()");
rw_assert (success, 0, __LINE__, "vector<UserClass>::erase()");
}
/**************************************************************************/
template <class T, class Allocator>
void test_push_back (const std::vector<T, Allocator>*)
{
rw_info (0, 0, 0, "std::vector<UserClass>::push_back(const_reference)");
typedef std::vector<T, Allocator> MyVector;
typedef typename MyVector::value_type ValueType;
typedef typename MyVector::size_type SizeType;
typedef typename MyVector::pointer Pointer;
typedef typename MyVector::const_pointer ConstPointer;
typedef typename MyVector::iterator Iterator;
MyVector v1;
MyVector v2;
const ValueType val = ValueType ();
for (SizeType i = 0; i != SizeType (4096); ++i) {
// perform the two operations from Table 68
v1.push_back (val);
v2.insert (v2.end (), val);
// verify that effects on both sequences
// are identical as required by Table 68
rw_assert (v1.size () == v2.size (),
0, __LINE__,
"Expected std::vector::size to "
"compare equal; got %zu and %zu",
v1.size (), v2.size ());
rw_assert (v1.capacity () == v2.capacity (),
0, __LINE__,
"Expected std::vector::capacity to "
"compare equal; got %zu and %zu",
v1.capacity (), v2.capacity ());
rw_assert (v1.end () - v1.begin () == v2.end () - v2.begin (),
0, __LINE__,
"Expected std::vector::end() - std::vector::begin() "
"to compare equal; got %zu and %zu",
v1.end () - v1.begin (), v2.end () - v2.begin ());
}
}
/**************************************************************************/
static int
run_test (int /* argc */, char** /* argv */)
{
if (rw_opt_no_complexity) {
rw_note (0, 0, __LINE__, "complexity test disabled");
}
else {
test_complexity ();
}
if (rw_opt_no_push_back) {
rw_note (0, 0, __LINE__, "push_back test disabled");
}
else {
test_push_back ((std::vector<UserClass, std::allocator<UserClass> >*)0);
}
if (rw_opt_no_insert) {
rw_note (0, 0, __LINE__, "insert test disabled");
}
else {
test_insert ();
}
if (rw_opt_no_insert_range) {
rw_note (0, 0, __LINE__, "insert range test disabled");
}
else {
if (rw_opt_no_input_iter) {
rw_note (0, 0, __LINE__,
"InputIterator test disabled");
}
else {
test_insert_range (InputIter<UserClass>(0, 0, 0));
}
if (rw_opt_no_forward_iter) {
rw_note (0, 0, __LINE__,
"ForwardIterator test disabled");
}
else {
test_insert_range (ConstFwdIter<UserClass>());
}
if (rw_opt_no_bidir_iter) {
rw_note (0, 0, __LINE__,
"BidirectionalIterator test disabled");
}
else {
test_insert_range (ConstBidirIter<UserClass>());
}
if (rw_opt_no_random_iter) {
rw_note (0, 0, __LINE__,
"RandomAccessIterator test disabled");
}
else {
test_insert_range (ConstRandomAccessIter<UserClass>());
}
}
if (rw_opt_no_insert_at_end) {
rw_note (0, 0, __LINE__, "insert at end test disabled");
}
else {
test_insert_at_end ();
}
return 0;
}
/**************************************************************************/
int main (int argc, char** argv)
{
return rw_test (argc, argv, __FILE__,
"lib.vector.modifiers",
0 /* no comment */,
run_test,
"|-nloops#1 "
"|-no-insert# "
"|-no-insert_range# "
"|-no-insert_at_end# "
"|-no-complexity# "
"|-no-input_iter# "
"|-no-forward_iter# "
"|-no-bidir_iter# "
"|-no-random_iter# "
"|-no-push_back#",
&rw_opt_nloops,
&rw_opt_no_insert,
&rw_opt_no_insert_range,
&rw_opt_no_insert_at_end,
&rw_opt_no_complexity,
&rw_opt_no_input_iter,
&rw_opt_no_forward_iter,
&rw_opt_no_bidir_iter,
&rw_opt_no_random_iter,
&rw_opt_no_push_back,
0 /* sentinel*/);
}