[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