blob: 83b507d1a2f827858cbf4da161057f4453db2f45 [file] [log] [blame]
/***************************************************************************
*
* 25.libc.cpp - test exercising 25.4 [lib.alg.c.library]
*
* $Id$
*
***************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* Copyright 1994-2006 Rogue Wave Software.
*
***************************************************************************/
#include <cstdlib> // for bsearch, qsort
#include <csignal> // for signal
#include <csetjmp> // for setjmp, longjmp
#include <rw_alg_test.h>
#include <rw_value.h> // for UserClass
#include <rw_driver.h> // for rw_test()
/**************************************************************************/
// used as a special value in comp below
static int global[] = { 0, 0 };
extern "C" {
static std::jmp_buf jmp_env;
// SIGABRT handler
static void handle_ABRT (int)
{
// jump outta here to prevent abort() from trying too hard...
std::longjmp (jmp_env, 1);
}
static 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 UserClass*, x)).data_.val_
- (*_RWSTD_STATIC_CAST (const UserClass*, y)).data_.val_;
}
}
extern "C++" {
static 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 UserClass*, x)).data_.val_
- (*_RWSTD_STATIC_CAST (const UserClass*, y)).data_.val_;
}
}
/**************************************************************************/
// exrcises std::qqsort (25.4.4)
static void
test_qsort (int line,
const char *src,
std::size_t nsrc,
bool cxx)
{
UserClass* const xsrc = UserClass::from_char (src, nsrc);
UserClass* 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 \"C%{?}++%{;}\" qsort (\"%s\", ...) ==> "
"\"%{X=*.*}\" not sorted",
__LINE__, cxx, src, int (sizeof (*xsrc)), int (nsrc), -1, xsrc);
delete[] xsrc;
}
/**************************************************************************/
// exrcises std::qsort (25.4.4 Note)
static 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 \"C%{?}++%{;}\" qsort() aborted "
"on exception", __LINE__, cxx);
}
}
catch (const void* x) {
success = x >= src && x < src + nsrc;
}
catch (...) {
}
rw_assert (success, 0, line,
"line %d: extern \"C%{?}++%{;}\" qsort() failed to propagate "
"exception", __LINE__, cxx);
#else // if defined (_RWSTD_NO_EXCEPTIONS)
_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)
static void
test_bsearch (int line,
const char *src,
std::size_t nsrc,
const char key_val,
std::size_t res,
bool cxx)
{
UserClass* const xsrc = UserClass::from_char (src, nsrc,
true); // must be sorted
RW_ASSERT (0 == nsrc || 0 != xsrc);
UserClass key;
key.data_.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 UserClass* exp_res = res == _RWSTD_SIZE_MAX ? 0 : xsrc + res;
bool success = result == exp_res;
rw_assert (success, 0, line,
"line %d: extern \"C%{?}++%{;}\" bsearch (\"%s\", %#c, ...) "
"== %p, got %p, difference is %td elements",
__LINE__, cxx, src, key_val, result, exp_res,
_RWSTD_STATIC_CAST (const UserClass*, result) - exp_res);
delete[] xsrc;
}
/**************************************************************************/
// exrcises std::bsearch (25.4.4 Note)
static 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 \"C%{?}++%{;}\" bsearch() aborted "
"on exception", __LINE__, cxx);
}
}
catch (const void* x) {
success = x >= src && x < src + nsrc;
}
catch (...) {
}
rw_assert (success, 0, line,
"line %d: extern \"C%{?}++%{;}\" bsearch() failed to propagate "
"exception", __LINE__, cxx);
#else // if defined (_RWSTD_NO_EXCEPTIONS)
_RWSTD_UNUSED (line);
_RWSTD_UNUSED (src);
_RWSTD_UNUSED (nsrc);
_RWSTD_UNUSED (key);
_RWSTD_UNUSED (cxx);
#endif // _RWSTD_NO_EXCEPTIONS
}
/**************************************************************************/
static int rw_opt_no_c; // --no-c
static int rw_opt_no_cxx; // --no-cpp
static int rw_opt_no_bsearch; // --no-bsearch
static int rw_opt_no_qsort; // --no-qsort
static int rw_opt_no_exceptions; // --no-exceptions
/**************************************************************************/
static void
test_qsort (bool cxx)
{
rw_info (0, 0, 0,
"extern \"C%{?}++%{;}\" qsort (void*, size_t, size_t, "
"int (*compar)(const void*, const void*))", cxx);
#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 \"C%{?}++%{;}\" qsort() exceptions tests "
"disabled", cxx);
}
else {
test_qsort_exception (__LINE__, global,
sizeof global / sizeof *global, cxx);
}
}
/**************************************************************************/
static void
test_bsearch (bool cxx)
{
rw_info (0, 0, 0,
"extern \"C%{?}++%{;}\" bsearch (const void*, const void*, "
"size_t, size_t, int (*compar)(const void*, const void*))",
cxx);
#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 \"C%{?}++%{;}\" bsearch() exceptions "
"tests disabled", cxx);
}
else {
test_bsearch_exception (__LINE__, global,
sizeof global / sizeof *global, global, cxx);
}
}
/**************************************************************************/
static 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, "tests of extern \"C\" cfunctions disabled");
else
test_libc (false);
if (rw_opt_no_cxx)
rw_note (0, 0, 0, "tests of extern \"C++\" functions 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-extern_c# "
"|-no-extern_cxx# "
"|-no-bsearch# "
"|-no-qsort# "
"|-no-exceptions",
&rw_opt_no_c,
&rw_opt_no_cxx,
&rw_opt_no_bsearch,
&rw_opt_no_qsort,
&rw_opt_no_exceptions);
}