blob: dad797076f31d92e5e6d3d1c7c5f3b070492e96b [file] [log] [blame]
/***************************************************************************
*
* 18.limits_traps.cpp - test exercising std::numeric_limits::traps
*
* $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 2005-2006 Rogue Wave Software.
*
**************************************************************************/
#include <limits>
#include <csignal> // for SIGFPE, signal
#include <rw_any.h> // for rw_any_t
#include <rw_cmdopt.h> // for rw_enabled()
#include <rw_driver.h> // for rw_test(), ...
/**************************************************************************/
#ifdef _RWSTD_OS_LINUX
// use siglongjmp() and sigsetjmp() on Linux to avoid
// http://sourceware.org/bugzilla/show_bug.cgi?id=2351
# include <setjmp.h> // for siglongjmp, sigsetjmp
jmp_buf jmp_env;
extern "C" {
void handle_fpe (int)
{
siglongjmp (jmp_env, 1);
}
} // extern "C"
# define RW_SIGSETJMP(env, signo) sigsetjmp (env, signo)
#else // if !defined (_RWSTD_OS_LINUX)
# include <csetjmp> // for longjmp, setjmp
std::jmp_buf jmp_env;
extern "C" {
void handle_fpe (int)
{
std::longjmp (jmp_env, 1);
}
} // extern "C"
# define RW_SIGSETJMP(env, ignore) setjmp (env)
#endif // _RWSTD_OS_LINUX
/**************************************************************************/
#ifdef _MSC_VER
// silence useless MSVC warnings:
// 4800: 'int' : forcing value to bool 'true' or 'false'
// 4804: '/' : unsafe use of type 'bool' in operation
# pragma warning (disable: 4800 4804)
// use Structured Exception Handling to detect arithmetic exceptions
# define TRY __try
# define EXCEPT(arg) __except (arg)
#else
# define TRY if (1)
# define EXCEPT(ignore) else if (0)
#endif // _MSC_VER
template <class numT>
inline void
try_trap (const volatile numT &one, const volatile numT &zero,
numT &result, bool &trapped)
{
TRY {
result = one / zero;
}
EXCEPT (1) {
// Windows SEH hackery
trapped = true;
}
}
template <class numT>
numT test_traps (numT, int lineno, bool)
{
static const char* const tname = rw_any_t (numT ()).type_name ();
if (!rw_enabled (tname)) {
rw_note (0, 0, 0, "numeric_limits<%s>::traps test disabled", tname);
return numT ();
}
const bool traps = std::numeric_limits<numT>::traps;
rw_info (0, 0, 0, "std::numeric_limits<%s>::traps = %b", tname, traps);
#ifdef SIGFPE
std::signal (SIGFPE, handle_fpe);
#else // if !defined (SIGFPE)
if (!rw_warn (!traps, 0, lineno,
"SIGFPE not #defined and numeric_limits<%s>::traps == %b, "
"cannot test", tname, traps)) {
return numT ();
}
#endif // SIGFPE
numT result = numT ();
// set the environment
const int jumped = RW_SIGSETJMP (jmp_env, SIGFPE);
volatile numT zero = numT (jumped);
volatile numT one = numT (1);
bool trapped = false;
if (jumped) {
// setjmp() call above returned from the SIGFPE handler
// as a result of a floating point exception triggered
// by the division by zero in the else block below
result = zero / one;
trapped = true;
}
else {
// setjmp() call above returned after setting up the jump
// environment; see of division by zero traps (if so, it
// will generate a SIGFPE which will be caught by the
// signal hanlder above and execution will resume by
// returning from setjmp() above again, but this time
// with a non-zero value
try_trap (one, zero, result, trapped);
}
rw_assert (trapped == traps, 0, lineno,
"numeric_limits<%s>::traps == %b, got %b",
tname, trapped, traps);
return result;
}
/**************************************************************************/
static int
run_test (int, char*[])
{
#define TEST(T, floating) test_traps ((T)0, __LINE__, floating)
#ifndef _RWSTD_NO_NATIVE_BOOL
TEST (bool, false);
#endif // _RWSTD_NO_NATIVE_BOOL
TEST (char, false);
TEST (signed char, false);
TEST (unsigned char, false);
TEST (short, false);
TEST (unsigned short, false);
TEST (int, false);
TEST (unsigned int, false);
TEST (long, false);
TEST (unsigned long, false);
#ifndef _RWSTD_NO_LONG_LONG
TEST (_RWSTD_LONG_LONG, false);
TEST (unsigned _RWSTD_LONG_LONG, false);
#endif // _RWSTD_NO_LONG_LONG
#ifndef _RWSTD_NO_NATIVE_WCHAR_T
TEST (wchar_t, false);
#endif // _RWSTD_NO_NATIVE_WCHAR_T
TEST (float, true);
TEST (double, true);
#ifndef _RWSTD_NO_LONG_DOUBLE
TEST (long double, true);
#endif // _RWSTD_NO_LONG_DOUBLE
return 0;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
return rw_test (argc, argv, __FILE__,
"lib.numeric.limits.members",
"traps data member",
run_test,
0, 0);
}