The attached file contains the ported tests for the lib.alg.c.library
functions.
With best wishes,
Anton Pevtsov
/***************************************************************************
*
* libc.cpp - test exercising 25.4 [lib.alg.c.library]
*
* $Id: //stdlib/dev/tests/stdlib/algorithm/libc.cpp#12 $
*
***************************************************************************
*
* Copyright (c) 1994-2005 Quovadx, Inc., acting through its Rogue Wave
* Software division. Licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0. Unless required by
* applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under
* the License.
*
**************************************************************************/
#include <cstdlib> // for bsearch, qsort
#include <csignal> // for signal
#include <csetjmp> // for setjmp, longjmp
#include <alg_test.h>
#include <driver.h> // for rw_test()
/**************************************************************************/
// used as a special value in comp below
int global[] = { 0, 0 };
extern "C" {
static std::jmp_buf jmp_env;
// SIGABRT handler
void handle_ABRT (int)
{
// jump outta here to prevent abort() from trying too hard...
std::longjmp (jmp_env, 1);
}
int c_comp (const void *x, const void *y)
{
#ifndef _RWSTD_NO_EXCEPTIONS
// verify that a thrown exception can be caught
if (x >= global && x < global + sizeof global / sizeof *global)
throw x;
#endif // _RWSTD_NO_EXCEPTIONS
return (*_RWSTD_STATIC_CAST (const X*, x)).val_
- (*_RWSTD_STATIC_CAST (const X*, y)).val_;
}
}
extern "C++" {
int cxx_comp (const void *x, const void *y)
{
#ifndef _RWSTD_NO_EXCEPTIONS
// verify that a thrown exception can be caught
if (x >= global && x < global + sizeof global / sizeof *global)
throw x;
#endif // _RWSTD_NO_EXCEPTIONS
return (*_RWSTD_STATIC_CAST (const X*, x)).val_
- (*_RWSTD_STATIC_CAST (const X*, y)).val_;
}
}
/**************************************************************************/
// exrcises std::qqsort (25.4.4)
void test_qsort (int line,
const char *src,
std::size_t nsrc,
bool cxx)
{
X* const xsrc = X::from_char (src, nsrc);
X* const xsrc_end = xsrc + nsrc;
RW_ASSERT (0 == nsrc || 0 != xsrc);
if (cxx)
std::qsort (xsrc, nsrc, sizeof *xsrc, cxx_comp);
else
std::qsort (xsrc, nsrc, sizeof *xsrc, c_comp);
bool success = is_sorted_lt (xsrc, xsrc_end);
rw_assert (success, 0, line,
"line %d: extern \"%s\" qsort (\"%s\", ...) ==> \"%{X=*.*}\" "
"not sorted",
__LINE__, cxx ? "C++" : "C", src, int (nsrc), -1, xsrc);
delete[] xsrc;
}
// exrcises std::qsort (25.4.4 Note)
void test_qsort_exception (int line,
int *src,
std::size_t nsrc,
bool cxx)
{
#ifndef _RWSTD_NO_EXCEPTIONS
// install a SIGABRT handler in case libc can't throw
// exceptions and aborts instead (e.g., glibc/gcc)
std::signal (SIGABRT, handle_ABRT);
bool success = false;
try {
if (0 == setjmp (jmp_env)) {
if (cxx)
std::qsort (src, nsrc, sizeof *src, cxx_comp);
else
std::qsort (src, nsrc, sizeof *src, c_comp);
}
else {
// prevent double assertion
success = true;
rw_assert (false, 0, line,
"line %d: extern \"%s\" qsort() aborted on exception",
__LINE__, cxx ? "C++" : "C");
}
}
catch (const void* x) {
success = x >= src && x < src + nsrc;
}
catch (...) {
}
rw_assert (success, 0, line,
"line %d: extern \"%s\" qsort() failed to propagate exception",
__LINE__, cxx ? "C++" : "C");
#else
_RWSTD_UNUSED (line);
_RWSTD_UNUSED (src);
_RWSTD_UNUSED (nsrc);
_RWSTD_UNUSED (key);
_RWSTD_UNUSED (cxx);
#endif // _RWSTD_NO_EXCEPTIONS
}
/**************************************************************************/
// exrcises std::bsearch (25.4.3)
void test_bsearch (int line,
const char *src,
std::size_t nsrc,
const char key_val,
std::size_t res,
bool cxx)
{
X* const xsrc = X::from_char (src, nsrc, true); // must be sorted
RW_ASSERT (0 == nsrc || 0 != xsrc);
X key;
key.val_ = key_val;
const void* result = cxx ?
std::bsearch (&key, xsrc, nsrc, sizeof *xsrc, cxx_comp)
: std::bsearch (&key, xsrc, nsrc, sizeof *xsrc, c_comp);
const X* exp_res = res == _RWSTD_SIZE_MAX ? 0 : xsrc + res;
bool success = result == exp_res;
rw_assert (success, 0, line,
"line %d: extern \"%s\" bsearch (\"%s\", %#c, ...) = %p, "
"got %p, difference is %td elements",
__LINE__, cxx ? "C++" : "C", src, key_val, result, exp_res,
_RWSTD_STATIC_CAST (const X*, result) - exp_res);
delete[] xsrc;
}
// exrcises std::bsearch (25.4.4 Note)
void test_bsearch_exception (int line,
const int *src,
std::size_t nsrc,
const int *key,
bool cxx)
{
#ifndef _RWSTD_NO_EXCEPTIONS
// install a SIGABRT handler in case libc can't throw
// exceptions and aborts instead (e.g., glibc/gcc)
std::signal (SIGABRT, handle_ABRT);
bool success = false;
try {
if (0 == setjmp (jmp_env)) {
if (cxx)
std::bsearch (key, src, nsrc, sizeof *src, cxx_comp);
else
std::bsearch (key, src, nsrc, sizeof *src, c_comp);
}
else {
// prevent double assertion
success = true;
rw_assert (false, 0, line,
"line %d: extern \"%s\" bsearch() aborted on exception",
__LINE__, cxx ? "C++" : "C");
}
}
catch (const void* x) {
success = x >= src && x < src + nsrc;
}
catch (...) {
}
rw_assert (success, 0, line,
"line %d: extern \"%s\" bsearch() failed to propagate "
"exception", __LINE__, cxx ? "C++" : "C");
#else
_RWSTD_UNUSED (line);
_RWSTD_UNUSED (src);
_RWSTD_UNUSED (nsrc);
_RWSTD_UNUSED (key);
_RWSTD_UNUSED (cxx);
#endif // _RWSTD_NO_EXCEPTIONS
}
/**************************************************************************/
/* extern */ int rw_opt_no_c; // --no-c
/* extern */ int rw_opt_no_cpp; // --no-cpp
/* extern */ int rw_opt_no_bsearch; // --no-bsearch
/* extern */ int rw_opt_no_qsort; // --no-qsort
/* extern */ int rw_opt_no_exceptions; // --no-exceptions
/**************************************************************************/
void test_qsort (bool cxx)
{
rw_info (0, 0, 0,
"extern \"%s\" qsort (void*, size_t, size_t, "
"int (*compar)(const void*, const void*))",
cxx ? "C++" : "C");
#define TEST(src) \
test_qsort (__LINE__, src, sizeof src - 1, cxx)
TEST ("a");
TEST ("ba");
TEST ("cba");
TEST ("dcba");
TEST ("edcba");
TEST ("fedcba");
TEST ("gfedcba");
TEST ("hgfedcba");
TEST ("ihgfedcba");
TEST ("jihgfedcba");
TEST ("ab");
TEST ("abc");
TEST ("abcd");
TEST ("abcde");
TEST ("abcdef");
TEST ("abcdefg");
TEST ("abcdefgh");
TEST ("abcdefghi");
TEST ("abcdefghij");
TEST ("aa");
TEST ("aabb");
TEST ("bbccaa");
TEST ("ddbbccaa");
TEST ("ddeebbccaa");
TEST ("aaaaaaaaaa");
TEST ("ababababab");
TEST ("bababababa");
#undef TEST
if (rw_opt_no_exceptions) {
rw_note (0, 0, 0, "extern \"%s\" qsort() exceptions tests disabled",
cxx ? "C++" : "C");
}
else {
test_qsort_exception (__LINE__, global,
sizeof global / sizeof *global, cxx);
}
}
/**************************************************************************/
void test_bsearch (bool cxx)
{
rw_info (0, 0, 0,
"extern \"%s\" bsearch (const void*, const void*, size_t, "
"size_t, int (*compar)(const void*, const void*))",
cxx ? "C++" : "C");
#define TEST(src, key, res) \
test_bsearch (__LINE__, src, sizeof src - 1, key, \
std::size_t(res), cxx)
TEST ("", 'a', -1);
TEST ("a", 'a', 0);
TEST ("a", 'b', -1);
TEST ("b", 'a', -1);
TEST ("ab", 'a', 0);
TEST ("ac", 'a', 0);
TEST ("ab", 'b', 1);
TEST ("bc", 'a', -1);
TEST ("acegi", 'i', 4);
TEST ("acegi", 'b', -1);
TEST ("acegi", 'g', 3);
TEST ("acegi", 'f', -1);
TEST ("acegi", 'e', 2);
TEST ("acegi", 'j', -1);
TEST ("acegi", 'c', 1);
TEST ("bdfhj", 'a', -1);
TEST ("abcdefghij", 'a', 0);
TEST ("abcdefghij", 'c', 2);
TEST ("abcdefghij", 'f', 5);
TEST ("abcdefghij", 'h', 7);
TEST ("abcdefghij", 'j', 9);
#undef TEST
if (rw_opt_no_exceptions) {
rw_note (0, 0, 0, "extern \"%s\" bsearch() exceptions tests "
"disabled", cxx ? "C++" : "C");
}
else {
test_bsearch_exception (__LINE__, global,
sizeof global / sizeof *global, global, cxx);
}
}
/**************************************************************************/
void test_libc (bool cxx)
{
if (rw_opt_no_qsort)
rw_note (0, 0, 0, "qsort test disabled");
else
test_qsort (cxx);
if (rw_opt_no_bsearch)
rw_note (0, 0, 0, "bsearch test disabled");
else
test_bsearch (cxx);
}
/**************************************************************************/
static int run_test (int, char*[])
{
if (rw_opt_no_c)
rw_note (0, 0, 0, "c-functions tests disabled");
else
test_libc (false);
if (rw_opt_no_cpp)
rw_note (0, 0, 0, "cpp-functions tests disabled");
else
test_libc (true);
return 0;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
return rw_test (argc, argv, __FILE__,
"lib.alg.c.library",
0 /* no comment */, run_test,
"|-no-c# "
"|-no-cpp# "
"|-no-bsearch# "
"|-no-qsort# "
"|-no-exceptions",
&rw_opt_no_c,
&rw_opt_no_cpp,
&rw_opt_no_bsearch,
&rw_opt_no_qsort,
&rw_opt_no_exceptions);
}