[prev in list] [next in list] [prev in thread] [next in thread]
List: apache-stdcxx-dev
Subject: [PATCH] Introducing 23.containers.h and 23.containers.cpp
From: Farid Zaripov <faridz () kyiv ! vdiweb ! com>
Date: 2007-02-21 1:28:49
Message-ID: 45DBA051.60205 () kyiv ! vdiweb ! com
[Download RAW message or body]
ChangeLog:
* 21.strings.h: #included 23.containers.h;
struct StringIds inherited from struct ContainerIds;
removed definitions of the AllocId and IteratorId.
* 23.containers.h: New file with definitions of helpers used
in clause 23 tests.
* 23.containers.cpp: Ditto.
The patch and new files are attached.
Farid.
["23.containers.h" (text/plain)]
/************************************************************************
*
* 23.containers.h - definitions of helpers used in clause 23 tests
*
* $Id: 23.containers.h
*
***************************************************************************
*
* 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.
*
**************************************************************************/
#ifndef RW_23_CONTAINERS_H_INCLUDED
#define RW_23_CONTAINERS_H_INCLUDED
#include <testdefs.h>
#include <rw_value.h> // for UserClass, UserPOD
#include <rw_char.h> // for rw_expand ()
#include <driver.h> // for rw_assert ()
/**************************************************************************/
// defines enumerations identifying the general template arguments,
// sets of overloaded functions, member types used in the declarations
// of their signatures, and specific overloads of such member functions
struct ContainerIds {
// identifiers for the T template argument
enum ElemId { UserPOD, UserClass };
// identifiers for the Allocator template argument
enum AllocId { DefaultAlloc, UserAlloc };
// identifiers for the Iterator template argument
// used with member templates
enum IteratorId {
None,
Input, Forward, Bidir, Random,
Pointer, ConstPointer,
Iterator, ConstIterator,
ReverseIterator, ConstReverseIterator
};
enum ContainerId {
List, Vector, Deque, Queue, Stack
};
// identifies a set of overloaded member or non-member
// container functions
enum FuncId {
// 6 bits, 64 functions max
// common
/* 0 */ fid_ctor,
/* 1 */ fid_op_set,
/* 2 */ fid_assign,
/* 3 */ fid_get_allocator,
/* 4 */ fid_begin,
/* */ fid_begin_const = fid_begin,
/* 5 */ fid_end,
/* */ fid_end_const = fid_end,
/* 6 */ fid_rbegin,
/* */ fid_rbegin_const = fid_rbegin,
/* 7 */ fid_rend,
/* */ fid_rend_const = fid_rend,
/* 8 */ fid_empty,
/* 9 */ fid_size,
/* 10 */ fid_max_size,
/* 11 */ fid_resize,
/* 12 */ fid_insert,
/* 13 */ fid_erase,
/* 14 */ fid_swap,
/* 15 */ fid_clear,
/* 16 */ fid_op_equal,
/* 17 */ fid_op_less,
/* 18 */ fid_op_not_equal,
/* 19 */ fid_op_greater,
/* 20 */ fid_op_greater_equal,
/* 21 */ fid_op_less_equal,
/* 22 */ fid_push_back,
// list, deque, vector
/* 23 */ fid_front,
/* */ fid_front_const = fid_front,
/* 24 */ fid_back,
/* */ fid_back_const = fid_back,
/* 25 */ fid_pop_back,
// list, deque
/* 26 */ fid_push_front,
/* 27 */ fid_pop_front,
// list
/* 28 */ fid_splice,
/* 29 */ fid_remove,
/* 30 */ fid_remove_if,
/* 31 */ fid_unique,
/* 32 */ fid_merge,
/* 33 */ fid_sort,
/* 34 */ fid_reverse,
// vector, string, deque
/* 35 */ fid_op_index,
/* */ fid_op_index_const = fid_op_index,
/* 36 */ fid_at,
/* */ fid_at_const = fid_at,
// vector, string
/* 37 */ fid_capacity,
/* 38 */ fid_reserve,
// vector<bool>
/* 39 */ fid_flip,
/* -- */ fid_bits = 6,
/* -- */ fid_mask = 63
};
// identifies the type of a function argument, including
// the implicit this
enum ArgId {
// 4 bits, 16 types max
/* 0 */ arg_void, // void
/* 1 */ arg_size, // size_type
/* 2 */ arg_val, // value_type
/* 3 */ arg_ref, // reference
/* 4 */ arg_cref, // const_reference
/* 5 */ arg_iter, // iterator
/* 6 */ arg_citer, // const_iterator
/* 7 */ arg_range, // Iterator, Iterator
/* 8 */ arg_cont, // container& (or this for member functions)
/* 9 */ arg_ccont, // const container& (or const this for members)
/* 10 */ arg_alloc, // const allocator&
/* 11 */ arg_pred, // Predicate
/* 12 */ arg_bpred, // BinaryPredicate
/* 13 */ arg_comp, // Compare
/* -- */ arg_bits = 4,
/* -- */ arg_mask = 15
};
enum {
// bit designating a member function
bit_member = 1 << (fid_bits + 6 * arg_bits)
};
static ArgId arg_type (_RWSTD_SIZE_T id, int argno) {
return ArgId (((id >> fid_bits) >> argno * arg_bits) & arg_mask);
}
};
/**************************************************************************/
struct ContainerFunc
{
ContainerIds::ElemId elem_id_;
ContainerIds::AllocId alloc_id_;
ContainerIds::IteratorId iter_id_;
ContainerIds::ContainerId cont_id_;
_RWSTD_SIZE_T which_;
};
// describes a single test case for any overload of any container
// function (the same test case can be used to exercise more
// than one overload of the same function)
struct ContainerTestCase
{
int line; // test case line number
int off; // offset (position argument)
int size; // size (count argument)
int off2; // offset 2 (position argument)
int size2; // size 2 (count argument)
int val; // value (single character to append)
const char* str; // controlled sequence
_RWSTD_SIZE_T str_len; // length of sequence
const char* arg; // sequence to insert
_RWSTD_SIZE_T arg_len; // length of sequence
const char* res; // resulting sequence
_RWSTD_SIZE_T nres; // length of sequence or expected result value
int bthrow; // exception expected
};
// describes a set of test cases for a single overload of a function
struct ContainerTest
{
// container function overload to exercise
_RWSTD_SIZE_T which;
// test cases to exercise overload with
const ContainerTestCase *cases;
// number of test cases
_RWSTD_SIZE_T case_count;
};
typedef void ContainerTestFunc (const ContainerFunc&, const ContainerTestCase&);
_TEST_EXPORT int
rw_run_cont_test (int, char**, const char*, const char*,
ContainerIds::ContainerId, ContainerTestFunc*,
const ContainerTest*, _RWSTD_SIZE_T);
typedef void VoidFunc ();
_TEST_EXPORT int
rw_run_cont_test (int, char**, const char*, const char*,
ContainerIds::ContainerId, VoidFunc* const*,
const ContainerTest*, _RWSTD_SIZE_T);
/**************************************************************************/
template <class T>
class ContainerTestCaseData
{
private:
// not defined, not copyable, not assignable
ContainerTestCaseData (const ContainerTestCaseData&);
void operator= (const ContainerTestCaseData&);
// for convenience
typedef _RWSTD_SIZE_T SizeType;
public:
SizeType strlen_; // the length of the expanded string
SizeType arglen_; // the length of the expanded argument
SizeType reslen_; // the length of the expanded result
// the offset and extent (the number of elements) of
// the first range into the container object being modified
SizeType off1_;
SizeType ext1_;
// the offset and extent (the number of elements) of
// the argument of the function call
SizeType off2_;
SizeType ext2_;
const T* str_; // pointer to the expanded string
const T* arg_; // pointer to the expanded argument
const T* res_; // pointer to the expanded result
const ContainerFunc &func_;
const ContainerTestCase &tcase_;
// converts the narrow (and possibly) condensed strings to fully
// expanded wide character arrays that can be used to construct
// container objects
ContainerTestCaseData (const ContainerFunc &func,
const ContainerTestCase &tcase)
: func_ (func), tcase_ (tcase) {
char buf [256];
strlen_ = sizeof (buf);
char* str = rw_expand (buf, tcase.str, tcase.str_len, &strlen_);
str_ = T::from_char (str, strlen_);
if (str != buf)
delete[] str;
arglen_ = sizeof (buf);
str = rw_expand (buf, tcase.arg, tcase.arg_len, &arglen_);
arg_ = T::from_char (str, arglen_);
if (str != buf)
delete[] str;
reslen_ = sizeof (buf);
str = rw_expand (buf, tcase.res, tcase.nres, &reslen_);
res_ = T::from_char (str, reslen_);
if (str != buf)
delete[] str;
// compute the offset and extent of the container object
// representing the controlled sequence and the offset
// and extent of the argument of the function call
const SizeType argl = tcase_.arg ? arglen_ : strlen_;
off1_ = SizeType (tcase_.off) < strlen_ ?
SizeType (tcase_.off) : strlen_;
ext1_ = off1_ + tcase_.size < strlen_ ?
SizeType (tcase_.size) : strlen_ - off1_;
off2_ = SizeType (tcase_.off2) < argl ?
SizeType (tcase_.off2) : argl;
ext2_ = off2_ + tcase_.size2 < argl ?
SizeType (tcase_.size2) : argl - off2_;
}
~ContainerTestCaseData () {
// clean up dynamically allocated memory
delete[] str_;
delete[] arg_;
delete[] res_;
}
};
/**************************************************************************/
// base class-functor for the range template overloads testing
template <class Cont>
struct ContRangeBase {
typedef typename Cont::value_type ContVal;
typedef typename Cont::iterator ContIter;
typedef typename Cont::const_iterator ContConstIter;
typedef typename Cont::reverse_iterator ContRevIter;
typedef typename Cont::const_reverse_iterator ContConstRevIter;
ContRangeBase () { }
virtual ~ContRangeBase () { /* silence warnings */ }
static ContIter
begin (Cont &cont, ContIter*) {
return cont.begin ();
}
static ContConstIter
begin (const Cont &cont, ContConstIter*) {
return cont.begin ();
}
static ContRevIter
begin (Cont &cont, ContRevIter*) {
return cont.rbegin ();
}
static ContConstRevIter
begin (const Cont &cont, ContConstRevIter*) {
return cont.rbegin ();
}
virtual Cont&
operator() (Cont &cont, const ContainerTestCaseData<ContVal>&) const {
RW_ASSERT (!"logic error: should be never called");
return cont;
}
};
/**************************************************************************/
# define CONTAINER_TEST_DISPATCH(Alloc, fname, func, tcase) \
if (ContainerIds::UserPOD == func.elem_id_) \
fname (UserPOD (), (Alloc<UserPOD>*)0, func, tcase); \
else \
fname (UserClass (), (Alloc<UserClass>*)0, func, tcase)
#define DEFINE_CONTAINER_TEST_DISPATCH(fname) \
static void \
fname (const ContainerFunc &func, \
const ContainerTestCase &tcase) { \
if (ContainerIds::DefaultAlloc == func.alloc_id_) { \
CONTAINER_TEST_DISPATCH (std::allocator, fname, func, tcase); \
} \
else if (ContainerIds::UserAlloc == func.alloc_id_) { \
CONTAINER_TEST_DISPATCH (UserAlloc, fname, func, tcase); \
} \
else \
RW_ASSERT (!"logic error: bad allocator"); \
} typedef void rw_unused_typedef
#define CONTAINER_TFUNC(T, Allocator) \
void (*)(T*, Allocator<T>*, \
const ContainerTestCaseData<T>&)
#define CONTAINER_TFUNC_ADDR(fname, T, Allocator) \
(VoidFunc*)(CONTAINER_TFUNC (T, Allocator)) \
&fname<T, Allocator<T> >
#define DEFINE_CONTAINER_TEST_FUNCTIONS(fname) \
static VoidFunc* const fname ## _func_array [] = { \
CONTAINER_TFUNC_ADDR (fname, UserPOD, std::allocator), \
CONTAINER_TFUNC_ADDR (fname, UserPOD, UserAlloc), \
\
CONTAINER_TFUNC_ADDR (fname, UserClass, std::allocator), \
CONTAINER_TFUNC_ADDR (fname, UserClass, UserAlloc) \
}
#endif // RW_23_CONTAINERS_H_INCLUDED
["23.containers.cpp" (text/plain)]
/************************************************************************
*
* 23.containers.cpp - definitions of helpers used in clause 23 tests
*
* $Id: 23.containers.cpp
*
***************************************************************************
*
* 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.
*
**************************************************************************/
// expand _TEST_EXPORT macros
#define _RWSTD_TEST_SRC
#include <memory> // for allocator
#include <23.containers.h>
#include <cmdopt.h> // for rw_enabled()
#include <rw_allocator.h> // for UserAlloc
#include <rw_printf.h> // for rw_asnprintf()
#include <ctype.h> // for isdigit()
#include <stdarg.h> // for va_arg, ...
#include <stddef.h> // for size_t
#include <stdlib.h> // for free()
#include <string.h> // for strcpy()
/**************************************************************************/
static const char
_rw_this_file[] = __FILE__;
static const char* const
_rw_elem_names[] = {
"UserPOD", "UserClass"
};
static const char* const
_rw_alloc_names[] = {
"allocator", "UserAlloc"
};
static const char* const
_rw_iter_names[] = {
"",
"InputIterator", "ForwardIterator", "BidirectionalIterator",
"RandomAccessIterator",
"pointer", "const_pointer",
"iterator", "const_iterator",
"reverse_iterator", "const_reverse_iterator"
};
static const char* const
_rw_cont_names[] = {
"list", "vector", "deque", "queue", "stack"
};
// order of elements depends on the values of ContainerIds::FuncId
static const char* const
_rw_func_names[] = {
0 /* special handling for the ctor */, "operator=", "assign",
"get_allocator", "begin", "end", "rbegin", "rend", "empty",
"size", "max_size", "resize", "insert", "erase", "swap",
"clear", "operator==", "operator<", "operator!=", "operator>",
"operator>=", "operator<=", "push_back", "front", "back",
"pop_back", "push_front", "pop_front", "splice", "remove",
"remove_if", "unique", "merge", "sort", "reverse", "operator[]",
"at", "capacity", "reserve", "flip"
};
/**************************************************************************/
const size_t MAX_OVERLOADS = 32;
// disabled (-1) or explicitly enabled (+1) for each overload
// of the cont function being tested
static int
_rw_opt_func [MAX_OVERLOADS];
// array of tests each exercising a single cont function
static const ContainerTest*
_rw_cont_tests;
// size of the array above
static size_t
_rw_cont_test_count;
static int
_rw_opt_elem_types [sizeof _rw_elem_names / sizeof *_rw_elem_names];
static int
_rw_opt_alloc_types [sizeof _rw_alloc_names / sizeof *_rw_alloc_names];
static int
_rw_opt_iter_types [sizeof _rw_iter_names / sizeof *_rw_iter_names];
static int
_rw_opt_no_exceptions;
static int
_rw_opt_no_exception_safety;
static int
_rw_opt_self_ref;
/**************************************************************************/
static size_t
_rw_get_func_inx (size_t fid)
{
size_t inx = _RWSTD_SIZE_MAX;
for (size_t i = 0; _rw_cont_test_count; ++i) {
if (fid == _rw_cont_tests [i].which) {
inx = i;
break;
}
}
RW_ASSERT (inx < _RWSTD_SIZE_MAX);
return inx;
}
/**************************************************************************/
static const char*
_rw_class_name (const ContainerFunc & func)
{
return _rw_cont_names [func.cont_id_];
}
/**************************************************************************/
// appends the signature of the function specified by which
// to the provided buffer; when the second argument is null,
// appends the mnemonic representing the signature, including
// the name of the function, as specified by the third argument
static void
_rw_sigcat (char **pbuf, size_t *pbufsize,
const ContainerFunc *func,
size_t which = 0)
{
// for convenience
typedef ContainerIds Ids;
if (func)
which = func->which_;
// determine whether the function is a member function
const bool is_member = 0 != (Ids::bit_member & which);
// get the bitmap describing the function's argument types
int argmap = (which & ~Ids::bit_member) >> Ids::fid_bits;
// determine whether the function is a const member function
bool is_const_member =
is_member && Ids::arg_ccont == (argmap & Ids::arg_mask);
// remove the *this argument if the function is a member
if (is_member)
argmap >>= Ids::arg_bits;
const char* funcname = 0;
if (0 == func) {
const Ids::FuncId fid = Ids::FuncId (which & ContainerIds::fid_mask);
switch (fid) {
// translate names with funky characters to mnemonics
case Ids::fid_ctor: funcname = "ctor"; break;
case Ids::fid_op_index: funcname = "op_index"; break;
case Ids::fid_op_set: funcname = "op_assign"; break;
case Ids::fid_op_equal: funcname = "op_equal"; break;
case Ids::fid_op_less: funcname = "op_less"; break;
case Ids::fid_op_not_equal: funcname = "op_not_equal"; break;
case Ids::fid_op_greater: funcname = "op_greater"; break;
case Ids::fid_op_greater_equal: funcname = "op_greater_equal"; break;
case Ids::fid_op_less_equal: funcname = "op_less_equal"; break;
case Ids::fid_get_allocator:
case Ids::fid_empty:
case Ids::fid_size:
case Ids::fid_max_size:
// prevent appending the "_const" bit to the mnemonics
// of member functions not overloaded on const
is_const_member = false;
// fall through
default: {
// determine the cont function name (for brief output)
const size_t nfuncs =
sizeof _rw_func_names / sizeof *_rw_func_names;
RW_ASSERT (size_t (fid) < nfuncs);
funcname = _rw_func_names [fid];
RW_ASSERT (0 != funcname);
break;
}
}
}
// iterator name for member templates, empty cont for other functions
const char* const iname = func ? _rw_iter_names [func->iter_id_] : "";
rw_asnprintf (pbuf, pbufsize,
"%{+}%{?}%s%{?}_const%{;}%{:}%{?}<%s>%{;}(%{;}",
0 == func, funcname, is_const_member, 0 != *iname, iname);
char iname_buf [80];
*iname_buf = '\0';
// iterate through the map of argument types one field at a time
// determining and formatting the type of each argument until
// void is reached
for (size_t argno = 0; argmap; ++argno, argmap >>= Ids::arg_bits) {
const char* pfx = "";
const char* sfx = "";
const int argtype = argmap & Ids::arg_mask;
const char* tname = 0;
if (func) {
switch (argtype) {
case Ids::arg_size: tname = "size_type"; break;
case Ids::arg_val: tname = "value_type"; break;
case Ids::arg_ref: tname = "reference"; break;
case Ids::arg_cref: tname = "const_reference"; break;
case Ids::arg_iter: tname = "iterator"; break;
case Ids::arg_citer: tname = "const_iterator"; break;
case Ids::arg_range:
if ('\0' == *iname_buf) {
strcpy (iname_buf, iname);
strcat (iname_buf, ", ");
strcat (iname_buf, iname);
}
tname = iname_buf;
break;
case Ids::arg_ccont:
pfx = "const ";
// fall through
case Ids::arg_cont:
tname = _rw_class_name (*func);
sfx = "&";
break;
case Ids::arg_alloc: tname = "const allocator_type&"; break;
case Ids::arg_pred: tname = "Predicate"; break;
case Ids::arg_bpred: tname = "BinaryPredicate"; break;
case Ids::arg_comp: tname = "Compare"; break;
}
}
else {
switch (argtype) {
case Ids::arg_size: tname = "size"; break;
case Ids::arg_val: tname = "val"; break;
case Ids::arg_ref: tname = "ref"; break;
case Ids::arg_cref: tname = "cref"; break;
case Ids::arg_iter: tname = "iter"; break;
case Ids::arg_citer: tname = "citer"; break;
case Ids::arg_range: tname = "range"; break;
case Ids::arg_cont: tname = "cont"; break;
case Ids::arg_ccont: tname = "ccont"; break;
case Ids::arg_alloc: tname = "alloc"; break;
case Ids::arg_pred: tname = "pred"; break;
case Ids::arg_bpred: tname = "bpred"; break;
case Ids::arg_comp: tname = "comp"; break;
}
}
RW_ASSERT (0 != tname);
if ( 0 == func || is_member
|| Ids::arg_cont != argtype && Ids::arg_ccont != argtype) {
// append the name or mnemonic of the argument type
rw_asnprintf (pbuf, pbufsize, "%{+}%{?}_%{:}%{?}, %{;}%{;}%s%s%s",
0 == func, 0 < argno, pfx, tname, sfx);
}
else {
// in non-member functions use ${CLASS} to format
// the cont argument in order to expand
// its template argument cont
rw_asnprintf (pbuf, pbufsize,
"%{+}%{?}, %{;}%{?}const %{;}%{$CLASS}&",
0 < argno, Ids::arg_ccont == argtype);
}
}
if (func)
rw_asnprintf (pbuf, pbufsize, "%{+})%{?} const%{;}", is_const_member);
}
/**************************************************************************/
// returns the zero-based index of the argument type specified
// by arg in the function signature given by which
static int
_rw_argno (size_t which, int arg)
{
// get the bitmap describing the function's argument types
int argmap = (which & ~ContainerIds::bit_member) >> ContainerIds::fid_bits;
int argno = 0;
// iterate over argument types looking for the first one
// that equals arg
for (; argmap; argmap >>= ContainerIds::arg_bits, ++argno) {
if ((argmap & ContainerIds::arg_mask) == arg) {
return argno;
}
}
// return -1 when the function doesn't take an argument
// of the specified type
return -1;
}
/**************************************************************************/
// temporary, shuld be defined in 23.list.h
struct ListIds : ContainerIds
{
enum OverloadId {};
};
static void
_rw_list_sigcat (char** pbuf, size_t * pbufsize, ListIds::OverloadId which,
bool self, const char* str, size_t str_len,
const char* arg, size_t arg_len,
const ContainerTestCase &tcase)
{
// temporary empty
}
/**************************************************************************/
// temporary, should be defined in 23.deque.h
struct VectorIds : ContainerIds
{
enum OverloadId {};
};
static void
_rw_vector_sigcat (char** pbuf, size_t * pbufsize, VectorIds::OverloadId which,
bool self, const char* str, size_t str_len,
const char* arg, size_t arg_len,
const ContainerTestCase &tcase)
{
// temporary empty
}
/**************************************************************************/
// temporary, should be defined in 23.deque.h
struct DequeIds : ContainerIds
{
enum OverloadId {};
};
static void
_rw_deque_sigcat (char** pbuf, size_t * pbufsize, DequeIds::OverloadId which,
bool self, const char* str, size_t str_len,
const char* arg, size_t arg_len,
const ContainerTestCase &tcase)
{
// temporary empty
}
/**************************************************************************/
// temporary, should be defined in 23.queue.h
struct QueueIds : ContainerIds
{
enum OverloadId {};
};
static void
_rw_queue_sigcat (char** pbuf, size_t * pbufsize, QueueIds::OverloadId which,
bool self, const char* str, size_t str_len,
const char* arg, size_t arg_len,
const ContainerTestCase &tcase)
{
// temporary empty
}
/**************************************************************************/
// temporary, should be defined in 23.stack.h
struct StackIds : ContainerIds
{
enum OverloadId {};
};
static void
_rw_stack_sigcat (char** pbuf, size_t * pbufsize, StackIds::OverloadId which,
bool self, const char* str, size_t str_len,
const char* arg, size_t arg_len,
const ContainerTestCase &tcase)
{
// temporary empty
}
/**************************************************************************/
// sets the {CLASS}, {FUNC}, {FUNCSIG}, and optionally {FUNCALL}
// environment variables as follows:
// CLASS: the name of cont specialization
// FUNC: the name of the cont function
// FUNCSIG: the name and signature of a specific overload
// of the cont function
// FUNCALL: a cont describing the call to the cont function
// with function with function arguments expanded (as specified
// by the TestCase argument)
static void
_rw_setvars (const ContainerFunc &func,
const ContainerTestCase *pcase = 0)
{
char* buf = 0;
size_t bufsize = 0;
const char* const class_name = _rw_class_name (func);
if (0 == pcase) {
// set the {Elem}, {Allocator}, {Iterator} and {Container}
// environment variables to the name of the element type
// and the Allocator and Iterator and Container specializations
rw_fprintf (0, "%{$Elem!:*}", _rw_elem_names [func.elem_id_]);
rw_fprintf (0, "%{$Allocator!:*}", _rw_alloc_names [func.alloc_id_]);
rw_fprintf (0, "%{$Iterator!:*}", _rw_iter_names [func.iter_id_]);
rw_fprintf (0, "%{$Container!:*}", class_name);
// set the {CLASS}, {FUNC}, and {FUNCSIG} environment variables
// to the name of the specialization of the template, the name
// of the container function, and the name of the overload of the
// container function, respectively, when no test case is given
// format container specializations, leaving out the name
// of the default allocator for brevity
rw_asnprintf (&buf, &bufsize,
"std::%s<%s%{?}, %s<%2$s>%{;}>",
class_name,
_rw_elem_names [func.elem_id_],
ContainerIds::DefaultAlloc != func.alloc_id_,
_rw_alloc_names [func.alloc_id_]);
// set the {CLASS} variable to the name of the specialization
// of container
rw_fprintf (0, "%{$CLASS!:*}", buf);
free (buf);
buf = 0;
bufsize = 0;
// determine the container function name
const size_t funcinx = func.which_ & ContainerIds::fid_mask;
const size_t nfuncs = sizeof _rw_func_names / sizeof *_rw_func_names;
RW_ASSERT (funcinx < nfuncs);
// get the undecorated function name; ctors are treated
// specially so that we can have string, wstring, or
// cont, depending on the template arguments
const char* const funcname = _rw_func_names [funcinx] ?
_rw_func_names [funcinx] : class_name;
// determine whether the function is a member function
const bool is_member = 0 != (func.which_ & ContainerIds::bit_member);
// set the {FUNC} variable to the unqualified/undecorated
// name of the container function (member or otherwise)
rw_asnprintf (&buf, &bufsize, "%{?}std::%{;}%s",
!is_member, funcname);
rw_fprintf (0, "%{$FUNC!:*}", buf);
// append the function signature
_rw_sigcat (&buf, &bufsize, &func);
rw_fprintf (0, "%{$FUNCSIG!:*}", buf);
free (buf);
return;
}
// do the function call arguments reference *this?
const bool self = 0 == pcase->arg;
char str_buf [256];
char arg_buf [256];
char *str;
char *arg;
size_t str_len = sizeof str_buf;
size_t arg_len = sizeof arg_buf;
if (pcase->str)
str = rw_expand (str_buf, pcase->str, pcase->str_len, &str_len);
else
str = 0;
if (pcase->arg)
arg = rw_expand (arg_buf, pcase->arg, pcase->arg_len, &arg_len);
else
arg = 0;
// determine whether the function is a member function
const bool is_member = 0 != (func.which_ & ContainerIds::bit_member);
// determine whether the function is a ctor
bool is_ctor = ContainerIds::fid_ctor == (func.which_ & ContainerIds::fid_mask);
if (is_ctor) {
// for ctors append just the class name here
// the class name will inserted below during argument
// formatting
rw_asnprintf (&buf, &bufsize, "%{$CLASS}::%s", class_name);
}
else if (is_member) {
// for other members append the ctor argument(s) followed
// by the cont member function name
rw_asnprintf (&buf, &bufsize,
"%{$CLASS} (%{?}%{#*s}%{;}).%{$FUNC}",
str != 0, int (str_len), str);
}
else {
// for non-members append just the function name here
// the class name will inserted below during argument
// formatting
rw_asnprintf (&buf, &bufsize, "%{$FUNC}");
}
// format and append container function arguments abbreviating complex
// expressions as much as possible to make them easy to understand
switch (func.cont_id_) {
case ContainerIds::List:
_rw_list_sigcat (&buf, &bufsize,
_RWSTD_STATIC_CAST (ListIds::OverloadId, func.which_),
self, str, str_len, arg, arg_len, *pcase);
break;
case ContainerIds::Vector:
_rw_vector_sigcat (&buf, &bufsize,
_RWSTD_STATIC_CAST (VectorIds::OverloadId, func.which_),
self, str, str_len, arg, arg_len, *pcase);
break;
case ContainerIds::Deque:
_rw_deque_sigcat (&buf, &bufsize,
_RWSTD_STATIC_CAST (DequeIds::OverloadId, func.which_),
self, str, str_len, arg, arg_len, *pcase);
break;
case ContainerIds::Queue:
_rw_queue_sigcat (&buf, &bufsize,
_RWSTD_STATIC_CAST (QueueIds::OverloadId, func.which_),
self, str, str_len, arg, arg_len, *pcase);
break;
case ContainerIds::Stack:
_rw_stack_sigcat (&buf, &bufsize,
_RWSTD_STATIC_CAST (StackIds::OverloadId, func.which_),
self, str, str_len, arg, arg_len, *pcase);
break;
default:
RW_ASSERT (!"unknown container id");
}
rw_fprintf (0, "%{$FUNCALL!:*}", buf);
free (buf);
if (str != str_buf)
delete[] str;
if (arg != arg_buf)
delete[] arg;
}
/**************************************************************************/
// helper function to reverse substring in the resulting sequence
_RWSTD_INTERNAL ContainerTestCase
_rw_reverse_results (const ContainerTestCase &tsrc,
size_t off, size_t ext)
{
// expand expected results
size_t res_len = 0;
char* const new_res = rw_expand ((char*)0, tsrc.res, tsrc.nres, &res_len);
// reverse them
const size_t res_off = off;
const size_t res_ext = (ext < res_len ? ext : res_len) - 1;
char* beg = new_res + res_off;
char* end = beg + res_ext;
for (; beg < end; ++beg, --end) {
const char tmp = *beg;
*beg = *end;
*end = tmp;
}
// form new test case
const ContainerTestCase new_case = {
tsrc.line, tsrc.off, tsrc.size, tsrc.off2,
tsrc.size2, tsrc.val, tsrc.str, tsrc.str_len,
tsrc.arg, tsrc.arg_len, new_res, res_len, tsrc.bthrow
};
return new_case;
}
template <class T, class Allocator>
void
_rw_dispatch (T*, Allocator*,
VoidFunc* const *farray,
const ContainerFunc &func,
const ContainerTestCase &tcase)
{
typedef ContainerTestCaseData<T> Data;
typedef void TestFunc (T*, Allocator*, const Data&);
const size_t inx = func.elem_id_ * 2 + func.alloc_id_;
TestFunc* const tfunc = _RWSTD_REINTERPRET_CAST (TestFunc*, farray [inx]);
if (0 == tfunc) {
rw_error (0, __FILE__, __LINE__,
"logic error: null test function for %{$FUNCSIG}");
return;
}
const bool reverse_iter =
ContainerIds::ReverseIterator == func.iter_id_
|| ContainerIds::ConstReverseIterator == func.iter_id_;
const Data tdata (func, tcase);
if (reverse_iter) {
// special processing for reverse iterators
const size_t func_id = tdata.func_.which_ & ContainerIds::fid_mask;
const bool like_ctor =
ContainerIds::fid_ctor == func_id
|| ContainerIds::fid_assign == func_id;
// ctor and assignment operator require the full container reverse
const size_t off = like_ctor ? 0 : tdata.off1_;
const size_t ext = like_ctor ? tdata.reslen_ : tdata.ext2_;
const ContainerTestCase rev_tcase =
_rw_reverse_results (tcase, off, ext);
const Data rev_tdata (func, rev_tcase);
tfunc ((T*)0, (Allocator*)0, rev_tdata);
// clean up allocated memory, if any
delete[] rev_tcase.res;
}
else
tfunc ((T*)0, (Allocator*)0, tdata);
}
template <class T>
void
_rw_dispatch (T*,
VoidFunc* const *farray,
const ContainerFunc &func,
const ContainerTestCase &tcase)
{
if (ContainerIds::DefaultAlloc == func.alloc_id_) {
typedef std::allocator<T> Alloc;
_rw_dispatch ((T*)0, (Alloc*)0, farray, func, tcase);
}
else if (ContainerIds::UserAlloc == func.alloc_id_) {
typedef UserAlloc<T> Alloc;
_rw_dispatch ((T*)0, (Alloc*)0, farray, func, tcase);
}
else {
RW_ASSERT (!"logic error: unknown Allocator argument");
}
}
static void
_rw_dispatch (VoidFunc* const *farray,
const ContainerFunc &func,
const ContainerTestCase &tcase)
{
if (ContainerIds::UserPOD == func.elem_id_) {
_rw_dispatch ((UserPOD*)0, farray, func, tcase);
}
else if (ContainerIds::UserClass == func.elem_id_) {
_rw_dispatch ((UserClass*)0, farray, func, tcase);
}
else {
RW_ASSERT (!"logic error: unknown T argument");
}
}
/**************************************************************************/
// exercise a single test case for the given function
static void
_rw_test_case (const ContainerFunc &func,
const ContainerTestCase &tcase,
ContainerTestFunc *test_callback,
VoidFunc* const *farray)
{
// check to see if this is an exception safety test case
// and avoid running it when exception safety has been
// disabled via a command line option
if (-1 == tcase.bthrow && _rw_opt_no_exception_safety) {
// issue only the first note
rw_note (1 < _rw_opt_no_exception_safety++, _rw_this_file, __LINE__,
"exception safety tests disabled");
return;
}
// check to see if this is a test case that involves the throwing
// of an exception and avoid running it when exceptions have been
// disabled
if (tcase.bthrow && _rw_opt_no_exceptions) {
// issue only the first note
rw_note (1 < _rw_opt_no_exceptions++, _rw_this_file, __LINE__,
"exception tests disabled");
return;
}
const bool self_ref = 0 == tcase.arg;
// check for tests exercising self-referential modifications
// (e.g., insert(1, *this))
if (_rw_opt_self_ref < 0 && self_ref) {
// issue only the first note
rw_note (0, _rw_this_file, tcase.line,
"self-referential test disabled");
return;
}
else if (0 < _rw_opt_self_ref && !self_ref) {
// issue only the first note
rw_note (0, _rw_this_file, tcase.line,
"non-self-referential test disabled");
return;
}
// check to see if the test case is enabled
if (rw_enabled (tcase.line)) {
// set the {FUNCALL} environment variable to describe
// the function call specified by this test case
_rw_setvars (func, &tcase);
if (test_callback) {
// invoke the test callback function
test_callback (func, tcase);
}
else {
_rw_dispatch (farray, func, tcase);
}
}
else
rw_note (0, _rw_this_file, tcase.line,
"test on line %d disabled", tcase.line);
}
/**************************************************************************/
static ContainerIds::ContainerId
_rw_container_id;
static ContainerTestFunc*
_rw_test_callback;
static VoidFunc* const*
_rw_func_array;
// exercise all test cases defined for the given function
static void
_rw_run_cases (const ContainerFunc &func,
const ContainerTest &test)
{
// set the {CLASS}, {FUNC}, and {FUNCSIG} environment
// variable to the name of the container specialization
// and the container function being exercised
_rw_setvars (func);
// determine whether the function is a member function
const bool is_member = 0 != (ContainerIds::bit_member & test.which);
// compute the function overload's 0-based index
const size_t siginx = _rw_get_func_inx (test.which);
// check if tests of the function overload
// have been disabled
if (0 == rw_note (0 <= _rw_opt_func [siginx], _rw_this_file, __LINE__,
"%{?}%{$CLASS}::%{;}%{$FUNCSIG} tests disabled",
is_member))
return;
rw_info (0, 0, 0, "%{?}%{$CLASS}::%{;}%{$FUNCSIG}", is_member);
const size_t case_count = test.case_count;
// iterate over all test cases for this function
// overload invoking the test case handler for each
// in turn
for (size_t n = 0; n != case_count; ++n) {
const ContainerTestCase& tcase = test.cases [n];
_rw_test_case (func, tcase, _rw_test_callback, _rw_func_array);
}
}
/**************************************************************************/
void
_rw_toggle_options (int *opts, size_t count)
{
for (size_t i = 0; i != count; ++i) {
if (0 < opts [i]) {
// if one or more options has been explicitly enabled
// treat all those that haven't been as if they had
// been disabled
for (i = 0; i != count; ++i) {
if (0 == opts [i])
opts [i] = -1;
}
break;
}
}
}
static int
_rw_run_test (int, char*[])
{
#ifdef _RWSTD_NO_EXCEPTIONS
rw_note (0, 0, 0, "exception tests disabled (macro "
"_RWSTD_NO_EXCEPTIONS #defined)");
// disable all exception tests and avoid further notes
_rw_no_exceptions = 2;
_rw_no_exception_safety = 2;
#endif // _RWSTD_NO_EXCEPTIONS
// see if any option controlling a container function has been
// explicitly enabled and if so disable all those that haven't
// been (i.e., so that --enable-foo-size will have the effect
// of specifying --disable-foo-val and --disable-foo-range,
// given the three overloads of foo)
const size_t nopts = sizeof _rw_opt_func / sizeof *_rw_opt_func;
_rw_toggle_options (_rw_opt_func, nopts);
static const ContainerIds::ElemId elem_types[] = {
ContainerIds::UserPOD, ContainerIds::UserClass
};
static const ContainerIds::AllocId alloc_types[] = {
ContainerIds::DefaultAlloc, ContainerIds::UserAlloc
};
static const ContainerIds::IteratorId iter_types[] = {
ContainerIds::Input, ContainerIds::Forward,
ContainerIds::Bidir, ContainerIds::Random,
ContainerIds::Pointer, ContainerIds::ConstPointer,
ContainerIds::Iterator, ContainerIds::ConstIterator,
ContainerIds::ReverseIterator, ContainerIds::ConstReverseIterator
};
const size_t n_elem_types = sizeof elem_types / sizeof *elem_types;
const size_t n_alloc_types = sizeof alloc_types / sizeof *alloc_types;
const size_t n_iter_types = sizeof iter_types / sizeof *iter_types;
// see if any option controlling the container template arguments
// explicitly enabled and if so disable all those that haven't been
_rw_toggle_options (_rw_opt_elem_types, n_elem_types);
_rw_toggle_options (_rw_opt_alloc_types, n_alloc_types);
_rw_toggle_options (_rw_opt_iter_types, n_iter_types);
// exercise different T specializations last
for (size_t i = 0; i != n_elem_types; ++i) {
if (_rw_opt_elem_types [i] < 0) {
// issue only the first note
rw_note (-1 > _rw_opt_elem_types [i]--,
_rw_this_file, __LINE__,
"%s tests disabled", _rw_elem_names [i]);
continue;
}
for (size_t k = 0; k != n_alloc_types; ++k) {
if (_rw_opt_alloc_types [k] < 0) {
// issue only the first note
rw_note (-1 > _rw_opt_alloc_types [k]--,
_rw_this_file, __LINE__,
"%s tests disabled", _rw_alloc_names [k]);
continue;
}
for (size_t m = 0; m != _rw_cont_test_count; ++m) {
const ContainerTest& test = _rw_cont_tests [m];
// create an object uniquely identifying the overload
// of the container function exercised by the set of test
// cases defined to exercise it
ContainerFunc func = {
elem_types [i],
alloc_types [k],
ContainerIds::None,
_rw_container_id,
test.which
};
// determine whether the function is a template
if (-1 < _rw_argno (test.which, ContainerIds::arg_range)) {
// iterate over the standard iterator categories
// and iterator types the template might perhaps
// be specialized on
for (size_t l = 0; l != n_iter_types; ++l) {
if (_rw_opt_iter_types [l] < 0) {
// issue only the first note
rw_note (-1 > _rw_opt_iter_types [l]--,
_rw_this_file, __LINE__,
"%s tests disabled",
_rw_iter_names [l]);
continue;
}
func.iter_id_ = iter_types [l];
// exercise all test cases defined for
// the function template
_rw_run_cases (func, test);
}
}
else {
// exercise all test cases defined for the ordinary
// (i.e., non-template) function
_rw_run_cases (func, test);
}
}
}
}
return 0;
}
/**************************************************************************/
// add a bunch of toggle-type command line options based on the names array
static void
_rw_add_toggles (char **pbuf, size_t *pbufsize,
const char* const names[], size_t count)
{
for (size_t i = 0; i != count; ++i) {
rw_asnprintf (pbuf, pbufsize, "%{+}|-%s~ ", names [i]);
}
}
static void
_rw_add_container_toggles (char **pbuf, size_t *pbufsize)
{
_rw_add_toggles (pbuf, pbufsize, _rw_alloc_names,
sizeof _rw_alloc_names / sizeof *_rw_alloc_names);
_rw_add_toggles (pbuf, pbufsize, _rw_iter_names + 1,
sizeof _rw_iter_names / sizeof *_rw_iter_names - 1);
}
static int
_rw_run_test (int argc,
char *argv [],
const char *file,
const char *clause,
ContainerIds::ContainerId container,
ContainerTestFunc *test_callback,
VoidFunc* const *func_array,
const ContainerTest *tests,
size_t test_count)
{
// set the global variables accessed in _rw_run_test
_rw_container_id = container;
_rw_test_callback = test_callback;
_rw_func_array = func_array,
_rw_cont_tests = tests;
_rw_cont_test_count = test_count;
// put together a command line option specification with options
// to enable and disable tests exercising functions for all known
// specializations of the functions specified by the test array
char *optbuf = 0;
size_t optbufsize = 0;
rw_asnprintf (&optbuf, &optbufsize,
"|-no-exceptions# "
"|-no-exception-safety# "
"|-self-ref~ ");
const size_t n_elems = sizeof _rw_elem_names / sizeof *_rw_elem_names;
// see if any option has been explicitly enabled and if so,
// unconditionally disable all those that have not been
_rw_add_toggles (&optbuf, &optbufsize, _rw_elem_names, n_elems);
_rw_add_container_toggles (&optbuf, &optbufsize);
for (size_t i = 0; i != test_count; ++i) {
// for each function append a command line option specification
// to allow to enable or disable it
rw_asnprintf (&optbuf, &optbufsize, "%{+}|-");
_rw_sigcat (&optbuf, &optbufsize, 0, tests [i].which);
rw_asnprintf (&optbuf, &optbufsize, "%{+}~ ");
}
RW_ASSERT (test_count <= 32);
RW_ASSERT (test_count <= MAX_OVERLOADS);
// process command line arguments run tests
const int status =
rw_test (argc, argv, file, clause,
0, // comment
_rw_run_test, // test callback
optbuf, // option specification
// handlers controlling exceptions
&_rw_opt_no_exceptions,
&_rw_opt_no_exception_safety,
// handler controlling self-referential modifiers
&_rw_opt_self_ref,
// handlers controlling specializations of the template
// ...on the T template parameter
_rw_opt_elem_types + 0,
_rw_opt_elem_types + 1,
// ...on the Allocator template parameter
_rw_opt_alloc_types + 0,
_rw_opt_alloc_types + 1,
// FIXME: add handlers (and options) only for tests
// that exercise member templates
// handlers controlling specializations of the member
// template (if this is one) on the InputIterator
// template parameter
_rw_opt_iter_types + 0,
_rw_opt_iter_types + 1,
_rw_opt_iter_types + 2,
_rw_opt_iter_types + 3,
_rw_opt_iter_types + 4,
_rw_opt_iter_types + 5,
_rw_opt_iter_types + 6,
_rw_opt_iter_types + 7,
_rw_opt_iter_types + 8,
_rw_opt_iter_types + 9,
// FIXME: install exactly as many handlers (and options)
// as there are distinct functions being exercised
// handlers for up to 32 overloads
_rw_opt_func + 0,
_rw_opt_func + 1,
_rw_opt_func + 2,
_rw_opt_func + 3,
_rw_opt_func + 4,
_rw_opt_func + 5,
_rw_opt_func + 6,
_rw_opt_func + 7,
_rw_opt_func + 8,
_rw_opt_func + 9,
_rw_opt_func + 10,
_rw_opt_func + 11,
_rw_opt_func + 12,
_rw_opt_func + 13,
_rw_opt_func + 14,
_rw_opt_func + 15,
_rw_opt_func + 16,
_rw_opt_func + 17,
_rw_opt_func + 18,
_rw_opt_func + 19,
_rw_opt_func + 20,
_rw_opt_func + 21,
_rw_opt_func + 22,
_rw_opt_func + 23,
_rw_opt_func + 24,
_rw_opt_func + 25,
_rw_opt_func + 26,
_rw_opt_func + 27,
_rw_opt_func + 28,
_rw_opt_func + 29,
_rw_opt_func + 30,
_rw_opt_func + 31,
// sentinel
(void*)0);
// free storage allocated for the option specification
free (optbuf);
return status;
}
_TEST_EXPORT int
rw_run_cont_test (int argc,
char *argv [],
const char *file,
const char *clause,
ContainerIds::ContainerId container,
ContainerTestFunc *callback,
const ContainerTest *tests,
size_t count)
{
return _rw_run_test (argc, argv, file, clause, container,
callback, 0, tests, count);
}
_TEST_EXPORT int
rw_run_cont_test (int argc,
char *argv [],
const char *file,
const char *clause,
ContainerIds::ContainerId container,
VoidFunc* const *farray,
const ContainerTest *tests,
size_t count)
{
return _rw_run_test (argc, argv, file, clause, container,
0, farray, tests, count);
}
["21.strings.h.diff" (text/plain)]
31a32
> #include <23.containers.h> // for ContainerIds
38c39
< struct StringIds {
---
> struct StringIds: ContainerIds {
45,57d45
<
< // identifiers for the Allocator template argument
< enum AllocId { DefaultAlloc, UserAlloc };
<
< // identifiers for the Iterator template argument
< // used with meber templates
< enum IteratorId {
< None,
< Input, Forward, Bidir, Random,
< Pointer, ConstPointer,
< Iterator, ConstIterator,
< ReverseIterator, ConstReverseIterator
< };
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic