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);
}

Reply via email to