first commit

This commit is contained in:
Jose Caban
2025-06-07 11:34:38 -04:00
commit 0eb2d7c07d
4708 changed files with 1500614 additions and 0 deletions

View File

@@ -0,0 +1,814 @@
/***************************************************************************
*
* codecvt_length.cpp - test exercising the std::codecvt::length()
*
* $Id: 22.locale.codecvt.length.cpp 604041 2007-12-13 21:43:43Z sebor $
*
***************************************************************************
*
* 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 2004-2006 Rogue Wave Software.
*
**************************************************************************/
#ifdef __SUNPRO_CC
// working around a SunPro/SunOS 5.8 bug (PR #26255)
# include <time.h>
#endif // __SUNPRO_CC
#include <locale> // for codecvt
#include <climits> // for MB_LEN_MAX
#include <clocale> // for LC_CTYPE, setlocale()
#include <cstdlib> // for MB_CUR_MAX, free(), size_t
#include <cstring> // for strcpy(), strlen()
#include <cwchar> // for mbstate_t
#include <any.h> // for rw_any
#include <cmdopt.h> // for rw_enabled()
#include <driver.h> // for rw_test()
#include <file.h> // for rw_fwrite()
#include <rw_locale.h> // for rw_localedef(), rw_find_mb_locale()
#include <rw_printf.h> // for rw_printf()
/****************************************************************************/
typedef std::codecvt<char, char, std::mbstate_t> Codecvt;
typedef std::codecvt_byname<char, char, std::mbstate_t> CodecvtByname;
#ifndef _RWSTD_NO_WCHAR_T
typedef std::codecvt<wchar_t, char, std::mbstate_t> WCodecvt;
typedef std::codecvt_byname<wchar_t, char, std::mbstate_t> WCodecvtByname;
#endif // _RWSTD_NO_WCHAR_T
/****************************************************************************/
// the root of the locale directory (RWSTD_LOCALE_ROOT)
// set in main() instead of here to avoid Solaris 7 putenv() bug (PR #30017)
const char* locale_root /* = set in main() */;
// creates a table-based multibyte locale
const char* create_locale ()
{
char cm_fname [1024];
if (rw_snprintf (cm_fname, sizeof cm_fname, "%s%c%s",
locale_root, _RWSTD_PATH_SEP, "charmap") < 0)
return 0;
static const char charmap[] = {
"<code_set_name> test_charmap\n"
"<comment_char> %\n"
"<escape_char> /\n"
"<mb_cur_min> 1\n"
"<mb_cur_max> 9\n"
"CHARMAP\n"
"<U0000> /x30 0 \n"
"<U0001> /x31 1 \n"
"<U0002> /x32/x32 22 \n"
"<U0003> /x33/x33/x33 333 \n"
"<U0004> /x34/x34/x34/x34 4444 \n"
"<U0005> /x35/x35/x35/x35/x35 55555 \n"
"<U0006> /x36/x36/x36/x36/x36/x36 666666 \n"
"<U0007> /x37/x37/x37/x37/x37/x37/x37 7777777 \n"
"<U0008> /x38/x38/x38/x38/x38/x38/x38/x38 88888888 \n"
"<U0009> /x39/x39/x39/x39/x39/x39/x39/x39/x39 999999999 \n"
"<U0010> /x41 A \n"
"<U0011> /x42 B \n"
"<U0012> /x43 C \n"
"END CHARMAP\n"
};
if (std::size_t (-1) == rw_fwrite (cm_fname, charmap))
return 0;
char src_fname [1024];
if (rw_snprintf (src_fname, sizeof src_fname, "%s%c%s",
locale_root, _RWSTD_PATH_SEP, "source") < 0)
return 0;
if (std::size_t (-1) == rw_fwrite (src_fname, "LC_CTYPE\nEND LC_CTYPE\n"))
return 0;
// invoke localedef to create the named locale
// silence the following warnings:
// 701: no compatible locale found
// 702: member of portable character set <x> not found
// in the character map
// 706: iconv_open() failed
const char* const locname =
rw_localedef ("-w701 -w702 -w706",
src_fname, cm_fname, "mb_cur_max-9");
return locname;
}
/****************************************************************************/
template <class internT>
void test_length (internT /* dummy */,
int line,
const std::mbstate_t *pstate,
const std::codecvt<internT, char, std::mbstate_t> &cvt,
const char *from,
std::size_t nchars,
int maxi,
int result)
{
static const std::mbstate_t initial_state = std::mbstate_t ();
const char* const tname = rw_any_t (internT ()).type_name ();
std::mbstate_t state = pstate ? *pstate : initial_state;
if (std::size_t (-1) == nchars)
nchars = std::strlen (from);
const int res = cvt.length (state, from, from + nchars, maxi);
rw_assert (res == result, 0, line,
"line %d: codecvt<%s, char, mbstate_t>::length("
"state, from=%{*s}, from + %zu, %d) == %d, got %d",
__LINE__, tname, sizeof *from, from, nchars, maxi, result, res);
rw_assert (!pstate || 0 == std::memcmp (pstate, &state, sizeof state),
0, line,
"line %d: codecvt<%s, char, mbstate_t>::length("
"state, from=%{*s}, from + %zu, %d) unexpected state",
__LINE__, tname, from, nchars, maxi);
}
/****************************************************************************/
void test_codecvt (const Codecvt *pcvt = 0)
{
if (0 == pcvt)
rw_info (0, 0, 0,
"std::codecvt<char, char, mbstate_t>::length "
"(state_type&, const extern_type*, const "
"extern_type*, size_t)");
const std::locale classic = std::locale::classic ();
const Codecvt &cvt = pcvt ? *pcvt : std::use_facet<Codecvt>(classic);
#undef TEST
#define TEST(from, nchars, maxi, result) \
test_length (char (), __LINE__, 0, cvt, from, nchars, maxi, result)
// +--------------- source sequence of externT characters
// | +-------- size of sequence in externT characters
// | | +----- maximum number of internT characters
// | | | +-- expected result
// | | | |
// V V V V
TEST (0, 0, 0, 0);
TEST ("", 0, 0, 0);
TEST ("a", 1, 0, 0);
TEST ("ab", 2, 1, 1);
TEST ("ab", 2, 2, 2);
TEST ("ab", 2, 3, 2);
TEST ("abc", 3, 0, 0);
TEST ("abc", 3, 1, 1);
TEST ("abc", 3, 2, 2);
TEST ("abc", 3, 3, 3);
TEST ("abc", 3, 4, 3);
}
/****************************************************************************/
static void
test_codecvt_byname ()
{
rw_info (0, 0, 0,
"std::codecvt_byname<char, char, mbstate_t>::length "
"(state_type&, const extern_type*, const extern_type*, "
"size_t)");
const CodecvtByname cvt ("");
test_codecvt (&cvt);
}
/****************************************************************************/
static void
test_wcodecvt ()
{
rw_info (0, 0, 0,
"std::codecvt<wchar_t, char, mbstate_t>::length "
"(state_type&, const extern_type*, const extern_type*, "
"size_t)");
#ifndef _RWSTD_NO_WCHAR_T
const std::locale classic = std::locale::classic ();
const WCodecvt &cvt = std::use_facet<WCodecvt>(classic);
#undef TEST
#define TEST(from, nchars, maxi, result) \
test_length (wchar_t (), __LINE__, 0, cvt, from, nchars, maxi, result)
// +--------------- source sequence of externT characters
// | +-------- size of sequence in externT characters
// | | +----- maximum number of internT characters
// | | | +-- expected result
// | | | |
// V V V V
TEST (0, 0, 0, 0);
TEST ("", 0, 0, 0);
TEST ("a", 1, 0, 0);
TEST ("ab", 2, 1, 1);
TEST ("ab", 2, 2, 2);
TEST ("ab", 2, 3, 2);
TEST ("abc", 3, 0, 0);
TEST ("abc", 3, 1, 1);
TEST ("abc", 3, 2, 2);
TEST ("abc", 3, 3, 3);
TEST ("abc", 3, 4, 3);
#else // if defined (_RWSTD_NO_WCHAR_T)
rw_warn (0, 0, __LINE__, "_RWSTD_NO_WCHAR_T #defined, cannot test");
#endif // _RWSTD_NO_WCHAR_T
}
/****************************************************************************/
#ifndef _RWSTD_NO_WCHAR_T
// exercises an algorithmic multibyte encoding
static void
test_wcodecvt_byname_algorithmic ()
{
rw_info (0, 0, 0, "locale (\"UTF-8@UCS\") [algorithmic encoding]");
// lowercase utf ==> relaxed checking (i.e., some, but not all,
// invalid UTF-8 sequence are accepted)
const WCodecvtByname cvt_relaxd ("utf-8@UCS");
// capital UTF ==> strict checking
const WCodecvtByname cvt_strict ("UTF-8@UCS");
#undef STRICT
#define STRICT(from, nc, maxi, res) \
test_length (wchar_t (), __LINE__, 0, cvt_strict, from, nc, maxi, res)
#undef RELAXD
#define RELAXD(from, nc, maxi, res) \
test_length (wchar_t (), __LINE__, 0, cvt_relaxd, from, nc, maxi, res)
#undef TEST
#define TEST(from, nc, maxi, res) \
STRICT (from, nc, maxi, res); \
RELAXD (from, nc, maxi, res)
// 22.2.1.5.2 [lib.locale.codecvt.virtuals]
// including the resolution of lwg issue 305
//
// -9- Preconditions: (from<=from_end) well-defined and true; state
// initialized, if at the beginning of a sequence, or else equal
// to the result of converting the preceding characters in the
// sequence.
//
// -9a- Effects: The effect on the state argument is "as if" it called
// do_in(state, from, from_end, from, to, to+max, to) for to pointing
// to a buffer of at least max elements.
//
// -10- Returns: (from_next-from) where from_next is the largest value
// in the range [from,from_end] such that the sequence of values
// in the range [from,from_next) represents max or fewer valid
// complete characters of type internT. The instantiation
// codecvt<char, char, mbstate_t> returns the lesser of max
// and (from_end-from).
// Note that the function returns the number of externT characters
// (i.e., those of type char for the required instantiations)
// +--------------- source sequence of externT characters
// | +-------- size of sequence in externT characters
// | | +----- maximum number of internT characters
// | | | +-- expected result in externT characters
// | | | |
// V V V V
TEST (0, 0, 0, 0);
TEST ("", 0, 0, 0);
TEST ("a", 1, 0, 0);
TEST ("ab", 2, 1, 1);
TEST ("ab", 2, 2, 2);
TEST ("ab", 2, 3, 2);
TEST ("abc", 3, 0, 0);
TEST ("abc", 3, 1, 1);
TEST ("abc", 3, 2, 2);
TEST ("abc", 3, 3, 3);
TEST ("abc", 3, 4, 3);
// invalid sequences rejected in both the strict and relaxed mode
TEST ("\x80", 1, 0, 0);
TEST ("\xc0", 1, 0, 0);
TEST ("\x80\x00", 2, 0, 0);
TEST ("\xc0\x00", 2, 0, 0);
// valid 2-byte UTF-8 sequences (except for overlong sequences)
// 110x xxxx 10xx xxxx
// i.e., first byte: c0-df
// second byte: 80-bf
TEST ("\xc2", 1, 0, 0);
TEST ("\xc2\x81", 1, 1, 0);
TEST ("\xc2\x82", 2, 1, 2);
TEST ("\xc2\x83", 2, 2, 2);
// the second byte doesn't follow the correct pattern
// and will be rejected in strict mode (but will be
// accepted in relaxed mode)
STRICT ("\xc2\x01", 2, 1, 0);
RELAXD ("\xc2\x01", 2, 1, 2);
TEST ("\xc2\x80\xc0", 3, 0, 0);
TEST ("\xc2\x80\xc0\x81", 3, 1, 2);
TEST ("\xc2\x80\xc0\x82", 3, 2, 2);
STRICT ("\xc2\x80\xc2\x01", 4, 2, 2);
RELAXD ("\xc2\x80\xc2\x01", 4, 2, 4);
TEST ("\xc2\x80\xc2\x81", 4, 0, 0);
TEST ("\xc2\x80\xc2\x82", 4, 1, 2);
TEST ("\xc2\x80\xc2\x83", 4, 2, 4);
TEST ("\xc2\x80\xc2\x84", 4, 3, 4);
}
// exercises a table-based multibyte encoding
static void
test_wcodecvt_byname_table_based ()
{
const char* const locname = create_locale ();
if (!rw_error (0 != locname, 0, __LINE__,
"failed to create a locale database")) {
return;
}
std::locale loc;
_TRY {
loc = std::locale (locname);
}
_CATCH (...) {
rw_error (0, 0, __LINE__,
"locale(\"%s\") unexpectedly threw an exception", locname);
return;
}
const WCodecvt &cvt_table = std::use_facet<WCodecvt>(loc);
rw_info (0, 0, 0, "locale (\"%s\") [table-based encoding]", locname);
#undef TEST
#define TEST(from, nc, maxi, res) \
test_length (wchar_t (), __LINE__, 0, cvt_table, \
from, std::size_t (nc), maxi, res)
TEST (0, 0, 0, 0);
TEST ("", 0, 0, 0);
TEST ("A", 1, 0, 0);
TEST ("AB", 2, 1, 1);
TEST ("AB", 2, 2, 2);
TEST ("AB", 2, 3, 2);
TEST ("ABC", 3, 0, 0);
TEST ("ABC", 3, 1, 1);
TEST ("ABC", 3, 2, 2);
TEST ("ABC", 3, 3, 3);
TEST ("ABC", 3, 4, 3);
TEST ("22", 1, 1, 0); // "22" --> L'2'
TEST ("22", 2, 1, 2);
TEST ("22", 2, 2, 2);
TEST ("333", 1, 1, 0); // "333" --> L'3'
TEST ("333", 2, 1, 0);
TEST ("333", 3, 1, 3);
TEST ("333", 3, 2, 3);
TEST ("4444", 1, 1, 0); // "4444" --> L'4'
TEST ("4444", 2, 1, 0);
TEST ("4444", 3, 1, 0);
TEST ("4444", 4, 1, 4);
TEST ("4444", 4, 2, 4);
TEST ("122", 1, 0, 0); // "122" --> L"12"
TEST ("122", 1, 1, 1);
TEST ("122", 1, 2, 1);
TEST ("122", 2, 2, 1);
TEST ("122", 3, 2, 3);
TEST ("122", 3, 3, 3);
TEST ("122333", 1, 0, 0); // "122333" --> L"123"
TEST ("122333", 1, 1, 1);
TEST ("122333", 1, 2, 1);
TEST ("122333", 4, 1, 1);
TEST ("122333", 4, 2, 3);
TEST ("122333", 4, 3, 3);
TEST ("122333", 5, 1, 1);
TEST ("122333", 5, 2, 3);
TEST ("122333", 5, 3, 3);
TEST ("122333", 5, 1, 1);
TEST ("122333", 5, 2, 3);
TEST ("122333", 5, 3, 3);
TEST ("122333", 6, 1, 1);
TEST ("122333", 6, 2, 3);
TEST ("122333", 6, 3, 6);
TEST ("122333", 6, 4, 6);
// 0 12 3 45 67 89
// I: +---++----+------++------++--++- (intern_type characters)
// E: 0....:....1....:....2....:....3. (extern_type characters)
TEST ("4444A55555B666666C77777770333122", -1, 1, 4);
TEST ("4444A55555B666666C77777770333122", -1, 2, 5);
TEST ("4444A55555B666666C77777770333122", -1, 3, 10);
TEST ("4444A55555B666666C77777770333122", -1, 4, 11);
TEST ("4444A55555B666666C77777770333122", -1, 5, 17);
TEST ("4444A55555B666666C77777770333122", -1, 6, 18);
TEST ("4444A55555B666666C77777770333122", -1, 7, 25);
TEST ("4444A55555B666666C77777770333122", -1, 8, 26);
TEST ("4444A55555B666666C77777770333122", -1, 9, 29);
TEST ("4444A55555B666666C77777770333122", -1, 10, 30);
TEST ("4444A55555B666666C77777770333122", -1, 11, 32);
TEST ("4444.55555B666666C77777770333122", -1, 11, 4);
TEST ("4444A55555.666666C77777770333122", -1, 11, 10);
TEST ("4444A55555B666666.77777770333122", -1, 11, 17);
TEST ("4444A55555B666666C7777777.333122", -1, 11, 25);
TEST ("4444A55555B666666C77777770333.22", -1, 11, 29);
}
// exercises a libc-based multibyte encoding
static void
test_wcodecvt_byname_libc_based ()
{
// compute `mb_cur_max' multibyte characters in increasing
// length from 1 to mb_cur_max bytes long
// i.e., initialize the first (N + 1) elements of mb_chars as follows:
// mb_chars [0] = "0"; // where "0" is a single byte character
// mb_chars [1] = "11"; // where "11" is a two-byte character
// mb_chars [2] = "222"; // where "222" is a three-byte character
// mb_chars [N] = "NNN...N"; // where "NNN...N" is an N-byte character
std::size_t mb_cur_max = 0;
rw_mbchar_array_t mb_chars;
const char* const locname = rw_find_mb_locale (&mb_cur_max, mb_chars);
if (!rw_warn (0 != locname, 0, __LINE__,
"failed to find a multibyte locale")) {
return;
}
std::locale loc;
_TRY {
loc = std::locale (locname);
}
_CATCH (...) {
rw_error (0, 0, __LINE__,
"locale(\"%s\") unexpectedly threw an exception", locname);
return;
}
const WCodecvt &cvt_libc = std::use_facet<WCodecvt>(loc);
rw_info (0, 0, 0, "locale (\"%s\") [libc-based encoding, "
"single-byte characters]", locname);
//////////////////////////////////////////////////////////////////
// exercise sequences containing single-byte characters
#undef TEST
#define TEST(from, nc, maxi, res) \
test_length (wchar_t (), __LINE__, 0, cvt_libc, \
from, std::size_t (nc), std::size_t (maxi), res)
TEST (0, 0, 0, 0);
TEST ("", 0, 0, 0);
TEST ("A", 1, 0, 0);
TEST ("AB", 2, 1, 1);
TEST ("AB", 2, 2, 2);
TEST ("AB", 2, 3, 2);
TEST ("ABC", 3, 0, 0);
TEST ("ABC", 3, 1, 1);
TEST ("ABC", 3, 2, 2);
TEST ("ABC", 3, 3, 3);
TEST ("ABC", 3, 4, 3);
// exercise embedded NULs
TEST ("\0BC", 3, 3, 3);
TEST ("A\0C", 3, 3, 3);
TEST ("AB\0", 3, 3, 3);
TEST ("\0\0C", 3, 3, 3);
TEST ("A\0\0", 3, 3, 3);
TEST ("\0B\0", 3, 3, 3);
TEST ("\0\0\0", 3, 3, 3);
//////////////////////////////////////////////////////////////////
// exercise sequences containing 2-byte characters
if (!rw_warn (2 <= mb_cur_max, 0, __LINE__,
"no multibyte characters found, skipping test")) {
return;
}
char* sequences = 0;
// verify the length of each character
for (std::size_t i = 0; i < mb_cur_max; ++i) {
const std::size_t mb_len = std::strlen (mb_chars [i]);
if (!rw_error (i + 1 == mb_len, 0, __LINE__,
"unexpected multibyte character length: "
"%zu, expected %zu", mb_len, i + 1)) {
return;
}
sequences = rw_sprintfa ("%s%s%#s",
sequences ? sequences : "",
i ? ", " : "", mb_chars [i]);
}
rw_info (0, 0, 0, "locale (\"%s\") [libc-based encoding, "
"MB_CUR_MAX = %zu, multi-byte characters: %s]",
locname, mb_cur_max, sequences);
std::free (sequences);
#ifdef _RWSTD_OS_SUNOS
if (!rw_warn (std::strcmp ("5.7", _RWSTD_OS_RELEASE), 0, __LINE__,
"skipping tests due to a SunOS 5.7 libc bug")) {
return;
}
#endif // _RWSTD_OS_SUNOS
char mb_string [256];
// create a sequence of two multibyte characters
rw_sprintf (mb_string, "%s%s", mb_chars [0], mb_chars [1]);
// +------------------- source sequence of multibyte externT characters
// | +-------- lenght of externT sequence in chars (bytes)
// | | +----- maximum number of internT characters
// | | | +-- expected result in externT characters (bytes)
// | | | |
// V V V V
TEST (mb_string, 0, 0, 0);
TEST (mb_string, 1, 1, 1);
TEST (mb_string, 1, 1, 1);
TEST (mb_string, 2, 1, 1);
TEST (mb_string, 2, 2, 1);
TEST (mb_string, 3, 1, 1);
TEST (mb_string, 3, 2, 3);
TEST (mb_string, 3, 3, 3);
TEST (mb_string, 3, -1, 3);
// exercise embedded NULs
rw_sprintf (mb_string, "%c%s%s", '\0', mb_chars [0], mb_chars [1]);
TEST (mb_string, 4, 3, 4);
rw_sprintf (mb_string, "%s%c%s", mb_chars [0], '\0', mb_chars [1]);
TEST (mb_string, 4, 3, 4);
rw_sprintf (mb_string, "%s%s%c", mb_chars [0], mb_chars [1], '\0');
TEST (mb_string, 4, 3, 4);
rw_sprintf (mb_string, "%c%c%s", '\0', '\0', mb_chars [0]);
TEST (mb_string, 3, 3, 3);
rw_sprintf (mb_string, "%c%c%s", '\0', '\0', mb_chars [1]);
TEST (mb_string, 4, 3, 4);
//////////////////////////////////////////////////////////////////
// exercise sequences containing 3-byte characters
if (mb_cur_max < 3)
return;
// create a sequence of three multibyte characters, 3, 2,
// and 1 byte long (and total length of (3+2+1)=6 bytes)
// with the following pattern: "<333><22><1>"
rw_sprintf (mb_string, "%s%s%s",
mb_chars [2], mb_chars [1], mb_chars [0]);
TEST (mb_string, 0, 3, 0); // ""
TEST (mb_string, 1, 3, 0); // "3"
TEST (mb_string, 2, 3, 0); // "33"
TEST (mb_string, 3, 3, 3); // "333" -> 1 complete internT
TEST (mb_string, 4, 3, 3); // "3332"
TEST (mb_string, 5, 3, 5); // "33322" -> 2 complete internT's
TEST (mb_string, 6, 3, 6); // "333221" -> 3 complete internT's
TEST (mb_string, 6, 4, 6);
TEST (mb_string, 6, -1, 6);
//////////////////////////////////////////////////////////////////
// exercise sequences containing 4-byte characters
if (mb_cur_max < 4)
return;
// create a sequence of four multibyte characters, 4, 3, 2,
// and 1 byte long (and total length of (4+3+2+1)=10 bytes)
// with the following pattern: "<4444><333><22><1>"
rw_sprintf (mb_string, "%s%s%s%s",
mb_chars [3], mb_chars [2], mb_chars [1], mb_chars [0]);
TEST (mb_string, 0, 4, 0); // ""
TEST (mb_string, 1, 4, 0); // "4"
TEST (mb_string, 2, 4, 0); // "44"
TEST (mb_string, 3, 4, 0); // "444"
TEST (mb_string, 4, 4, 4); // "4444" -> 1 complete internT
TEST (mb_string, 5, 4, 4); // "44443"
TEST (mb_string, 6, 4, 4); // "444433"
TEST (mb_string, 7, 4, 7); // "4444333" -> 2 complete internT's
TEST (mb_string, 8, 4, 7); // "44443332"
TEST (mb_string, 9, 4, 9); // "444433322" -> 3 complete internT's
TEST (mb_string, 10, 4, 10); // "4444333221" -> 4 complete internT's
TEST (mb_string, 10, 5, 10);
TEST (mb_string, 10, -1, 10);
//////////////////////////////////////////////////////////////////
// exercise sequences containing 5-byte characters
if (mb_cur_max < 5)
return;
// create a sequence of five multibyte characters, 5, 4, 3, 2,
// and 1 byte long (and total length of (5+4+3+2+1)=15 bytes)
// with the following pattern: "<55555><4444><333><22><1>"
rw_sprintf (mb_string, "%s%s%s%s%s",
mb_chars [4], mb_chars [3], mb_chars [2], mb_chars [1],
mb_chars [0]);
TEST (mb_string, 0, 5, 0); // ""
TEST (mb_string, 1, 5, 0); // "5"
TEST (mb_string, 2, 5, 0); // "55"
TEST (mb_string, 3, 5, 0); // "555"
TEST (mb_string, 4, 5, 0); // "5555"
TEST (mb_string, 5, 5, 5); // "55555"
TEST (mb_string, 6, 5, 5); // "555554"
TEST (mb_string, 7, 5, 5); // "5555544"
TEST (mb_string, 8, 5, 5); // "55555444"
TEST (mb_string, 9, 5, 9); // "555554444"
TEST (mb_string, 10, 5, 9); // "5555544443"
TEST (mb_string, 11, 5, 9); // "55555444433"
TEST (mb_string, 12, 5, 12); // "555554444333"
TEST (mb_string, 13, 5, 12); // "5555544443332"
TEST (mb_string, 14, 5, 14); // "55555444433322"
TEST (mb_string, 15, 5, 15); // "555554444333221"
TEST (mb_string, 15, 6, 15);
TEST (mb_string, 15, -1, 15);
// create a sequence of five multibyte characters, each 5 bytes long
// with the following pattern: "<55555><55555><55555><55555><55555>"
rw_sprintf (mb_string, "%s%s%s%s%s",
mb_chars [4], mb_chars [4], mb_chars [4], mb_chars [4],
mb_chars [4]);
TEST (mb_string, 5, 5, 5); // "<55555>"
TEST (mb_string, 6, 5, 5); // "<55555><5"
TEST (mb_string, 9, 5, 5); // "<55555><5555"
TEST (mb_string, 10, 1, 5); // "<55555><55555>"
TEST (mb_string, 10, 2, 10);
TEST (mb_string, 10, 5, 10);
TEST (mb_string, 11, 5, 10); // "<55555><55555><5"
TEST (mb_string, 14, 5, 10); // "<55555><55555><5555"
TEST (mb_string, 15, 5, 15); // "<55555><55555><55555>"
rw_sprintf (mb_string, "%s%s%s%s%s",
mb_chars [4], mb_chars [0], mb_chars [4], mb_chars [4],
mb_chars [4]);
// internT: 0 1 2 3 4 5
// externT: <-----><-><-----><-----><-----><
// "<55555><1><55555><55555><55555>"
TEST (mb_string, 5, 5, 5); // |-----> > > > >
TEST (mb_string, 6, 5, 6); // |--------> > > >
TEST (mb_string, 7, 5, 6); // |----------- > > >
TEST (mb_string, 8, 5, 6); // |------------ > > >
TEST (mb_string, 9, 5, 6); // |------------- > > >
TEST (mb_string, 10, 5, 6); // |-------------- > > >
TEST (mb_string, 11, 5, 11); // |---------------> > >
TEST (mb_string, 12, 5, 11); // |---------------- > >
TEST (mb_string, 15, 5, 11); // |--------------------- > >
TEST (mb_string, 16, 5, 16); // |----------------------> >
TEST (mb_string, 21, 5, 21); // |----------------------------->
}
#endif // _RWSTD_NO_WCHAR_T
static void
test_wcodecvt_byname ()
{
rw_info (0, 0, 0,
"std::codecvt_byname<wchar_t, char, mbstate_t>::length "
"(state_type&, const extern_type*, const extern_type*, "
"size_t)");
#ifndef _RWSTD_NO_WCHAR_T
test_wcodecvt_byname_algorithmic ();
test_wcodecvt_byname_table_based ();
test_wcodecvt_byname_libc_based ();
#else // if defined (_RWSTD_NO_WCHAR_T)
rw_warn (0, 0, __LINE__, "_RWSTD_NO_WCHAR_T #defined, cannot test");
#endif // _RWSTD_NO_WCHAR_T
}
/****************************************************************************/
static int no_codecvt;
static int no_codecvt_byname;
static int no_wcodecvt;
static int no_wcodecvt_byname;
static int
run_test (int, char*[])
{
// set up RWSTD_LOCALE_ROOT and other environment variables
// here as opposed to at program startup to work around a
// SunOS 5.7 bug in putenv() (PR #30017)
locale_root = rw_set_locale_root ();
#undef TEST
#define TEST(what) \
if (no_ ## what) { \
rw_note (0, 0, __LINE__, "%s test disabled", #what); \
} \
else { \
test_ ## what (); \
} typedef void unused_typedef
if (rw_enabled ("char")) {
TEST (codecvt);
TEST (codecvt_byname);
}
else {
rw_note (0, 0, 0, "char tests disabled");
}
if (rw_enabled ("wchar_t")) {
TEST (wcodecvt);
TEST (wcodecvt_byname);
}
else {
rw_note (0, 0, 0, "wchar_t tests disabled");
}
return 0;
}
/****************************************************************************/
int main (int argc, char *argv[])
{
return rw_test (argc, argv, __FILE__,
"lib.locale.codecvt.virtuals",
0 /* no comment */, run_test,
"|-no-codecvt# "
"|-no-codecvt_byname# "
"|-no-wcodecvt# "
"|-no-wcodecvt_byname# ",
&no_codecvt,
&no_codecvt_byname,
&no_wcodecvt,
&no_wcodecvt_byname);
}

View File

@@ -0,0 +1,564 @@
/************************************************************************
*
* 22.locale.codecvt.mt.cpp
*
* test exercising the thread safety of the codecvt facet
*
* $Id: 22.locale.codecvt.mt.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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.
*
**************************************************************************/
#include <ios> // for ios
#include <iterator> // for ostreambuf_iterator
#include <locale> // for locale, codecvt
#include <cstring> // for strlen()
#include <cwchar> // for codecvt
#include <rw_locale.h>
#include <rw_thread.h>
#include <driver.h>
#include <valcmp.h> // for rw_strncmp ()
// maximum number of threads allowed by the command line interface
#define MAX_THREADS 32
#define MAX_LOOPS 100000
// default number of threads (will be adjusted to the number
// of processors/cores later)
int rw_opt_nthreads = 1;
// the number of times each thread should iterate (unless specified
// otherwise on the command line)
int rw_opt_nloops = 5000;
// number of locales to use
int rw_opt_nlocales = MAX_THREADS;
// should all threads share the same set of locale objects instead
// of creating their own?
int rw_opt_shared_locale;
/**************************************************************************/
// array of locale names to use for testing
static const char*
locales [MAX_THREADS];
// number of locale names in the array
static std::size_t
nlocales;
/**************************************************************************/
//
template <class internT> //, class externT = char, class stateT = std::mbstate_t>
struct MyCodecvtData_T
{
enum { BufferSize = 16 };
typedef char externT;
typedef std::mbstate_t stateT;
typedef std::codecvt_base::result resultT;
typedef std::size_t sizeT;
int encoding_;
sizeT length_;
int max_length_;
bool always_noconv_;
externT out_buffer_ [BufferSize];
resultT out_result_;
sizeT out_length_;
stateT out_state_;
internT in_buffer_ [BufferSize];
resultT in_result_;
sizeT in_length_;
stateT in_state_;
};
//
struct MyCodecvtData
{
// out, unshift, in, encoding, always_noconv, length, max_length
enum CvtId {
cvt_out,
cvt_unshift,
cvt_in,
cvt_encoding,
cvt_length,
cvt_max_length,
cvt_always_noconv,
cvt_max
};
// name of the locale the data corresponds to
const char* locale_name_;
// optionally set to the named locale for threads to share
std::locale locale_;
MyCodecvtData_T<char> char_data_;
MyCodecvtData_T<wchar_t> wchar_data_;
} my_codecvt_data [MAX_THREADS];
template <class charT>
struct MyBuffer {
const charT* const str;
const int str_len;
};
const MyBuffer<char> nsrc [] = {
{ "a\x80", 2 },
{ "b", 1 },
{ "c\0c", 3 },
{ "ddd", 3 },
{ "e\fce\0", 4 },
{ "ff\0ffff", 5 },
{ "gggg\0g", 6 },
{ "hh\0hhhh", 7 },
{ "i\ni\tiiii", 8 },
{ "jjjjjjjjj", 9 },
{ "kkkkkkkkkk", 10 }
};
const MyBuffer<wchar_t> wsrc [] = {
{ L"\x0905\x0916", 2 },
{ L"bb", 2 },
{ L"\x106c", 2 },
{ L"dddd", 4 },
{ L"\xd800\xd801", 2 },
{ L"ffffff", 6 },
{ L"\xdfff\xffff", 2 },
{ L"hhhhhhhh", 8 },
{ L"i\0i\1i", 4 },
{ L"jjjjjjjjjj", 10 },
{ L"kkkkkkkkkkk", 11 }
};
/**************************************************************************/
template <typename T>
struct test_is_char
{
enum { value = 0 };
};
template <>
struct test_is_char<char>
{
enum { value = 1 };
};
/**************************************************************************/
template <class internT>
void test_codecvt (const std::locale& loc,
const MyBuffer<internT>& in,
const MyBuffer<char>& out,
const MyCodecvtData_T<internT>& data,
const MyCodecvtData::CvtId id)
{
typedef char externT;
typedef std::mbstate_t stateT;
typedef std::size_t sizeT;
typedef std::codecvt<internT, externT, stateT> code_cvt_type;
const code_cvt_type& cvt =
std::use_facet<code_cvt_type>(loc);
switch (id) {
case MyCodecvtData::cvt_out:
{
externT out_buffer [MyCodecvtData_T<internT>::BufferSize];
out_buffer [0] = externT ();
const int out_len = RW_COUNT_OF (out_buffer);
const internT* from = in.str;
const internT* from_end = in.str + in.str_len;
const internT* from_next = 0;
externT* to = out_buffer;
externT* to_limit = out_buffer + out_len;
externT* to_next = 0;
std::mbstate_t state = std::mbstate_t ();
const typename MyCodecvtData_T<internT>::resultT result =
cvt.out (state, from, from_end, from_next,
to, to_limit, to_next);
const sizeT len = to_next - to;
RW_ASSERT (data.out_result_ == result);
RW_ASSERT (len == data.out_length_);
RW_ASSERT (!rw_strncmp (out_buffer, data.out_buffer_, len));
}
break;
case MyCodecvtData::cvt_unshift:
{
externT out_buffer [MyCodecvtData_T<internT>::BufferSize];
out_buffer [0] = externT ();
const int out_len = RW_COUNT_OF (out_buffer);
externT* to = out_buffer;
externT* to_limit = out_buffer + out_len;
externT* to_next = 0;
std::mbstate_t state = std::mbstate_t ();
const typename MyCodecvtData_T<internT>::resultT result =
cvt.unshift (state, to, to_limit, to_next);
// 22.2.1.5.2 p5
RW_ASSERT (to == to_next);
// 22.2.1.5.2 p6 required only for codecvt<char, char, mbstate_t>
RW_ASSERT ( !test_is_char<internT>::value
|| result == std::codecvt_base::noconv);
}
break;
case MyCodecvtData::cvt_in:
{
internT in_buffer [MyCodecvtData_T<internT>::BufferSize];
in_buffer [0] = internT ();
const int in_len = RW_COUNT_OF (in_buffer);
const int out_len = RW_COUNT_OF (data.out_buffer_);
const externT* from = data.out_buffer_;
const externT* from_end = data.out_buffer_ + out_len;
const externT* from_next = 0;
internT* to = in_buffer;
internT* to_limit = in_buffer + in_len;
internT* to_next = 0;
std::mbstate_t state = std::mbstate_t ();
const typename MyCodecvtData_T<internT>::resultT result =
cvt.in (state, from, from_end, from_next,
to, to_limit, to_next);
const sizeT len = to_next - to;
RW_ASSERT (data.in_result_ == result);
RW_ASSERT (len == data.in_length_);
RW_ASSERT (!rw_strncmp (in_buffer, data.in_buffer_, len));
}
break;
case MyCodecvtData::cvt_encoding:
RW_ASSERT (data.encoding_ == cvt.encoding ());
break;
case MyCodecvtData::cvt_length:
{
const externT* from = out.str;
const externT* from_end = out.str + out.str_len;
const size_t max = 32;
std::mbstate_t state = std::mbstate_t ();
const sizeT len = cvt.length (state, from, from_end, max);
RW_ASSERT (data.length_ == len);
}
break;
case MyCodecvtData::cvt_max_length:
RW_ASSERT (data.max_length_ == cvt.max_length ());
break;
case MyCodecvtData::cvt_always_noconv:
RW_ASSERT (data.always_noconv_ == cvt.always_noconv ());
break;
case MyCodecvtData::cvt_max:
break;
}
}
/**************************************************************************/
extern "C" {
bool test_char; // exercise codecvt<char,char>
bool test_wchar; // exercise codecvt<wchar_t,char>
static void*
thread_func (void*)
{
const int ni = RW_COUNT_OF (nsrc);
const int wi = RW_COUNT_OF (wsrc);
for (int i = 0; i != rw_opt_nloops; ++i) {
const int inx = i % nlocales;
const MyCodecvtData& data = my_codecvt_data [inx];
// construct a named locale, get a reference to the codecvt
// facet from it and use it to format a random money value
const std::locale loc =
rw_opt_shared_locale ? data.locale_
: std::locale (data.locale_name_);
const MyCodecvtData::CvtId op =
MyCodecvtData::CvtId (i % MyCodecvtData::cvt_max);
if (test_char) {
test_codecvt<char>(loc, nsrc [inx % ni], nsrc [inx % ni],
data.char_data_, op);
}
if (test_wchar) {
test_codecvt<wchar_t>(loc, wsrc [inx % wi], nsrc [inx % ni],
data.wchar_data_, op);
}
}
return 0;
}
} // extern "C"
/**************************************************************************/
template <class internT>
void run_test_fill (const std::locale& loc,
const MyBuffer<internT>& in,
const MyBuffer<char>& out,
MyCodecvtData_T<internT>& data)
{
typedef char externT;
typedef std::mbstate_t stateT;
typedef std::codecvt<internT, externT, stateT> code_cvt_type;
const code_cvt_type& cvt =
std::use_facet<code_cvt_type>(loc);
//fill in the appropriate fields of data
data.encoding_ = cvt.encoding ();
data.max_length_ = cvt.max_length ();
data.always_noconv_ = cvt.always_noconv ();
// length
{
const externT* from = out.str;
const externT* from_end = out.str + out.str_len;
const size_t max = 32;
std::mbstate_t state = std::mbstate_t ();
data.length_ = cvt.length (state, from, from_end, max);
}
// out
{
const int out_len = RW_COUNT_OF (data.out_buffer_);
const internT* from = in.str;
const internT* from_end = in.str + in.str_len;
const internT* from_next = 0;
externT* to = data.out_buffer_;
externT* to_limit = data.out_buffer_ + out_len;
externT* to_next = 0;
data.out_result_ = cvt.out (data.out_state_,
from, from_end, from_next,
to, to_limit, to_next);
data.out_length_ = to_next - to;
}
//// unshift
//{
// externT* to = data.out_buffer_;
// externT* to_limit = data.out_buffer_ + RW_COUNT_OF (data.out_buffer_);
// externT* to_next = 0;
// std::mbstate_t state = std::mbstate_t ();
// data.shift_result_ = cvt.unshift (state, to, to_limit, to_next);
//}
// in
{
const int out_len = RW_COUNT_OF (data.out_buffer_);
const int in_len = RW_COUNT_OF (data.in_buffer_);
const externT* from = data.out_buffer_;
const externT* from_end = data.out_buffer_ + out_len;
const externT* from_next = 0;
internT* to = data.in_buffer_;
internT* to_limit = data.in_buffer_ + in_len;
internT* to_next = 0;
data.in_result_ = cvt.in (data.in_state_,
from, from_end, from_next,
to, to_limit, to_next);
data.in_length_ = to_next - to;
}
}
static int
run_test (int, char**)
{
// find all installed locales for which setlocale (LC_ALL) succeeds
const char* const locale_list =
rw_opt_locales ? rw_opt_locales : rw_locales (_RWSTD_LC_ALL);
const std::size_t maxinx = RW_COUNT_OF (locales);
const int ni = RW_COUNT_OF (nsrc);
const int wi = RW_COUNT_OF (wsrc);
for (const char* name = locale_list;
*name;
name += std::strlen (name) + 1) {
const std::size_t inx = nlocales;
locales [inx] = name;
// fill in the money and results for this locale
MyCodecvtData& data = my_codecvt_data [inx];
data.locale_name_ = name;
try {
const std::locale loc (data.locale_name_);
run_test_fill<char>
(loc, nsrc [inx % ni], nsrc [inx % ni], data.char_data_);
run_test_fill<wchar_t>
(loc, wsrc [inx % wi], nsrc [inx % ni], data.wchar_data_);
if (rw_opt_shared_locale)
data.locale_ = loc;
nlocales += 1;
}
catch (...) {
rw_warn (!rw_opt_locales, 0, __LINE__,
"failed to create locale(%#s)", name);
}
if (nlocales == maxinx || nlocales == std::size_t (rw_opt_nlocales))
break;
}
// avoid divide by zero in thread if there are no locales to test
rw_fatal (nlocales != 0, 0, __LINE__,
"failed to create one or more usable locales!");
rw_info (0, 0, 0,
"testing std::codecvt<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
rw_opt_nthreads, 1 != rw_opt_nthreads,
rw_opt_nloops, 1 != rw_opt_nloops,
nlocales, int (nlocales), "%#s", locales);
///////////////////////////////////////////////////////////////////////
rw_info (0, 0, 0, "exercising std::codecvt<char, char>");
test_char = true;
test_wchar = false;
// create and start a pool of threads and wait for them to finish
int result =
rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
rw_opt_nthreads, thread_func);
///////////////////////////////////////////////////////////////////////
rw_info (0, 0, 0, "exercising std::codecvt<wchar_t, char>");
test_char = false;
test_wchar = true;
result =
rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
rw_opt_nthreads, thread_func);
///////////////////////////////////////////////////////////////////////
rw_info (0, 0, 0, "exercising std::codecvt<char, char> and "
"std::codecvt<wchar_t, char>");
test_char = true;
test_wchar = true;
result =
rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
rw_opt_nthreads, thread_func);
return result;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
#ifdef _RWSTD_REENTRANT
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
rw_opt_nthreads = rw_get_cpus ();
if (rw_opt_nthreads < 2)
rw_opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.codecvt",
"thread safety", run_test,
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // must be provided
"|-shared-locale# ",
&rw_opt_nloops,
int (MAX_THREADS),
&rw_opt_nthreads,
&rw_opt_nlocales,
&rw_opt_setlocales,
&rw_opt_shared_locale);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,221 @@
/************************************************************************
*
* 22.locale.cons.mt.cpp
*
* test exercising the thread safety of locale ctors
*
* $Id: 22.locale.cons.mt.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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.
*
**************************************************************************/
#include <locale> // for locale
#include <cstring> // for strlen()
#include <rw_locale.h>
#include <rw_thread.h> // for rw_get_processors (), rw_thread_pool()
#include <driver.h>
// maximum number of threads allowed by the command line interface
#define MAX_THREADS 32
// default number of threads (will be adjusted to the number
// of processors/cores later)
int opt_nthreads = 1;
// the number of times each thread should iterate (unless specified
// otherwise on the command line)
int opt_nloops = 20000;
// tristate flag set in response to the --no-combine/--enable-combine
// command line option
int opt_combine;
/**************************************************************************/
// array of locale names to use for testing
static const char*
locales [MAX_THREADS];
// number of locale names in the array
static std::size_t
nlocales;
/**************************************************************************/
extern "C" {
static void*
test_ctors (void*)
{
static const std::locale::category cats[] = {
std::locale::all,
std::locale::collate,
std::locale::ctype,
std::locale::messages,
std::locale::monetary,
std::locale::numeric,
std::locale::time,
std::locale::none
};
static const std::size_t ncats = sizeof cats / sizeof *cats;
// the next locale "advanced" in each iteration of the loop
std::locale next (locales [0]);
for (int i = 0; i != opt_nloops; ++i) {
// compute an index into the array of locales
const std::size_t linx = i % nlocales;
// create two locale objects from the same name and verify
// they are equal
const std::locale first (next.name ().c_str ());
const std::locale second (next.name ().c_str ());
RW_ASSERT (first == second);
// create another locale object as a copy of one of the two
// above and verify it's equal to the other
const std::locale third (first);
RW_ASSERT (second == third);
// compute the next index into the array of locales
const std::size_t ninx = (i + 1) % nlocales;
const char* const next_name = locales [ninx];
// create the next locale from a name
next = std::locale (next_name);
if (0 <= opt_combine) {
// compute an index into the array of categories
const std::size_t cinx = i % ncats;
const std::locale::category cat = cats [cinx];
// create a locale from another object and the name of yet
// another locale, combining some (none, one, or all) of their
// categories
const std::locale combined (first, next_name, cat);
// verify that the locales were created correctly
if ( std::locale::none == cat
#ifdef _MSC_VER
|| std::locale::messages == cat
#endif
|| first == next) {
RW_ASSERT (combined == first);
}
else if (std::locale::all == cat)
RW_ASSERT (combined == next);
else
RW_ASSERT (combined != first && combined != next);
// repeat the step above but with a locale object
const std::locale combined_2 (first, next, cat);
if ( std::locale::none == cat
#ifdef _MSC_VER
|| std::locale::messages == cat
#endif
|| first == next) {
RW_ASSERT (combined_2 == first);
}
else if (std::locale::all == cat)
RW_ASSERT (combined_2 == next);
else
RW_ASSERT (combined_2 != first && combined_2 != next);
}
}
return 0;
}
} // extern "C"
/**************************************************************************/
static int
run_test (int, char**)
{
// find all installed locales for which setlocale(LC_ALL) succeeds
const char* const locale_list =
rw_opt_locales ? rw_opt_locales : rw_locales (_RWSTD_LC_ALL);
const std::size_t maxinx = sizeof locales / sizeof *locales;
for (const char *name = locale_list; *name; name += std::strlen (name) +1) {
locales [nlocales++] = name;
if (nlocales == maxinx)
break;
}
int result;
rw_info (0, 0, 0,
"testing std::locale ctors with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
opt_nthreads, 1 != opt_nthreads,
opt_nloops, 1 != opt_nloops,
nlocales, int (nlocales), "%#s", locales);
// create and start a pool of threads and wait for them to finish
result = rw_thread_pool (0, std::size_t (opt_nthreads), 0,
test_ctors, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, test_ctors);
return result;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
#ifdef _RWSTD_REENTRANT
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
opt_nthreads = rw_get_cpus ();
if (opt_nthreads < 2)
opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.cons",
"thread safety", run_test,
"|-combine~ "
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-locales=", // must be provided
&opt_combine,
&opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
&rw_opt_setlocales);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,335 @@
/************************************************************************
*
* 22.locale.ctype.mt.cpp
*
* test exercising the thread safety of the ctype facet
*
* $Id: 22.locale.ctype.mt.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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.
*
**************************************************************************/
#include <locale> // for locale, ctype
#include <clocale> // for lconv, localeconv()
#include <cstdlib> // for mbstowcs()
#include <cstring> // for size_t, strcpy()
#include <rw_locale.h>
#include <rw_thread.h>
#include <driver.h>
#include <valcmp.h>
// maximum number of threads allowed by the command line interface
#define MAX_THREADS 16
// default number of threads (will be adjusted to the number
// of processors/cores later)
int opt_nthreads = 1;
// the number of times each thread should iterate (unless specified
// otherwise on the command line)
int opt_nloops = 200000;
#if !defined (_RWSTD_OS_HP_UX) || defined (_ILP32)
// number of locales to use
int opt_nlocales = MAX_THREADS;
#else // HP-UX in LP64 mode
// work around an inefficiency (small cache size?) on HP-UX
// in LP64 mode (see STDCXX-812)
int opt_nlocales = 10;
#endif // HP-UX 32/64 bit mode
// should all threads share the same set of locale objects instead
// of creating their own?
int opt_shared_locale;
/**************************************************************************/
// array of locale names to use for testing
static const char*
locales [MAX_THREADS];
// number of locale names in the array
static std::size_t
nlocales;
/**************************************************************************/
struct CtypeData
{
// the name of the locale the data corresponds to
const char *locale_name_;
// optionally set to the named locale for the threads to share
std::locale locale_;
// results of ctype<charT>::widen(char) for char and wchar_t
char widened_ [256];
wchar_t wwidened_ [256];
// array of wide characters to narrow and the number
// of valid elements in the array
wchar_t wide_ [1024];
std::size_t nwide_;
// results of ctype<charT>::narrow(charT, char) for char
// and wchar_t values of wide_ [i]
char narrowed_ [256];
char wnarrowed_ [1024];
} ctype_data [MAX_THREADS];
extern "C" {
bool test_char; // exercise num_put<char>
bool test_wchar; // exercise num_put<wchar_t>
static void*
thread_func (void*)
{
// number of narrow characters to test (should be 256)
const std::size_t nchars =
sizeof ctype_data->widened_ / sizeof *ctype_data->widened_;
for (int i = 0; i != opt_nloops; ++i) {
const std::size_t inx = std::size_t (i) % nlocales;
// save the name of the locale
const char* const locale_name = locales [inx];
const CtypeData* const data = ctype_data + inx;
// construct a named locale
const std::locale loc =
opt_shared_locale ? data->locale_ : std::locale (locale_name);
// "random" index/character value
const std::size_t cinx = std::size_t (i) % nchars;
if (test_char) {
// exercise the narrow char specialization of the facet
const std::ctype<char> &ct =
std::use_facet<std::ctype<char> >(loc);
const char wc = ct.widen (char (cinx));
RW_ASSERT (wc == data->widened_ [cinx]);
const char nc = ct.narrow (char (cinx), '\0');
RW_ASSERT (nc == data->narrowed_ [cinx]);
}
// both specializations may be tested at the same time
if (test_wchar) {
// exercise the wide char specialization of the facet
#ifndef _RWSTD_NO_WCHAR_T
const std::ctype<wchar_t> &wct =
std::use_facet<std::ctype<wchar_t> >(loc);
// "random" index into the wide character array
const std::size_t winx =
std::size_t (i) % data->nwide_;
const wchar_t wc = wct.widen (char (cinx));
RW_ASSERT (wc == data->wwidened_ [cinx]);
const char nc = wct.narrow (data->wide_ [winx], L'\0');
RW_ASSERT (nc == data->wnarrowed_ [winx]);
#endif // _RWSTD_NO_WCHAR_T
}
}
return 0;
}
} // extern "C"
/**************************************************************************/
static int
run_test (int, char**)
{
// find all installed locales for which setlocale(LC_ALL) succeeds
const char* const locale_list =
rw_opt_locales ? rw_opt_locales : rw_locales (_RWSTD_LC_ALL);
const std::size_t maxinx = sizeof locales / sizeof *locales;
// iterate over locales, initializing a global ctype_data array
// with LC_CTYPE data obtained from each locale
for (const char *name = locale_list; *name;
name += std::strlen (name) + 1) {
const std::size_t inx = nlocales;
locales [inx] = name;
CtypeData* const pdata = ctype_data + nlocales;
// compute the number of wide characters to populate
const std::size_t nwide =
sizeof pdata->wide_ / sizeof pdata->wide_ [0];
try {
const std::locale loc (name);
const std::ctype<char> &ct =
std::use_facet<std::ctype<char> >(loc);
const std::ctype<wchar_t> &wct =
std::use_facet<std::ctype<wchar_t> >(loc);
pdata->locale_name_ = name;
const std::size_t nchars =
sizeof pdata->widened_ / sizeof *pdata->widened_;
for (std::size_t i = 0; i != nchars; ++i) {
pdata->widened_ [i] = ct.widen (char (i));
pdata->wwidened_ [i] = wct.widen (char (i));
pdata->narrowed_ [i] = ct.narrow (char (i), '\0');
}
pdata->nwide_ = rw_get_wchars (pdata->wide_, nwide);
for (std::size_t i = 0; i != pdata->nwide_; ++i)
pdata->wnarrowed_ [i] = wct.narrow (pdata->wide_ [i], L'\0');
if (opt_shared_locale)
pdata->locale_ = loc;
++nlocales;
}
catch (...) {
// skip over a bad locale
}
if (nlocales == maxinx || nlocales == std::size_t (opt_nlocales))
break;
}
// avoid divide by zero in thread if there are no locales to test
rw_fatal (nlocales != 0, 0, __LINE__,
"failed to create one or more usable locales!");
rw_info (0, 0, 0,
"testing std::ctype<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
opt_nthreads, 1 != opt_nthreads,
opt_nloops, 1 != opt_nloops,
nlocales, int (nlocales), "%#s", locales);
rw_info (0, 0, 0, "exercising std::ctype<char>");
test_char = true;
test_wchar = false;
// create and start a pool of threads and wait for them to finish
int result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
#ifndef _RWSTD_NO_WCHAR_T
rw_info (0, 0, 0, "exercising std::ctype<wchar_t>");
test_char = false;
test_wchar = true;
// start a pool of threads to exercise the thread safety
// of the wchar_t specialization
result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
// exercise both the char and the wchar_t specializations
// at the same time
rw_info (0, 0, 0,
"exercising both std::ctype<char> and std::ctype<wchar_t>");
test_char = true;
test_wchar = true;
// start a pool of threads to exercise wstring thread safety
result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
#endif // _RWSTD_NO_WCHAR_T
return result;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
#ifdef _RWSTD_REENTRANT
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
opt_nthreads = rw_get_cpus ();
if (opt_nthreads < 2)
opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.ctype",
"thread safety", run_test,
"|-nloops#0 " // arg must be non-negative
"|-nthreads#0-* " // arg must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // arg must be provided
"|-shared-locale# ",
&opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
&opt_nlocales,
&rw_opt_setlocales,
&opt_shared_locale);
}

View File

@@ -0,0 +1,730 @@
/***************************************************************************
*
* 22.locale.ctype.narrow.cpp - tests exercising the narrow() and widen()
* member functions of the ctype facet
*
* $Id: 22.locale.ctype.narrow.cpp 650350 2008-04-22 01:35:17Z sebor $
*
***************************************************************************
*
* 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 2001-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
// DESCRIPTION: The test iterates over a subset of locales installed
// on a machine, calling the C character classification functions and
// their C++ counterpart(s), comparing the results of the calls against
// one another.
#include <rw/_defs.h>
#if defined __linux__
// on Linux define _XOPEN_SOURCE to get CODESET defined in <langinfo.h>
# define _XOPEN_SOURCE 500 /* Single Unix conformance */
// bring __int32_t into scope (otherwise <wctype.h> fails to compile)
# include <sys/types.h>
#endif // __linux__
// see Onyx PR #28150
#if defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x540
# include <wchar.h>
#endif // defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x540
#include <locale>
#include <climits>
#include <clocale>
#include <cstring>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cwchar> // for WEOF, btowc(), wctob()
#include <cwctype> // for iswxxx()
#if !defined (_MSC_VER)
# if !defined (LC_MESSAGES)
# define LC_MESSAGES _RWSTD_LC_MESSAGES
# endif // LC_MESSAGES
# include <langinfo.h>
#endif // _MSC_VER
#include <driver.h>
#include <file.h> // for SLASH
#include <rw_locale.h> // for rw_locale_query()
/**************************************************************************/
// the root of the locale directory (RWSTD_LOCALE_ROOT)
// not set here to avoid Solaris 7 putenv() bug (PR #30017)
const char* locale_root;
#define NLOOPS 25
#define MAX_STR_SIZE 16
#define LOCALES "{{en-US,de-DE,fr-FR,es-ES}-*-{ISO-8859-*,UTF-8,CP125?}," \
"{ja-JP-*-{EUC-JP,SHIFT_JIS,UTF-8,CP125?}}," \
"{zh-CN-*-{GB*,UTF-8,CP125?}}," \
"{ru-RU-*-{KOI*,UTF-8,CP125?}}}"
const char* locale_list = 0;
#define BEGIN_LOCALE_LOOP(num, locname, loop_cntrl) \
if (!locale_list) locale_list = rw_locale_query (LC_CTYPE, LOCALES); \
for (const char* locname = locale_list; \
locname && *locname; locname += std::strlen (locname) + 1) { \
_TRY { \
const std::locale loc (locname); \
const std::ctype<char> &ctc = \
_STD_USE_FACET (std::ctype<char>, loc); \
_RWSTD_UNUSED (ctc); \
const std::ctype<charT> &ctp = \
_STD_USE_FACET (std::ctype<charT>, loc); \
for (int loop_cntrl = 0; loop_cntrl < int (num); loop_cntrl++)
#define END_LOCALE_LOOP(locname) \
} \
_CATCH (...) { \
rw_assert (0, 0, __LINE__, \
"locale (\"%s\") threw an exception", locname); \
} \
}
// for notational convenience
typedef unsigned char UChar;
#define ALPHA std::ctype_base::alpha
#define UPPER std::ctype_base::upper
#define LOWER std::ctype_base::lower
#define DIGIT std::ctype_base::digit
#define SPACE std::ctype_base::space
#define CNTRL std::ctype_base::cntrl
#define PUNCT std::ctype_base::punct
#define XDIGIT std::ctype_base::xdigit
#define GRAPH std::ctype_base::graph
#define PRINT std::ctype_base::print
// wrapper functions for the c library char and wchar_t functions
std::ctype_base::mask libc_mask (int mask, char ch, const char *locname)
{
char curlocname [256];
if (locname) {
std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
if (0 == std::setlocale (LC_CTYPE, locname))
return std::ctype_base::mask ();
}
const int c = UChar (ch);
int result = 0;
if (mask & ALPHA && (std::isalpha)(c))
result |= ALPHA;
if (mask & CNTRL && (std::iscntrl)(c))
result |= CNTRL;
if (mask & DIGIT && (std::isdigit)(c))
result |= DIGIT;
if (mask & GRAPH && (std::isgraph)(c))
result |= GRAPH;
if (mask & LOWER && (std::islower)(c))
result |= LOWER;
if (mask & PRINT && (std::isprint)(c))
result |= PRINT;
if (mask & PUNCT && (std::ispunct)(c))
result |= PUNCT;
if (mask & SPACE && (std::isspace)(c))
result |= SPACE;
if (mask & UPPER && (std::isupper)(c))
result |= UPPER;
if (mask & XDIGIT && (std::isxdigit)(c))
result |= XDIGIT;
if (locname)
std::setlocale (LC_CTYPE, curlocname);
return std::ctype_base::mask (result);
}
inline bool libc_is (std::ctype_base::mask mask, char ch, const char *locname)
{
const std::ctype_base::mask m = libc_mask (mask, ch, locname);
return 0 != (m & mask);
}
const char* narrow (char *dst, const char *src)
{
if (src == dst || !src || !dst)
return src;
std::memcpy (dst, src, std::strlen (src) + 1);
return dst;
}
const char* widen (char *dst, const char *src)
{
if (src == dst || !src || !dst)
return src;
std::memcpy (dst, src, std::strlen (src) + 1);
return dst;
}
char widen (char, char ch, const char*)
{
return ch;
}
char narrow (char ch, const char*)
{
return ch;
}
// cond1() verifies condition [1] in test_narrow_widen()
// below using libc functions
bool cond1 (std::ctype_base::mask mask, char ch, const char *locname)
{
char curlocname [256];
std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
if (0 == std::setlocale (LC_CTYPE, locname))
return false;
#ifdef __SUNPRO_CC
// working around a SunPro bug (PR #28150)
using std::wint_t;
#endif // __SUNPRO_CC
#ifndef _RWSTD_NO_BTOWC
const std::wint_t wc = std::btowc (UChar (ch));
#elif !defined (_RWSTD_NO_MBSTOWCS)
wchar_t tmp;
const std::wint_t wc = 1 == std::mbstowcs (&tmp, &ch, 1) ? tmp : WEOF;
#else
const std::wint_t wc = WEOF;
#endif // _RWSTD_NO_BTOWC, _RWSTD_NO_MBSTOWCS
const bool result =
WEOF == wc || libc_is (mask, ch, 0) || !libc_is (mask, wchar_t (wc), 0);
std::setlocale (LC_CTYPE, curlocname);
return result;
}
// cond3() overloads verify condition [3] in test_narrow_widen()
// below using libc functions
bool cond3 (std::ctype_base::mask, char, const char*)
{
return true;
}
#ifndef _RWSTD_NO_WCHAR_T
const char* narrow (char *dst, const wchar_t *src)
{
static char buf [4096];
if (!src)
return 0;
if (!dst)
dst = buf;
std::size_t len = std::wcslen (src);
_RWSTD_ASSERT (len < sizeof buf);
len = std::wcstombs (dst, src, sizeof buf / sizeof *buf);
if (std::size_t (-1) == len)
*dst = 0;
return dst;
}
const wchar_t* widen (wchar_t *dst, const char *src)
{
static wchar_t buf [4096];
if (!src)
return 0;
if (!dst)
dst = buf;
std::size_t len = std::strlen (src);
_RWSTD_ASSERT (len < sizeof buf /sizeof *buf);
len = std::mbstowcs (dst, src, sizeof buf / sizeof *buf);
if (std::size_t (-1) == len)
*dst = 0;
return dst;
}
std::ctype_base::mask libc_mask (int mask, wchar_t ch, const char *locname)
{
char curlocname [256];
if (locname) {
std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
if (0 == std::setlocale (LC_CTYPE, locname))
return std::ctype_base::mask ();
}
int result = 0;
if (mask & ALPHA && (std::iswalpha)(ch))
result |= ALPHA;
if (mask & CNTRL && (std::iswcntrl)(ch))
result |= CNTRL;
if (mask & DIGIT && (std::iswdigit)(ch))
result |= DIGIT;
if (mask & GRAPH && (std::iswgraph)(ch))
result |= GRAPH;
if (mask & LOWER && (std::iswlower)(ch))
result |= LOWER;
if (mask & PRINT && (std::iswprint)(ch))
result |= PRINT;
if (mask & PUNCT && (std::iswpunct)(ch))
result |= PUNCT;
if (mask & SPACE && (std::iswspace)(ch))
result |= SPACE;
if (mask & UPPER && (std::iswupper)(ch))
result |= UPPER;
if (mask & XDIGIT && (std::iswxdigit)(ch))
result |= XDIGIT;
if (locname)
std::setlocale (LC_CTYPE, curlocname);
return std::ctype_base::mask (result);
}
bool libc_is (std::ctype_base::mask mask, wchar_t ch, const char *locname)
{
const std::ctype_base::mask m = libc_mask (mask, ch, locname);
return 0 != (m & mask);
}
wchar_t widen (wchar_t, char ch, const char *locname)
{
char curlocname [256];
std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
if (0 == std::setlocale (LC_CTYPE, locname))
return UChar (ch);
wchar_t result;
#ifndef _RWSTD_NO_BTOWC
result = std::btowc (UChar (ch));
#elif !defined (_RWSTD_NO_MBTOWC)
if (1 != std::mbtowc (&result, &ch, 1))
result = wchar_t (WEOF);
#else
result = UChar (ch);
#endif // _RWSTD_NO_BTOWC, _RWSTD_NO_MBTOWC
if (locname)
std::setlocale (LC_CTYPE, curlocname);
return result;
}
char narrow (wchar_t ch, const char *locname)
{
char curlocname [256];
std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
if (0 == std::setlocale (LC_CTYPE, locname))
return UChar (ch);
char result [MB_LEN_MAX];
#ifndef _RWSTD_NO_WCTOB
result [0] = std::wctob (ch);
#elif !defined (_RWSTD_NO_WCTOMB)
if (1 != std::wctomb (result, ch))
result [0] = '\377';
#else
result [0] = char (ch);
#endif // _RWSTD_NO_WCTOB, _RWSTD_NO_WCTOMB
if (locname)
std::setlocale (LC_CTYPE, curlocname);
return result [0];
}
bool cond3 (std::ctype_base::mask mask, wchar_t ch, const char *locname)
{
char curlocname [256];
std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
if (0 == std::setlocale (LC_CTYPE, locname))
return false;
#ifndef _RWSTD_NO_WCTOB
const int byte = std::wctob (ch);
#elif !defined (_RWSTD_NO_WCTOMB)
char buf [MB_LEN_MAX];
const int byte = 1 == std::wctomb (buf, ch) ? buf [0] : EOF;
#else
const int byte = EOF;
#endif // _RWSTD_NO_WCTOB, _RWSTD_NO_WCTOMB
const bool result =
EOF == byte || !libc_is (mask, char (byte), 0) || libc_is (mask, ch, 0);
std::setlocale (LC_CTYPE, curlocname);
return result;
}
#endif // _RWSTD_NO_WCHAR_T
/**************************************************************************/
template <class charT>
void test_narrow_widen (charT, const char *cname)
{
// 22.2.1.1.2, p11 requires that the conditions below hold for all
// facets ctc and ct whose types are ctype<char> and ctype<charT>,
// respectively:
// [1] (ctc.is (M, c) || !ct.is (M, ctc.do_widen (c))) holds for
// all narrow characters c
// i.e., narrow characters that are NOT members of a certain
// category may not belong to the same category when widened
// Note: this implies that some sort of code conversion may
// be necessary in order to implement a conforming do_widen()
// 22.2.1.1.2, p13 requires that:
// [2] (ct.do_widen (ct.do_narrow (c, dfault)) == c) holds unless
// (ct.do_narrow (c, dfault) == dfault) holds
// [3] (ct.is (M, c) || !ctc.is (M, ct.do_narrow (c, dfault))) holds
// unless (ct.do_narrow(c, dfault) == dfault) holds
//
// C99: each of the iswxxx() functions returns true for each
// wide character that corresponds (as if by a call to the
// wctob() function) to a single-byte character for which the
// corresponding character classification function from 7.4.1
// returns true, except that the iswgraph() and iswpunct()
// functions may differ with respect to wide characters other
// than L' ' that are both printing and white-space wide
// characters.
//
// [4] (ct.do_narrow (c, default) - '0') evaluates to the digit
// value of the character for all c for which ct.is(digit, c)
// returns true
rw_info (0, 0, __LINE__,
"std::ctype<%s>::narrow(%1$s), widen(char)",
cname);
rw_info (0, 0, __LINE__,
"std::ctype<%s>::narrow(const %1$s*, const %1$s*, char*), "
"widen(const char*, const char*, %1$s*)", cname);
#define STR(x) #x
// verify condition [1] above; if it fails, verify that
// the same condition also fails to hold when using the
// corresponding libc functions
#define COND1(what) \
if (!(ctc.is (what, c) || !ctp.is (what, ctp.widen (c)))) { \
rw_assert (!cond1 (what, c, locname), 0, __LINE__, \
"ctype<char>::is (" STR (what) ", %{#lc})" \
" || !ctype<%1$s>::is (" STR (what) ", " \
"ctype<%s>::widen (%{#lc}) = %{#lc})" \
" returned false in locale(%#s)", \
c, cname, c, ctp.widen (c), locname); \
} else (void)0
// verify condition [3] above; if it fails, verify that
// the same condition also fails to hold when using the
// corresponding libc functions
#define COND3(what) \
if ( ctp.narrow (ch, dfault) != dfault \
&& !(ctp.is (what, ch) || !ctc.is (what, ctp.narrow (ch, dfault)))) { \
rw_assert (!cond3 (what, ch, locname), 0, __LINE__, \
"ctype<%s>::is (" STR (what) ", %{#lc})" \
" || !ctype<char>::is (" STR (what) ", " \
"ctype<%1$s>::narrow (%{#lc}, %{#c}) = %{#lc})" \
" returned false in locale(%#s)", cname, ch, \
ch, dfault, ctp.narrow (ch, '\0'), \
locname); \
} else (void)0
char c_locname [256];
std::strcpy (c_locname, std::setlocale (LC_ALL, 0));
BEGIN_LOCALE_LOOP (UCHAR_MAX, locname, i) {
#if defined (_RWSTD_OS_SUNOS) && _RWSTD_OS_MAJOR == 5 && _RWSTD_OS_MINOR <= 10
// avoid a libc SIGSEGV in mbtowc() in zh_HK and zh_TW
// locales encoded using the BIG5 codeset (see bug #603)
if ( 0 == std::strncmp ("zh_HK.BIG5", locname, 10)
|| 0 == std::strncmp ("zh_TW.BIG5", locname, 10))
continue;
#endif // SunOS < 5.10
{
// verify that the global C locale stays unchanged
const char* const curlocname = std::setlocale (LC_ALL, 0);
rw_assert (!std::strcmp (c_locname, curlocname), 0, __LINE__,
"setlocale(LC_ALL, 0) == \"%s\", got \"%s\"",
c_locname, curlocname);
}
if (0 == i)
rw_info (0, 0, __LINE__, "std::ctype<%s> in locale(%#s)",
cname, locname);
const char c = char (i);
const charT ch = charT (i);
// verify that condition [1] holds
COND1 (ALPHA);
COND1 (CNTRL);
COND1 (DIGIT);
COND1 (GRAPH);
COND1 (LOWER);
COND1 (PRINT);
COND1 (PUNCT);
COND1 (SPACE);
COND1 (UPPER);
COND1 (XDIGIT);
// verify that condition [2] holds
char dfault = c ? '\0' : '\1';
const charT ret = ctp.widen (ctp.narrow (ch, dfault));
if (ret != charT (dfault) && ret != ch) {
rw_assert (ch != widen (ch, narrow (ch, locname), locname),
0, __LINE__,
"ctype<%s>::widen (ctype<%1$s>::narrow "
"(%{#lc}, %{#c})) == %{#c}; got %{#c} "
"in locale (%#s)",
cname, ch, dfault, ch, ret, locname);
}
// finally verify that condition [3] holds
COND3 (ALPHA);
COND3 (CNTRL);
COND3 (DIGIT);
COND3 (GRAPH);
COND3 (LOWER);
COND3 (PRINT);
COND3 (PUNCT);
COND3 (SPACE);
COND3 (UPPER);
COND3 (XDIGIT);
// now perform a relitively simple sanity check on the 3-argument
// overloads of narrow() and widen(). Make sure that the 3-argument
// overloads return the same value that the other overload produces
// Only do this the first time through the locale list.
if (i == 0) {
// arrays of all tested narrow and wide characters
charT wide_chars [UCHAR_MAX + 1];
char narrow_chars [UCHAR_MAX + 1];
charT narrow_in [UCHAR_MAX + 1];
char widen_in [UCHAR_MAX + 1];
// zero out the last element to allow printing
wide_chars [UCHAR_MAX] = charT ();
narrow_chars [UCHAR_MAX] = char ();
narrow_in [UCHAR_MAX] = charT ();
widen_in [UCHAR_MAX] = char ();
// set the `dfault' character to something unlikely
// but other than '\0'
dfault = '\377';
for (unsigned j = 0; j <= UCHAR_MAX; j++) {
wide_chars [j] = ctp.widen (char (j));
narrow_chars [j] = ctp.narrow (wide_chars [j], dfault);
narrow_in [j] = ctp.widen (char (j));
widen_in [j] = char (j);
}
charT widen_out [UCHAR_MAX + 1];
char narrow_out [UCHAR_MAX + 1];
widen_out [UCHAR_MAX] = charT ();
narrow_out [UCHAR_MAX] = char ();
// narrow source buffer into the destination
// and compare with expected values
ctp.narrow (narrow_in,
narrow_in + UCHAR_MAX + 1,
dfault,
narrow_out);
bool success =
!std::memcmp (narrow_chars, narrow_out, sizeof narrow_chars);
rw_assert (success, 0, __LINE__,
"ctype<%s>::narrow (%{*.*Ac}\", ... , %{#c}) "
"== %{.*Ac}, got %{.*Ac} in locale (%#s)", cname,
int (sizeof *narrow_in), UCHAR_MAX, narrow_in, dfault,
UCHAR_MAX, narrow_chars, UCHAR_MAX, narrow_out,
locname);
// widen source buffer into the destination
// and compare with expected values
ctp.widen (widen_in,
widen_in + UCHAR_MAX + 1,
widen_out);
success = !std::memcmp (wide_chars, widen_out, sizeof wide_chars);
rw_assert (success, 0, __LINE__,
"ctype<%s>::widen (%{.*Ac}, ...) == "
"%{*.*Ac}, got %{*.*Ac} in locale (%#s)",
cname, UCHAR_MAX, widen_in,
int (sizeof *wide_chars), UCHAR_MAX, wide_chars,
int (sizeof *wide_chars), UCHAR_MAX, widen_out,
locname);
}
} END_LOCALE_LOOP (locname);
}
/**************************************************************************/
// exercise the behavior of the libc-based C++ locale implementation
template <class charT>
void test_libc (charT, const char *cname)
{
test_narrow_widen (charT (), cname);
}
/**************************************************************************/
// exercise the behavior of our own C++ locale implementation
template <class charT>
void test_libstd (charT, const char *cname)
{
rw_warn (0, 0, __LINE__,
"stdcxx implementation of std::ctype<%s> not exercised",
cname);
}
/**************************************************************************/
template <class charT>
void run_test (charT, const char *cname)
{
if (0) {
// do a compile time only test on use_facet and has_facet
_STD_HAS_FACET (std::ctype_byname<charT>, std::locale ());
_STD_USE_FACET (std::ctype_byname<charT>, std::locale ());
}
// exercise the behavior of the libc-based C++ locale implementation
test_libc (charT (), cname);
// exercise the behavior of our own C++ locale implementation
test_libstd (charT (), cname);
}
/**************************************************************************/
static int
run_test (int, char**)
{
// set the global locale_list pointer to point to the array
// of NUL-separated locale names set on the command line via
// the --locales=... option, if specified, or to 0 (in which
// case we'll generate our own list)
locale_list = rw_opt_locales;
run_test (char (), "char");
#ifndef _RWSTD_NO_WCHAR_T
run_test (wchar_t (), "wchar_t");
#endif // _RWSTD_NO_WCHAR_T
return 0;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
return rw_test (argc, argv, __FILE__,
"lib.category.ctype",
"narrow and widen",
run_test,
"|-locales= ",
&rw_opt_setlocales,
(void*)0 /* sentinel */);
}

View File

@@ -0,0 +1,863 @@
/***************************************************************************
*
* 22.locale.ctype.scan.cpp - Tests exercising the scan() of ctype facet
*
* $Id: 22.locale.ctype.scan.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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 2001-2006 Rogue Wave Software.
*
**************************************************************************/
// DESCRIPTION: test iterates over the locales installed on a machine,
// calling the C character classification functions and
// their C++ counterpart(s), comparing the results of
// the calls against one another.
#include <rw/_defs.h>
#if defined __linux__
// on Linux define _XOPEN_SOURCE to get CODESET defined in <langinfo.h>
# define _XOPEN_SOURCE 500 /* Single Unix conformance */
// bring __int32_t into scope (otherwise <wctype.h> fails to compile)
# include <sys/types.h>
#endif // __linux__
// see Onyx PR #28150
#if defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x540
# include <wchar.h>
#endif // defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x540
#include <locale>
#include <climits>
#include <clocale>
#include <cstring>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cwchar> // for WEOF, btowc(), wctob()
#include <cwctype> // for iswxxx()
#if !defined (_MSC_VER)
# if !defined (LC_MESSAGES)
# define LC_MESSAGES _RWSTD_LC_MESSAGES
# endif // LC_MESSAGES
# include <langinfo.h>
#endif // _MSC_VER
#include <driver.h>
#include <file.h> // for SLASH
#include <rw_locale.h> // for rw_locale_query()
/**************************************************************************/
// the root of the locale directory (RWSTD_LOCALE_ROOT)
// not set here to avoid Solaris 7 putenv() bug (PR #30017)
const char* locale_root;
#define NLOOPS 25
#define MAX_STR_SIZE 16
#define LOCALES "{{en-US,de-DE,fr-FR,es-ES}-*-{ISO-8859-*,UTF-8,CP125?}," \
"{ja-JP-*-{EUC-JP,SHIFT_JIS,UTF-8,CP125?}}," \
"{zh-CN-*-{GB*,UTF-8,CP125?}}," \
"{ru-RU-*-{KOI*,UTF-8,CP125?}}}"
const char* locale_list = 0;
#define BEGIN_LOCALE_LOOP(num, locname, loop_cntrl) \
if (!locale_list) locale_list = rw_locale_query (LC_CTYPE, LOCALES); \
for (const char* locname = locale_list; \
locname && *locname; locname += std::strlen (locname) + 1) { \
_TRY { \
const std::locale loc (locname); \
const std::ctype<char> &ctc = \
_STD_USE_FACET (std::ctype<char>, loc); \
_RWSTD_UNUSED (ctc); \
const std::ctype<charT> &ctp = \
_STD_USE_FACET (std::ctype<charT>, loc); \
for (int loop_cntrl = 0; loop_cntrl < int (num); loop_cntrl++)
#define END_LOCALE_LOOP(locname) \
} \
_CATCH (...) { \
rw_assert (0, 0, __LINE__, \
"locale (\"%s\") threw an exception", locname); \
} \
}
// for notational convenience
typedef unsigned char UChar;
#define ALPHA std::ctype_base::alpha
#define UPPER std::ctype_base::upper
#define LOWER std::ctype_base::lower
#define DIGIT std::ctype_base::digit
#define SPACE std::ctype_base::space
#define CNTRL std::ctype_base::cntrl
#define PUNCT std::ctype_base::punct
#define XDIGIT std::ctype_base::xdigit
#define GRAPH std::ctype_base::graph
#define PRINT std::ctype_base::print
// wrapper functions for the c library char and wchar_t functions
int libc_isalpha (char ch)
{
return (std::isalpha)(UChar (ch));
}
int libc_isspace (char ch)
{
return (std::isspace)(UChar (ch));
}
int libc_isprint (char ch)
{
return (std::isprint)(UChar (ch));
}
int libc_iscntrl (char ch)
{
return (std::iscntrl)(UChar (ch));
}
int libc_isupper (char ch)
{
return (std::isupper)(UChar (ch));
}
int libc_islower (char ch)
{
return (std::islower)(UChar (ch));
}
int libc_isdigit (char ch)
{
return (std::isdigit)(UChar (ch));
}
int libc_ispunct (char ch)
{
return (std::ispunct)(UChar (ch));
}
int libc_isxdigit (char ch)
{
return (std::isxdigit)(UChar (ch));
}
int libc_isalnum (char ch)
{
return (std::isalnum)(UChar (ch));
}
int libc_isgraph (char ch)
{
return (std::isgraph)(UChar (ch));
}
std::ctype_base::mask libc_mask (int mask, char ch, const char *locname)
{
char curlocname [256];
if (locname) {
std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
if (0 == std::setlocale (LC_CTYPE, locname))
return std::ctype_base::mask ();
}
const int c = UChar (ch);
int result = 0;
if (mask & ALPHA && (std::isalpha)(c))
result |= ALPHA;
if (mask & CNTRL && (std::iscntrl)(c))
result |= CNTRL;
if (mask & DIGIT && (std::isdigit)(c))
result |= DIGIT;
if (mask & GRAPH && (std::isgraph)(c))
result |= GRAPH;
if (mask & LOWER && (std::islower)(c))
result |= LOWER;
if (mask & PRINT && (std::isprint)(c))
result |= PRINT;
if (mask & PUNCT && (std::ispunct)(c))
result |= PUNCT;
if (mask & SPACE && (std::isspace)(c))
result |= SPACE;
if (mask & UPPER && (std::isupper)(c))
result |= UPPER;
if (mask & XDIGIT && (std::isxdigit)(c))
result |= XDIGIT;
if (locname)
std::setlocale (LC_CTYPE, curlocname);
return std::ctype_base::mask (result);
}
inline bool libc_is (std::ctype_base::mask mask, char ch, const char *locname)
{
const std::ctype_base::mask m = libc_mask (mask, ch, locname);
return 0 != (m & mask);
}
std::size_t c_strlen (const char *s1)
{
return std::strlen (s1);
}
const char* widen (char *dst, const char *src)
{
if (src == dst || !src || !dst)
return src;
std::memcpy (dst, src, std::strlen (src) + 1);
return dst;
}
char widen (char, char ch, const char*)
{
return ch;
}
#ifndef _RWSTD_NO_WCHAR_T
int libc_isalpha (wchar_t ch)
{
return (std::iswalpha)(ch);
}
int libc_isspace (wchar_t ch)
{
return (std::iswspace)(ch);
}
int libc_isprint (wchar_t ch)
{
return (std::iswprint)(ch);
}
int libc_iscntrl (wchar_t ch)
{
return (std::iswcntrl)(ch);
}
int libc_isupper (wchar_t ch)
{
return (std::iswupper)(ch);
}
int libc_islower (wchar_t ch)
{
return (std::iswlower)(ch);
}
int libc_isdigit (wchar_t ch)
{
return (std::iswdigit)(ch);
}
int libc_ispunct (wchar_t ch)
{
return (std::iswpunct)(ch);
}
int libc_isxdigit (wchar_t ch)
{
return (std::iswxdigit)(ch);
}
int libc_isalnum (wchar_t ch)
{
return (std::iswalnum)(ch);
}
int libc_isgraph (wchar_t ch)
{
return (std::iswgraph)(ch);
}
wchar_t libc_tolower (wchar_t ch)
{
return (std::towlower)(ch);
}
wchar_t libc_toupper (wchar_t ch)
{
return (std::towupper)(ch);
}
std::size_t c_strlen (const wchar_t *s1)
{
return std::wcslen (s1);
}
const wchar_t* widen (wchar_t *dst, const char *src)
{
static wchar_t buf [4096];
if (!src)
return 0;
if (!dst)
dst = buf;
std::size_t len = std::strlen (src);
_RWSTD_ASSERT (len < sizeof buf /sizeof *buf);
len = std::mbstowcs (dst, src, sizeof buf / sizeof *buf);
if (std::size_t (-1) == len)
*dst = 0;
return dst;
}
std::ctype_base::mask libc_mask (int mask, wchar_t ch, const char *locname)
{
char curlocname [256];
if (locname) {
std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
if (0 == std::setlocale (LC_CTYPE, locname))
return std::ctype_base::mask ();
}
int result = 0;
if (mask & ALPHA && (std::iswalpha)(ch))
result |= ALPHA;
if (mask & CNTRL && (std::iswcntrl)(ch))
result |= CNTRL;
if (mask & DIGIT && (std::iswdigit)(ch))
result |= DIGIT;
if (mask & GRAPH && (std::iswgraph)(ch))
result |= GRAPH;
if (mask & LOWER && (std::iswlower)(ch))
result |= LOWER;
if (mask & PRINT && (std::iswprint)(ch))
result |= PRINT;
if (mask & PUNCT && (std::iswpunct)(ch))
result |= PUNCT;
if (mask & SPACE && (std::iswspace)(ch))
result |= SPACE;
if (mask & UPPER && (std::iswupper)(ch))
result |= UPPER;
if (mask & XDIGIT && (std::iswxdigit)(ch))
result |= XDIGIT;
if (locname)
std::setlocale (LC_CTYPE, curlocname);
return std::ctype_base::mask (result);
}
bool libc_is (std::ctype_base::mask mask, wchar_t ch, const char *locname)
{
const std::ctype_base::mask m = libc_mask (mask, ch, locname);
return 0 != (m & mask);
}
wchar_t widen (wchar_t, char ch, const char *locname)
{
char curlocname [256];
std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
if (0 == std::setlocale (LC_CTYPE, locname))
return UChar (ch);
wchar_t result;
#ifndef _RWSTD_NO_BTOWC
result = std::btowc (UChar (ch));
#elif !defined (_RWSTD_NO_MBTOWC)
if (1 != std::mbtowc (&result, &ch, 1))
result = wchar_t (WEOF);
#else
result = UChar (ch);
#endif // _RWSTD_NO_BTOWC, _RWSTD_NO_MBTOWC
if (locname)
std::setlocale (LC_CTYPE, curlocname);
return result;
}
#endif // _RWSTD_NO_WCHAR_T
template <class charT>
void gen_str (charT *str, std::size_t size)
{
// generate a random string with the given size
// we do not attempt to check that the size is within the
// valid range for the string.
for (std::size_t i = 0; i < size; i++){
str [i] = UChar (std::rand () % UCHAR_MAX);
// only increment if we are not going to roll over
if (str [i] != charT (UCHAR_MAX - 1U))
++str [i];
}
str [size] = charT ();
_RWSTD_ASSERT (c_strlen (str) == size);
}
/**************************************************************************/
template <class charT>
void test_scan (charT, const char *cname)
{
rw_info (0, 0, __LINE__, "std::ctype<%s>::scan_is(), scan_not()", cname);
charT str [MAX_STR_SIZE + 1];
BEGIN_LOCALE_LOOP (NLOOPS, locname, j) {
const std::size_t size = std::size_t (j % MAX_STR_SIZE);
// generate a random string
gen_str (str, size);
// set the global C locale to default to make sure
// the C++ library does not asume a set value
std::setlocale (LC_CTYPE, "");
// call scan_is and scan_not using each mask and compare it to
// the results found when using the c library
const charT* alpha_is = ctp.scan_is (ALPHA, str, str + size);
const charT* alpha_not = ctp.scan_not (ALPHA, str, str + size);
const charT* space_is = ctp.scan_is (SPACE, str, str + size);
const charT* space_not = ctp.scan_not (SPACE, str, str + size);
const charT* print_is = ctp.scan_is (PRINT, str, str + size);
const charT* print_not = ctp.scan_not (PRINT, str, str + size);
const charT* cntrl_is = ctp.scan_is (CNTRL, str, str + size);
const charT* cntrl_not = ctp.scan_not (CNTRL, str, str + size);
const charT* upper_is = ctp.scan_is (UPPER, str, str + size);
const charT* upper_not = ctp.scan_not (UPPER, str, str + size);
const charT* lower_is = ctp.scan_is (LOWER, str, str + size);
const charT* lower_not = ctp.scan_not (LOWER, str, str + size);
const charT* digit_is = ctp.scan_is (DIGIT, str, str + size);
const charT* digit_not = ctp.scan_not (DIGIT, str, str + size);
const charT* punct_is = ctp.scan_is (PUNCT, str, str + size);
const charT* punct_not = ctp.scan_not (PUNCT, str, str + size);
const charT* xdigit_is = ctp.scan_is (XDIGIT, str, str + size);
const charT* xdigit_not = ctp.scan_not (XDIGIT, str, str + size);
// set the global C locale to locname for the C library call
std::setlocale (LC_CTYPE, locname);
// find the first character in the string that is of the specified
// type
charT first = 0;
charT first_not = 0;
_RWSTD_SIZE_T i;
int success;
#define SCAN(what) \
for (i = 0; i < size; i++) { \
if (libc_is##what (str [i])) { \
first = (str [i]); \
break; \
} \
} \
success = what##_is != (str + size) || 0 == first \
|| *what##_is != first; \
rw_assert (success, 0, __LINE__, \
"ctype<%s>::scan_is(" #what ", %{#lc}) " \
"== %{*Ac}, got %{*Ac} in locale (%#s)", \
cname, int (sizeof *str), first, \
int (sizeof *what##_is), what##_is, \
locname); \
\
first = 0; \
for (i = 0; i < size; i++) { \
if (!libc_is##what (str[i])) { \
first_not = (str[i]); \
break; \
} \
} \
success = what##_not != (str + size) || 0 == first_not \
|| *what##_not == first_not; \
rw_assert (success, 0, __LINE__, \
"ctype<%s>::scan_not(" #what ", %{#lc}) " \
"== %{*Ac}, got %{*Ac} in locale (%#s)", \
cname, int (sizeof *str), first, \
int (sizeof *what##_not), what##_not, \
locname); \
\
first_not = 0
// test all classes of characters
SCAN (alpha);
SCAN (space);
SCAN (print);
SCAN (cntrl);
SCAN (upper);
SCAN (lower);
SCAN (digit);
SCAN (punct);
SCAN (xdigit);
} END_LOCALE_LOOP (locname);
}
/**************************************************************************/
template <class charT>
void test_libc (charT, const char *cname)
{
test_scan (charT (), cname);
}
/**************************************************************************/
template <class charT>
void test_libstd_scan_is (charT, const char *cname,
const std::ctype<charT> &ct,
const char* str, std::ctype_base::mask mask,
int expected_idx, int fwiden = 0)
{
// convert narrow string to a (possibly) wide representation
charT wstrbuf [256];
charT* wstr = wstrbuf;
// If instructed to use the facet widen method, do so, otherwise
// use widen helper function that in turn uses C lib mbstowcs
if (fwiden == 0)
widen (wstrbuf, str);
else
ct.widen (str, str + std::strlen (str), wstrbuf);
const int success =
&wstr [expected_idx] == ct.scan_is (mask, wstr, wstr + c_strlen (wstr));
rw_assert (success, 0, __LINE__,
"ctype<%s>::scan_is() returned an unexpected value",
cname);
}
/**************************************************************************/
template <class charT>
void test_libstd_scan_not (charT, const char *cname,
const std::ctype<charT> &ct,
const char* str, std::ctype_base::mask mask,
int expected_idx, int fwiden = 0)
{
// convert narrow string to a (possibly) wide representation
charT wstrbuf [256];
charT* wstr = wstrbuf;
// If instructed to use the facet widen method, do so, otherwise
// use widen helper function that in turn uses C lib mbstowcs
if (fwiden == 0)
widen (wstrbuf, str);
else
ct.widen (str, str + std::strlen (str), wstrbuf);
const int success =
&wstr[expected_idx] == ct.scan_not (mask, wstr, wstr + c_strlen (wstr));
rw_assert (success, 0, __LINE__,
"ctype<%s>::scan_not() returned an unexpected value",
cname);
}
/**************************************************************************/
template <class charT>
void test_libstd (charT, const char *cname)
{
const char cmap_1[] = {
"<code_set_name> \"ANSI_X3.4-1968\"\n"
"<mb_cur_max> 1\n"
"<mb_cur_min> 1\n"
"CHARMAP\n"
"<U0000> \\x00\n"
"<U0001> \\x01\n"
"<U0002> \\x02\n"
"<U0003> \\x03\n"
"<U0004> \\x04\n"
"<U0005> \\x05\n"
"<U0006> \\x06\n"
"<U0007> \\x07\n"
"<U0008> \\x08\n"
"<U0009> \\x09\n"
"<U000a> \\x0a\n"
"<U000b> \\x0b\n"
"<U000c> \\x0c\n"
"<U000d> \\x0d\n"
"<U000e> \\x0e\n"
"<U000f> \\x0f\n"
"<U0010> \\x10\n"
"<U0011> \\x11\n"
"<U0012> \\x12\n"
"<U0013> \\x13\n"
"<U0014> \\x14\n"
"<U0015> \\x15\n"
"<U0016> \\x16\n"
"<U0017> \\x17\n"
"<U0018> \\x18\n"
"<U0019> \\x19\n"
"<U001a> \\x1a\n"
"<U001b> \\x1b\n"
"<U001c> \\x1c\n"
"<U001d> \\x1d\n"
"<U001e> \\x1e\n"
"<U001f> \\x1f\n"
"<U0020> \\x20\n"
"<U0021> \\x21\n"
"<U0022> \\x22\n"
"<U0023> \\x23\n"
"<U0024> \\x24\n"
"<U0025> \\x25\n"
"<U0026> \\x26\n"
"<U0027> \\x27\n"
"<U0028> \\x28\n"
"<U0029> \\x29\n"
"<U002a> \\x2a\n"
"<U002b> \\x2b\n"
"<U002c> \\x2c\n"
"<U002d> \\x2d\n"
"<U002e> \\x2e\n"
"<U002f> \\x2f\n"
"<U0030> \\x30\n"
"<U0031> \\x31\n"
"<U0032> \\x32\n"
"<U0033> \\x33\n"
"<U0034> \\x34\n"
"<U0035> \\x35\n"
"<U0036> \\x36\n"
"<U0037> \\x37\n"
"<U0038> \\x38\n"
"<U0039> \\x39\n"
"<U003a> \\x3a\n"
"<U003b> \\x3b\n"
"<U003c> \\x3c\n"
"<U003d> \\x3d\n"
"<U003e> \\x3e\n"
"<U003f> \\x3f\n"
"<U0040> \\x40\n"
"<U0041> \\x41\n"
"<U0042> \\x42\n"
"<U0043> \\x43\n"
"<U0044> \\x44\n"
"<U0045> \\x45\n"
"<U0046> \\x46\n"
"<U0047> \\x47\n"
"<U0048> \\x48\n"
"<U0049> \\x49\n"
"<U004a> \\x4a\n"
"<U004b> \\x4b\n"
"<U004c> \\x4c\n"
"<U004d> \\x4d\n"
"<U004e> \\x4e\n"
"<U004f> \\x4f\n"
"<U0050> \\x50\n"
"<U0051> \\x51\n"
"<U0052> \\x52\n"
"<U0053> \\x53\n"
"<U0054> \\x54\n"
"<U0055> \\x55\n"
"<U0056> \\x56\n"
"<U0057> \\x57\n"
"<U0058> \\x58\n"
"<U0059> \\x59\n"
"<U005a> \\x5a\n"
"<U005b> \\x5b\n"
"<U005c> \\x5c\n"
"<U005d> \\x5d\n"
"<U005e> \\x5e\n"
"<U005f> \\x5f\n"
"<U0060> \\x60\n"
"<U0061> \\x61\n"
"<U0062> \\x62\n"
"<U0063> \\x63\n"
"<U0064> \\x64\n"
"<U0065> \\x65\n"
"<U0066> \\x66\n"
"<U0067> \\x67\n"
"<U0068> \\x68\n"
"<U0069> \\x69\n"
"<U006a> \\x6a\n"
"<U006b> \\x6b\n"
"<U006c> \\x6c\n"
"<U006d> \\x6d\n"
"<U006e> \\x6e\n"
"<U006f> \\x6f\n"
"<U0070> \\x70\n"
"<U0071> \\x71\n"
"<U0072> \\x72\n"
"<U0073> \\x73\n"
"<U0074> \\x74\n"
"<U0075> \\x75\n"
"<U0076> \\x76\n"
"<U0077> \\x77\n"
"<U0078> \\x78\n"
"<U0079> \\x79\n"
"<U007a> \\x7a\n"
"<U007b> \\x7b\n"
"<U007c> \\x7c\n"
"<U007d> \\x7d\n"
"<U007e> \\x7e\n"
"<U007f> \\x7f\n"
"<U1000> \\xa0\n"
"<U1001> \\xa1\n"
"<U1002> \\xa2\n"
"END CHARMAP\n"
};
const char loc_1[] = {
"escape_char /\n"
"LC_CTYPE\n"
"# <A> <B> <C> MYANMAR LETTER KHA\n"
"upper <U0041>;<U0042>;<U0043>;<U1001>\n"
" <a> <b> <c> MYANMAR LETTER KA\n"
"lower <U0061>;<U0062>;<U0063>;<U1000>\n"
"alpha <U0061>;<U0062>;<U0063>;<U0041>;"
"<U0042>;<U0043>;<U1000>;<U1001>\n"
"digit <U0031>;<U0032>;<U0033>;<U1002>\n"
"space <U0020>\n"
"cntrl <U0000>\n"
" <!> <\">\n"
"punct <U0021>; <U0022>\n"
"graph <U0041>;<U0042>;<U0043>;<U0061>;<U0062>;<U0063>;"
"<U1000>;<U1001>;<U1002>;<U1003>;<U1004>;<U1005>;"
"<U0031>;<U0032>;<U0033>;<U0020>;<U0021>;<U0022>\n"
"print <U0041>;<U0042>;<U0043>;"
"<U0061>;<U0062>;<U0063>;"
"<U1000>;<U1001>;<U1002>;<U1003>;<U1004>;<U1005>;"
"<U0031>;<U0032>;<U0033>;<U0020>;<U0021>;<U0022>\n"
"xdigit <U0041>;<U0042>;<U0043>;<U0061>;<U0062>;"
"<U0063>;<U0031>;<U0032>;<U0033>\n"
"END LC_CTYPE\n"
};
//invoke rw_create_locale to build a locale to test with
const char* const locname = rw_create_locale (cmap_1, loc_1);
if (!rw_error (0 != locname, 0, __LINE__,
"failed to create a locale in %s", locale_root))
return;
const std::locale loc (locname);
const std::ctype<charT> &ct =
_STD_USE_FACET (std::ctype<charT>, loc);
ct._C_opts |= ct._C_use_libstd;
ct._C_opts &= ~ct._C_use_libc;
// now check the scan functions
rw_info (0, 0, __LINE__,
"std::ctype<%s>::scan_is(const %1$s*, const %1$s, mask*) "
"in locale(%#s)", cname, locname);
test_libstd_scan_is (charT (), cname, ct, "abc1BC", DIGIT, 3);
test_libstd_scan_is (charT (), cname, ct, "abc123B ", SPACE, 7);
test_libstd_scan_is (charT (), cname, ct, "abc123", LOWER, 0);
test_libstd_scan_is (charT (), cname, ct, "abc123", UPPER, 6);
test_libstd_scan_is (charT (), cname, ct, "abc1ABC", DIGIT | UPPER, 3);
test_libstd_scan_is (charT (), cname, ct, "abcA2BC", DIGIT | UPPER, 3);
if (sizeof(charT) > 1) {
test_libstd_scan_is (charT (), cname, ct, "ABC\xa0xyz", LOWER, 3, 1);
test_libstd_scan_is (charT (), cname, ct, "abcx\xa1yz", UPPER, 4, 1);
}
rw_info (0, 0, __LINE__,
"std::ctype<%s>::scan_not(const %1$s*, const %1$s, mask*) "
"in locale(%#s)", cname, locname);
test_libstd_scan_not (charT (), cname, ct, "abc1BC", ALPHA, 3);
test_libstd_scan_not (charT (), cname, ct, "aaBBcc", LOWER, 2);
test_libstd_scan_not (charT (), cname, ct, "abc1BC", DIGIT, 0);
test_libstd_scan_not (charT (), cname, ct, "abc1BC", PRINT, 6);
if (sizeof(charT) > 1) {
test_libstd_scan_not (charT (), cname, ct, "abc\xa2xyz", ALPHA, 3, 1);
test_libstd_scan_not (charT (), cname, ct, "123\xa1yz ", DIGIT, 3, 1);
}
}
/**************************************************************************/
template <class charT>
void run_test (charT, const char *cname)
{
if (0) {
// do a compile time only test on use_facet and has_facet
_STD_HAS_FACET (std::ctype_byname<charT>, std::locale ());
_STD_USE_FACET (std::ctype_byname<charT>, std::locale ());
}
test_libc (charT (), cname);
test_libstd (charT (), cname);
}
/**************************************************************************/
static int
run_test (int, char**)
{
run_test (char (), "char");
run_test (wchar_t (), "wchar_t");
return 0;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
return rw_test (argc, argv, __FILE__,
"lib.category.ctype",
0 /* no comment */,
run_test,
"",
(void*)0 /* sentinel */);
}

View File

@@ -0,0 +1,496 @@
/***************************************************************************
*
* 22.locale.ctype.tolower.cpp - Tests exercising the tolower() of ctype facet
*
* $Id: 22.locale.ctype.tolower.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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 2001-2006 Rogue Wave Software.
*
**************************************************************************/
// DESCRIPTION: test iterates over the locales installed on a machine,
// calling the C character classification functions and
// their C++ counterpart(s), comparing the results of
// the calls against one another.
#include <rw/_defs.h>
#if defined __linux__
// on Linux define _XOPEN_SOURCE to get CODESET defined in <langinfo.h>
# define _XOPEN_SOURCE 500 /* Single Unix conformance */
// bring __int32_t into scope (otherwise <wctype.h> fails to compile)
# include <sys/types.h>
#endif // __linux__
// see Onyx PR #28150
#if defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x540
# include <wchar.h>
#endif // defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x540
#include <locale>
#include <climits>
#include <clocale>
#include <cstring>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cwchar> // for WEOF, btowc(), wctob()
#include <cwctype> // for iswxxx()
#if !defined (_MSC_VER)
# if !defined (LC_MESSAGES)
# define LC_MESSAGES _RWSTD_LC_MESSAGES
# endif // LC_MESSAGES
# include <langinfo.h>
#endif // _MSC_VER
#include <driver.h>
#include <file.h> // for SLASH
#include <rw_locale.h> // for rw_locale_query()
/**************************************************************************/
// the root of the locale directory (RWSTD_LOCALE_ROOT)
// not set here to avoid Solaris 7 putenv() bug (PR #30017)
const char* locale_root;
#define NLOOPS 25
#define MAX_STR_SIZE 16
#define LOCALES "{{en-US,de-DE,fr-FR,es-ES}-*-{ISO-8859-*,UTF-8,CP125?}," \
"{ja-JP-*-{EUC-JP,SHIFT_JIS,UTF-8,CP125?}}," \
"{zh-CN-*-{GB*,UTF-8,CP125?}}," \
"{ru-RU-*-{KOI*,UTF-8,CP125?}}}"
const char* locale_list = 0;
#define BEGIN_LOCALE_LOOP(num, locname, loop_cntrl) \
const char* locale_list = rw_locale_query (LC_CTYPE, LOCALES); \
for (const char* locname = locale_list; \
locname && *locname; locname += std::strlen (locname) + 1) { \
_TRY { \
const std::locale loc (locname); \
const std::ctype<char> &ctc = \
_STD_USE_FACET (std::ctype<char>, loc); \
_RWSTD_UNUSED (ctc); \
const std::ctype<charT> &ctp = \
_STD_USE_FACET (std::ctype<charT>, loc); \
for (int loop_cntrl = 0; loop_cntrl < int (num); loop_cntrl++)
#define END_LOCALE_LOOP(locname) \
} \
_CATCH (...) { \
rw_assert (0, 0, __LINE__, \
"locale (\"%s\") threw an exception", locname); \
} \
}
// for notational convenience
typedef unsigned char UChar;
#define ALPHA std::ctype_base::alpha
#define UPPER std::ctype_base::upper
#define LOWER std::ctype_base::lower
#define DIGIT std::ctype_base::digit
#define SPACE std::ctype_base::space
#define CNTRL std::ctype_base::cntrl
#define PUNCT std::ctype_base::punct
#define XDIGIT std::ctype_base::xdigit
#define GRAPH std::ctype_base::graph
#define PRINT std::ctype_base::print
// wrapper functions for the c library char and wchar_t functions
char libc_tolower (char ch)
{
return std::tolower (UChar (ch));
}
char libc_toupper (char ch)
{
return (std::toupper)(UChar (ch));
}
const char* widen (char *dst, const char *src)
{
if (src == dst || !src || !dst)
return src;
std::memcpy (dst, src, std::strlen (src) + 1);
return dst;
}
char widen (char, char ch, const char*)
{
return ch;
}
#ifndef _RWSTD_NO_WCHAR_T
wchar_t libc_tolower (wchar_t ch)
{
return (std::towlower)(ch);
}
wchar_t libc_toupper (wchar_t ch)
{
return (std::towupper)(ch);
}
const wchar_t* widen (wchar_t *dst, const char *src)
{
static wchar_t buf [4096];
if (!src)
return 0;
if (!dst)
dst = buf;
std::size_t len = std::strlen (src);
_RWSTD_ASSERT (len < sizeof buf /sizeof *buf);
len = std::mbstowcs (dst, src, sizeof buf / sizeof *buf);
if (std::size_t (-1) == len)
*dst = 0;
return dst;
}
wchar_t widen (wchar_t, char ch, const char *locname)
{
char curlocname [256];
std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
if (0 == std::setlocale (LC_CTYPE, locname))
return UChar (ch);
wchar_t result;
#ifndef _RWSTD_NO_BTOWC
result = std::btowc (UChar (ch));
#elif !defined (_RWSTD_NO_MBTOWC)
if (1 != std::mbtowc (&result, &ch, 1))
result = wchar_t (WEOF);
#else
result = UChar (ch);
#endif // _RWSTD_NO_BTOWC, _RWSTD_NO_MBTOWC
if (locname)
std::setlocale (LC_CTYPE, curlocname);
return result;
}
#endif // _RWSTD_NO_WCHAR_T
/**************************************************************************/
template <class charT>
void test_tolower (charT, const char *cname)
{
rw_info (0, 0, __LINE__, "std::ctype<%s>::tolower(%1$s)", cname);
BEGIN_LOCALE_LOOP (UCHAR_MAX, locname, i) {
const charT ch = charT (i);
// set the global C locale to locname for the C library call
std::setlocale (LC_CTYPE, locname);
const charT lch = libc_tolower (ch);
// set the global C locale to default to make sure
// the C++ library does not asume a set value
std::setlocale (LC_CTYPE, "");
// exercise tolower using ctype<>::tolower ()
rw_assert (lch == (ctp.tolower)(ch), 0, __LINE__,
"ctype<%s>::tolower(%{#lc}) == %{#lc}, got %{#lc} "
"in locale(%#s)",
cname, ch, lch, (ctp.tolower)(ch), locname);
// exercise tolower using tolower (char, locale)
rw_assert (lch == (charT)(std::tolower)(ch, loc), 0, __LINE__,
"tolower<%s>(%{#lc}, locale(%#s)) == %{#lc}, got %{#lc}",
cname, ch, locname, lch, (std::tolower)(ch, loc));
} END_LOCALE_LOOP (locname);
}
/**************************************************************************/
template <class charT>
void test_libc (charT, const char *cname)
{
test_tolower (charT (), cname);
}
/**************************************************************************/
template <class charT>
void test_libstd_tolower (charT, const char *cname,
const std::ctype<charT> &ct,
const char *locname)
{
rw_info (0, 0, __LINE__,
"std::ctype<%s>::tolower(%1$s) in locale(%#s)",
cname, locname);
int success;
#undef TEST
#define TEST(lower, upper) \
success = ct.widen (lower) == ct.tolower (ct.widen (upper)); \
rw_assert (success, 0, __LINE__, \
"ctype<%s>::tolower(%d) == %d, got %d", \
cname, upper, lower, ct.tolower((charT)upper))
TEST ('a', 'A');
TEST ('b', 'B');
TEST ('c', 'C');
if (sizeof(charT) > 1)
TEST ('\xa0', '\xa1');
#undef TEST
}
/**************************************************************************/
template <class charT>
void test_libstd (charT, const char *cname)
{
const char cmap_1[] = {
"<code_set_name> \"ANSI_X3.4-1968\"\n"
"<mb_cur_max> 1\n"
"<mb_cur_min> 1\n"
"CHARMAP\n"
"<U0000> \\x00\n"
"<U0001> \\x01\n"
"<U0002> \\x02\n"
"<U0003> \\x03\n"
"<U0004> \\x04\n"
"<U0005> \\x05\n"
"<U0006> \\x06\n"
"<U0007> \\x07\n"
"<U0008> \\x08\n"
"<U0009> \\x09\n"
"<U000a> \\x0a\n"
"<U000b> \\x0b\n"
"<U000c> \\x0c\n"
"<U000d> \\x0d\n"
"<U000e> \\x0e\n"
"<U000f> \\x0f\n"
"<U0010> \\x10\n"
"<U0011> \\x11\n"
"<U0012> \\x12\n"
"<U0013> \\x13\n"
"<U0014> \\x14\n"
"<U0015> \\x15\n"
"<U0016> \\x16\n"
"<U0017> \\x17\n"
"<U0018> \\x18\n"
"<U0019> \\x19\n"
"<U001a> \\x1a\n"
"<U001b> \\x1b\n"
"<U001c> \\x1c\n"
"<U001d> \\x1d\n"
"<U001e> \\x1e\n"
"<U001f> \\x1f\n"
"<U0020> \\x20\n"
"<U0021> \\x21\n"
"<U0022> \\x22\n"
"<U0023> \\x23\n"
"<U0024> \\x24\n"
"<U0025> \\x25\n"
"<U0026> \\x26\n"
"<U0027> \\x27\n"
"<U0028> \\x28\n"
"<U0029> \\x29\n"
"<U002a> \\x2a\n"
"<U002b> \\x2b\n"
"<U002c> \\x2c\n"
"<U002d> \\x2d\n"
"<U002e> \\x2e\n"
"<U002f> \\x2f\n"
"<U0030> \\x30\n"
"<U0031> \\x31\n"
"<U0032> \\x32\n"
"<U0033> \\x33\n"
"<U0034> \\x34\n"
"<U0035> \\x35\n"
"<U0036> \\x36\n"
"<U0037> \\x37\n"
"<U0038> \\x38\n"
"<U0039> \\x39\n"
"<U003a> \\x3a\n"
"<U003b> \\x3b\n"
"<U003c> \\x3c\n"
"<U003d> \\x3d\n"
"<U003e> \\x3e\n"
"<U003f> \\x3f\n"
"<U0040> \\x40\n"
"<U0041> \\x41\n"
"<U0042> \\x42\n"
"<U0043> \\x43\n"
"<U0044> \\x44\n"
"<U0045> \\x45\n"
"<U0046> \\x46\n"
"<U0047> \\x47\n"
"<U0048> \\x48\n"
"<U0049> \\x49\n"
"<U004a> \\x4a\n"
"<U004b> \\x4b\n"
"<U004c> \\x4c\n"
"<U004d> \\x4d\n"
"<U004e> \\x4e\n"
"<U004f> \\x4f\n"
"<U0050> \\x50\n"
"<U0051> \\x51\n"
"<U0052> \\x52\n"
"<U0053> \\x53\n"
"<U0054> \\x54\n"
"<U0055> \\x55\n"
"<U0056> \\x56\n"
"<U0057> \\x57\n"
"<U0058> \\x58\n"
"<U0059> \\x59\n"
"<U005a> \\x5a\n"
"<U005b> \\x5b\n"
"<U005c> \\x5c\n"
"<U005d> \\x5d\n"
"<U005e> \\x5e\n"
"<U005f> \\x5f\n"
"<U0060> \\x60\n"
"<U0061> \\x61\n"
"<U0062> \\x62\n"
"<U0063> \\x63\n"
"<U0064> \\x64\n"
"<U0065> \\x65\n"
"<U0066> \\x66\n"
"<U0067> \\x67\n"
"<U0068> \\x68\n"
"<U0069> \\x69\n"
"<U006a> \\x6a\n"
"<U006b> \\x6b\n"
"<U006c> \\x6c\n"
"<U006d> \\x6d\n"
"<U006e> \\x6e\n"
"<U006f> \\x6f\n"
"<U0070> \\x70\n"
"<U0071> \\x71\n"
"<U0072> \\x72\n"
"<U0073> \\x73\n"
"<U0074> \\x74\n"
"<U0075> \\x75\n"
"<U0076> \\x76\n"
"<U0077> \\x77\n"
"<U0078> \\x78\n"
"<U0079> \\x79\n"
"<U007a> \\x7a\n"
"<U007b> \\x7b\n"
"<U007c> \\x7c\n"
"<U007d> \\x7d\n"
"<U007e> \\x7e\n"
"<U007f> \\x7f\n"
"<U1000> \\xa0\n"
"<U1001> \\xa1\n"
"<U1002> \\xa2\n"
"END CHARMAP\n"
};
const char loc_1[] = {
"escape_char /\n"
"LC_CTYPE\n"
"toupper (<U0061>,<U0041>);(<U0062>,<U0042>);"
"(<U0063>,<U0043>);(<U1000>,<U1001>)\n"
"tolower (<U0041>,<U0061>);(<U0042>,<U0062>);"
"(<U0043>,<U0063>);(<U1001>,<U1000>)\n"
"END LC_CTYPE\n"
};
//invoke rw_create_locale to build a locale to test with
const char* const locname = rw_create_locale (cmap_1, loc_1);
if (!rw_error (0 != locname, 0, __LINE__,
"failed to create a locale in %s", locale_root))
return;
const std::locale loc (locname);
const std::ctype<charT> &ct =
_STD_USE_FACET (std::ctype<charT>, loc);
ct._C_opts |= ct._C_use_libstd;
ct._C_opts &= ~ct._C_use_libc;
test_libstd_tolower (charT (), cname, ct, locname);
}
/**************************************************************************/
template <class charT>
void run_test (charT, const char *cname)
{
if (0) {
// do a compile time only test on use_facet and has_facet
_STD_HAS_FACET (std::ctype_byname<charT>, std::locale ());
_STD_USE_FACET (std::ctype_byname<charT>, std::locale ());
}
test_libc (charT (), cname);
test_libstd (charT (), cname);
}
/**************************************************************************/
static int
run_test (int, char**)
{
run_test (char (), "char");
run_test (wchar_t (), "wchar_t");
return 0;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
return rw_test (argc, argv, __FILE__,
"lib.category.ctype",
0 /* no comment */,
run_test,
"",
(void*)0 /* sentinel */);
}

View File

@@ -0,0 +1,497 @@
/***************************************************************************
*
* 22.locale.ctype.toupper.cpp - Tests exercising the toupper() of ctype facet
*
* $Id: 22.locale.ctype.toupper.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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 2001-2006 Rogue Wave Software.
*
**************************************************************************/
// DESCRIPTION: test iterates over the locales installed on a machine,
// calling the C character classification functions and
// their C++ counterpart(s), comparing the results of
// the calls against one another.
#include <rw/_defs.h>
#if defined __linux__
// on Linux define _XOPEN_SOURCE to get CODESET defined in <langinfo.h>
# define _XOPEN_SOURCE 500 /* Single Unix conformance */
// bring __int32_t into scope (otherwise <wctype.h> fails to compile)
# include <sys/types.h>
#endif // __linux__
// see Onyx PR #28150
#if defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x540
# include <wchar.h>
#endif // defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x540
#include <locale>
#include <climits>
#include <clocale>
#include <cstring>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cwchar> // for WEOF, btowc(), wctob()
#include <cwctype> // for iswxxx()
#if !defined (_MSC_VER)
# if !defined (LC_MESSAGES)
# define LC_MESSAGES _RWSTD_LC_MESSAGES
# endif // LC_MESSAGES
# include <langinfo.h>
#endif // _MSC_VER
#include <driver.h>
#include <file.h> // for SLASH
#include <rw_locale.h> // for rw_locale_query()
/**************************************************************************/
// the root of the locale directory (RWSTD_LOCALE_ROOT)
// not set here to avoid Solaris 7 putenv() bug (PR #30017)
const char* locale_root;
#define NLOOPS 25
#define MAX_STR_SIZE 16
#define LOCALES "{{en-US,de-DE,fr-FR,es-ES}-*-{ISO-8859-*,UTF-8,CP125?}," \
"{ja-JP-*-{EUC-JP,SHIFT_JIS,UTF-8,CP125?}}," \
"{zh-CN-*-{GB*,UTF-8,CP125?}}," \
"{ru-RU-*-{KOI*,UTF-8,CP125?}}}"
const char* locale_list = 0;
#define BEGIN_LOCALE_LOOP(num, locname, loop_cntrl) \
if (!locale_list) locale_list = rw_locale_query (LC_CTYPE, LOCALES); \
for (const char* locname = locale_list; \
locname && *locname; locname += std::strlen (locname) + 1) { \
_TRY { \
const std::locale loc (locname); \
const std::ctype<char> &ctc = \
_STD_USE_FACET (std::ctype<char>, loc); \
_RWSTD_UNUSED (ctc); \
const std::ctype<charT> &ctp = \
_STD_USE_FACET (std::ctype<charT>, loc); \
for (int loop_cntrl = 0; loop_cntrl < int (num); loop_cntrl++)
#define END_LOCALE_LOOP(locname) \
} \
_CATCH (...) { \
rw_assert (0, 0, __LINE__, \
"locale (\"%s\") threw an exception", locname); \
} \
}
// for notational convenience
typedef unsigned char UChar;
#define ALPHA std::ctype_base::alpha
#define UPPER std::ctype_base::upper
#define LOWER std::ctype_base::lower
#define DIGIT std::ctype_base::digit
#define SPACE std::ctype_base::space
#define CNTRL std::ctype_base::cntrl
#define PUNCT std::ctype_base::punct
#define XDIGIT std::ctype_base::xdigit
#define GRAPH std::ctype_base::graph
#define PRINT std::ctype_base::print
// wrapper functions for the c library char and wchar_t functions
char libc_tolower (char ch)
{
return std::tolower (UChar (ch));
}
char libc_toupper (char ch)
{
return (std::toupper)(UChar (ch));
}
const char* widen (char *dst, const char *src)
{
if (src == dst || !src || !dst)
return src;
std::memcpy (dst, src, std::strlen (src) + 1);
return dst;
}
char widen (char, char ch, const char*)
{
return ch;
}
#ifndef _RWSTD_NO_WCHAR_T
wchar_t libc_tolower (wchar_t ch)
{
return (std::towlower)(ch);
}
wchar_t libc_toupper (wchar_t ch)
{
return (std::towupper)(ch);
}
const wchar_t* widen (wchar_t *dst, const char *src)
{
static wchar_t buf [4096];
if (!src)
return 0;
if (!dst)
dst = buf;
std::size_t len = std::strlen (src);
_RWSTD_ASSERT (len < sizeof buf /sizeof *buf);
len = std::mbstowcs (dst, src, sizeof buf / sizeof *buf);
if (std::size_t (-1) == len)
*dst = 0;
return dst;
}
wchar_t widen (wchar_t, char ch, const char *locname)
{
char curlocname [256];
std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
if (0 == std::setlocale (LC_CTYPE, locname))
return UChar (ch);
wchar_t result;
#ifndef _RWSTD_NO_BTOWC
result = std::btowc (UChar (ch));
#elif !defined (_RWSTD_NO_MBTOWC)
if (1 != std::mbtowc (&result, &ch, 1))
result = wchar_t (WEOF);
#else
result = UChar (ch);
#endif // _RWSTD_NO_BTOWC, _RWSTD_NO_MBTOWC
if (locname)
std::setlocale (LC_CTYPE, curlocname);
return result;
}
#endif // _RWSTD_NO_WCHAR_T
/**************************************************************************/
template <class charT>
void test_toupper (charT, const char *cname)
{
rw_info (0, 0, __LINE__, "std::ctype<%s>::toupper(%1$s)", cname);
BEGIN_LOCALE_LOOP (UCHAR_MAX, locname2, i) {
const charT ch = charT (i);
// set the global C locale to the locale name for the C library call
std::setlocale (LC_CTYPE, locname2);
const charT uch = libc_toupper (ch);
// set the global C locale to default to make sure
// the C++ library does not asume a set value
std::setlocale (LC_CTYPE, "");
// exercise toupper using ctype<>::toupper ()
rw_assert (uch == (ctp.toupper)(ch), 0, __LINE__,
"ctype<%s>::toupper(%{#lc}) == %{#lc}, got %{#lc} "
"in locale(%#s)",
cname, ch, uch, (ctp.toupper)(ch), locname2);
// exercise toupper using toupper (char, locale)
rw_assert (uch == (charT)(std::toupper)(ch, loc), 0, __LINE__,
"toupper<%s>(%{#lc}, locale(%#s)) == %{#lc}, got %{#lc}",
cname, ch, locname2, uch, (std::toupper)(ch, loc));
} END_LOCALE_LOOP (locname2);
}
/**************************************************************************/
template <class charT>
void test_libc (charT, const char *cname)
{
test_toupper (charT (), cname);
}
/**************************************************************************/
template <class charT>
void test_libstd_toupper (charT, const char *cname,
const std::ctype<charT> &ct,
const char *locname)
{
rw_info (0, 0, __LINE__,
"std::ctype<%s>::toupper(%1$s) in locale(%#s)",
cname, locname);
int success;
#undef TEST
#define TEST(lower, upper) \
success = ct.widen (upper) == ct.toupper (ct.widen (lower)); \
rw_assert (success, 0, __LINE__, \
"ctype<%s>::toupper(%d) == %d, got %d", cname, \
lower, upper, ct.toupper((charT)lower));
TEST ('a', 'A');
TEST ('b', 'B');
TEST ('c', 'C');
if (sizeof(charT) > 1)
TEST ('\xa0', '\xa1');
#undef TEST
}
/**************************************************************************/
template <class charT>
void test_libstd (charT, const char *cname)
{
const char cmap_1[] = {
"<code_set_name> \"ANSI_X3.4-1968\"\n"
"<mb_cur_max> 1\n"
"<mb_cur_min> 1\n"
"CHARMAP\n"
"<U0000> \\x00\n"
"<U0001> \\x01\n"
"<U0002> \\x02\n"
"<U0003> \\x03\n"
"<U0004> \\x04\n"
"<U0005> \\x05\n"
"<U0006> \\x06\n"
"<U0007> \\x07\n"
"<U0008> \\x08\n"
"<U0009> \\x09\n"
"<U000a> \\x0a\n"
"<U000b> \\x0b\n"
"<U000c> \\x0c\n"
"<U000d> \\x0d\n"
"<U000e> \\x0e\n"
"<U000f> \\x0f\n"
"<U0010> \\x10\n"
"<U0011> \\x11\n"
"<U0012> \\x12\n"
"<U0013> \\x13\n"
"<U0014> \\x14\n"
"<U0015> \\x15\n"
"<U0016> \\x16\n"
"<U0017> \\x17\n"
"<U0018> \\x18\n"
"<U0019> \\x19\n"
"<U001a> \\x1a\n"
"<U001b> \\x1b\n"
"<U001c> \\x1c\n"
"<U001d> \\x1d\n"
"<U001e> \\x1e\n"
"<U001f> \\x1f\n"
"<U0020> \\x20\n"
"<U0021> \\x21\n"
"<U0022> \\x22\n"
"<U0023> \\x23\n"
"<U0024> \\x24\n"
"<U0025> \\x25\n"
"<U0026> \\x26\n"
"<U0027> \\x27\n"
"<U0028> \\x28\n"
"<U0029> \\x29\n"
"<U002a> \\x2a\n"
"<U002b> \\x2b\n"
"<U002c> \\x2c\n"
"<U002d> \\x2d\n"
"<U002e> \\x2e\n"
"<U002f> \\x2f\n"
"<U0030> \\x30\n"
"<U0031> \\x31\n"
"<U0032> \\x32\n"
"<U0033> \\x33\n"
"<U0034> \\x34\n"
"<U0035> \\x35\n"
"<U0036> \\x36\n"
"<U0037> \\x37\n"
"<U0038> \\x38\n"
"<U0039> \\x39\n"
"<U003a> \\x3a\n"
"<U003b> \\x3b\n"
"<U003c> \\x3c\n"
"<U003d> \\x3d\n"
"<U003e> \\x3e\n"
"<U003f> \\x3f\n"
"<U0040> \\x40\n"
"<U0041> \\x41\n"
"<U0042> \\x42\n"
"<U0043> \\x43\n"
"<U0044> \\x44\n"
"<U0045> \\x45\n"
"<U0046> \\x46\n"
"<U0047> \\x47\n"
"<U0048> \\x48\n"
"<U0049> \\x49\n"
"<U004a> \\x4a\n"
"<U004b> \\x4b\n"
"<U004c> \\x4c\n"
"<U004d> \\x4d\n"
"<U004e> \\x4e\n"
"<U004f> \\x4f\n"
"<U0050> \\x50\n"
"<U0051> \\x51\n"
"<U0052> \\x52\n"
"<U0053> \\x53\n"
"<U0054> \\x54\n"
"<U0055> \\x55\n"
"<U0056> \\x56\n"
"<U0057> \\x57\n"
"<U0058> \\x58\n"
"<U0059> \\x59\n"
"<U005a> \\x5a\n"
"<U005b> \\x5b\n"
"<U005c> \\x5c\n"
"<U005d> \\x5d\n"
"<U005e> \\x5e\n"
"<U005f> \\x5f\n"
"<U0060> \\x60\n"
"<U0061> \\x61\n"
"<U0062> \\x62\n"
"<U0063> \\x63\n"
"<U0064> \\x64\n"
"<U0065> \\x65\n"
"<U0066> \\x66\n"
"<U0067> \\x67\n"
"<U0068> \\x68\n"
"<U0069> \\x69\n"
"<U006a> \\x6a\n"
"<U006b> \\x6b\n"
"<U006c> \\x6c\n"
"<U006d> \\x6d\n"
"<U006e> \\x6e\n"
"<U006f> \\x6f\n"
"<U0070> \\x70\n"
"<U0071> \\x71\n"
"<U0072> \\x72\n"
"<U0073> \\x73\n"
"<U0074> \\x74\n"
"<U0075> \\x75\n"
"<U0076> \\x76\n"
"<U0077> \\x77\n"
"<U0078> \\x78\n"
"<U0079> \\x79\n"
"<U007a> \\x7a\n"
"<U007b> \\x7b\n"
"<U007c> \\x7c\n"
"<U007d> \\x7d\n"
"<U007e> \\x7e\n"
"<U007f> \\x7f\n"
"<U1000> \\xa0\n"
"<U1001> \\xa1\n"
"<U1002> \\xa2\n"
"END CHARMAP\n"
};
const char loc_1[] = {
"escape_char /\n"
"LC_CTYPE\n"
"toupper (<U0061>,<U0041>);(<U0062>,<U0042>);"
"(<U0063>,<U0043>);(<U1000>,<U1001>)\n"
"tolower (<U0041>,<U0061>);(<U0042>,<U0062>);"
"(<U0043>,<U0063>);(<U1001>,<U1000>)\n"
"END LC_CTYPE\n"
};
//invoke rw_create_locale to build a locale to test with
const char* const locname = rw_create_locale (cmap_1, loc_1);
if (!rw_error (0 != locname, 0, __LINE__,
"failed to create a locale in %s", locale_root))
return;
const std::locale loc (locname);
const std::ctype<charT> &ct =
_STD_USE_FACET (std::ctype<charT>, loc);
ct._C_opts |= ct._C_use_libstd;
ct._C_opts &= ~ct._C_use_libc;
test_libstd_toupper (charT (), cname, ct, locname);
}
/**************************************************************************/
template <class charT>
void run_test (charT, const char *cname)
{
if (0) {
// do a compile time only test on use_facet and has_facet
_STD_HAS_FACET (std::ctype_byname<charT>, std::locale ());
_STD_USE_FACET (std::ctype_byname<charT>, std::locale ());
}
test_libc (charT (), cname);
test_libstd (charT (), cname);
}
/**************************************************************************/
static int
run_test (int, char**)
{
run_test (char (), "char");
run_test (wchar_t (), "wchar_t");
return 0;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
return rw_test (argc, argv, __FILE__,
"lib.category.ctype",
0 /* no comment */,
run_test,
"",
(void*)0 /* sentinel */);
}

View File

@@ -0,0 +1,152 @@
/***************************************************************************
*
* 22.locale.ctype.widen.cpp - tests exercising std::ctype<charT>::widen()
*
* $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-2008 Rogue Wave Software.
*
**************************************************************************/
#include <locale>
#include <driver.h>
typedef unsigned char UChar;
#ifndef _RWSTD_NO_WCHAR_T
typedef std::ctype<wchar_t> WCtype;
#endif // _RWSTD_NO_WCHAR_T
/**************************************************************************/
static void
test_char ()
{
rw_info (0, __FILE__, __LINE__, "std::ctype<char>::widen(char)");
const std::locale loc;
const WCtype& ctp = std::use_facet<WCtype> (loc);
for (int i = 0; i != int (_RWSTD_UCHAR_MAX) + 1; ++i) {
// compute the argument, and the expected and actual results
const char narrow = char (i);
const char expect = narrow;
const char wide = ctp.widen (narrow);
rw_assert (expect == wide, __FILE__, __LINE__,
"std::ctype<char>::widen(%#c) == %#c, got %#c",
narrow, expect, wide);
}
}
/**************************************************************************/
// will leave this here for now since it appears to be a placeholder
// for further testing
static void
test_byname_char ()
{
rw_info (0, __FILE__, __LINE__,
"std::ctype_byname<char>::widen(char)");
rw_warn (false, __FILE__, __LINE__,
"ctype_byname<char>::widen() not exercised");
}
/**************************************************************************/
static void
test_wchar_t ()
{
rw_info (0, __FILE__, __LINE__,
"std::ctype<wchar_t>::widen(char)");
#ifndef _RWSTD_NO_WCHAR_T
const std::locale loc;
const WCtype& ctp = std::use_facet<WCtype> (loc);
for (int i = 0; i != int (_RWSTD_UCHAR_MAX) + 1; ++i) {
// compute the argument, and the expected and actual results
const char narrow = char (i);
const wchar_t expect = wchar_t (UChar (narrow));
const wchar_t wide = ctp.widen (narrow);
rw_assert (expect == wide, __FILE__, __LINE__,
"std::ctype<wchar_t>::widen(%#c) == %#Lc, got %#Lc",
narrow, expect, wide);
}
#else // if defined (_RWSTD_NO_WCHAR_T)
rw_warn (false, __FILE__, __LINE__,
"ctype<wchar_t>::widen() not exercised: "
"macro _RWSTD_NO_WCHAR_T defined");
#endif // _RWSTD_NO_WCHAR_T
}
/**************************************************************************/
// another placeholder for further testing?
static void
test_byname_wchar_t ()
{
rw_info (0, __FILE__, __LINE__,
"std::ctype_byname<wchar_t>::widen(char)");
rw_warn (false, __FILE__, __LINE__,
"ctype_byname<wchar_t>::widen() not exercised");
}
/**************************************************************************/
static int
run_test (int /*unused*/, char* /*unused*/ [])
{
test_char ();
test_byname_char ();
test_wchar_t ();
test_byname_wchar_t ();
return 0;
}
/*extern*/ int
main (int argc, char* argv [])
{
return rw_test (argc, argv, __FILE__,
"lib.locale.ctype.widen",
0, // no comment
run_test, "", 0);
}

View File

@@ -0,0 +1,626 @@
/************************************************************************
*
* 22.locale.globals.mt.cpp
*
* test exercising the thread safety of [locale.global.templates]
*
* $Id: 22.locale.globals.mt.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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.
*
**************************************************************************/
#include <locale> // for locale
#include <cwchar> // for mbstate_t
#include <cstring> // for strlen()
#include <rw_locale.h> // for rw_locales()
#include <rw_thread.h> // for rw_get_processors(), rw_thread_pool()
#include <driver.h> // for rw_test()
// maximum number of threads allowed by the command line interface
#define MAX_THREADS 16
// default number of threads (will be adjusted to the number
// of processors/cores later)
int opt_nthreads = 1;
// the number of times each thread should iterate (unless specified
// otherwise on the command line)
int opt_nloops = 20000;
enum {
opt_inx_codecvt,
opt_inx_collate,
opt_inx_ctype,
opt_inx_messages,
opt_inx_moneypunct,
opt_inx_moneypunct_intl,
opt_inx_numpunct,
opt_inx_money_get,
opt_inx_money_put,
opt_inx_num_get,
opt_inx_num_put,
opt_inx_time_get,
opt_inx_time_put,
opt_nfacets
};
// tri-state options to enable/disable individual facets
// opt_facets [i] < 0: facet is initially explicitly disabled
// opt_facets [i] == 0: option not specified on the command line
// opt_facets [i] > 0: facet is initially explicitly enabled
int opt_facets [opt_nfacets];
// disable exceptions?
int opt_no_exceptions;
/**************************************************************************/
// array of locale names to use for testing
static const char*
locales [MAX_THREADS];
// number of locale names in the array
static std::size_t
nlocales;
/**************************************************************************/
// convenience typedefs for all required specializations of standard facets
typedef std::codecvt<char, char, std::mbstate_t> Codecvt;
typedef std::collate<char> Collate;
typedef std::ctype<char> Ctype;
typedef std::messages<char> Messages;
typedef std::moneypunct<char, false> Moneypunct0;
typedef std::moneypunct<char, true> Moneypunct1;
typedef std::numpunct<char> Numpunct;
typedef std::money_get<char> MoneyGet;
typedef std::money_put<char> MoneyPut;
typedef std::num_get<char> NumGet;
typedef std::num_put<char> NumPut;
typedef std::time_get<char> TimeGet;
typedef std::time_put<char> TimePut;
typedef std::collate_byname<char> CollateByname;
typedef std::ctype_byname<char> CtypeByname;
typedef std::codecvt_byname<char, char, std::mbstate_t> CodecvtByname;
typedef std::messages_byname<char> MessagesByname;
typedef std::moneypunct_byname<char, false> Moneypunct0Byname;
typedef std::moneypunct_byname<char, true> Moneypunct1Byname;
typedef std::numpunct_byname<char> NumpunctByname;
typedef std::time_get_byname<char> TimeGetByname;
typedef std::time_put_byname<char> TimePutByname;
#ifndef _RWSTD_NO_WCHAR_T
typedef std::collate<wchar_t> WCollate;
typedef std::ctype<wchar_t> WCtype;
typedef std::codecvt<wchar_t, char, std::mbstate_t> WCodecvt;
typedef std::messages<wchar_t> WMessages;
typedef std::moneypunct<wchar_t, false> WMoneypunct0;
typedef std::moneypunct<wchar_t, true> WMoneypunct1;
typedef std::numpunct<wchar_t> WNumpunct;
typedef std::money_get<wchar_t> WMoneyGet;
typedef std::money_put<wchar_t> WMoneyPut;
typedef std::num_get<wchar_t> WNumGet;
typedef std::num_put<wchar_t> WNumPut;
typedef std::time_get<wchar_t> WTimeGet;
typedef std::time_put<wchar_t> WTimePut;
typedef std::collate_byname<wchar_t> WCollateByname;
typedef std::ctype_byname<wchar_t> WCtypeByname;
typedef std::codecvt_byname<wchar_t, char, std::mbstate_t> WCodecvtByname;
typedef std::messages_byname<wchar_t> WMessagesByname;
typedef std::moneypunct_byname<wchar_t, false> WMoneypunct0Byname;
typedef std::moneypunct_byname<wchar_t, true> WMoneypunct1Byname;
typedef std::numpunct_byname<wchar_t> WNumpunctByname;
typedef std::time_get_byname<wchar_t> WTimeGetByname;
typedef std::time_put_byname<wchar_t> WTimePutByname;
#endif // _RWSTD_NO_WCHAR_T
extern "C" {
static void*
test_has_facet (void*)
{
const std::locale classic (std::locale::classic ());
for (int i = 0; i != opt_nloops; ++i) {
// save the name of the locale
const char* const locale_name = locales [i % nlocales];
// construct a named locale and imbue it in the ios object
// so that the locale is used not only by the num_put facet
// but also by the numpunct facet
const std::locale loc (locale_name);
const bool byname = loc != classic;
// call has_facet for each base facet only of it's enabled
#define HAS(Facet, opt) \
(0 <= opt_facets [opt_inx_ ## opt] ? std::has_facet<Facet>(loc) : true)
HAS (Codecvt, codecvt);
HAS (Collate, collate);
HAS (Ctype, ctype);
HAS (Messages, messages);
HAS (Moneypunct0, moneypunct);
HAS (Moneypunct1, moneypunct_intl);
HAS (MoneyGet, money_get);
HAS (MoneyPut, money_put);
HAS (Numpunct, numpunct);
HAS (NumGet, num_get);
HAS (NumPut, num_put);
HAS (TimeGet, time_get);
HAS (TimePut, time_put);
// call has_facet for each _byname facet only of it's enabled
#define HAS_BYNAME(Facet, opt) \
(0 <= opt_facets [opt_inx_ ## opt] ? \
byname == std::has_facet<Facet>(loc) : true)
HAS_BYNAME (CodecvtByname, codecvt);
HAS_BYNAME (CollateByname, collate);
HAS_BYNAME (CtypeByname, ctype);
HAS_BYNAME (MessagesByname, messages);
HAS_BYNAME (Moneypunct0Byname, moneypunct);
HAS_BYNAME (Moneypunct1Byname, moneypunct_intl);
HAS_BYNAME (TimeGetByname, time_get);
HAS_BYNAME (TimePutByname, time_put);
#ifndef _RWSTD_NO_WCHAR_T
HAS (WCodecvt, codecvt);
HAS (WCollate, collate);
HAS (WCtype, ctype);
HAS (WMessages, messages);
HAS (WMoneypunct0, moneypunct);
HAS (WMoneypunct1, moneypunct_intl);
HAS (WMoneyGet, money_get);
HAS (WMoneyPut, money_put);
HAS (WNumpunct, numpunct);
HAS (WNumGet, num_get);
HAS (WNumPut, num_put);
HAS (WTimeGet, time_get);
HAS (WTimePut, time_put);
HAS_BYNAME (WCodecvtByname, codecvt);
HAS_BYNAME (WCollateByname, collate);
HAS_BYNAME (WCtypeByname, ctype);
HAS_BYNAME (WMessagesByname, messages);
HAS_BYNAME (WMoneypunct0Byname, moneypunct);
HAS_BYNAME (WMoneypunct1Byname, moneypunct_intl);
HAS_BYNAME (WTimeGetByname, time_get);
HAS_BYNAME (WTimePutByname, time_put);
#endif // _RWSTD_NO_WCHAR_T
}
return 0;
}
} // extern "C"
static void
use_facet_loop (const std::locale &classic, int i)
{
static const std::locale::facet* const dummy =
(std::locale::facet*)1;
// save the name of the locale
const char* const locale_name = locales [i % nlocales];
// construct a named locale and imbue it in the ios object
// so that the locale is used not only by the num_put facet
// but also by the numpunct facet
const std::locale loc (locale_name);
const bool byname = loc != classic;
{
#define USE(Facet, opt) \
(0 <= opt_facets [opt_inx_ ## opt] ? &std::use_facet<Facet>(loc) : dummy)
const std::locale::facet* const bases[] = {
// get pointers to the char specializations of facets
USE (Collate, collate),
USE (Ctype, ctype),
USE (Codecvt, codecvt),
USE (Messages, messages),
USE (Moneypunct0, moneypunct),
USE (Moneypunct1, moneypunct_intl),
USE (MoneyGet, money_get),
USE (MoneyPut, money_put),
USE (Numpunct, numpunct),
USE (NumGet, num_get),
USE (NumPut, num_put),
USE (TimeGet, time_get),
USE (TimePut, time_put)
};
if (byname) {
// get pointers to the char specializations
// of byname facets
const std::locale::facet* const derived[] = {
USE (CollateByname, collate),
USE (CtypeByname, ctype),
USE (CodecvtByname, codecvt),
USE (MessagesByname, messages),
USE (Moneypunct0Byname, moneypunct),
USE (Moneypunct1Byname, moneypunct_intl),
// no money_get_byname or money_put_byname
USE (MoneyGet, money_get),
USE (MoneyPut, money_put),
USE (NumpunctByname, numpunct),
// no num_get_byname or num_put_byname
USE (NumGet, num_get),
USE (NumPut, num_put),
USE (TimeGetByname, time_get),
USE (TimePutByname, time_put)
};
const std::size_t nbases = sizeof bases / sizeof *bases;
for (std::size_t j = 0; j != nbases; ++j) {
RW_ASSERT (bases [j] != 0);
RW_ASSERT (bases [j] == derived [j]);
}
}
else if (0 == opt_no_exceptions) {
bool threw;
#define TEST_USE_FACET(Facet, opt) \
try { \
threw = false; \
if (0 <= opt_facets [opt_inx_ ## opt]) \
std::use_facet<Facet>(loc); \
} \
catch (...) { threw = true; } \
RW_ASSERT (threw || opt_facets [opt_inx_ ## opt] < 0)
TEST_USE_FACET (CollateByname, collate);
TEST_USE_FACET (CtypeByname, ctype);
TEST_USE_FACET (CodecvtByname, codecvt);
TEST_USE_FACET (MessagesByname, messages);
TEST_USE_FACET (Moneypunct0Byname, moneypunct);
TEST_USE_FACET (Moneypunct1Byname, moneypunct_intl);
TEST_USE_FACET (NumpunctByname, numpunct);
TEST_USE_FACET (TimeGetByname, time_get);
TEST_USE_FACET (TimePutByname, time_put);
}
}
#ifndef _RWSTD_NO_WCHAR_T
{
const std::locale::facet* const bases[] = {
// get pointers to the char specializations of facets
USE (WCollate, collate),
USE (WCtype, ctype),
USE (WCodecvt, codecvt),
USE (WMessages, messages),
USE (WMoneypunct0, moneypunct),
USE (WMoneypunct1, moneypunct_intl),
USE (WMoneyGet, money_get),
USE (WMoneyPut, money_put),
USE (WNumpunct, numpunct),
USE (WNumGet, num_get),
USE (WNumPut, num_put),
USE (WTimeGet, time_get),
USE (WTimePut, time_put)
};
if (byname) {
// get pointers to the char specializations
// of byname facets
const std::locale::facet* const derived[] = {
USE (WCollateByname, collate),
USE (WCtypeByname, ctype),
USE (WCodecvtByname, codecvt),
USE (WMessagesByname, messages),
USE (WMoneypunct0Byname, moneypunct),
USE (WMoneypunct1Byname, moneypunct_intl),
// no money_get_byname or money_put_byname
USE (WMoneyGet, money_get),
USE (WMoneyPut, money_put),
USE (WNumpunctByname, numpunct),
// no num_get_byname or num_put_byname
USE (WNumGet, num_get),
USE (WNumPut, num_put),
USE (WTimeGetByname, time_get),
USE (WTimePutByname, time_put)
};
const std::size_t nbases = sizeof bases / sizeof *bases;
for (std::size_t j = 0; j != nbases; ++j) {
RW_ASSERT (bases [j] != 0);
RW_ASSERT (bases [j] == derived [j]);
}
}
else if (0 == opt_no_exceptions) {
bool threw;
TEST_USE_FACET (WCollateByname, collate);
TEST_USE_FACET (WCtypeByname, ctype);
TEST_USE_FACET (WCodecvtByname, codecvt);
TEST_USE_FACET (WMessagesByname, messages);
TEST_USE_FACET (WMoneypunct0Byname, moneypunct);
TEST_USE_FACET (WMoneypunct1Byname, moneypunct_intl);
TEST_USE_FACET (WNumpunctByname, numpunct);
TEST_USE_FACET (WTimeGetByname, time_get);
TEST_USE_FACET (WTimePutByname, time_put);
}
}
#endif // _RWSTD_NO_WCHAR_T
}
extern "C" {
static void*
test_use_facet (void*)
{
const std::locale classic (std::locale::classic ());
for (int i = 0; i != opt_nloops; ++i) {
try {
use_facet_loop (classic, i);
}
catch (...) {
// what to do here?
}
}
return 0;
}
} // extern "C"
/**************************************************************************/
int opt_has_facet; // exercise std::has_facet?
int opt_use_facet; // exercise std::use_facet?
static int
run_test (int, char**)
{
for (std::size_t i = 0; i != opt_nfacets; ++i) {
if (0 < opt_facets [i]) {
for (std::size_t j = 0; j != opt_nfacets; ++j) {
if (opt_facets [j] == 0)
opt_facets [j] = -1;
}
break;
}
}
rw_note (0 <= opt_facets [opt_inx_codecvt], 0, __LINE__,
"std::codecvt tests disabled");
rw_note (0 <= opt_facets [opt_inx_collate], 0, __LINE__,
"std::collate tests disabled");
rw_note (0 <= opt_facets [opt_inx_ctype], 0, __LINE__,
"std::ctype tests disabled");
rw_note (0 <= opt_facets [opt_inx_messages], 0, __LINE__,
"std::messages tests disabled");
rw_note (0 <= opt_facets [opt_inx_moneypunct], 0, __LINE__,
"std::moneypunct<charT, false> tests disabled");
rw_note (0 <= opt_facets [opt_inx_moneypunct_intl], 0, __LINE__,
"std::moneypunct<charT, true> tests disabled");
rw_note (0 <= opt_facets [opt_inx_money_get], 0, __LINE__,
"std::money_get tests disabled");
rw_note (0 <= opt_facets [opt_inx_money_put], 0, __LINE__,
"std::money_put tests disabled");
rw_note (0 <= opt_facets [opt_inx_numpunct], 0, __LINE__,
"std::numpunct tests disabled");
rw_note (0 <= opt_facets [opt_inx_num_get], 0, __LINE__,
"std::num_get tests disabled");
rw_note (0 <= opt_facets [opt_inx_num_put], 0, __LINE__,
"std::num_put tests disabled");
rw_note (0 <= opt_facets [opt_inx_time_get], 0, __LINE__,
"std::time_get tests disabled");
rw_note (0 <= opt_facets [opt_inx_time_put], 0, __LINE__,
"std::time_put tests disabled");
rw_note (0 == opt_no_exceptions, 0, __LINE__,
"tests involving exceptions disabled");
// find all installed locales for which setlocale(LC_ALL) succeeds
const char* const locale_list =
rw_opt_locales ? rw_opt_locales : rw_locales (_RWSTD_LC_ALL);
const std::size_t maxinx = sizeof locales / sizeof *locales;
// set to true if the classic "C" locale is on the lost
bool has_classic = false;
for (const char *name = locale_list; *name; name += std::strlen (name) +1) {
locales [nlocales++] = name;
if (!has_classic && 0 == std::strcmp ("C", name))
has_classic = true;
if (nlocales == maxinx)
break;
}
// when the classic "C" locale isn't on the list put it there
// unless the list was explicitly specified on the command line
if (1 < nlocales && !has_classic && 0 == rw_opt_locales)
locales [0] = "C";
int result;
rw_info (0, 0, 0,
"testing std::locale globals with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
opt_nthreads, 1 != opt_nthreads,
opt_nloops, 1 != opt_nloops,
nlocales, int (nlocales), "%#s", locales);
if (opt_has_facet >= 0) {
rw_info (0, 0, 0,
"template <class T> bool std::has_facet (const locale&)");
// create and start a pool of threads and wait for them to finish
result = rw_thread_pool (0, std::size_t (opt_nthreads), 0,
test_has_facet, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, test_has_facet);
}
else {
rw_note (0, 0, 0, "std::has_facet test disabled");
}
if (opt_use_facet >= 0) {
rw_info (0, 0, 0,
"template <class T> const T& std::use_facet (const locale&)");
#ifdef _RWSTD_NO_DYNAMIC_CAST
// if dynamic_cast isn't supported, then [has,use]_facet()
// can't reliably detect if a facet is installed or not.
rw_warn (0 != opt_no_exceptions, 0, __LINE__,
"dynamic_cast not supported "
"(macro _RWSTD_NO_DYNAMIC_CAST is #defined), "
"disabling exceptions tests");
opt_no_exceptions = 1;
#endif // _RWSTD_NO_DYNAMIC_CAST
#ifdef _RWSTD_NO_THREAD_SAFE_EXCEPTIONS
// avoid exercising exceptions (triggered by use_facet) if
// their implementation in the runtime isn't thread-safe
rw_warn (0, 0, 0,
"exceptions not thread safe (macro "
"_RWSTD_NO_THREAD_SAFE_EXCEPTIONS is #defined), "
"disabling exceptions tests");
opt_no_exceptions = 1;
#endif // _RWSTD_NO_THREAD_SAFE_EXCEPTIONS
// create and start a pool of threads and wait for them to finish
result = rw_thread_pool (0, std::size_t (opt_nthreads), 0,
test_use_facet, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, test_use_facet);
}
else {
rw_note (0, 0, 0, "std::use_facet test disabled");
}
return result;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
#ifdef _RWSTD_REENTRANT
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
opt_nthreads = rw_get_cpus ();
if (opt_nthreads < 2)
opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.global.templates",
"thread safety", run_test,
"|-has_facet~ "
"|-use_facet~ "
"|-nloops#0 " // arg must be non-negative
"|-nthreads#0-* " // arg must be in [0, MAX_THREADS]
"|-locales= " // argument must be provided
"|-no-exceptions# " // disable exceptions
"|-codecvt~ " // enable/disable individual facets
"|-collate~ "
"|-ctype~ "
"|-messages~ "
"|-moneypunct~ "
"|-moneypunct_intl~ "
"|-money_get~ "
"|-money_put~ "
"|-numpunct~ "
"|-num_get~ "
"|-num_put~ "
"|-time_get~ "
"|-time_put~ ",
&opt_has_facet,
&opt_use_facet,
&opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
&rw_opt_setlocales,
&opt_no_exceptions,
opt_facets + opt_inx_codecvt,
opt_facets + opt_inx_collate,
opt_facets + opt_inx_ctype,
opt_facets + opt_inx_messages,
opt_facets + opt_inx_moneypunct,
opt_facets + opt_inx_moneypunct_intl,
opt_facets + opt_inx_money_get,
opt_facets + opt_inx_money_put,
opt_facets + opt_inx_numpunct,
opt_facets + opt_inx_num_get,
opt_facets + opt_inx_num_put,
opt_facets + opt_inx_time_get,
opt_facets + opt_inx_time_put);
}

View File

@@ -0,0 +1,888 @@
/***************************************************************************
*
* 22.locale.messages.cpp - tests exercising the std::messages facet
*
* $Id: 22.locale.messages.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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 2001-2006 Rogue Wave Software.
*
**************************************************************************/
#include <locale>
#include <driver.h> // for rw_test()
#include <environ.h> // for rw_putenv()
#include <file.h> // for rw_nextfd()
#include <rw_locale.h> // for rw_locales(), rw_create_catalog()
#include <rw_process.h> // for rw_system()
#include <cstring> // for strlen()
#include <cstdlib> // for getenv()
#include <cstdio> // for remove()
#include <clocale> // for LC_ALL
#include <cwchar> // for mbsinit()
#ifndef _RWSTD_NO_NEW_HEADER
# if defined (_MSC_VER)
# include <io.h> // for _open()
# include <direct.h> // for getcwd()
# else
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h> // for getcwd()
# endif
# include <fcntl.h> // for mode flags for _open
#endif // _RWSTD_NO_NEW_HEADER
#undef open
#undef close
#if defined (_MSC_VER)
# define open(f,m) _open (f, _##m)
# define close(f) _close (f)
#else
# define open(f,m) open (f, m)
# define close(f) close (f)
#endif // defined (_MSC_VER)
/***************************************************************************/
template <class charT>
struct CodeCvt: std::codecvt<charT, char, std::mbstate_t>
{
typedef std::codecvt<charT, char, std::mbstate_t> Base;
typedef typename Base::extern_type extern_type;
typedef typename Base::intern_type intern_type;
typedef typename Base::state_type state_type;
typedef typename Base::result result;
static bool used_;
static bool partial_;
static bool noconv_;
static bool check_state_;
static bool valid_state_;
CodeCvt (std::size_t ref = 1U)
: Base (ref) {
used_ = partial_ = noconv_ = check_state_ = valid_state_ = false;
}
protected:
// override base class virtual function to make the messages
// facet use codecvt<char, char>::in() (the base returns true)
bool do_always_noconv () const _THROWS (()) {
return false;
}
result
do_in (state_type &state,
const extern_type *from,
const extern_type *from_end,
const extern_type *&from_next,
intern_type *to,
intern_type *to_end,
intern_type *&to_next) const {
used_ = true;
#ifndef _RWSTD_NO_MBSINIT
if (check_state_)
valid_state_ = std::mbsinit (&state) != 0;
#else // if (_RWSTD_NO_MBSINIT)
if (check_state_)
valid_state_ = true;
#endif // _RWSTD_NO_MBSINIT
const result res =
Base::do_in (state, from, from_end, from_next,
to, to_end, to_next);
if (partial_)
return std::codecvt_base::partial;
if (noconv_)
return std::codecvt_base::noconv;
return res;
}
};
template <class charT>
bool CodeCvt<charT>::used_;
template <class charT>
bool CodeCvt<charT>::partial_;
template <class charT>
bool CodeCvt<charT>::noconv_;
template <class charT>
bool CodeCvt<charT>::check_state_;
template <class charT>
bool CodeCvt<charT>::valid_state_;
/***************************************************************************/
// finds the first named locale other than "C" or "POSIX"; returns
// a pointer to the name of the locale on success, 0 on failure
const char*
find_named_locale ()
{
const char *name = rw_locales (LC_ALL, "");
if (!name)
return 0;
char namebuf [256];
// get the full name of the "C" locale for comparison with aliases
const char* const classic_name =
std::strcpy (namebuf, std::setlocale (LC_ALL, "C"));
do {
if (std::strcmp (name, "C") && std::strcmp (name, "POSIX")) {
// skip over any aliases of the "C" and "POSIX" locales
const char* const fullname = std::setlocale (LC_ALL, name);
if (std::strcmp (fullname, classic_name)) {
// skip over the C and POSIX locales
_TRY {
const std::locale loc (name);
_RWSTD_UNUSED (loc);
std::setlocale (LC_ALL, "C");
return name;
}
_CATCH (...) { }
}
}
name += std::strlen (name) + 1;
} while (*name);
std::setlocale (LC_ALL, "C");
return 0;
}
/***************************************************************************/
#ifndef _WIN32
# define CAT_NAME "./rwstdmessages.cat"
# define MSG_NAME "rwstdmessages.msg"
#else
# define CAT_NAME "rwstdmessages.dll"
# define MSG_NAME "rwstdmessages.rc"
#endif
#define NLS_CAT_NAME "rwstdmessages"
#define MAX_SETS 5
#define MAX_MESSAGES 5
int msg_id (int set, int id)
{
#ifdef _WIN32
return (set - 1) * 5 + id;
#else
_RWSTD_UNUSED (set);
return id;
#endif
}
/***************************************************************************/
static const char* const
messages [MAX_SETS][MAX_MESSAGES] = {
{ "First set, first message",
"First set, second message",
"First set, third message",
"First set, fourth message",
"First set, fifth message"
},
{ "Second set, first message",
"Second set, second message",
"Second set, third message",
"Second set, fourth message",
"Second set, fifth message"
},
{ "Third set, first message",
"Third set, second message",
"Third set, third message",
"Third set, fourth message",
"Third set, fifth message"
},
{ "Fourth set, first message",
"Fourth set, second message",
"Fourth set, third message",
"Fourth set, fourth message",
"Fourth set, fifth message"
},
{ "Fifth set, first message",
"Fifth set, second message",
"Fifth set, third message",
"Fifth set, fourth message",
"Fifth set, fifth message"
}
};
static std::string catalog;
/***************************************************************************/
template <class charT>
std::basic_string<charT> widen (std::string message)
{
std::basic_string<charT> result;
for (std::size_t i = 0; i < message.length(); i++) {
result.push_back ((charT)message[i]);
}
return result;
}
/***************************************************************************/
// Test that the message facet exists in the locale and that
// we can get a reference to it.
template <class charT>
void test_has_facet (const char *loc_name, const char *cname)
{
// construct a copy of the named locale or default
// when no name is specified
const std::locale loc =
loc_name ? std::locale (loc_name) : std::locale ();
typedef std::messages<charT> Messages;
// verify that the facet exists in the locale
bool facet_exists = std::has_facet<Messages>(loc);
rw_assert (facet_exists, 0, __LINE__,
"has_facet<messages<%s> >(locale(%{?}%#s%{;})) == true",
cname, 0 != loc_name, loc_name);
try {
// verify that use facet doesn't throw an exception
std::use_facet<Messages>(loc);
}
#ifndef _RWSTD_NO_EXCEPTIONS
catch (std::exception &ex) {
rw_assert (0, 0, __LINE__,
"use_fact<messages<%s> >(locale(%{?}%#s%{;})) "
"unexpectedly threw exception(%#s)",
cname, 0 != loc_name, loc_name, ex.what ());
}
catch (...) {
rw_assert (0, 0, __LINE__,
"use_fact<messages<%s> >(locale(%{?}%#s%{;})) "
"unexpectedly threw an unknown exception",
cname, 0 != loc_name, loc_name);
}
typedef std::messages_byname<charT> MessagesByname;
const bool byname = loc_name
&& std::strcmp (loc_name, "C") && std::strcmp (loc_name, "POSIX");
facet_exists = std::has_facet<MessagesByname>(loc);
rw_assert (byname == facet_exists, 0, __LINE__,
"has_fact<messages_byname<%s> >(locale(%{?}%#s%{;})) == %b",
cname, 0 != loc_name, loc_name);
try {
// verify that use facet throws an exception only
// for the default and "C" locales
std::use_facet<MessagesByname>(loc);
rw_assert (byname, 0, __LINE__,
"use_fact<messages_byname<%s> >(locale(%{?}%#s%{;})) "
"failed to throw",
cname, 0 != loc_name, loc_name);
}
catch (std::exception &ex) {
rw_assert (!byname, 0, __LINE__,
"use_fact<messages_byname<%s> >(locale(%{?}%#s%{;})) "
"unexpectedly threw exception(%#s)",
cname, 0 != loc_name, loc_name, ex.what ());
}
catch (...) {
rw_assert (0, 0, __LINE__,
"use_fact<messages<%s> >(locale(%{?}%#s%{;})) "
"unexpectedly threw an unknown exception",
cname, 0 != loc_name, loc_name);
}
#endif // _RWSTD_NO_EXCEPTIONS
}
/***************************************************************************/
template <class charT>
std::messages_base::catalog
open_catalog (const std::messages<charT> &msgs,
const char *cat_name, const std::locale &loc,
int expect, const char *cname, int line)
{
std::messages_base::catalog cat = -1;
// expect is set to:
// * 0 (or greater) when the caller expects the call to open()
// to succeed
// * -1 when the caller expects the call to open() to fail
// by returning -1
// * -2 (or less) when the caller expects the call to open()
// to exit by throwing an exception
const bool expect_success = expect >= 0;
const bool expect_failure = expect == -1;
const bool expect_exception = expect < -1;
const char* const nlspath = std::getenv ("NLSPATH");
try {
// an already closed cat should throw an exception
cat = (msgs.open)(cat_name, loc);
const bool success =
expect_success && -1 < cat || expect_failure && cat < 0;
rw_assert (success, 0, line,
"messages<%s>::open(%#s, locale(%#s))"
"%{?} > -1%{:}%{?} == -1 %{;}%{;}, got %d"
"%{?}; failed to throw an exception%{;}; NLSPATH=%s",
cname, cat_name, loc.name ().c_str (),
expect_success, expect_failure, cat,
expect_exception, nlspath);
}
#ifndef _RWSTD_NO_EXCEPTIONS
catch (std::exception &ex) {
rw_assert (expect_exception, 0, line,
"messages<%s>::open(%#s, locale(%#s)) unexpectedly "
"threw exception(%#s); NLSPATH=%s",
cname, cat_name, loc.name ().c_str (), ex.what (), nlspath);
}
catch (...) {
rw_assert (expect_exception, 0, line,
"messages<%s>::open(%#s, locale(%#s)) unexpectedly "
"threw an unknown exception; NLSPATH=%s",
cname, cat_name, loc.name ().c_str (), nlspath);
}
#endif // _RWSTD_NO_EXCEPTIONS
return cat;
}
/***************************************************************************/
template <class charT>
void
close_catalog (const std::messages<charT> &msgs,
std::messages_base::catalog cat,
bool expect_exception,
const char *cname, int line)
{
try {
// an already closed cat should throw an exception
(msgs.close)(cat);
rw_assert (!expect_exception, 0, line,
"messages<%s>::close(%d) failed "
"to throw an expected exception",
cname, cat);
}
#ifndef _RWSTD_NO_EXCEPTIONS
catch (std::exception &ex) {
rw_assert (expect_exception, 0, line,
"messages<%s>::close(%d) unexpectedly "
"threw exception(%#s)",
cname, cat, ex.what ());
}
catch (...) {
rw_assert (expect_exception, 0, line,
"messages<%s>::close(%d) unexpectedly "
"threw an unknown exception",
cname, cat);
}
#endif // _RWSTD_NO_EXCEPTIONS
}
/***************************************************************************/
template <class charT>
void test_open_close (const char *loc_name, const char *cname)
{
int fdcount [2];
int next_fd [2];
#ifndef _WIN32
next_fd [0] = rw_nextfd (fdcount + 0);
#else
// don't test file descriptor leaking on Win32 to avoid
// invalid parameter error
// catalog functions not uses file descriptors
next_fd [0] = fdcount [0] = 0;
#endif
rw_info (0, 0, __LINE__,
"std::messages<%s>::open() and close() in locale(#%s)",
cname, loc_name);
// construct a copy of the named locale or default
// when no name is specified
const std::locale loc =
loc_name ? std::locale (loc_name) : std::locale ();
const std::messages<charT>& msgs =
std::use_facet<std::messages<charT> >(loc);
const std::messages_base::catalog cat =
open_catalog (msgs, CAT_NAME, loc, 0, cname, __LINE__);
// close a (presumably successfully) opened catalog
close_catalog (msgs, cat, cat < 0, cname, __LINE__);
// an already closed cat should throw an exception
close_catalog (msgs, cat, true, cname, __LINE__);
// verify that no file descriptor has leaked
#ifndef _WIN32
next_fd [1] = rw_nextfd (fdcount + 1);
#else
next_fd [1] = fdcount [1] = 0;
#endif
rw_assert (next_fd [1] == next_fd [0] && fdcount [0] == fdcount [1],
0, __LINE__,
"std::messages<%s>::close() leaked %d file descriptor(s) "
"(or descriptor mismatch)",
cname, fdcount [1] - fdcount [0]);
}
/***************************************************************************/
template <class charT>
void test_get (const char *loc_name,
const char* const text[5][5],
const char *cname)
{
// construct a copy of the named locale or default
// when no name is specified
const std::locale loc =
loc_name ? std::locale (loc_name) : std::locale ();
const std::messages<charT>& msgs =
std::use_facet<std::messages<charT> > (loc);
const charT def[] = {
'N', 'o', ' ', 'm', 'e', 's', 's', 'a', 'g', 'e', '.', '\0'
};
std::messages_base::catalog cat = -1;
cat = open_catalog (msgs, CAT_NAME, loc, 0, cname, __LINE__);
if (cat < 0)
return;
typedef std::char_traits<charT> Traits;
typedef std::allocator<charT> Allocator;
typedef std::basic_string<charT, Traits, Allocator> String;
for (int setId = 1; setId <= MAX_SETS; ++setId) {
for (int msgId = 1; msgId <= MAX_MESSAGES; ++msgId) {
const int id = msg_id (setId, msgId);
const String got = msgs.get (cat, setId, id, def);
rw_assert (got == widen<charT>(text [setId - 1][msgId - 1]),
0, __LINE__,
"messages<%s>::get(%d, %d, %d, %{*Ac}) == %#s, "
"got %{#*S}",
cname, cat, setId, id,
int (sizeof *def), def,
text [setId - 1][msgId - 1],
int (sizeof (charT)), &got);
}
}
// bad catalog id
const std::messages_base::catalog bad_cat = 777;
try {
// get() will either throw or return `def'
// when passed a bad catalog id
const String got = msgs.get (bad_cat, 1, 1, def);
rw_assert (def == got, 0, __LINE__,
"messages<%s>::get(%d, 1, 1, %{*Ac}) == %{*Ac}, got %{#*S}",
cname, bad_cat, int (sizeof *def), def,
int (sizeof *def), def, int (sizeof (charT)), &got);
}
#ifndef _RWSTD_NO_EXCEPTIONS
catch (std::exception &ex) {
rw_assert (true, 0, __LINE__,
"messages<%s>::get(%d, 1, 1, %{*Ac}) unexpectedly threw "
"exception(%#s)", cname, bad_cat, int (sizeof *def), def,
ex.what ());
}
#endif // _RWSTD_NO_EXCEPTIONS
// Bad set id
#if !defined (_WIN32) && !defined (_WIN64)
// When we use resource files for the message catalogs
// the set ids are ignored.
rw_assert (msgs.get (cat, 777, 1, def) == def, 0, __LINE__,
"messages<%s>::get(%d, 777, 1, %{#*Ac}) == %{#*Ac}",
cname, cat, int (sizeof *def), def, int (sizeof *def), def);
#endif // !defined (_WIN32) && !defined (_WIN64)
// Bad message id
rw_assert (msgs.get (cat, 1, 777, def) == def, 0, __LINE__,
"messages<%s>::get(%d, 777, 1) == \"\"", cname);
close_catalog (msgs, cat, false, cname, __LINE__);
}
/***************************************************************************/
template <class charT>
void test_use_codecvt (const char *cname)
{
CodeCvt<charT> cvt (1);
const std::locale loc (std::locale::classic (), &cvt);
const charT def[] = {
'N', 'o', ' ', 'm', 'e', 's', 's', 'a', 'g', 'e', '.', '\0'
};
const std::messages<charT>& msgs =
std::use_facet <std::messages<charT> >(loc);
cvt.used_ = false;
std::messages_base::catalog cat = -1;
cat = open_catalog (msgs, CAT_NAME, loc, 0, cname, __LINE__);
if (cat < 0)
return;
cvt.check_state_ = true;
const int msgid = msg_id (1, 1);
std::basic_string<charT> got = msgs.get (cat, 1, msgid, def);
rw_assert (cvt.used_, 0, __LINE__,
"messages<%s>::get(%d, 1, %d, const char_type*) "
"uses codecvt<%1$s, char>", cname, cat, msgid);
rw_assert (cvt.valid_state_, 0, __LINE__,
"messages<%s>::get(%d, 1, %d, const char_type*) "
"initializes mbstate_t argument", cname, cat, msgid);
cvt.check_state_ = false;
cvt.partial_ = true;
got = msgs.get (cat, 1, msgid, def);
rw_assert (got == def, 0, __LINE__,
"messages<%s>::get(%d, 1, %d, %{*Ac}) == %{*Ac}",
cname, cat, msgid, int (sizeof *def), def,
int (sizeof *def), def);
cvt.partial_ = false;
cvt.noconv_ = true;
got = msgs.get (cat, 1, msgid, def);
rw_assert (got == widen<charT>(std::string(messages[0][0])), 0, __LINE__,
"messages<%s>::get(%d, 1, %d, %{*Ac}) == %#s, got %{#*S}",
cname, cat, msgid, int (sizeof *def), def,
messages [0][0], int (sizeof (charT)), &got);
cvt.noconv_ = false;
close_catalog (msgs, cat, false, cname, __LINE__);
cvt.used_ = false;
}
/***************************************************************************/
template <class charT>
void test_use_nls_path (const char *cname)
{
// get working directory
char cwd [2048];
cwd [0] = '\0';
if (!rw_error (0 != getcwd (cwd, 2048), 0, __LINE__,
"getcwd(%#p, %u) failed: %{#m} (%m)", cwd, 2048))
return;
char* const nlspath = new char [std::strlen (cwd) + 512];
// create NLSPATH string
std::sprintf (nlspath, "NLSPATH=%s/%%N.cat", cwd);
rw_putenv (nlspath);
const std::locale loc;
const std::messages<charT>& msgs =
std::use_facet <std::messages<charT> >(loc);
const std::messages_base::catalog cat =
open_catalog (msgs, NLS_CAT_NAME, loc, 0, "char", __LINE__);
if (-1 < cat)
close_catalog (msgs, cat, false, cname, __LINE__);
delete[] nlspath;
}
/***************************************************************************/
template <class charT>
void stress_test (const char *cname)
{
// NLSPATH must be defined
RW_ASSERT (0 != std::getenv ("NLSPATH"));
char catalog_names [24][24];
const std::size_t NCATS = sizeof catalog_names / sizeof *catalog_names;
std::messages_base::catalog cats [NCATS];
// detect descriptor leaks
const int fd1 = open (__FILE__, O_RDONLY);
const std::locale loc = std::locale::classic ();
const std::messages<charT>& msgs =
std::use_facet<std::messages<charT> > (loc);
std::size_t i;
for (i = 0; i < NCATS; i++) {
char msg_name [NCATS];
#ifndef _WIN32
std::sprintf (msg_name, "rwstdmessages_%d.msg", int (i));
#else
std::sprintf (msg_name, "rwstdmessages_%d.rc", int (i));
#endif
rw_create_catalog (msg_name, catalog.c_str ());
const char* const dot = std::strrchr (msg_name, '.');
std::strncpy (catalog_names[i], msg_name, dot - msg_name);
*(catalog_names[i] + (dot - msg_name)) = '\0';
// open each catalog (expect success)
cats [i] = open_catalog (msgs, catalog_names [i],
loc, 0, cname, __LINE__);
}
// close smallest first and check for descriptor leaks
for (i = 0; i < NCATS; ++i) {
if (-1 != cats [i])
close_catalog (msgs, cats [i], false, cname, __LINE__);
}
int fd2 = open (__FILE__, O_RDONLY);
rw_assert (fd2 - fd1 == 1, 0, __LINE__,
"messages<%s>::close() leaked %d file descriptors",
cname, fd2 - fd1 - 1);
// open again, close largest first and check for descriptor leaks
for (i = 0; i < NCATS; ++i) {
cats [i] = open_catalog (msgs, catalog_names [i],
loc, 0, cname, __LINE__);
}
for (i = NCATS; i-- > 0; ) {
if (-1 != cats [i])
close_catalog (msgs, cats [i], false, cname, __LINE__);
}
// close again fd2
close (fd2);
fd2 = open (__FILE__, O_RDONLY);
rw_assert (fd2 - fd1 == 1, 0, __LINE__,
"messages<%s>::close() leaked %d file descriptors",
cname, fd2 - fd1 - 1);
close (fd1);
close (fd2);
rw_system (SHELL_RM_F "rwstdmessages_*");
}
/**************************************************************************/
int opt_has_facet;
int opt_open_close;
int opt_get;
int opt_codecvt;
int opt_nlspath;
int opt_stress_test;
template <class charT>
void test_messages (charT, const char *cname, const char *locname)
{
if (rw_note (0 <= opt_has_facet, 0, __LINE__,
"has_facet<messages<%s> > tests disabled", cname)) {
// exercise has_facet and use_facet in the default locale
test_has_facet<charT>(0, cname);
// exercise has_facet and use_facet in locale("C")
test_has_facet<charT>("C", cname);
// exercise has_facet and use_facet in a named locale
test_has_facet<charT>(locname, cname);
}
if (rw_note (0 <= opt_open_close, 0, __LINE__,
"messages<%s>::open() and close() tests disabled", cname)) {
test_open_close<charT>("C", cname);
test_open_close<charT>(locname, cname);
}
if (rw_note (0 <= opt_has_facet, 0, __LINE__,
"messages<%s>::get() tests disabled", cname)) {
test_get<charT>("C", messages, cname);
test_get<charT>(locname, messages, cname);
}
if (rw_note (0 <= opt_has_facet, 0, __LINE__,
"messages<%s> codecvt tests disabled", cname))
test_use_codecvt<charT>(cname);
if (rw_note (0 <= opt_nlspath, 0, __LINE__,
"messages<%s> NLSPATH tests disabled", cname))
test_use_nls_path<charT>(cname);
if (rw_note (0 <= opt_has_facet, 0, __LINE__,
"messages<%s> codecvt tests disabled", cname))
stress_test<charT>(cname);
}
/**************************************************************************/
static int
run_test (int, char*[])
{
#ifdef _RWSTD_OS_AIX
// must do this so that NLSPATH lookup works correctly for both
// the C and POSIX locales.
const int p = rw_putenv ("LC__FASTMSG=false");
rw_note (!p, 0, __LINE__, "failed to set LC__FASTMSG");
#endif // _RWSTD_OS_AIX
#ifdef _RWSTD_NO_DYNAMIC_CAST
// if dynamic_cast isn't supported then has_facet() can't
// reliably detect if a facet is installed or not.
rw_warn (0 != opt_has_facet, 0, __LINE__,
"dynamic_cast not supported, disabling has_facet tests");
opt_has_facet = -1;
#endif // _RWSTD_NO_DYNAMIC_CAST
for (int i = 0; i < MAX_SETS; ++i) {
for (int j = 0; j < MAX_MESSAGES; ++j)
catalog.append (messages [i][j], std::strlen (messages [i][j]) + 1);
catalog.append (1, '\0');
}
const char* const locname = find_named_locale ();
rw_create_catalog (MSG_NAME, catalog.c_str ());
test_messages (char (), "char", locname);
#ifndef _RWSTD_NO_WCHAR_T
test_messages (wchar_t (), "wchar_t", locname);
#endif // _RWSTD_NO_WCHAR_T
std::remove (CAT_NAME);
return 0;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
return rw_test (argc, argv, __FILE__,
"lib.category.messages",
0 /* no comment */,
run_test,
"|-has_facet~ "
"|-open_close~ "
"|-get~ "
"|-codecvt~ "
"|-nlspath~ "
"|-stress-test~ ",
&opt_has_facet,
&opt_open_close,
&opt_get,
&opt_codecvt,
&opt_nlspath,
&opt_stress_test,
(void*)0 /* sentinel */);
}

View File

@@ -0,0 +1,340 @@
/************************************************************************
*
* 22.locale.messages.mt.cpp
*
* test exercising the thread safety of the messages facet
*
* $Id: 22.locale.messages.mt.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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.
*
**************************************************************************/
#include <locale>
#include <driver.h> // for rw_test()
#include <rw_locale.h> // for rw_create_catalog()
#include <rw_thread.h>
#include <valcmp.h> // for rw_strncmp ()
#include <cstring> // for strlen()
#include <cstdio> // for remove()
// maximum number of threads allowed by the command line interface
#define MAX_THREADS 32
#define MAX_LOOPS 100000
// default number of threads (will be adjusted to the number
// of processors/cores later)
int rw_opt_nthreads = 1;
// the number of times each thread should iterate (unless specified
// otherwise on the command line)
int rw_opt_nloops = 100000;
// locale for threads to share
static const
std::locale locale;
// message catalog for threads to share
static
std::messages_base::catalog catalog;
static
std::messages_base::catalog wcatalog;
/**************************************************************************/
#ifndef _WIN32
# define CAT_NAME "./rwstdmessages.cat"
# define MSG_NAME "rwstdmessages.msg"
#else
# define CAT_NAME "rwstdmessages.dll"
# define MSG_NAME "rwstdmessages.rc"
#endif
#define MAX_SETS 5
#define MAX_MESSAGES 5
int msg_id (int set, int id)
{
#ifdef _WIN32
return (set - 1) * 5 + id;
#else
_RWSTD_UNUSED (set);
return id;
#endif
}
/**************************************************************************/
static const char* const
messages [MAX_SETS][MAX_MESSAGES] = {
{ "First set, first message",
"First set, second message",
"First set, third message",
"First set, fourth message",
"First set, fifth message"
},
{ "Second set, first message",
"Second set, second message",
"Second set, third message",
"Second set, fourth message",
"Second set, fifth message"
},
{ "Third set, first message",
"Third set, second message",
"Third set, third message",
"Third set, fourth message",
"Third set, fifth message"
},
{ "Fourth set, first message",
"Fourth set, second message",
"Fourth set, third message",
"Fourth set, fourth message",
"Fourth set, fifth message"
},
{ "Fifth set, first message",
"Fifth set, second message",
"Fifth set, third message",
"Fifth set, fourth message",
"Fifth set, fifth message"
}
};
static std::string str_messages;
/**************************************************************************/
template <class T>
void test_open_close (const std::locale& loc,
const std::messages<T>& msgs,
const std::string& name)
{
std::messages_base::catalog cat =
(msgs.open) (name, loc);
RW_ASSERT (! (cat < 0));
(msgs.close) (cat);
}
template <class T>
void test_get (const std::messages<T>& msgs,
const std::messages_base::catalog cat,
int set, int msgid,
const std::basic_string<T>& dflt)
{
// the msg_id() thing seems like a bug to me. if anything, the user
// should never need to write or call msg_id().
const typename std::messages<T>::string_type res =
msgs.get (cat, set, msg_id (set, msgid), dflt);
RW_ASSERT (!rw_strncmp (messages [set-1][msgid-1], res.c_str ()));
}
/**************************************************************************/
extern "C" {
bool test_char; // exercise messages<char>
bool test_wchar; // exercise messages<wchar_t>
static void*
thread_func (void*)
{
const std::string name (CAT_NAME);
const std::messages<char>& nmsgs =
std::use_facet<std::messages<char> >(locale);
const std::string ndflt ("\1\2\3\4");
#ifndef _RWSTD_NO_WCHAR_T
const std::messages<wchar_t>& wmsgs =
std::use_facet<std::messages<wchar_t> >(locale);
const std::wstring wdflt (L"\1\2\3\4");
#endif // _RWSTD_NO_WCHAR_T
for (int i = 0; i != rw_opt_nloops; ++i) {
int set = 1 + i % MAX_SETS;
int msgid = 1 + i % MAX_MESSAGES;
if (test_char) {
if (i & 1) {
test_get<char>(nmsgs, catalog, set, msgid, ndflt);
}
else {
test_open_close<char>(locale, nmsgs, name);
}
}
if (test_wchar) {
#ifndef _RWSTD_NO_WCHAR_T
if (i & 1) {
test_get<wchar_t>(wmsgs, wcatalog, set, msgid, wdflt);
}
else {
test_open_close<wchar_t>(locale, wmsgs, name);
}
#endif // _RWSTD_NO_WCHAR_T
}
}
return 0;
}
} // extern "C"
/**************************************************************************/
static int
run_test (int, char**)
{
for (int i = 0; i < MAX_SETS; ++i) {
for (int j = 0; j < MAX_MESSAGES; ++j)
str_messages.append (messages [i][j], std::strlen (messages [i][j]) + 1);
str_messages.append (1, '\0');
}
// generate a message catalog
rw_create_catalog (MSG_NAME, str_messages.c_str ());
const std::string name (CAT_NAME);
const std::messages<char>& nmsgs =
std::use_facet<std::messages<char> >(locale);
catalog = (nmsgs.open) (name, locale);
#ifndef _RWSTD_NO_WCHAR_T
const std::messages<wchar_t>& wmsgs =
std::use_facet<std::messages<wchar_t> >(locale);
wcatalog = (wmsgs.open) (name, locale);
#endif
rw_info (0, 0, 0,
"testing std::messages<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each",
rw_opt_nthreads, 1 != rw_opt_nthreads,
rw_opt_nloops, 1 != rw_opt_nloops);
///////////////////////////////////////////////////////////////////////
test_char = true;
test_wchar = false;
rw_info (0, 0, 0, "exercising std::messages<char>");
int result =
rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0,
thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
rw_opt_nthreads, thread_func);
///////////////////////////////////////////////////////////////////////
#ifndef _RWSTD_NO_WCHAR_T
test_char = false;
test_wchar = true;
rw_info (0, 0, 0, "exercising std::messages<wchar_t>");
result =
rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0,
thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
rw_opt_nthreads, thread_func);
///////////////////////////////////////////////////////////////////////
test_char = true;
test_wchar = true;
rw_info (0, 0, 0, "exercising std::messages<char> and "
"std::messages<wchar_t>");
result =
rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0,
thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
rw_opt_nthreads, thread_func);
#endif // _RWSTD_NO_WCHAR_T
///////////////////////////////////////////////////////////////////////
(nmsgs.close) (catalog);
#ifndef _RWSTD_NO_WCHAR_T
(wmsgs.close) (wcatalog);
#endif // _RWSTD_NO_WCHAR_T
std::remove (CAT_NAME);
return result;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
#ifdef _RWSTD_REENTRANT
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
rw_opt_nthreads = rw_get_cpus ();
if (rw_opt_nthreads < 2)
rw_opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.messages",
"thread safety", run_test,
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* ", // must be in [0, MAX_THREADS]
&rw_opt_nloops,
int (MAX_THREADS),
&rw_opt_nthreads);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,478 @@
/************************************************************************
*
* 22.locale.money.get.mt.cpp
*
* test exercising the thread safety of the money_get facet
*
* $Id: 22.locale.money.get.mt.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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.
*
**************************************************************************/
#include <ios> // for ios
#include <iterator> // for ostreambuf_iterator
#include <locale> // for locale, money_get
#include <cstring> // for strlen()
#include <rw_locale.h>
#include <rw_thread.h>
#include <driver.h>
#include <valcmp.h> // for rw_strncmp ()
// maximum number of threads allowed by the command line interface
#define MAX_THREADS 32
#define MAX_LOOPS 100000
// the number of times each thread should iterate (unless specified
// otherwise on the command line)
int opt_nloops = 100000;
// default number of threads (will be adjusted to the number
// of processors/cores later)
int opt_nthreads = 1;
#if !defined (_RWSTD_OS_HP_UX) || defined (_ILP32)
// number of locales to use
int opt_nlocales = MAX_THREADS;
#else // HP-UX in LP64 mode
// work around a small cache size on HP-UX in LP64 mode
// in LP64 mode (see STDCXX-812)
int opt_nlocales = 9;
#endif // HP-UX 32/64 bit mode
// should all threads share the same set of locale objects instead
// of creating their own?
int opt_shared_locale;
/**************************************************************************/
// array of locale names to use for testing
static const char*
locales [MAX_THREADS];
// number of locale names in the array
static std::size_t
nlocales;
/**************************************************************************/
//
struct MyMoneyData
{
enum { BufferSize = 16 };
enum GetId {
get_ldbl,
get_string,
get_max
};
// name of the locale the data corresponds to
const char* locale_name_;
// optionally set to the named locale for threads to share
std::locale locale_;
// international or domestic format flag
bool intl_;
//
long double units_;
// narrow locale specific representations of units_
char ncs_ [BufferSize];
std::string ncs_digits_;
#ifndef _RWSTD_NO_WCHAR_T
// wide locale specific representations of units_
wchar_t wcs_ [BufferSize];
std::wstring wcs_digits_;
#endif // _RWSTD_NO_WCHAR_T
} my_money_data [MAX_THREADS];
template <class charT, class Traits>
struct MyIos: std::basic_ios<charT, Traits>
{
MyIos () {
this->init (0);
}
};
template <class charT, class Traits>
struct MyStreambuf: std::basic_streambuf<charT, Traits>
{
typedef std::basic_streambuf<charT, Traits> Base;
MyStreambuf ()
: Base () {
}
void pubsetg (const charT *gbeg, std::streamsize n) {
this->setg (_RWSTD_CONST_CAST (charT*, gbeg),
_RWSTD_CONST_CAST (charT*, gbeg),
_RWSTD_CONST_CAST (charT*, gbeg) + n);
}
void pubsetp (charT *pbeg, std::streamsize n) {
this->setp (pbeg, pbeg + n);
}
};
extern "C" {
bool test_char; // exercise money_get<char>
bool test_wchar; // exercise money_get<wchar_t>
static void*
thread_func (void*)
{
MyIos<char, std::char_traits<char> > nio;
MyStreambuf<char, std::char_traits<char> > nsb;
std::basic_string<char, std::char_traits<char> > str;
nio.rdbuf (&nsb);
#ifndef _RWSTD_NO_WCHAR_T
MyIos<wchar_t, std::char_traits<wchar_t> > wio;
MyStreambuf<wchar_t, std::char_traits<wchar_t> > wsb;
std::basic_string<wchar_t, std::char_traits<wchar_t> > wstr;
wio.rdbuf (&wsb);
#endif // _RWSTD_NO_WCHAR_T
std::ios_base::iostate state = std::ios_base::goodbit;
#ifndef _RWSTD_NO_LONG_DOUBLE
long double ldbl = 0.;
#endif // _RWSTD_NO_LONG_DOUBLE
for (int i = 0; i != opt_nloops; ++i) {
// save the name of the locale
const MyMoneyData& data = my_money_data [i % nlocales];
// construct a named locale, get a reference to the money_get
// facet from it and use it to format a random money value
const std::locale loc =
opt_shared_locale ? data.locale_
: std::locale (data.locale_name_);
if (test_char) {
// exercise the narrow char specialization of the facet
const std::money_get<char> &ng =
std::use_facet<std::money_get<char> >(loc);
nio.imbue (loc);
nsb.pubsetg (data.ncs_, RW_COUNT_OF (data.ncs_));
if (i & 1) {
ng.get (std::istreambuf_iterator<char>(&nsb),
std::istreambuf_iterator<char>(),
data.intl_, nio, state, ldbl);
RW_ASSERT (! (state & std::ios_base::failbit));
RW_ASSERT (! rw_ldblcmp (ldbl, data.units_));
}
else {
ng.get (std::istreambuf_iterator<char>(&nsb),
std::istreambuf_iterator<char>(),
data.intl_, nio, state, str);
RW_ASSERT (! (state & std::ios_base::failbit));
RW_ASSERT (! rw_strncmp (str.c_str (),
data.ncs_digits_.c_str ()));
}
}
// both specializations may be tested at the same time
if (test_wchar) {
// exercise the wide char specialization of the facet
#ifndef _RWSTD_NO_WCHAR_T
const std::money_get<wchar_t> &wg =
std::use_facet<std::money_get<wchar_t> >(loc);
wio.imbue (loc);
wsb.pubsetg (data.wcs_, RW_COUNT_OF (data.wcs_));
if (i & 1) {
wg.get (std::istreambuf_iterator<wchar_t>(&wsb),
std::istreambuf_iterator<wchar_t>(),
data.intl_, wio, state, ldbl);
RW_ASSERT (! (state & std::ios_base::failbit));
RW_ASSERT (! rw_ldblcmp (ldbl, data.units_));
}
else {
wg.get (std::istreambuf_iterator<wchar_t>(&wsb),
std::istreambuf_iterator<wchar_t>(),
data.intl_, wio, state, wstr);
RW_ASSERT (! (state & std::ios_base::failbit));
RW_ASSERT (! rw_strncmp(wstr.c_str (),
data.wcs_digits_.c_str ()));
}
#endif // _RWSTD_NO_WCHAR_T
}
}
return 0;
}
} // extern "C"
/**************************************************************************/
static int
run_test (int, char**)
{
MyIos<char, std::char_traits<char> > nio;
MyStreambuf<char, std::char_traits<char> > nsb;
nio.rdbuf (&nsb);
#ifndef _RWSTD_NO_WCHAR_T
MyIos<wchar_t, std::char_traits<wchar_t> > wio;
MyStreambuf<wchar_t, std::char_traits<wchar_t> > wsb;
wio.rdbuf (&wsb);
#endif // _RWSTD_NO_WCHAR_T
// find all installed locales for which setlocale (LC_ALL) succeeds
const char* const locale_list =
rw_opt_locales ? rw_opt_locales : rw_locales (_RWSTD_LC_ALL);
const std::size_t maxinx = RW_COUNT_OF (locales);
for (const char* name = locale_list;
*name;
name += std::strlen (name) + 1) {
const std::size_t inx = nlocales;
locales [inx] = name;
// fill in the money and results for this locale
MyMoneyData& data = my_money_data [inx];
data.locale_name_ = name;
try {
const std::locale loc (data.locale_name_);
// exercise domestic formats every other iteration
// and international formats the rest
data.intl_ = 0 == (inx & 5);
// initialize with random but valid values
long double units = 1.f + inx;
// exercise postive and negative values
if (inx & 1)
units += (units * 3.14159);
else
units -= (units * 2.71828);
// local scope
{
const std::money_put<char> &np =
std::use_facet<std::money_put<char> >(loc);
const std::money_get<char> &ng =
std::use_facet<std::money_get<char> >(loc);
std::ios::iostate state = std::ios::goodbit;
nio.imbue (loc);
// write the value to buffer from long double
nsb.pubsetp (data.ncs_, RW_COUNT_OF (data.ncs_));
*np.put (std::ostreambuf_iterator<char>(&nsb),
data.intl_, nio, ' ', units) = '\0';
rw_fatal (!nio.fail (), __FILE__, __LINE__,
"money_put<char>::put(...) "
"failed for locale(%#s)", data.locale_name_);
// read the value back so threads know what to expect
nsb.pubsetg (data.ncs_, RW_COUNT_OF (data.ncs_));
ng.get (std::istreambuf_iterator<char>(&nsb),
std::istreambuf_iterator<char>(),
data.intl_, nio, state, data.units_);
// read back as string, again for threads
nsb.pubsetg (data.ncs_, RW_COUNT_OF (data.ncs_));
ng.get (std::istreambuf_iterator<char>(&nsb),
std::istreambuf_iterator<char>(),
data.intl_, nio, state, data.ncs_digits_);
if (state & std::ios_base::failbit)
continue;
}
#ifndef _RWSTD_NO_WCHAR_T
// local scope
{
const std::money_put<wchar_t> &wp =
std::use_facet<std::money_put<wchar_t> >(loc);
const std::money_get<wchar_t> &wg =
std::use_facet<std::money_get<wchar_t> >(loc);
std::ios::iostate state = std::ios::goodbit;
wio.imbue (loc);
// write the value to buffer from long double
wsb.pubsetp (data.wcs_, RW_COUNT_OF (data.wcs_));
*wp.put (std::ostreambuf_iterator<wchar_t>(&wsb),
data.intl_, wio, L' ', units) = L'\0';
rw_fatal (!nio.fail (), __FILE__, __LINE__,
"money_put<wchar_t>::put(...) "
"failed for locale(%#s)", data.locale_name_);
// read back as string, again for threads
wsb.pubsetg (data.wcs_, RW_COUNT_OF (data.wcs_));
wg.get (std::istreambuf_iterator<wchar_t>(&wsb),
std::istreambuf_iterator<wchar_t>(),
data.intl_, wio, state, data.wcs_digits_);
if (state & std::ios_base::failbit)
continue;
}
#endif // _RWSTD_NO_WCHAR_T
if (opt_shared_locale)
data.locale_ = loc;
nlocales += 1;
}
catch (...) {
rw_warn (!rw_opt_locales, 0, __LINE__,
"failed to create locale(%#s)", name);
}
if (nlocales == maxinx || nlocales == std::size_t (opt_nlocales))
break;
}
// avoid divide by zero in thread if there are no locales to test
rw_fatal (nlocales != 0, 0, __LINE__,
"failed to create one or more usable locales!");
rw_info (0, 0, 0,
"testing std::money_get<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
opt_nthreads, 1 != opt_nthreads,
opt_nloops, 1 != opt_nloops,
nlocales, int (nlocales), "%#s", locales);
rw_info (0, 0, 0, "exercising std::money_get<char>");
test_char = true;
test_wchar = false;
// create and start a pool of threads and wait for them to finish
int result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
#ifndef _RWSTD_NO_WCHAR_T
rw_info (0, 0, 0, "exercising std::money_get<wchar_t>");
test_char = false;
test_wchar = true;
// start a pool of threads to exercise wstring thread safety
result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
// exercise both the char and the wchar_t specializations
// at the same time
rw_info (0, 0, 0,
"exercising both std::money_get<char> "
"and std::money_get<wchar_t>");
test_char = true;
test_wchar = true;
// start a pool of threads to exercise wstring thread safety
result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
#endif // _RWSTD_NO_WCHAR_T
return result;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
#ifdef _RWSTD_REENTRANT
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
opt_nthreads = rw_get_cpus ();
if (opt_nthreads < 2)
opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.money.get",
"thread safety", run_test,
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // must be provided
"|-shared-locale# ",
&opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
&opt_nlocales,
&rw_opt_setlocales,
&opt_shared_locale);
}

View File

@@ -0,0 +1,870 @@
/***************************************************************************
*
* 22.locale.money.put.cpp - tests exercising the std::money_put facet
*
* $Id: 22.locale.money.put.cpp 651095 2008-04-23 22:50:27Z sebor $
*
***************************************************************************
*
* 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 2001-2006 Rogue Wave Software.
*
**************************************************************************/
#include <ios>
#include <locale>
#include <cstdio> // for sprintf()
#include <cmdopt.h> // for rw_enabled()
#include <driver.h> // for rw_assert(), rw_test(), ...
#include <valcmp.h> // for rw_strncmp()
/**************************************************************************/
// set to non-zero value when grouping shouldn't be exercised
static int no_grouping;
// set to non-zero value when the basic_string overloads
// of moneY-put::put() shouldn't be exercised
static int no_basic_string;
/**************************************************************************/
template <class charT, bool Intl>
struct Punct: std::moneypunct<charT, Intl>
{
typedef typename std::moneypunct<charT>::char_type char_type;
typedef typename std::moneypunct<charT>::string_type string_type;
static char_type decimal_point_;
static char_type thousands_sep_;
static const char *grouping_;
static const char_type *curr_symbol_;
static const char_type *positive_sign_;
static const char_type *negative_sign_;
static std::money_base::pattern pos_format_;
static std::money_base::pattern neg_format_;
static int frac_digits_;
static int n_thousands_sep_; // number of calls to do_thousands_sep()
Punct (): std::moneypunct<charT>(1) { }
char_type do_decimal_point () const {
return decimal_point_;
}
int do_frac_digits () const {
return frac_digits_;
}
virtual string_type do_curr_symbol () const {
return curr_symbol_ ? curr_symbol_ : string_type ();
}
virtual std::string do_grouping () const {
return grouping_;
}
virtual char_type do_thousands_sep () const {
++n_thousands_sep_;
return thousands_sep_;
}
virtual string_type do_positive_sign () const {
return positive_sign_ ? positive_sign_ : string_type ();
}
virtual string_type do_negative_sign () const {
return negative_sign_ ? negative_sign_ : string_type ();
}
virtual std::money_base::pattern do_pos_format () const {
return pos_format_;
}
virtual std::money_base::pattern do_neg_format () const {
return neg_format_;
}
};
template <class charT, bool Intl>
const char*
Punct<charT, Intl>::grouping_ = "";
template <class charT, bool Intl>
typename Punct<charT, Intl>::char_type
Punct<charT, Intl>::decimal_point_ = ':';
template <class charT, bool Intl>
typename Punct<charT, Intl>::char_type
Punct<charT, Intl>::thousands_sep_ = ';';
template <class charT, bool Intl>
const typename Punct<charT, Intl>::char_type*
Punct<charT, Intl>::curr_symbol_;
template <class charT, bool Intl>
const typename Punct<charT, Intl>::char_type*
Punct<charT, Intl>::positive_sign_;
template <class charT, bool Intl>
const typename Punct<charT, Intl>::char_type*
Punct<charT, Intl>::negative_sign_;
template <class charT, bool Intl>
std::money_base::pattern
Punct<charT, Intl>::pos_format_ = { {
std::money_base::symbol,
std::money_base::sign,
std::money_base::none,
std::money_base::value
} };
template <class charT, bool Intl>
std::money_base::pattern
Punct<charT, Intl>::neg_format_ = { {
std::money_base::symbol,
std::money_base::sign,
std::money_base::none,
std::money_base::value
} };
template <class charT, bool Intl>
int
Punct<charT, Intl>::n_thousands_sep_;
template <class charT, bool Intl>
int
Punct<charT, Intl>::frac_digits_;
/**************************************************************************/
template <class charT>
struct Ios: std::basic_ios<charT>
{
Ios () { this->init (0); }
};
template <class charT>
struct MoneyPut: std::money_put<charT, charT*>
{
// default ctor defined in order to make it possible
// to define const objects of the type w/o explictly
// initializing them
typedef std::money_put<charT, charT*> Base;
MoneyPut (): Base () { /* no-op */ }
};
/**************************************************************************/
bool test_neg_zero;
/**************************************************************************/
std::money_base::pattern
set_pattern (const char *format)
{
std::money_base::pattern pat;
for (unsigned i = 0; i != sizeof pat.field / sizeof *pat.field; ++i) {
switch (format [i]) {
case '\0': case '@': pat.field [i] = std::money_base::none; break;
case '\1': case ' ': pat.field [i] = std::money_base::space; break;
case '\2': case '$': pat.field [i] = std::money_base::symbol; break;
case '\3': case '-': pat.field [i] = std::money_base::sign; break;
case '\4': case '1': pat.field [i] = std::money_base::value; break;
default:
_RWSTD_ASSERT (!!"bad format specifier");
}
}
return pat;
}
template <class charT>
int type_test (int lineno,
charT /* unused */,
long double val /* value to format */,
const char *str /* expected result */,
char fill = ' ',
int flags = 0,
int frac_digits = 0,
int width = 0,
const char *format = 0 /* pattern or printf() format */,
const char *grouping = 0)
{
if (!rw_enabled (lineno)) {
rw_note (0, __FILE__, __LINE__, "test on line %d disabled", lineno);
return 0;
}
static const char* const cname = 1 < sizeof (charT) ? "wchar_t" : "char";
static int i = 0; // assertion number per specialization of type_test()
if (!i) {
rw_info (0, 0, 0, "std::money_put<%s>::put(ostreambuf_iterator"
"<%s>, bool, ios_base, %s, long double)",
cname, cname, cname);
rw_info (0, 0, 0, "std::money_put<%s>::put(ostreambuf_iterator"
"<%s>, bool, ios_base, %s, "
"const basic_string<%s>&))",
cname, cname, cname, cname);
}
//////////////////////////////////////////////////////////////////
// exercise put (..., long double) overload
int nfail = 0; // number of failed assertions
// unless 0, or unless it starts with '%', the `format' argument
// is treated as a money_base::pattern string; otherwise the
// default pattern is used
// default format as in locale ("C")
const char *fmt_pat = !format || *format == '%' ? "\2\3\4\0" : format;
if (!grouping) {
// default grouping as in locale ("C")
grouping = "";
}
const Punct<charT, false> pun;
// take care to initialize Punct static data before installing
// the facet in case locale or the base facet calls the overridden
// virtuals early to cache the results
pun.grouping_ = grouping;
pun.frac_digits_ = frac_digits;
if (val < 0.0) {
pun.neg_format_ = set_pattern (fmt_pat);
pun.pos_format_ = std::money_base::pattern ();
}
else if (val > 0.0) {
pun.neg_format_ = std::money_base::pattern ();
pun.pos_format_ = set_pattern (fmt_pat);
}
else {
// 0.0 and -0.0
pun.neg_format_ = set_pattern (fmt_pat);
pun.pos_format_ = pun.neg_format_;
}
// ios-derived object to pass to the facet
Ios<charT> ios;
// money_put-derived object
const MoneyPut<charT> mp;
// install the moneypunct facet in a locale and imbue the latter
// in the ios-derived object used by money_put
std::locale loc (ios.getloc (), (const std::moneypunct<charT>*)&pun);
ios.imbue (loc);
// set the formatting flags and the width
ios.flags (std::ios_base::fmtflags (flags));
ios.width (std::streamsize (width));
bool success;
charT buf [256] = { 0 };
if (rw_enabled ("long double")) {
// exercise 22.2.6.2.1, long double overload
*mp.put (buf, false, ios, charT (fill), val) = charT ();
rw_assert (0 == ios.width (), __FILE__, lineno,
"money_put<%s>::put (%#p, false, const ios_base&, "
"%{#c}, %LfL) reset width from %d",
cname, buf, fill, val, width);
success = 0 == rw_strncmp (buf, str);
if (!success)
++nfail;
rw_assert (success, __FILE__, lineno,
"money_put<%s>::put (%#p, false, "
"const ios_base&, %{#c}, %LfL) == %{#s} got %{#s}; "
"flags = %{If}, grouping = %{#s}",
cname, buf,
fill, val, str, buf,
flags, grouping);
}
else {
static int msg_issued;
rw_note (msg_issued++, __FILE__, 0, "long double test disabled");
}
//////////////////////////////////////////////////////////////////
// exercise put (..., const basic_string&) overload
if (frac_digits < 0) {
// do not perform string test(s) for negative values of frac_digits
// (extension implemented only for the long double overload of put())
++i;
return nfail;
}
if (no_basic_string) {
rw_note (0, __FILE__, __LINE__,
"basic_string<%s> test on line %d disabled", lineno, cname);
return nfail;
}
// zero out buffer
std::char_traits<charT>::assign (buf, sizeof buf / sizeof *buf, charT ());
// if the format string starts with a '%',
// use it to format the floating point value
if (!format || *format != '%')
format = "%.0" _RWSTD_LDBL_PRINTF_PREFIX "f";
char valbuf [256] = "";
const int valbuflen = std::sprintf (valbuf, format, val);
RW_ASSERT (0 < valbuflen && valbuflen < int (sizeof valbuf));
typedef std::char_traits<charT> Traits;
typedef std::allocator<charT> Allocator;
const std::basic_string<charT, Traits, Allocator>
valstr (valbuf, valbuf + valbuflen);
// set width (reset by a previous call)
ios.width (std::streamsize (width));
// exercise 22.2.6.2.1, basic_string overload
*mp.put (buf, false, ios, charT (fill), valstr) = charT ();
success = 0 == rw_strncmp (buf, str);
if (!success)
++nfail;
rw_assert (success, __FILE__, lineno,
"money_put<%s>::put (%#p, false, "
"const ios_base&, %{#S}) == %{#s} got %{#s}; "
"flags = %{If}, grouping = %{#s}",
cname, fill, &valstr, buf, str,
flags, grouping);
++i;
return nfail;
}
/**************************************************************************/
// for convenience
#define Boolalpha std::ios_base::boolalpha
#define Dec std::ios_base::dec
#define Fixed std::ios_base::fixed
#define Hex std::ios_base::hex
#define Internal std::ios_base::internal
#define Left std::ios_base::left
#define Oct std::ios_base::oct
#define Right std::ios_base::right
#define Scientific std::ios_base::scientific
#define Showbase std::ios_base::showbase
#define Showpoint std::ios_base::showpoint
#define Showpos std::ios_base::showpos
#define Skipws std::ios_base::skipws
#define Unitbuf std::ios_base::unitbuf
#define Uppercase std::ios_base::uppercase
#define Bin std::ios_base::bin
#define Adjustfield std::ios_base::adjustfield
#define Basefield std::ios_base::basefield
#define Floatfield std::ios_base::floatfield
#define Nolock std::ios_base::nolock
#define Nolockbuf std::ios_base::nolockbuf
#define Eofbit std::ios_base::eofbit
#define Failbit std::ios_base::failbit
#define Goodbit std::ios_base::goodbit
template <class charT>
void ldbl_test (charT)
{
static const charT curr_symbol1 [8] = { '$', '\0' };
Punct<charT, false>::curr_symbol_ = curr_symbol1;
Punct<charT, false>::decimal_point_ = ':';
Punct<charT, false>::thousands_sep_ = ';';
static const charT signs1[][4] = {
// negative positive
{ '~', '\0' }, { '\0', },
};
Punct<charT, false>::negative_sign_ = signs1 [0];
Punct<charT, false>::positive_sign_ = signs1 [1];
int ntried = 0;
int nfailed = 0;
#define T __LINE__, charT ()
#define TEST ++ntried, nfailed += type_test
// enum part { none, space, symbol, sign, value };
// no symbol, empty sign, default format
TEST (T, 0., "0", ' ');
TEST (T, 1., "1", ' ');
TEST (T, 12., "12", ' ');
TEST (T, 123., "123", ' ');
TEST (T, 1234., "1234", ' ');
TEST (T, 12345., "12345", ' ');
TEST (T, 123456., "123456", ' ');
TEST (T, 1234567., "1234567", ' ');
TEST (T, 12345678., "12345678", ' ');
TEST (T, 123456789., "123456789", ' ');
TEST (T, 12345678.9, "12345679", ' ');
TEST (T, 1234567.89, "1234568", ' ');
TEST (T, 123456.789, "123457", ' ');
TEST (T, 12345.6789, "12346", ' ');
TEST (T, 1234.56789, "1235", ' ');
TEST (T, 123.456789, "123", ' ');
TEST (T, 12.3456789, "12", ' ');
TEST (T, 1.23456789, "1", ' ');
TEST (T, .123456789, "0", ' ');
// exercise correct handling of frac_digits
TEST (T, 9876543210., "987654321:0", ' ', 0, 1);
TEST (T, 876543210., "8765432:10", ' ', 0, 2);
TEST (T, 76543210., "76543:210", ' ', 0, 3);
TEST (T, 6543210., "654:3210", ' ', 0, 4);
TEST (T, 543210., "5:43210", ' ', 0, 5);
TEST (T, 43210., "0:043210", ' ', 0, 6);
TEST (T, 3210., "0:0003210", ' ', 0, 7);
TEST (T, 210., "0:00000210", ' ', 0, 8);
TEST (T, 10., "0:000000010", ' ', 0, 9);
TEST (T, 1., "0:000000001", ' ', 0, 9);
TEST (T, 0., "0:000000000", ' ', 0, 9);
TEST (T, 200., "0:000000200", ' ', 0, 9);
TEST (T, 3000., "0:000003000", ' ', 0, 9);
TEST (T, 40000., "0:000040000", ' ', 0, 9);
TEST (T, 500000., "0:000500000", ' ', 0, 9);
TEST (T, 6000000., "0:006000000", ' ', 0, 9);
TEST (T, 70000000., "0:070000000", ' ', 0, 9);
TEST (T, 800000000., "0:800000000", ' ', 0, 9);
TEST (T, -900000000., "~0:900000000", ' ', 0, 9);
TEST (T, -80000000., "~0:080000000", ' ', 0, 9);
TEST (T, -7000000., "~0:007000000", ' ', 0, 9);
TEST (T, -600000., "~0:000600000", ' ', 0, 9);
TEST (T, -50000., "~0:000050000", ' ', 0, 9);
TEST (T, -4000., "~0:000004000", ' ', 0, 9);
TEST (T, -300., "~0:000000300", ' ', 0, 9);
TEST (T, -20., "~0:000000020", ' ', 0, 9);
TEST (T, -1., "~0:000000001", ' ', 0, 9);
if (test_neg_zero)
TEST (T, -0., "~0:000000000", ' ', 0, 9);
// extension: fixed and negative frac_digits
TEST (T, 1.0, "1:0", ' ', Fixed, -1);
TEST (T, 2.0, "2:00", ' ', Fixed, -2);
TEST (T, 3.0, "3:000", ' ', Fixed, -3);
TEST (T, 4.1, "4:1000", ' ', Fixed, -4);
TEST (T, 52.34, "52:34000", ' ', Fixed, -5);
TEST (T, 634.56789, "634:5679", ' ', Fixed, -4);
// exhaustively exercise valid permutations of format patterns
// (`none' allowed in all but the first position by 22.2.6.3, p1)
TEST (T, 12, "12", '\0', 0, 0, 0, "\3\0\4\2", "");
TEST (T, 123, "123", '\0', 0, 0, 0, "\3\0\2\4", "");
TEST (T, 1234, "1234", '\0', 0, 0, 0, "\3\2\4\0", "");
TEST (T, 2345, "2345", '\0', 0, 0, 0, "\3\4\2\0", "");
TEST (T, 3456, "3456", '\0', 0, 0, 0, "\3\4\0\2", "");
TEST (T, 4567, "4567", '\0', 0, 0, 0, "\4\0\2\3", "");
TEST (T, 5678, "5678", '\0', 0, 0, 0, "\4\2\0\3", "");
TEST (T, 6789, "6789", '\0', 0, 0, 0, "\4\2\3\0", "");
TEST (T, 7890, "7890", '\0', 0, 0, 0, "\4\0\3\2", "");
TEST (T, 8901, "8901", '\0', 0, 0, 0, "\2\4\0\3", "");
TEST (T, 9012, "9012", '\0', 0, 0, 0, "\2\0\4\3", "");
TEST (T, 123, "123", '\0', 0, 0, 0, "\2\0\3\4", "");
// format using `space' in valid positions (all but
// the first and last as specified by 22.2.6.3, p1)
// the actual space character (not the fill char)
// is required
TEST (T, 9, " 9", '*', 0, 0, 0, "\3\1\4\2", "");
TEST (T, 98, " 98", '*', 0, 0, 0, "\3\1\2\4", "");
TEST (T, 987, "987 ", '*', 0, 0, 0, "\3\4\1\2", "");
TEST (T, 876, "876 ", '*', 0, 0, 0, "\4\1\2\3", "");
TEST (T, 765, "765 ", '*', 0, 0, 0, "\4\2\1\3", "");
TEST (T, 654, "654 ", '*', 0, 0, 0, "\4\1\3\2", "");
TEST (T, 543, "543 ", '*', 0, 0, 0, "\2\4\1\3", "");
TEST (T, 432, " 432", '*', 0, 0, 0, "\2\1\4\3", "");
TEST (T, 321, " 321", '*', 0, 0, 0, "\2\1\3\4", "");
TEST (T, 0, "$0", '\0', Showbase, 0, 0, "\2\3\4\0", "");
TEST (T, 1, "$1", '\0', Showbase, 0, 0, "\2\3\4\0", "");
TEST (T, 12, "$12", '\0', Showbase, 0, 0, "\2\3\4\0", "");
TEST (T, 123, "$123", '\0', Showbase, 0, 0, "\2\3\4\0", "");
TEST (T, 1234, "$1234", '\0', Showbase, 0, 0, "\2\3\4\0", "");
TEST (T, 12345, "$12345", '\0', Showbase, 0, 0, "\2\3\4\0", "");
TEST (T, 123456, "$123456", '\0', Showbase, 0, 0, "\2\3\4\0", "");
TEST (T, 1234567, "$1234567", '\0', Showbase, 0, 0, "\2\3\4\0", "");
TEST (T, 12345678, "$12345678", '\0', Showbase, 0, 0, "\2\3\4\0", "");
TEST (T, 0, "$0", '\0', Showbase, 0, 0, 0, "\2");
TEST (T, 1, "$1", '\0', Showbase, 0, 0, 0, "\2\2");
TEST (T, 12, "$12", '\0', Showbase, 0, 0, 0, "\2");
TEST (T, 123, "$1;23", '\0', Showbase, 0, 0, 0, "\2\2");
TEST (T, 1234, "$12;34", '\0', Showbase, 0, 0, 0, "\2");
TEST (T, 12345, "$1;23;45", '\0', Showbase, 0, 0, 0, "\2\2");
TEST (T, 123456, "$12;34;56", '\0', Showbase, 0, 0, 0, "\2");
TEST (T, 1234567, "$1;23;45;67", '\0', Showbase, 0, 0, 0, "\2\2");
TEST (T, 12345678, "$12;34;56;78", '\0', Showbase, 0, 0, 0, "\2");
TEST (T, 123456789, "$1;23;45;67;89", '\0', Showbase, 0, 0, 0, "\2\2");
if (test_neg_zero)
TEST (T, -0.0, "$~0", '\0', Showbase, 0, 0, 0, "\3\3");
TEST (T, -1, "$~1", '\0', Showbase, 0, 0, 0, "\3");
TEST (T, -12, "$~12", '\0', Showbase, 0, 0, 0, "\3\3");
TEST (T, -123, "$~123", '\0', Showbase, 0, 0, 0, "\3");
TEST (T, -1234, "$~1;234", '\0', Showbase, 0, 0, 0, "\3\3");
TEST (T, -12345, "$~12;345", '\0', Showbase, 0, 0, 0, "\3");
TEST (T, -123456, "$~123;456", '\0', Showbase, 0, 0, 0, "\3\3");
TEST (T, -1234567, "$~1;234;567", '\0', Showbase, 0, 0, 0, "\3");
TEST (T, -12345678, "$~12;345;678", '\0', Showbase, 0, 0, 0, "\3\3");
TEST (T, -123456789, "$~123;456;789", '\0', Showbase, 0, 0, 0, "\3");
// for convenience
const char *f = "\3\2\4\0"; // { sign, symbol, value, none }
TEST (T, -321, "~$32;1", '\0', Showbase, 0, 0, f, "\1\2");
TEST (T, -4322, "~$432;2", '\0', Showbase, 0, 0, f, "\1\3");
TEST (T, -54323, "~$5;4;3;2;3", '\0', Showbase, 0, 0, f, "\1\1");
TEST (T, -654324, "~$6;5;4;3;2;4", '\0', Showbase, 0, 0, f, "\1\1");
TEST (T, -7654325, "~$765;432;5", '\0', Showbase, 0, 0, f, "\1\3");
TEST (T, -87654326, "~$8;7;6;5;4;3;26", '\0', Showbase, 0, 0, f, "\2\1");
TEST (T, -987654327, "~$98;76;54;32;7", '\0', Showbase, 0, 0, f, "\1\2");
static const charT curr_symbol2 [8] = { 'X', 'Y', '\0' };
Punct<charT, false>::curr_symbol_ = curr_symbol2;
static const charT signs2[][8] = {
// negative positive
{ '(', ')', '\0' }, { '{', '}', '\0' }
};
Punct<charT, false>::negative_sign_ = signs2 [0];
Punct<charT, false>::positive_sign_ = signs2 [1];
Punct<charT, false>::thousands_sep_ = '.';
Punct<charT, false>::decimal_point_ = '.';
f = "\3\4\1\2"; // { sign, value, space, symbol }
TEST (T, -1357911, "(1.3.5.7.9.1.1 XY)", '*', Showbase, 0, 0, f, "\1");
TEST (T, -2468012, "(2.46.80.12 XY)", '-', Showbase, 0, 0, f, "\2");
TEST (T, -3692513, "(3.692.513 XY)", ' ', Showbase, 0, 0, f, "\3");
TEST (T, -9999914, "(999.9914 XY)", '@', Showbase, 0, 0, f, "\4");
TEST (T, -1000015, "(10.00015 XY)", '#', Showbase, 0, 0, f, "\5");
TEST (T, -16, "(16 XY)", ')', Showbase, 0, 0, f, "\6");
TEST (T, +1357917, "{1.3.5.7.9.1.7 XY}", ',', Showbase, 0, 0, f, "\1");
TEST (T, +2468018, "{2.46.80.18 XY}", '+', Showbase, 0, 0, f, "\2");
TEST (T, +3692519, "{3.692.519 XY}", '0', Showbase, 0, 0, f, "\3");
TEST (T, +9999920, "{999.9920 XY}", '1', Showbase, 0, 0, f, "\4");
TEST (T, +1000021, "{10.00021 XY}", '\0', Showbase, 0, 0, f, "\5");
TEST (T, +22, "{22 XY}", '{', Showbase, 0, 0, f, "\6");
TEST (T, +123, "{123 }", '_', 0, 0, 0, f, "\6");
TEST (T, -224, "(224 )", '_', 0, 0, 0, f, "\7");
TEST (T, +325, "{ XY325}", ' ', Showbase, 0, 0, "\3\1\2\4", "\xa");
TEST (T, -426, "( XY426)", ' ', Showbase, 0, 0, "\3\1\2\4", "\xb");
TEST (T, +527, "{XY 527}", ' ', Showbase, 0, 0, "\3\2\1\4", "\xc");
TEST (T, -628, "(XY 628)", ' ', Showbase, 0, 0, "\3\2\1\4", "\xd");
TEST (T, +729, "{XY729}", ' ', Showbase, 0, 0, "\3\2\0\4", "\xe");
TEST (T, -830, "(XY830)", ' ', Showbase, 0, 0, "\3\2\0\4", "\xf");
TEST (T, +931, "{XY931}", ' ', Showbase, 0, 0, "\3\0\2\4", "\x10");
TEST (T, -1032, "(XY1032)", ' ', Showbase, 0, 0, "\3\0\2\4");
TEST (T, +1133, "1133{XY}", ' ', Showbase, 0, 0, "\4\3\2\0");
TEST (T, -1234, "1234XY()", ' ', Showbase, 0, 0, "\4\2\3\0");
TEST (T, +1335, "1335XY{}", ' ', Showbase, 0, 0, "\4\2\0\3");
TEST (T, -1436, "1436XY ()", ' ', Showbase, 0, 0, "\4\2\1\3");
TEST (T, +1537, "1537XY{}", ' ', Showbase, 0, 0, "\4\0\2\3");
TEST (T, -1638, "1638 XY()", ' ', Showbase, 0, 0, "\4\1\2\3");
TEST (T, +1739, "XY1739{}", ' ', Showbase, 0, 0, "\2\4\0\3");
TEST (T, -1840, "XY1840 ()", ' ', Showbase, 0, 0, "\2\4\1\3");
TEST (T, +1941, "XY1941{}", ' ', Showbase, 0, 0, "\2\0\4\3");
TEST (T, -2042, "XY 2042()", ' ', Showbase, 0, 0, "\2\1\4\3");
TEST (T, +2143, "XY{2143}", ' ', Showbase, 0, 0, "\2\3\4\0");
TEST (T, -2244, "XY(2244)", ' ', Showbase, 0, 0, "\2\3\0\4");
TEST (T, +2345, "XY{ 2345}", ' ', Showbase, 0, 0, "\2\3\1\4");
// 22.2.6.2, p2:
// ...copies of `fill' are inserted as necessary to pad to the
// specified width. For the value `af' equal to (str.flags()
// & str.adjustfield), if (af == str.internal) is true, the fill
// characters are placed where `none' or `space' appears in the
// formatting pattern; otherwise if (af == str.left) is true, they
// are placed after the other characters; otherwise, they are
// placed before the other characters.
TEST (T, -2446, "___XY( 2446)", '_', Showbase, 0, 12, "\2\3\1\4");
TEST (T, +2547, "____XY{2547}", '_', Showbase, 0, 12, "\2\3\0\4");
TEST (T, -2648, "___XY( 2648)", '_', Showbase | Right, 0, 12, "\2\3\1\4");
TEST (T, +2749, "____XY{2749}", '_', Showbase | Right, 0, 12, "\2\3\0\4");
TEST (T, -2850, "XY( 2850)___", '_', Showbase | Left, 0, 12, "\2\3\1\4");
TEST (T, +2951, "XY{2951}____", '_', Showbase | Left, 0, 12, "\2\3\0\4");
TEST (T, -3052, "___XY( 3052)", '_',
Showbase | Left | Right, 0, 12, "\2\3\1\4");
TEST (T, +3153, "____XY{3153}", '_',
Showbase | Left | Right, 0, 12, "\2\3\0\4");
TEST (T, -3254, "___XY( 3254)", '_',
Showbase | Left | Right | Internal, 0, 12, "\2\3\1\4");
TEST (T, +3355, "____XY{3355}", '_',
Showbase | Left | Right | Internal, 0, 12, "\2\3\0\4");
TEST (T, -3456, "XY( ___3456)", '_',
Showbase | Internal, 0, 12, "\2\3\1\4");
TEST (T, +3557, "XY{____3557}", '_',
Showbase | Internal, 0, 12, "\2\3\0\4");
TEST (T, -3658, "XY____(3658)", '_',
Showbase | Internal, 0, 12, "\2\0\3\4");
TEST (T, +3759, "XY{3759____}", '_',
Showbase | Internal, 0, 12, "\2\3\4\0");
TEST (T, 3759, "XY{37.59}", '_',
Showbase | Internal, 0, 8, "\2\3\4\0", "\2");
TEST (T, 3760, "XY{ 37.60}", '_',
Showbase | Internal, 0, 8, "\2\3\1\4", "\2");
TEST (T, 12345678900000000000.0, "XY{ ........1.23.45678.9000.00.000.0.00}",
'.', Showbase | Internal, 0, 40, "\2\3\1\4", "\2\1\3\2\4\5\2");
TEST (T, 1234567890000000000.0, "{ ...........1234.56789.0000.000.00.0XY}",
'.', Showbase | Internal, 0, 40, "\3\1\4\2", "\1\2\3\4\5\6");
// exercise justification with non-zero frac_digits
TEST (T, 1, "_____{0.1}", '_', 0, 1, 10, "-@1$");
TEST (T, 12, "_____{1.2}", '_', 0, 1, 10, "-@1$");
TEST (T, 123, "____{1.23}", '_', 0, 2, 10, "-@1$");
TEST (T, 1234, "_{12.34XY}", '_', Showbase, 2, 10, "-@1$");
TEST (T, 1235, "_{ 12.35XY}", '_', Showbase, 2, 11, "- 1$");
TEST (T, 2, "******{0.2}", '*', Right, 1, 11, "-@1$");
TEST (T, 23, "******{2.3}", '*', Right, 1, 11, "-@1$");
TEST (T, 234, "*****{2.34}", '*', Right, 2, 11, "-@1$");
TEST (T, 2345, "**{23.45XY}", '*', Right | Showbase, 2, 11, "-@1$");
TEST (T, 2346, "**{ 23.46XY}", '*', Right | Showbase, 2, 12, "- 1$");
TEST (T, 3, "{0.3}#######", '#', Left, 1, 12, "-@1$");
TEST (T, 34, "{3.4}#######", '#', Left, 1, 12, "-@1$");
TEST (T, 345, "{3.45}######", '#', Left, 2, 12, "-@1$");
TEST (T, 3456, "{34.56XY}###", '#', Left | Showbase, 2, 12, "-@1$");
TEST (T, 3457, "{ 34.57XY}###", '#', Left | Showbase, 2, 13, "- 1$");
TEST (T, 4, "{=====0.4}", '=', Internal, 1, 10, "-@1$");
TEST (T, 45, "{=====4.5}", '=', Internal, 1, 10, "-@1$");
TEST (T, 456, "{====4.56}", '=', Internal, 2, 10, "-@1$");
TEST (T, 4567, "{=45.67XY}", '=', Internal | Showbase, 2, 10, "-@1$");
TEST (T, 4568, "{ =45.68XY}", '=', Internal | Showbase, 2, 11, "- 1$");
Punct<charT, false>::thousands_sep_ = ',';
Punct<charT, false>::decimal_point_ = '.';
// justification with grouping
TEST (T, 105, "====={1,0.5}", '=', 0, 1, 12, "-@1$", "\1");
TEST (T, 1056, "===={1,05.6}", '=', 0, 1, 12, "-@1$", "\2");
TEST (T, 10567, "==={1,05.67}", '=', 0, 2, 12, "-@1$", "\2");
TEST (T, 105678, "=={10,56.78XY}", '=', Showbase, 2, 14, "-@1$", "\2");
TEST (T, 105679, "={ 10,56.79XY}", '=', Showbase, 2, 14, "- 1$", "\2");
TEST (T, 105680, "={ 1,056,80XY}", '=', Showbase, 0, 14, "- 1$", "\2\3");
int flags = Right | Showbase;
TEST (T, 106, ">>>>>{1,0.6}", '>', Right, 1, 12, "-@1$", "\1");
TEST (T, 1057, ">>>>{1,05.7}", '>', Right, 1, 12, "-@1$", "\2");
TEST (T, 10568, ">>>{1,05.68}", '>', Right, 2, 12, "-@1$", "\2");
TEST (T, 105679, ">>{10,56.79XY}", '>', flags, 2, 14, "-@1$", "\2");
TEST (T, 105680, ">{ 10,56.80XY}", '>', flags, 2, 14, "- 1$", "\2");
TEST (T, 105681, ">{ 1,056,81XY}", '>', flags, 0, 14, "- 1$", "\2\3");
flags = Left | Showbase;
TEST (T, 107, "{1,0.7}<<<<<", '<', Left, 1, 12, "-@1$", "\1");
TEST (T, 1058, "{1,05.8}<<<<", '<', Left, 1, 12, "-@1$", "\2");
TEST (T, 10569, "{1,05.69}<<<", '<', Left, 2, 12, "-@1$", "\2");
TEST (T, 105680, "{10,56.80XY}<<", '<', flags, 2, 14, "-@1$", "\2");
TEST (T, 105681, "{ 10,56.81XY}<", '<', flags, 2, 14, "- 1$", "\2");
TEST (T, 105682, "{ 1,056,82XY}<", '<', flags, 0, 14, "- 1$", "\2\3");
flags = Internal | Showbase;
TEST (T, 108, "{^^^^^1,0.8}", '^', Internal, 1, 12, "-@1$", "\1");
TEST (T, 1059, "{^^^^1,05.9}", '^', Internal, 1, 12, "-@1$", "\2");
TEST (T, 10570, "{^^^1,05.70}", '^', Internal, 2, 12, "-@1$", "\2");
TEST (T, 105681, "{^^10,56.81XY}", '^', flags, 2, 14, "-@1$", "\2");
TEST (T, 105682, "{ ^10,56.82XY}", '^', flags, 2, 14, "- 1$", "\2");
TEST (T, 105683, "{ ^1,056,83XY}", '^', flags, 0, 14, "- 1$", "\2\3");
flags = Left | Right | Showbase;
TEST (T, 109, "#####{1,0.9}", '#', Left | Right, 1, 12, "-@1$", "\1");
TEST (T, 1060, "####{1,06.0}", '#', Left | Right, 1, 12, "-@1$", "\2");
TEST (T, 10571, "###{1,05.71}", '#', Left | Right, 2, 12, "-@1$", "\2");
TEST (T, 105682, "##{10,56.82XY}", '#', flags, 2, 14, "-@1$", "\2");
TEST (T, 105683, "#{ 10,56.83XY}", '#', flags, 2, 14, "- 1$", "\2");
TEST (T, 105684, "#{ 10,56,84XY}", '#', flags, 0, 14, "- 1$", "\2");
// verify that mon_put (..., const basic_string&) ignores the part
// of the string starting with the first non-numeric character
#undef FMT
#define FMT(fmt) "%.0" _RWSTD_LDBL_PRINTF_PREFIX "f" fmt
// using default format "\2\3\4\0": {symbol, sign, value, none}
TEST (T, 10, "{1.0}", ' ', 0, 1, -1, FMT (" "));
TEST (T, 10, "{1.0}", ' ', 0, 1, -1, FMT ("."));
TEST (T, -11, "(1.1)", ' ', 0, 1, -1, FMT (" "));
TEST (T, -11, "(1.1)", ' ', 0, 1, -1, FMT ("."));
TEST (T, 101, "{1.01}", ' ', 0, 2, -1, FMT (" "));
TEST (T, 101, "{1.01}", ' ', 0, 2, -1, FMT ("."));
Punct<charT, false>::negative_sign_ = signs1 [0];
Punct<charT, false>::positive_sign_ = signs1 [1];
TEST (T, 1012, "1,0.12", ' ', 0, 2, -1, FMT (" 0"), "\1");
TEST (T, 1013, "1,0.13", ' ', 0, 2, -1, FMT (".1"), "\1");
TEST (T, -1014, "~1,01.4", ' ', 0, 1, -1, FMT ("~2"), "\2");
TEST (T, -1015, "~1,01.5", ' ', 0, 1, -1, FMT (",3"), "\2");
}
/**************************************************************************/
void grouping_test ()
{
if (!rw_enabled ("char")) {
rw_note (0, __FILE__, __LINE__, "char test disabled");
return;
}
rw_info (0, 0, 0, "std::money_put<%s>::put(ostreambuf_iterator"
"<%s>, bool, ios_base, %s, long double); correct use of "
"moneypunct<%s, false>::grouping() and thousands_sep()",
"char", "char", "char", "char");
typedef Punct<char, false> PunctT;
// construct a "replacement" moneypunct-derived facet
const PunctT pun;
// group after every digit
PunctT::grouping_ = "\1";
// reset the do_thousands_sep()-call counter
PunctT::thousands_sep_ = ';';
PunctT::decimal_point_ = ':';
PunctT::n_thousands_sep_ = 0;
// construct and initialize a basic_ios-derived object
struct Ios: std::basic_ios<char> { Ios () { this->init (0); } } ios;
// construct a money_put-derived facet to exercise
struct MoneyPut: std::money_put<char, char*> { } mp;
// imbue a stream object with a custom locale
// containing the replacement punctuation facet
std::locale l;
std::locale loc (l, (const std::moneypunct<char>*)&pun);
ios.imbue (loc);
// decimal output, no special formatting
ios.setf (std::ios::fmtflags ());
char buf [40] = "";
*mp.put (buf, false, ios, '\0', 123456789.0L) = '\0';
// verify that the number was formatted correctly
rw_assert (0 == rw_strncmp (buf, "1;2;3;4;5;6;7;8;9"), __FILE__, __LINE__,
"money_put<char, char*>::do_put(..., 123456789.0L) "
"== %#s, got %#s", "1;2;3;4;5;6;7;8;9", buf);
// verify that do_thousands_sep() was called at least once
// (but not necessarily for each thousands separator inserted
// into the output, since the value is allowed to be cached)
rw_assert (0 != PunctT::n_thousands_sep_, __FILE__, __LINE__,
"money_put<char, char*>::do_put(..., 123456789.0L) "
"called moneypunct<char>::do_thousands_sep()");
}
/**************************************************************************/
static int
run_test (int, char*[])
{
// check to see if we can test -0.0
static volatile double d = -0.0;
test_neg_zero = 1.0 / d < d;
if (no_grouping)
rw_note (0, __FILE__, __LINE__, "grouping test disabled");
else
grouping_test ();
if (rw_enabled ("char"))
ldbl_test (char ());
else
rw_note (0, __FILE__, __LINE__, "char test disabled");
#ifndef _RWSTD_NO_WCHAR_T
if (rw_enabled ("wchar_t"))
ldbl_test (wchar_t ());
else
rw_note (0, __FILE__, __LINE__, "wchar_t test disabled");
#endif // _RWSTD_NO_WCHAR_T
return 0;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
return rw_test (argc, argv, __FILE__,
"lib.locale.money.put",
0 /* no comment */, run_test,
"|-no-grouping# |-no-basic_string#",
&no_grouping, &no_basic_string);
}

View File

@@ -0,0 +1,484 @@
/************************************************************************
*
* 22.locale.money.put.mt.cpp
*
* test exercising the thread safety of the money_put facet
*
* $Id: 22.locale.money.put.mt.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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.
*
**************************************************************************/
#include <ios> // for ios
#include <iterator> // for ostreambuf_iterator
#include <locale> // for locale, money_put
#include <cstring> // for strlen()
#include <rw_locale.h>
#include <rw_thread.h>
#include <driver.h>
#include <valcmp.h> // for rw_strncmp ()
// maximum number of threads allowed by the command line interface
#define MAX_THREADS 32
#define MAX_LOOPS 100000
// default number of threads (will be adjusted to the number
// of processors/cores later)
int opt_nthreads = 1;
// the number of times each thread should iterate (unless specified
// otherwise on the command line)
int opt_nloops = 100000;
#if !defined (_RWSTD_OS_HP_UX) || defined (_ILP32)
// number of locales to use
int opt_nlocales = MAX_THREADS;
#else // HP-UX in LP64 mode
// work around a small locale cache on HP-UX in LP64 mode
// (see STDCXX-812)
int opt_nlocales = 9;
#endif // HP-UX 32/64 bit mode
// should all threads share the same set of locale objects instead
// of creating their own?
int opt_shared_locale;
/**************************************************************************/
// array of locale names to use for testing
static const char*
locales [MAX_THREADS];
// number of locale names in the array
static std::size_t
nlocales;
/**************************************************************************/
static const char n_money_vals[][20] = {
"1", "12", "123", "1234", "12345", "123456", "1234567", "12345678",
"-9", "-98", "-987", "-9876", "-98765", "-987654", "-9876543",
"1.9", "-12.89", "123.789", "-1234.6789", "-12345.56789"
};
#ifndef _RWSTD_NO_WCHAR_T
static const wchar_t w_money_vals[][20] = {
L"1", L"12", L"123", L"1234", L"12345", L"123456", L"1234567",
L"-9", L"-98", L"-987", L"-9876", L"-98765", L"-987654", L"-9876543",
L"1.9", L"-12.89", L"123.789", L"-1234.6789", L"-12345.56789"
};
#endif // _RWSTD_NO_WCHAR_T
//
struct MyMoneyData
{
enum { BufferSize = 16 };
enum PutId {
put_ldbl,
put_string,
put_max
};
// name of the locale the data corresponds to
const char* locale_name_;
// optionally set to the named locale for threads to share
std::locale locale_;
// international or domestic format flag
bool intl_;
// the time struct used to generate strings below
double money_value_;
// type of the data we created string from
PutId type_;
// index into string array [n,w]_money_vals
unsigned money_index_;
// narrow representations of money_
char ncs_ [BufferSize];
#ifndef _RWSTD_NO_WCHAR_T
// wide representations of money_
wchar_t wcs_ [BufferSize];
#endif // _RWSTD_NO_WCHAR_T
} my_money_data [MAX_THREADS];
template <class charT, class Traits>
struct MyIos: std::basic_ios<charT, Traits>
{
MyIos () {
this->init (0);
}
};
template <class charT, class Traits>
struct MyStreambuf: std::basic_streambuf<charT, Traits>
{
typedef std::basic_streambuf<charT, Traits> Base;
MyStreambuf ()
: Base () {
}
void pubsetp (charT *pbeg, std::streamsize n) {
this->setp (pbeg, pbeg + n);
}
};
extern "C" {
bool test_char; // exercise money_put<char>
bool test_wchar; // exercise money_put<wchar_t>
static void*
thread_func (void*)
{
char ncs [MyMoneyData::BufferSize];
MyIos<char, std::char_traits<char> > nio;
MyStreambuf<char, std::char_traits<char> > nsb;
nio.rdbuf (&nsb);
#ifndef _RWSTD_NO_WCHAR_T
wchar_t wcs [MyMoneyData::BufferSize];
MyIos<wchar_t, std::char_traits<wchar_t> > wio;
MyStreambuf<wchar_t, std::char_traits<wchar_t> > wsb;
wio.rdbuf (&wsb);
#endif // _RWSTD_NO_WCHAR_T
for (int i = 0; i != opt_nloops; ++i) {
// save the name of the locale
const MyMoneyData& data = my_money_data [i % nlocales];
// construct a named locale, get a reference to the money_put
// facet from it and use it to format a random money value
const std::locale loc =
opt_shared_locale ? data.locale_
: std::locale (data.locale_name_);
if (test_char) {
// exercise the narrow char specialization of the facet
const std::money_put<char> &np =
std::use_facet<std::money_put<char> >(loc);
nio.imbue (loc);
nsb.pubsetp (ncs, RW_COUNT_OF (ncs));
switch (data.type_) {
case MyMoneyData::put_ldbl:
*np.put (std::ostreambuf_iterator<char>(&nsb),
data.intl_, nio, ' ', data.money_value_) = '\0';
break;
case MyMoneyData::put_string:
*np.put (std::ostreambuf_iterator<char>(&nsb),
data.intl_, nio, ' ',
n_money_vals [data.money_index_]) = '\0';
break;
case MyMoneyData::put_max:
// avoid enumeration value `put_max' not handled in switch
// this case should never happen
break;
}
RW_ASSERT (!nio.fail ());
RW_ASSERT (!rw_strncmp (ncs, data.ncs_));
}
// both specializations may be tested at the same time
if (test_wchar) {
// exercise the wide char specialization of the facet
#ifndef _RWSTD_NO_WCHAR_T
const std::money_put<wchar_t> &wp =
std::use_facet<std::money_put<wchar_t> >(loc);
wio.imbue (loc);
wsb.pubsetp (wcs, RW_COUNT_OF (wcs));
switch (data.type_) {
case MyMoneyData::put_ldbl:
*wp.put (std::ostreambuf_iterator<wchar_t>(&wsb),
data.intl_, wio, ' ', data.money_value_) = L'\0';
break;
case MyMoneyData::put_string:
*wp.put (std::ostreambuf_iterator<wchar_t>(&wsb),
data.intl_, wio, ' ',
w_money_vals [data.money_index_]) = L'\0';
break;
case MyMoneyData::put_max:
// avoid enumeration value `put_max' not handled in switch
// this case should never happen
break;
}
RW_ASSERT (!wio.fail ());
RW_ASSERT (!rw_strncmp (wcs, data.wcs_));
#endif // _RWSTD_NO_WCHAR_T
}
}
return 0;
}
} // extern "C"
/**************************************************************************/
static int
run_test (int, char**)
{
MyIos<char, std::char_traits<char> > nio;
MyStreambuf<char, std::char_traits<char> > nsb;
nio.rdbuf (&nsb);
#ifndef _RWSTD_NO_WCHAR_T
MyIos<wchar_t, std::char_traits<wchar_t> > wio;
MyStreambuf<wchar_t, std::char_traits<wchar_t> > wsb;
wio.rdbuf (&wsb);
#endif // _RWSTD_NO_WCHAR_T
// find all installed locales for which setlocale (LC_ALL) succeeds
const char* const locale_list =
rw_opt_locales ? rw_opt_locales : rw_locales (_RWSTD_LC_ALL);
const std::size_t maxinx = RW_COUNT_OF (locales);
for (const char* name = locale_list;
*name;
name += std::strlen (name) + 1) {
const std::size_t inx = nlocales;
locales [inx] = name;
// fill in the money and results for this locale
MyMoneyData& data = my_money_data [inx];
data.locale_name_ = name;
try {
const std::locale loc (data.locale_name_);
// initialize with random but valid values
data.money_value_ = inx;
data.type_ = MyMoneyData::PutId (nlocales % MyMoneyData::put_max);
data.money_index_ = inx % RW_COUNT_OF (n_money_vals);
// exercise domestic formats every other iteration
// and international formats the rest
data.intl_ = 0 == (inx & 1);
// exercise postive and negative values
if (inx & 1)
data.money_value_ *= -1.;
// add some random fractional digits
if (inx & 2)
data.money_value_ += data.money_value_ / 3.14;
const std::money_put<char> &np =
std::use_facet<std::money_put<char> >(loc);
nio.imbue (loc);
nsb.pubsetp (data.ncs_, RW_COUNT_OF (data.ncs_));
switch (data.type_) {
case MyMoneyData::put_ldbl:
*np.put (std::ostreambuf_iterator<char>(&nsb),
data.intl_, nio, ' ', data.money_value_) = '\0';
break;
case MyMoneyData::put_string:
*np.put (std::ostreambuf_iterator<char>(&nsb),
data.intl_, nio, ' ',
n_money_vals [data.money_index_]) = '\0';
break;
case MyMoneyData::put_max:
// avoid enumeration value `put_max' not handled in switch
// this case should never happen
break;
}
rw_assert (!nio.fail (), __FILE__, __LINE__,
"money_put<char>::put(...) "
"failed for locale(%#s)",
data.locale_name_);
#ifndef _RWSTD_NO_WCHAR_T
const std::money_put<wchar_t> &wp =
std::use_facet<std::money_put<wchar_t> >(loc);
wio.imbue (loc);
wsb.pubsetp (data.wcs_, RW_COUNT_OF (data.wcs_));
switch (data.type_) {
case MyMoneyData::put_ldbl:
*wp.put (std::ostreambuf_iterator<wchar_t>(&wsb),
data.intl_, wio, L' ', data.money_value_) = '\0';
break;
case MyMoneyData::put_string:
*wp.put (std::ostreambuf_iterator<wchar_t>(&wsb),
data.intl_, wio, L' ',
w_money_vals [data.money_index_]) = L'\0';
break;
case MyMoneyData::put_max:
// avoid enumeration value `put_max' not handled in switch
// this case should never happen
break;
}
rw_assert (!nio.fail (), __FILE__, __LINE__,
"money_put<wchar_t>::put(...) "
"failed for locale(%#s)",
data.locale_name_);
#endif // _RWSTD_NO_WCHAR_T
if (opt_shared_locale)
data.locale_ = loc;
nlocales += 1;
}
catch (...) {
rw_warn (!rw_opt_locales, 0, __LINE__,
"failed to create locale(%#s)", name);
}
if (nlocales == maxinx || nlocales == std::size_t (opt_nlocales))
break;
}
// avoid divide by zero in thread if there are no locales to test
rw_fatal (nlocales != 0, 0, __LINE__,
"failed to create one or more usable locales!");
rw_info (0, 0, 0,
"testing std::money_put<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
opt_nthreads, 1 != opt_nthreads,
opt_nloops, 1 != opt_nloops,
nlocales, int (nlocales), "%#s", locales);
rw_info (0, 0, 0, "exercising std::money_put<char>");
test_char = true;
test_wchar = false;
// create and start a pool of threads and wait for them to finish
int result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
#ifndef _RWSTD_NO_WCHAR_T
rw_info (0, 0, 0, "exercising std::money_put<wchar_t>");
test_char = false;
test_wchar = true;
// start a pool of threads to exercise wstring thread safety
result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
// exercise both the char and the wchar_t specializations
// at the same time
rw_info (0, 0, 0,
"exercising both std::money_put<char> "
"and std::money_put<wchar_t>");
test_char = true;
test_wchar = true;
// start a pool of threads to exercise wstring thread safety
result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
#endif // _RWSTD_NO_WCHAR_T
return result;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
#ifdef _RWSTD_REENTRANT
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
opt_nthreads = rw_get_cpus ();
if (opt_nthreads < 2)
opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.money.put",
"thread safety", run_test,
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // must be provided
"|-shared-locale# ",
&opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
&opt_nlocales,
&rw_opt_setlocales,
&opt_shared_locale);
}

View File

@@ -0,0 +1,857 @@
/***************************************************************************
*
* 22.locale.moneypunct.cpp - tests for the moneypunct facet
*
* $Id: 22.locale.moneypunct.cpp 651095 2008-04-23 22:50:27Z sebor $
*
***************************************************************************
*
* 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 1998-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
#include <locale>
#include <cassert>
#include <clocale> // for LC_ALL, setlocale()
#include <cstdio> // for fprintf(), stderr
#include <cstdlib> // for getenv()
#include <cstring> // for memcmp(), strerror()
#include <driver.h> // for rw_test()
#include <environ.h> // for rw_putenv()
#include <rw_locale.h> // for rw_locales()
#include <rw_printf.h> // for rw_fprintf()
/**************************************************************************/
typedef unsigned char UChar;
/**************************************************************************/
// does a deep copy of struct lconv
std::lconv* lconvdup (const std::lconv *plconv)
{
if (!plconv)
return 0;
const std::size_t
decimal_point_sz = std::strlen (plconv->decimal_point) + 1,
thousands_sep_sz = std::strlen (plconv->thousands_sep) + 1,
grouping_sz = std::strlen (plconv->grouping) + 1,
int_curr_symbol_sz = std::strlen (plconv->int_curr_symbol) + 1,
currency_symbol_sz = std::strlen (plconv->currency_symbol) + 1,
mon_decimal_point_sz = std::strlen (plconv->mon_decimal_point) + 1,
mon_thousands_sep_sz = std::strlen (plconv->mon_thousands_sep) + 1,
mon_grouping_sz = std::strlen (plconv->mon_grouping) + 1,
positive_sign_sz = std::strlen (plconv->positive_sign) + 1,
negative_sign_sz = std::strlen (plconv->negative_sign) + 1;
const std::size_t total_sz =
decimal_point_sz
+ thousands_sep_sz
+ grouping_sz
+ int_curr_symbol_sz
+ currency_symbol_sz
+ mon_decimal_point_sz
+ mon_thousands_sep_sz
+ mon_grouping_sz
+ positive_sign_sz
+ negative_sign_sz;
const std::size_t bufsize = sizeof (std::lconv) + total_sz;
char *pbuf = _RWSTD_STATIC_CAST (char*, operator new (bufsize));
std::lconv *plconv2 = _RWSTD_REINTERPRET_CAST (std::lconv*, pbuf);
plconv2->decimal_point = (pbuf += sizeof (std::lconv));
std::memcpy (pbuf, plconv->decimal_point, decimal_point_sz);
plconv2->thousands_sep = (pbuf += decimal_point_sz);
std::memcpy (pbuf, plconv->thousands_sep, thousands_sep_sz);
plconv2->grouping = (pbuf += thousands_sep_sz);
std::memcpy (pbuf, plconv->grouping, grouping_sz);
plconv2->int_curr_symbol = (pbuf += grouping_sz);
std::memcpy (pbuf, plconv->int_curr_symbol, int_curr_symbol_sz);
plconv2->currency_symbol = (pbuf += int_curr_symbol_sz);
std::memcpy (pbuf, plconv->currency_symbol, currency_symbol_sz);
plconv2->mon_decimal_point = (pbuf += currency_symbol_sz);
std::memcpy (pbuf, plconv->mon_decimal_point, mon_decimal_point_sz);
plconv2->mon_thousands_sep = (pbuf += mon_decimal_point_sz);
std::memcpy (pbuf, plconv->mon_thousands_sep, mon_thousands_sep_sz);
plconv2->mon_grouping = (pbuf += mon_thousands_sep_sz);
std::memcpy (pbuf, plconv->mon_grouping, mon_grouping_sz);
plconv2->positive_sign = (pbuf += mon_grouping_sz);
std::memcpy (pbuf, plconv->positive_sign, positive_sign_sz);
plconv2->negative_sign = (pbuf += positive_sign_sz);
std::memcpy (pbuf, plconv->negative_sign, negative_sign_sz);
plconv2->int_frac_digits = plconv->int_frac_digits;
plconv2->frac_digits = plconv->frac_digits;
plconv2->p_cs_precedes = plconv->p_cs_precedes;
plconv2->p_sep_by_space = plconv->p_sep_by_space;
plconv2->n_cs_precedes = plconv->n_cs_precedes;
plconv2->n_sep_by_space = plconv->n_sep_by_space;
plconv2->p_sign_posn = plconv->p_sign_posn;
plconv2->n_sign_posn = plconv->n_sign_posn;
#ifndef _RWSTD_NO_LCONV_INT_FMAT
plconv2->int_p_cs_precedes = plconv->int_p_cs_precedes;
plconv2->int_p_sep_by_space = plconv->int_p_sep_by_space;
plconv2->int_n_cs_precedes = plconv->int_n_cs_precedes;
plconv2->int_n_sep_by_space = plconv->int_n_sep_by_space;
plconv2->int_p_sign_posn = plconv->int_p_sign_posn;
plconv2->int_n_sign_posn = plconv->int_n_sign_posn;
#endif // _RWSTD_NO_LCONV_INT_FMAT
return plconv2;
}
/**************************************************************************/
template <class charT>
class Test
{
std::locale loc_;
bool intl_; // international?
const char *char_name_; // charT name ("char" or "wchar_t")
const char *locname_;
const char *lang_;
const char *lc_all_;
const char *lc_monetary_;
public:
typedef std::moneypunct<charT, false> Punct;
typedef std::moneypunct<charT, true> IntlPunct;
Test (const char *cname, bool intl)
: loc_ (), intl_ (intl),
char_name_ (cname),
locname_ (0), lang_ (0), lc_all_ (0), lc_monetary_ (0) { }
void runTest ();
void check_decimal_point (charT);
void check_thousands_sep (charT);
void check_frac_digits (int);
void check_grouping (const std::string&);
typedef std::char_traits<charT> Traits;
typedef std::allocator<charT> Allocator;
typedef std::basic_string<charT, Traits, Allocator> String;
void check_curr_symbol (const String&);
void check_positive_sign (const String&);
void check_negative_sign (const String&);
void check_format (const std::lconv&);
void check_format (bool, std::money_base::pattern, const UChar [3]);
bool check_moneypunct (const char*);
};
/**************************************************************************/
template <class charT>
void Test<charT>::
runTest()
{
// create a copy of the classic C locale
loc_ = std::locale::classic ();
// verify (at compile time) that _bynam facets can be used
// to specialize use_facet() and has_facet()
typedef std::moneypunct_byname<charT, false> MoneyPunctByname;
typedef std::moneypunct_byname<charT, true> MoneyPunctIntlByname;
if (1) {
if (_STD_HAS_FACET (MoneyPunctByname, loc_))
_RWSTD_USE_FACET (MoneyPunctByname, loc_);
if (_STD_HAS_FACET (MoneyPunctIntlByname, loc_))
_RWSTD_USE_FACET (MoneyPunctIntlByname, loc_);
}
// note that values in 7.4 of C89, and 7.11, p2 of C99, respectively,
// or '\0' and '\0' for decimal_point and thousands_sep, are specified
// in 22.2.3.1.2, p1 and p2 of C++98 to be '.', and ',' in the C locale
//
check_decimal_point (charT ('.'));
check_thousands_sep (charT (','));
check_frac_digits (0 /* i.e., not available, or same as CHAR_MAX in C */);
check_grouping ("");
const charT empty[] = { '\0' };
check_curr_symbol (empty);
check_positive_sign (empty);
check_negative_sign (empty);
// verify 22.2.6.3.2, p7:
// moneypunct<char>, moneypunct<wchar_t>, moneypunct<char,true>, and
// moneypunct<wchar_t,true>, return an object of type pattern initialized
// to { symbol, sign, none, value }
std::money_base::pattern fmat = {
// initializer must be properly bracketed to prevent g++ warnings
{
std::money_base::symbol,
std::money_base::sign,
std::money_base::none,
std::money_base::value
}
};
const UChar cpat [4] = { '?', '?', '?', 0 };
check_format (false /* negative */, fmat, cpat);
check_format (true /* positive */, fmat, cpat);
// exercise the native locale (affected by the environment
// variables LANG, LC_ALL, LC_MONETARY, etc.)
check_moneypunct (""); // native locale
// the name of the first non-C (and non-POSIX) locale
const char *first_non_c = 0;
// exercise named locales (including "C" and "POSIX")
for (const char* s = rw_locales (); s && *s; s += std::strlen (s) + 1) {
if (check_moneypunct (s))
if ( !first_non_c
&& std::strcmp ("C", s)
&& std::strcmp ("POSIX", s)) {
first_non_c = s;
}
}
if (!first_non_c)
return;
// verify that moneypunct behaves correctly when LC_ALL is set
// to the name of the (non-C, non-POSIX) locale
char envvar [80];
// make sure buffer doesn't overflow
assert (std::strlen(first_non_c) + sizeof "LC_ALL=" <= sizeof envvar);
std::sprintf (envvar, "LC_ALL=%s", first_non_c);
rw_putenv (envvar);
check_moneypunct ("");
// remove LC_ALL from the environment
rw_putenv ("LC_ALL=");
}
/**************************************************************************/
std::string convert (const char*, const char *s, const char*)
{
return std::string (s);
}
// convert a multibyte character string in an external representation
// to wstring object in an internal representation
std::wstring
convert (const char *locname, const char *s, const wchar_t*)
{
// save the name of the original locale
std::string saved_loc;
if (const char *savename = std::setlocale (LC_ALL, 0))
saved_loc = savename;
// switch to (named) locale
const char *loc = std::setlocale (LC_ALL, locname);
if (!loc) {
rw_fprintf (rw_stderr,
"%s:%d: setlocale (LC_ALL, %s) = 0: %m\n",
locname);
return std::wstring ();
}
// use an extension: allocate but do not initialize
std::wstring res ((wchar_t*)0, 64);
for ( ; ; ) {
// try to convert, resizing buffer if necessary
std::size_t n =
std::mbstowcs (&res [0], s, res.capacity ());
if (res.capacity () == n)
// increase capacity
res.reserve (res.capacity () * 2);
else if (std::size_t (-1) == n) {
// restore the original locale before printing out
// the error message (we don't want it localized)
std::setlocale (LC_ALL, saved_loc.c_str ());
rw_fprintf (rw_stderr,
"%s:%d: mbstowcs(..., %#s, %zu) "
"= -1: %m\n", __FILE__, __LINE__,
s, res.capacity ());
res = std::wstring (); // mbstowcs() error
return res;
}
else {
// shrink if necessary
res.resize (n);
break;
}
}
// restore original locale
std::setlocale (LC_ALL, saved_loc.c_str ());
return res;
}
/**************************************************************************/
template <class charT>
bool Test<charT>::
check_moneypunct (const char *locname)
{
// (try to) set the global C locale
char locnamebuf [256];
const char *loc = std::setlocale (LC_ALL, locname);
if (!loc)
return false;
loc = std::strcpy (locnamebuf, loc);
locname_ = loc;
// the values of the environment variables LANG, LC_ALL,
// and LC_MONETARY (and others) affect the native locale
lang_ = std::getenv ("LANG");
lc_all_ = std::getenv ("LC_ALL");
lc_monetary_ = std::getenv ("LC_MONETARY");
if (!lang_)
lang_ = "(null)";
if (!lc_all_)
lc_all_ = "(null)";
if (!lc_monetary_)
lc_monetary_ = "(null)";
_TRY {
// get a pointer to lconv and copy data to a temporray buffer
const std::lconv* const plconv = lconvdup (std::localeconv ());
if (!plconv)
return false;
// reset to default locale given by LC_LANG
std::setlocale (LC_ALL, "");
// create a new C++ locale object
loc_ = std::locale (locname);
// check that newly constructed locale matches
// the MBCS mon_decimal_point and mon_thousands_sep must
// be properly converted (i.e., *mon_decimal_point may not
// the same as s [0] after the conversion)
String s;
// `locname' may be the empty string, in which case `loc'
// will be set to the actual name of the locale
if ( std::strcmp ("C", locname)
&& std::strcmp ("C", loc)) {
// named locale other than "C" or "POISX"
s = ::convert (locname, plconv->mon_decimal_point, (charT*)0);
check_decimal_point (s.size () ? s [0] : charT ());
s = ::convert (locname, plconv->mon_thousands_sep, (charT*)0);
check_thousands_sep (s.size () ? s [0] : charT ());
check_frac_digits (plconv->int_frac_digits);
}
else {
// note that values in 7.4 of C89, and 7.11, p2 of C99,
// respectively, or '\0' and '\0' for decimal_point and
// thousands_sep, are specified in 22.2.3.1.2, p1 and p2
// of C++98 to be '.', and ',' in the C locale
check_decimal_point (charT ('.'));
check_thousands_sep (charT (','));
// frac_digits is specified as CHAR_MAX (i.e., not available) by C99
// verify that the C++ value is NOT CHAR_MAX, but rather 0 (it could
// be negative with the same result)
check_frac_digits (0);
}
check_grouping (plconv->mon_grouping);
// convert a (possibly) multibyte string in external
// representation to one in internal representation
s = intl_ ? ::convert (locname, plconv->int_curr_symbol, (charT*)0)
: ::convert (locname, plconv->currency_symbol, (charT*)0);
check_curr_symbol (s);
s = ::convert (locname, plconv->positive_sign, (charT*)0);
check_positive_sign (s);
s = ::convert (locname, plconv->negative_sign, (charT*)0);
check_negative_sign (s);
check_format (*plconv);
// cast away constness to work around compiler bugs (e.g., MSVC 6)
operator delete (_RWSTD_CONST_CAST (std::lconv*, plconv));
}
_CATCH (...) {
return false;
}
return true;
}
/**************************************************************************/
template <class charT>
void Test<charT>::
check_decimal_point (charT result)
{
const charT c = intl_ ? _RWSTD_USE_FACET (IntlPunct, loc_).decimal_point ()
: _RWSTD_USE_FACET (Punct, loc_).decimal_point ();
rw_assert (std::char_traits<charT>::eq (c, result), 0, __LINE__,
"moneypunct<%s, %b>::decimal_point() == %#lc, got %#lc "
"in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
char_name_, intl_, result, c,
locname_, lang_, lc_all_, lc_monetary_);
}
/**************************************************************************/
template <class charT>
void Test<charT>::
check_thousands_sep (charT result)
{
const charT c = intl_ ? _RWSTD_USE_FACET (IntlPunct, loc_).thousands_sep ()
: _RWSTD_USE_FACET (Punct, loc_).thousands_sep ();
rw_assert (std::char_traits<charT>::eq (c, result), 0, __LINE__,
"moneypunct<%s, %b>::thousands_sep() == %#lc, got %#lc "
"in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
char_name_, intl_, result, c,
locname_, lang_, lc_all_, lc_monetary_);
}
/**************************************************************************/
template <class charT>
void Test<charT>::
check_frac_digits (int result)
{
const int i = intl_ ? _RWSTD_USE_FACET (IntlPunct, loc_).frac_digits ()
: _RWSTD_USE_FACET (Punct, loc_).frac_digits ();
rw_assert (i == result, 0, __LINE__,
"moneypunct<%s, %b>::frac_digits() == %d, got %d "
"in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
char_name_, intl_, result, i,
locname_, lang_, lc_all_, lc_monetary_);
}
/**************************************************************************/
template <class charT>
void Test<charT>::
check_grouping (const std::string &result)
{
const std::string s = intl_ ?
_RWSTD_USE_FACET (IntlPunct, loc_).grouping ()
: _RWSTD_USE_FACET (Punct, loc_).grouping ();
if ( s != result
&& s.size () != result.size () && s.size () && result.size ()) {
// if the grouping is not exactly the same as the expected result,
// verify that the actual grouping is equivalent to the expected
// one, e.g., that "\003\003" is equivalent to "\003"
const std::string *lng = s.size () > result.size () ? &result : &s;
const std::string *shrt = s.size () < result.size () ? &result : &s;
std::size_t i = shrt->size () - 1;
for ( ; i != lng->size (); ++i)
if ((*shrt) [shrt->size () - 1] != (*lng)[i])
break;
rw_assert (i == lng->size (), 0, __LINE__,
"numpunct<%s, %b>::grouping() equivalent to %#s, got %#s "
"in locale (%#s) with LANG=%s, LC_ALL=%s, "
"LC_MONETARY=%s",
char_name_, intl_, result.c_str (), s.c_str (),
locname_, lang_, lc_all_, lc_monetary_);
}
else
rw_assert (s == result, 0, __LINE__,
"moneypunct<%s, %b>::grouping() == %#s, got %#s "
"in locale (%#s) with LANG=%s, LC_ALL=%s, "
"LC_MONETARY=%s",
char_name_, intl_, result.c_str (), s.c_str (),
locname_, lang_, lc_all_, lc_monetary_);
#if 0
// Test disabled: what's meant here is that the pattern, NOT the value,
// is defined identically as that of numpunct<charT>::do_grouping().
// The values are often going to be different since one uses
// lconv::grouping, and the other lconv::mon_grouping.
// 22.2.6.3.2, p3: do_grouping() returns a pattern defined identically
// as the result of numpunct<charT>::do_grouping().
const std::string grp =
_RWSTD_USE_FACET (std::numpunct<charT>, loc_).grouping ();
rw_assert (s == grp, 0, __LINE__,
"moneypunct<%s, %b>::grouping() == numpunct<>::grouping() == "
"%{*Ac}, got %{*Ac} in locale (\"%s\") with LANG=%s, LC_ALL=%s, "
"LC_MONETARY=%s",
char_name_, intl_,
int (sizeof (charT)), result.c_str (),
int (sizeof (charT)), s.c_str (),
locname_, lang_, lc_all_, lc_monetary_);
#endif // 0
}
/**************************************************************************/
template <class charT>
void Test<charT>::
check_curr_symbol (const String &result)
{
const String s = intl_ ? _RWSTD_USE_FACET (IntlPunct, loc_).curr_symbol ()
: _RWSTD_USE_FACET (Punct, loc_).curr_symbol ();
rw_assert (s == result, 0, __LINE__,
"moneypunct<%s, %b>::curr_symbol() == %{*Ac}, got %{*Ac} "
"in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
char_name_, intl_,
int (sizeof (charT)), result.c_str (),
int (sizeof (charT)), s.c_str (),
locname_, lang_, lc_all_, lc_monetary_);
}
/**************************************************************************/
template <class charT>
void Test<charT>::
check_positive_sign (const String &result)
{
const String s = intl_ ?
_RWSTD_USE_FACET (IntlPunct, loc_).positive_sign ()
: _RWSTD_USE_FACET (Punct, loc_).positive_sign ();
rw_assert (s == result, 0, __LINE__,
"moneypunct<%s, %b>::positive_sign() == %{*Ac}, got %{*Ac} "
"in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
char_name_, intl_,
int (sizeof (charT)), result.c_str (),
int (sizeof (charT)), s.c_str (),
locname_, lang_, lc_all_, lc_monetary_);
}
/**************************************************************************/
template <class charT>
void Test<charT>::
check_negative_sign (const String &result)
{
const String s = intl_ ?
_RWSTD_USE_FACET (IntlPunct, loc_).negative_sign ()
: _RWSTD_USE_FACET (Punct, loc_).negative_sign ();
rw_assert (s == result, 0, __LINE__,
"moneypunct<%s, %b>::negative_sign() == %{*Ac}, got %{*Ac} "
"in locale (\"%s\") with LANG=%s, LC_ALL=%s, LC_MONETARY=%s",
char_name_, intl_,
int (sizeof (charT)), result.c_str (),
int (sizeof (charT)), s.c_str (),
locname_, lang_, lc_all_, lc_monetary_);
}
/**************************************************************************/
template <class charT>
void Test<charT>::
check_format (const std::lconv &lc)
{
const UChar cpat [2][2][3] = {
// ^ ^ ^
// | | |
// | | +--- cs_precedes, sep_by_space, sign_posn
// | +------ positive, negative
// +--------- local, international
{
// C90 positive local format
{ lc.p_cs_precedes, lc.p_sep_by_space, lc.p_sign_posn },
// C90 negative local format
{ lc.n_cs_precedes, lc.n_sep_by_space, lc.n_sign_posn }
},
#ifndef _RWSTD_NO_LCONV_INT_FMAT
{ // C99 positive international format
{ lc.int_p_cs_precedes, lc.int_p_sep_by_space, lc.int_p_sign_posn},
// C99 negative international format
{ lc.int_n_cs_precedes, lc.int_n_sep_by_space, lc.int_n_sign_posn }
}
#else // if defined (_RWSTD_NO_LCONV_INT_FMAT)
{
{ lc.p_cs_precedes, lc.p_sep_by_space, lc.p_sign_posn },
{ lc.n_cs_precedes, lc.n_sep_by_space, lc.n_sign_posn }
}
#endif // _RWSTD_NO_LCONV_INT_FMAT
};
// cs_precedes [0..1]:
//
// An integer set to 1 if the currency_symbol precedes the value
// for a monetary value, and set to 0 if the symbol succeeds
// the value.
// sep_by_space [0..2]:
//
// 0 No space separates the currency_symbol from the value for
// a monetary value.
// 1 If the currency symbol and sign string are adjacent, a space
// separates them from the value; otherwise, a space separates
// the currency symbol from the value.
// 2 If the currency symbol and sign string are adjacent, a space
// separates them; otherwise, a space separates the sign string
// from the value.
// sign_posn [0..4]:
//
// An integer set to a value indicating the positioning of the
// positive_sign for a monetary value. The following integer
// values shall be recognized:
//
// 0 Parentheses enclose the value and the currency_symbol.
// 1 The sign string precedes the value and the currency_symbol.
// 2 The sign string succeeds the value and the currency_symbol.
// 3 The sign string immediately precedes the currency_symbol.
// 4 The sign string immediately succeeds the currency_symbol.
enum {
none = std::money_base::none,
space = std::money_base::space,
symbol = std::money_base::symbol,
sign = std::money_base::sign,
value = std::money_base::value
};
static const std::money_base::pattern patterns[] = {
/* 000: -1$. */ { { sign, value, symbol, none } }, // "\3\4\2\0"
/* 001: -1$. */ { { sign, value, symbol, none } }, // "\3\4\2\0"
/* 002: 1$-. */ { { value, symbol, sign, none } }, // "\4\2\3\0"
/* 003: 1-$. */ { { value, sign, symbol, none } }, // "\4\3\2\0"
/* 004: 1$-. */ { { value, symbol, sign, none } }, // "\4\2\3\0"
/* 010: -1 $ */ { { sign, value, space, symbol } }, // "\3\4\1\2"
/* 011: -1 $ */ { { sign, value, space, symbol } }, // "\3\4\1\2"
/* 012: 1 $- */ { { value, space, symbol, sign } }, // "\4\1\2\3"
/* 013: 1 -$ */ { { value, space, sign, symbol } }, // "\4\3\3\2"
/* 014: 1 $- */ { { value, space, symbol, sign } }, // "\4\1\2\3"
/* 020: - 1$ */ { { sign, space, value, symbol } }, // "\3\1\4\2"
/* 021: - 1$ */ { { sign, space, value, symbol } }, // "\3\\14\2"
/* 022: 1$ - */ { { value, symbol, space, sign } }, // "\4\2\1\3"
/* 023: 1- $ */ { { value, sign, space, symbol } }, // "\4\3\1\2"
/* 024: 1$ - */ { { value, symbol, space, sign } }, // "\4\2\1\3"
/* 100: -$1. */ { { sign, symbol, value, none } }, // "\3\2\4\0"
/* 101: -$1. */ { { sign, symbol, value, none } }, // "\3\2\4\0"
/* 102: $1-. */ { { symbol, value, sign, none } }, // "\2\4\3\0"
/* 103: -$1. */ { { sign, symbol, value, none } }, // "\3\2\4\0"
/* 104: $-1. */ { { symbol, sign, value, none } }, // "\2\3\4\0"
/* 110: -$ 1 */ { { sign, symbol, space, value } }, // "\3\2\1\4"
/* 111: -$ 1 */ { { sign, symbol, space, value } }, // "\3\2\1\4"
/* 112: $ 1- */ { { symbol, space, value, sign } }, // "\2\1\4\3"
/* 113: -$ 1 */ { { sign, symbol, space, value } }, // "\3\2\1\4"
/* 114: $- 1 */ { { symbol, sign, space, value } }, // "\2\3\1\4"
/* 120: - $1 */ { { sign, space, symbol, value } }, // "\3\1\2\4"
/* 121: - $1 */ { { sign, space, symbol, value } }, // "\3\1\2\4"
/* 122: $1 - */ { { symbol, value, space, sign } }, // "\2\4\1\3"
/* 123: - $1 */ { { sign, space, symbol, value } }, // "\3\1\2\4"
/* 124: $ -1 */ { { symbol, space, sign, value } } // "\2\1\3\4"
};
for (int neg = 0; neg != 2; ++neg) {
enum { cs_precedes, sep_by_space, sign_posn };
// ignore unspecified formats (-1)
if ( cpat [intl_][neg][cs_precedes] > 1
|| cpat [intl_][neg][sep_by_space] > 2
|| cpat [intl_][neg][sign_posn] > 4)
continue;
const int inx =
cpat [intl_][neg][cs_precedes] * 3 * 5
+ cpat [intl_][neg][sep_by_space] * 5
+ cpat [intl_][neg][sign_posn];
check_format (!neg, patterns [inx], cpat [intl_][neg]);
}
}
/**************************************************************************/
template <class charT>
void Test<charT>::
check_format (bool pos, std::money_base::pattern result, const UChar cpat [3])
{
const std::money_base::pattern pat =
intl_ ? pos ? _RWSTD_USE_FACET (IntlPunct, loc_).pos_format ()
: _RWSTD_USE_FACET (IntlPunct, loc_).neg_format ()
: pos ? _RWSTD_USE_FACET (Punct, loc_).pos_format ()
: _RWSTD_USE_FACET (Punct, loc_).neg_format ();
// number of times each symbol appears in pattern
int counts [5] = { 0 };
for (unsigned i = 0; i != sizeof pat.field / sizeof *pat.field; i++) {
if (UChar (pat.field [i] < char (sizeof counts / sizeof *counts)))
++counts [UChar (pat.field [i])];
// verify 22.2.6.3, p1
if (std::money_base::none == pat.field [i] && !i)
rw_assert (false, 0, __LINE__,
"moneypunct<%s, %b>::%s_format() == %{LM}, "
"none must not appear first",
char_name_, intl_, pos ? "pos" : "neg",
pat.field);
if ( std::money_base::space == pat.field [i]
&& !i && i != sizeof pat.field / sizeof *pat.field - 1)
rw_assert (false, 0, __LINE__,
"moneypunct<%s, %b>::%s_format() == %{LM}, "
"space must not appear first or last",
char_name_, intl_, pos ? "pos" : "neg",
pat.field);
}
// verify that the actual pattern matches the expected one
rw_assert (0 == std::memcmp (&pat, &result, sizeof pat), 0, __LINE__,
"moneypunct<%s, %b>::%s_format() == %{LM}, got %{LM}; "
"(cs_precedes = '\\%o', sep_by_space = '\\%o', "
"sign_posn = '\\%o')",
char_name_, intl_, pos ? "pos" : "neg",
pat.field, result.field, cpat [0], cpat [1], cpat [2]);
// verify 22.2.6.3, p1
rw_assert (1 == counts [std::money_base::symbol], 0, __LINE__,
"money_base::symbol must apear exactly once, did %d times",
counts [std::money_base::symbol]);
rw_assert (1 == counts [std::money_base::sign], 0, __LINE__,
"money_base::sign must apear exactly once, did %d times",
counts [std::money_base::sign]);
rw_assert (1 == counts [std::money_base::value], 0, __LINE__,
"money_base::value must apear exactly once, did %d times",
counts [std::money_base::value]);
rw_assert (1 == counts [std::money_base::space]
+ counts [std::money_base::none], 0, __LINE__,
"money_base::space or money_base::none must appear "
"exactly once, did %d times",
counts [std::money_base::space]
+ counts [std::money_base::none]);
}
/****************************************************************************/
static int
run_test (int, char**)
{
{
Test<char> t ("char", false);
t.runTest ();
}
{
Test<char> t ("char", true);
t.runTest ();
}
#ifndef _RWSTD_NO_WCHAR_T
{
Test<wchar_t> t ("wchar_t", false);
t.runTest ();
}
{
Test<wchar_t> t ("wchar_t", true);
t.runTest ();
}
#endif // _RWSTD_NO_WCHAR_T
return 0;
}
/****************************************************************************/
int main (int argc, char *argv[])
{
return rw_test (argc, argv, __FILE__,
"lib.locale.moneypunct",
0 /* no comment */,
run_test,
"",
(void*)0 /* sentinel */);
}

View File

@@ -0,0 +1,485 @@
/************************************************************************
*
* 22.locale.moneypunct.mt.cpp
*
* test exercising the thread safety of the moneypunct facet
*
* $Id: 22.locale.moneypunct.mt.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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.
*
**************************************************************************/
#include <ios> // for ios
#include <locale> // for locale, moneypunct
#include <cstdlib> // for mbstowcs(), size_t
#include <cstring> // for strcpy()
#include <rw_locale.h>
#include <rw_thread.h>
#include <driver.h>
#include <valcmp.h>
// maximum number of threads allowed by the command line interface
#define MAX_THREADS 32
// default number of threads (will be adjusted to the number
// of processors/cores later)
int rw_opt_nthreads = 1;
// the default number of times for each thread to iterate
#define DFLT_LOOPS 10000
// the number of times each thread should iterate (will be set to
// DFLT_LOOPS unless explicitly specified on the command line)
int rw_opt_nloops = -1;
/**************************************************************************/
// number of locales to test
static std::size_t
nlocales;
/**************************************************************************/
struct MoneypunctData
{
// the name of the locale the data goes with
const char* locale_name_;
char decimal_point_;
char thousands_sep_;
char grouping_ [32];
char curr_symbol_ [32];
char positive_sign_ [32];
char negative_sign_ [32];
int frac_digits_;
char pos_format_ [32];
char neg_format_ [32];
char int_curr_symbol_ [32];
int int_frac_digits_;
char int_pos_format_ [32];
char int_neg_format_ [32];
#ifndef _RWSTD_NO_WCHAR_T
wchar_t wdecimal_point_;
wchar_t wthousands_sep_;
wchar_t wcurr_symbol_ [32];
wchar_t wpositive_sign_ [32];
wchar_t wnegative_sign_ [32];
wchar_t wint_curr_symbol_ [32];
#endif // _RWSTD_NO_WCHAR_T
} punct_data [MAX_THREADS];
/**************************************************************************/
bool test_char; // exercise num_put<char>
bool test_wchar; // exercise num_put<wchar_t>
static void
thread_loop_body (std::size_t i)
{
const std::size_t inx = std::size_t (i) % (nlocales ? nlocales : 1);
const MoneypunctData* const data = punct_data + inx;
// construct a named locale
const std::locale loc (data->locale_name_);
if (test_char) {
// exercise the narrow char, local specialization of the facet
typedef std::moneypunct<char, false> Punct;
const Punct &mp = std::use_facet<Punct>(loc);
const char dp = mp.decimal_point ();
const char ts = mp.thousands_sep ();
const std::string grp = mp.grouping ();
const std::string cur = mp.curr_symbol ();
const std::string pos = mp.positive_sign ();
const std::string neg = mp.negative_sign ();
const int fd = mp.frac_digits ();
const Punct::pattern pfm = mp.pos_format ();
const Punct::pattern nfm = mp.neg_format ();
RW_ASSERT (dp == data->decimal_point_);
RW_ASSERT (ts == data->thousands_sep_);
RW_ASSERT (fd == data->frac_digits_);
RW_ASSERT (!rw_strncmp (grp.c_str (), data->grouping_));
RW_ASSERT (!rw_strncmp (cur.c_str (), data->curr_symbol_));
RW_ASSERT (!rw_strncmp (pos.c_str (), data->positive_sign_));
RW_ASSERT (!rw_strncmp (neg.c_str (), data->negative_sign_));
RW_ASSERT (!std::memcmp (&pfm, data->pos_format_, 4));
RW_ASSERT (!std::memcmp (&nfm, data->neg_format_, 4));
}
if (test_char) {
// exercise the narrow char, international specialization
typedef std::moneypunct<char, true> Punct;
const Punct &mp = std::use_facet<Punct>(loc);
const char dp = mp.decimal_point ();
const char ts = mp.thousands_sep ();
const std::string grp = mp.grouping ();
const std::string cur = mp.curr_symbol ();
const std::string pos = mp.positive_sign ();
const std::string neg = mp.negative_sign ();
const int fd = mp.frac_digits ();
const Punct::pattern pfm = mp.pos_format ();
const Punct::pattern nfm = mp.neg_format ();
RW_ASSERT (dp == data->decimal_point_);
RW_ASSERT (ts == data->thousands_sep_);
RW_ASSERT (fd == data->frac_digits_);
RW_ASSERT (!rw_strncmp (grp.c_str (), data->grouping_));
RW_ASSERT (!rw_strncmp (cur.c_str (), data->int_curr_symbol_));
RW_ASSERT (!rw_strncmp (pos.c_str (), data->positive_sign_));
RW_ASSERT (!rw_strncmp (neg.c_str (), data->negative_sign_));
RW_ASSERT (!std::memcmp (&pfm, data->int_pos_format_, 4));
RW_ASSERT (!std::memcmp (&nfm, data->int_neg_format_, 4));
}
// both specializations may be tested at the same time
#ifndef _RWSTD_NO_WCHAR_T
if (test_wchar) {
// exercise the wide char, local specialization of the facet
typedef std::moneypunct<wchar_t, false> Punct;
const Punct &mp = std::use_facet<Punct>(loc);
const wchar_t dp = mp.decimal_point ();
const wchar_t ts = mp.thousands_sep ();
const std::string grp = mp.grouping ();
const std::wstring cur = mp.curr_symbol ();
const std::wstring pos = mp.positive_sign ();
const std::wstring neg = mp.negative_sign ();
const int fd = mp.frac_digits ();
const Punct::pattern pfm = mp.pos_format ();
const Punct::pattern nfm = mp.neg_format ();
RW_ASSERT (dp == data->wdecimal_point_);
RW_ASSERT (ts == data->wthousands_sep_);
RW_ASSERT (fd == data->frac_digits_);
RW_ASSERT (!rw_strncmp (grp.c_str (), data->grouping_));
RW_ASSERT (!rw_strncmp (cur.c_str (), data->wcurr_symbol_));
RW_ASSERT (!rw_strncmp (pos.c_str (), data->wpositive_sign_));
RW_ASSERT (!rw_strncmp (neg.c_str (), data->wnegative_sign_));
RW_ASSERT (!std::memcmp (&pfm, data->pos_format_, 4));
RW_ASSERT (!std::memcmp (&nfm, data->neg_format_, 4));
}
if (test_wchar) {
// exercise the wide char, international specialization
typedef std::moneypunct<wchar_t, true> Punct;
const Punct &mp = std::use_facet<Punct>(loc);
const wchar_t dp = mp.decimal_point ();
const wchar_t ts = mp.thousands_sep ();
const std::string grp = mp.grouping ();
const std::wstring cur = mp.curr_symbol ();
const std::wstring pos = mp.positive_sign ();
const std::wstring neg = mp.negative_sign ();
const int fd = mp.frac_digits ();
const Punct::pattern pfm = mp.pos_format ();
const Punct::pattern nfm = mp.neg_format ();
RW_ASSERT (dp == data->wdecimal_point_);
RW_ASSERT (ts == data->wthousands_sep_);
RW_ASSERT (fd == data->frac_digits_);
RW_ASSERT (!rw_strncmp (grp.c_str (), data->grouping_));
RW_ASSERT (!rw_strncmp (cur.c_str (), data->wint_curr_symbol_));
RW_ASSERT (!rw_strncmp (pos.c_str (), data->wpositive_sign_));
RW_ASSERT (!rw_strncmp (neg.c_str (), data->wnegative_sign_));
RW_ASSERT (!std::memcmp (&pfm, data->int_pos_format_, 4));
RW_ASSERT (!std::memcmp (&nfm, data->int_neg_format_, 4));
}
#endif // _RWSTD_NO_WCHAR_T
}
extern "C" {
static void*
thread_func (void*)
{
for (int i = 0; i != rw_opt_nloops; ++i) {
thread_loop_body (std::size_t (i));
}
return 0;
}
} // extern "C"
/**************************************************************************/
static int
run_test (int, char**)
{
// find all installed locales for which setlocale(LC_ALL) succeeds
const char* const locale_list =
rw_opt_locales ? rw_opt_locales : rw_locales (_RWSTD_LC_ALL);
// array of locale names to use for testing
const char* locales [sizeof punct_data / sizeof *punct_data];
const std::size_t maxinx = sizeof locales / sizeof *locales;
// iterate over locales, initializing a global punct_data array
for (const char *name = locale_list; *name; name += std::strlen (name) +1) {
std::locale loc;
MoneypunctData* const pdata = punct_data + nlocales;
pdata->locale_name_ = name;
locales [nlocales] = name;
try {
loc = std::locale (name);
typedef std::moneypunct<char, false> Punct;
const Punct &mp = std::use_facet<Punct>(loc);
const char dp = mp.decimal_point ();
const char ts = mp.thousands_sep ();
const std::string grp = mp.grouping ();
const std::string cur = mp.curr_symbol ();
const std::string pos = mp.positive_sign ();
const std::string neg = mp.negative_sign ();
const int fd = mp.frac_digits ();
const Punct::pattern pfm = mp.pos_format ();
const Punct::pattern nfm = mp.neg_format ();
pdata->decimal_point_ = dp;
pdata->thousands_sep_ = ts;
pdata->frac_digits_ = fd;
std::strcpy (pdata->grouping_, grp.c_str ());
std::strcpy (pdata->curr_symbol_, cur.c_str ());
std::strcpy (pdata->positive_sign_, pos.c_str ());
std::strcpy (pdata->negative_sign_, neg.c_str ());
std::memcpy (pdata->pos_format_, &pfm, sizeof pfm);
std::memcpy (pdata->neg_format_, &nfm, sizeof nfm);
}
catch (...) {
rw_warn (0, 0, __LINE__,
"std::locale(%#s) threw an exception, skipping", name);
continue;
}
try {
typedef std::moneypunct<char, true> Punct;
const Punct &mp = std::use_facet<Punct>(loc);
const std::string cur = mp.curr_symbol ();
const int fd = mp.frac_digits ();
const Punct::pattern pfm = mp.pos_format ();
const Punct::pattern nfm = mp.neg_format ();
pdata->int_frac_digits_ = fd;
std::strcpy (pdata->int_curr_symbol_, cur.c_str ());
std::memcpy (pdata->int_pos_format_, &pfm, sizeof pfm);
std::memcpy (pdata->int_neg_format_, &nfm, sizeof nfm);
}
catch (...) {
rw_warn (0, 0, __LINE__,
"std::locale(%#s) threw an exception, skipping", name);
continue;
}
#ifndef _RWSTD_NO_WCHAR_T
try {
typedef std::moneypunct<wchar_t, false> Punct;
const Punct &mp = std::use_facet<Punct>(loc);
const wchar_t dp = mp.decimal_point ();
const wchar_t ts = mp.thousands_sep ();
const std::wstring cur = mp.curr_symbol ();
const std::wstring pos = mp.positive_sign ();
const std::wstring neg = mp.negative_sign ();
pdata->wdecimal_point_ = dp;
pdata->wthousands_sep_ = ts;
typedef std::wstring::traits_type Traits;
Traits::copy (pdata->wcurr_symbol_, cur.data (), cur.size ());
Traits::copy (pdata->wpositive_sign_, pos.data (), pos.size ());
Traits::copy (pdata->wnegative_sign_, neg.data (), neg.size ());
}
catch (...) {
rw_warn (0, 0, __LINE__,
"std::locale(%#s) threw an exception, skipping", name);
continue;
}
try {
typedef std::moneypunct<wchar_t, true> Punct;
const Punct &mp = std::use_facet<Punct>(loc);
const std::wstring cur = mp.curr_symbol ();
const std::wstring pos = mp.positive_sign ();
const std::wstring neg = mp.negative_sign ();
typedef std::wstring::traits_type Traits;
Traits::copy (pdata->wint_curr_symbol_, cur.data (), cur.size ());
}
catch (...) {
rw_warn (0, 0, __LINE__,
"std::locale(%#s) threw an exception, skipping", name);
continue;
}
#endif // _RWSTD_NO_WCHAR_T
++nlocales;
if (nlocales == maxinx)
break;
}
// unless the number of iterations was explicitly specified
// on the command line, decrease the number to equal the number
// of excericsed locales when only one thread is being tested
if (1 == rw_opt_nthreads && rw_opt_nloops < 0)
rw_opt_nloops = int (nlocales);
// when the number of iterations wasn't explicitly specified
// on the command line set it to the default value
if (rw_opt_nloops < 0)
rw_opt_nloops = DFLT_LOOPS;
rw_fatal (0 < nlocales, 0, __LINE__,
"must have at least one valid locale to test");
rw_info (0, 0, 0,
"testing std::moneypunct<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
rw_opt_nthreads, 1 != rw_opt_nthreads,
rw_opt_nloops, 1 != rw_opt_nloops,
nlocales, int (nlocales), "%#s", locales);
rw_info (0, 0, 0, "exercising std::moneypunct<char>");
test_char = true;
test_wchar = false;
// create and start a pool of threads and wait for them to finish
int result =
rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
rw_opt_nthreads, thread_func);
#ifndef _RWSTD_NO_WCHAR_T
rw_info (0, 0, 0, "exercising std::moneypunct<wchar_t>");
test_char = false;
test_wchar = true;
// start a pool of threads to exercise the thread safety
// of the wchar_t specialization
result =
rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
rw_opt_nthreads, thread_func);
// exercise both the char and the wchar_t specializations
// at the same time
rw_info (0, 0, 0,
"exercising both std::moneypunct<char> "
"and std::moneypunct<wchar_t>");
test_char = true;
test_wchar = true;
// start a pool of threads to exercise wstring thread safety
result =
rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
rw_opt_nthreads, thread_func);
#endif // _RWSTD_NO_WCHAR_T
return result;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
#ifdef _RWSTD_REENTRANT
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
rw_opt_nthreads = rw_get_cpus ();
if (rw_opt_nthreads < 2)
rw_opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.moneypunct",
"thread safety", run_test,
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-locales=", // must be provided
&rw_opt_nloops,
int (MAX_THREADS),
&rw_opt_nthreads,
&rw_opt_setlocales);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,572 @@
/************************************************************************
*
* 22.locale.num.get.mt.cpp
*
* test exercising the thread safety of the num_get facet
*
* $Id: 22.locale.num.get.mt.cpp 650350 2008-04-22 01:35:17Z sebor $
*
***************************************************************************
*
* 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.
*
**************************************************************************/
#include <ios> // for ios
#include <iterator> // for ostreambuf_iterator
#include <locale> // for locale, num_get
#include <cstring> // for strlen()
#include <rw_locale.h>
#include <rw_thread.h> // for rw_get_processors (), rw_thread_pool()
#include <driver.h>
#include <valcmp.h>
#define MAX_THREADS 32
#define MAX_LOOPS 100000
// default number of threads (will be adjusted to the number
// of processors/cores later)
int rw_opt_nthreads = 1;
// the number of times each thread should iterate
int rw_opt_nloops = MAX_LOOPS;
#if !defined (_RWSTD_OS_HP_UX) || defined (_ILP32)
// number of locales to use
int opt_nlocales = MAX_THREADS;
#else // HP-UX in LP64 mode
// work around an inefficiency (small cache size?) on HP-UX
// in LP64 mode (see STDCXX-812)
int opt_nlocales = 10;
#endif // HP-UX 32/64 bit mode
// should all threads share the same set of locale objects instead
// of creating their own?
int rw_opt_shared_locale;
/**************************************************************************/
// array of locale names to use for testing
static const char*
locales [MAX_THREADS];
// number of locale names in the array
static std::size_t
nlocales;
struct MyNumData {
enum { BufferSize = 32 };
enum PutId {
put_bool,
put_long,
put_ulong,
#ifndef _RWSTD_NO_LONG_LONG
put_llong,
put_ullong,
#endif // _RWSTD_NO_LONG_LONG
put_dbl,
#ifndef _RWSTD_NO_LONG_DOUBLE
put_ldbl,
#endif // _RWSTD_NO_LONG_DOUBLE
put_ptr,
put_max
};
// name of the locale the data corresponds to
const char* locale_name_;
// optionally set to the named locale for threads to share
std::locale locale_;
// the value that we will be formatting
double value_;
// the type of the data we get
PutId type_;
// holds the narrow/wide character representation of value_ and
// the number of used 'charT' in each buffer.
char ncs_ [BufferSize];
#ifndef _RWSTD_NO_WCHAR_T
wchar_t wcs_ [BufferSize];
#endif // _RWSTD_NO_WCHAR_T
} my_num_data [MAX_THREADS];
/**************************************************************************/
template <class charT, class Traits>
struct MyIos: std::basic_ios<charT, Traits>
{
MyIos () {
this->init (0);
}
};
template <class charT, class Traits>
struct MyStreambuf: std::basic_streambuf<charT, Traits>
{
typedef std::basic_streambuf<charT, Traits> Base;
MyStreambuf ()
: Base () {
}
void pubsetg (const charT *gbeg, std::streamsize n) {
this->setg (_RWSTD_CONST_CAST (charT*, gbeg),
_RWSTD_CONST_CAST (charT*, gbeg),
_RWSTD_CONST_CAST (charT*, gbeg) + n);
}
void pubsetp (charT *pbeg, std::streamsize n) {
this->setp (pbeg, pbeg + n);
}
};
template <class charT, class Traits>
void
test_put_data (const MyNumData &data,
const std::num_put<charT> &np,
const std::ostreambuf_iterator<charT, Traits> &iter,
std::basic_ios<charT, Traits> &io,
charT fill,
charT term)
{
switch (data.type_) {
case MyNumData::put_bool:
*np.put (iter, io, fill,
data.value_ < 1.f) = term;
break;
case MyNumData::put_long:
*np.put (iter, io, fill,
(long)data.value_) = term;
break;
case MyNumData::put_ulong:
*np.put (iter, io, fill,
(unsigned long)data.value_) = term;
break;
#ifndef _RWSTD_NO_LONG_LONG
case MyNumData::put_llong:
*np.put (iter, io, fill,
(_RWSTD_LONG_LONG)data.value_) = term;
break;
case MyNumData::put_ullong:
*np.put (iter, io, fill,
(unsigned _RWSTD_LONG_LONG)data.value_) = term;
break;
#endif // _RWSTD_NO_LONG_LONG
case MyNumData::put_dbl:
*np.put (iter, io, fill,
(double)data.value_) = term;
break;
#ifndef _RWSTD_NO_LONG_DOUBLE
case MyNumData::put_ldbl:
*np.put (iter, io, fill,
(long double)data.value_) = term;
break;
#endif // _RWSTD_NO_LONG_DOUBLE
case MyNumData::put_ptr:
*np.put (iter, io, fill,
(const void*)&data.value_) = term;
break;
case MyNumData::put_max:
// avoid enumeration value `put_max' not handled in switch
// this case should never happen
break;
}
}
template <class charT, class Traits>
void
test_get_data (const MyNumData &data,
const std::num_get<charT> &ng,
const std::istreambuf_iterator<charT, Traits> &iter,
const std::istreambuf_iterator<charT, Traits> &end,
std::basic_ios<charT, Traits> &io)
{
std::ios_base::iostate state = std::ios_base::goodbit;
switch (data.type_) {
case MyNumData::put_bool: {
const bool expected = data.value_ < 1.f;
bool checked;
ng.get (iter, end, io, state, checked);
RW_ASSERT (! (state & std::ios_base::failbit));
RW_ASSERT (checked == expected);
}
break;
case MyNumData::put_long: {
const long expected = (long)data.value_;
long checked;
ng.get (iter, end, io, state, checked);
RW_ASSERT (! (state & std::ios_base::failbit));
RW_ASSERT (checked == expected);
}
break;
case MyNumData::put_ulong: {
const unsigned long expected = (unsigned long)data.value_;
unsigned long checked;
ng.get (iter, end, io, state, checked);
RW_ASSERT (! (state & std::ios_base::failbit));
RW_ASSERT (checked == expected);
}
break;
#ifndef _RWSTD_NO_LONG_LONG
case MyNumData::put_llong: {
const _RWSTD_LONG_LONG expected = (_RWSTD_LONG_LONG)data.value_;
_RWSTD_LONG_LONG checked;
ng.get (iter, end, io, state, checked);
RW_ASSERT (! (state & std::ios_base::failbit));
RW_ASSERT (checked == expected);
}
break;
case MyNumData::put_ullong: {
const unsigned _RWSTD_LONG_LONG expected
= (unsigned _RWSTD_LONG_LONG)data.value_;
unsigned _RWSTD_LONG_LONG checked;
ng.get (iter, end, io, state, checked);
RW_ASSERT (! (state & std::ios_base::failbit));
RW_ASSERT (checked == expected);
}
break;
#endif // _RWSTD_NO_LONG_LONG
case MyNumData::put_dbl: {
const double expected = (double)data.value_;
double checked;
ng.get (iter, end, io, state, checked);
RW_ASSERT (! (state & std::ios_base::failbit));
RW_ASSERT (checked == expected);
}
break;
#ifndef _RWSTD_NO_LONG_DOUBLE
case MyNumData::put_ldbl: {
const long double expected = (long double)data.value_;
long double checked;
ng.get (iter, end, io, state, checked);
RW_ASSERT (! (state & std::ios_base::failbit));
RW_ASSERT (checked == expected);
}
break;
#endif // _RWSTD_NO_LONG_DOUBLE
case MyNumData::put_ptr: {
const void* expected = (const void*)&data.value_;
void* checked;
ng.get (iter, end, io, state, checked);
RW_ASSERT (! (state & std::ios_base::failbit));
RW_ASSERT (checked == expected);
}
break;
case MyNumData::put_max:
// avoid enumeration value `put_max' not handled in switch
// this case should never happen
break;
}
}
extern "C" {
bool test_char; // exercise num_get<char>
bool test_wchar; // exercise num_get<wchar_t>
static void*
thread_func (void*)
{
typedef std::char_traits<char> Traits;
MyIos<char, Traits> nio;
MyStreambuf<char, Traits> nsb;
nio.rdbuf (&nsb);
#ifndef _RWSTD_NO_WCHAR_T
typedef std::char_traits<wchar_t> WTraits;
MyIos<wchar_t, WTraits> wio;
MyStreambuf<wchar_t, WTraits> wsb;
wio.rdbuf (&wsb);
#endif // _RWSTD_NO_WCHAR_T
for (int i = 0; i != rw_opt_nloops; ++i) {
// fill in the value and results for this locale
const MyNumData& data = my_num_data [i % nlocales];
// construct a named locale and imbue it in the ios object
// so that the locale is used not only by the num_put facet
const std::locale loc =
rw_opt_shared_locale ? data.locale_
: std::locale (data.locale_name_);
if (test_char) {
// exercise the narrow char specialization of the facet
const std::num_get<char> &ng =
std::use_facet<std::num_get<char> >(loc);
nio.imbue (loc);
nsb.pubsetg (data.ncs_, Traits::length (data.ncs_));
test_get_data (data, ng,
std::istreambuf_iterator<char>(&nsb),
std::istreambuf_iterator<char>(),
nio);
RW_ASSERT (!nio.fail ());
}
// both specializations may be tested at the same time
if (test_wchar) {
// exercise the wide char specialization of the facet
#ifndef _RWSTD_NO_WCHAR_T
const std::num_get<wchar_t> &wp =
std::use_facet<std::num_get<wchar_t> >(loc);
wio.imbue (loc);
wsb.pubsetg (data.wcs_, WTraits::length (data.wcs_));
test_get_data (data, wp,
std::istreambuf_iterator<wchar_t>(&wsb),
std::istreambuf_iterator<wchar_t>(),
wio);
RW_ASSERT (!wio.fail ());
#endif // _RWSTD_NO_WCHAR_T
}
}
return 0;
}
} // extern "C"
/**************************************************************************/
static int
run_test (int, char**)
{
MyIos<char, std::char_traits<char> > nio;
MyStreambuf<char, std::char_traits<char> > nsb;
nio.rdbuf (&nsb);
#ifndef _RWSTD_NO_WCHAR_T
MyIos<wchar_t, std::char_traits<wchar_t> > wio;
MyStreambuf<wchar_t, std::char_traits<wchar_t> > wsb;
wio.rdbuf (&wsb);
#endif // _RWSTD_NO_WCHAR_T
// find all installed locales for which setlocale(LC_ALL) succeeds
const char* const locale_list =
rw_opt_locales ? rw_opt_locales : rw_locales (_RWSTD_LC_ALL);
const std::size_t maxinx = RW_COUNT_OF (locales);
for (const char *name = locale_list;
*name;
name += std::strlen (name) + 1) {
const std::size_t inx = nlocales;
locales [inx] = name;
// fill in the value and results for this locale
MyNumData& data = my_num_data [nlocales];
data.locale_name_ = name;
try {
const std::locale loc (data.locale_name_);
data.value_ = nlocales & 1 ? -1.f * nlocales : 1.f * nlocales;
data.type_ = MyNumData::PutId (nlocales % MyNumData::put_max);
// format data into buffers
const std::num_put<char> &np =
std::use_facet<std::num_put<char> >(loc);
nio.imbue (loc);
nsb.pubsetp (data.ncs_, RW_COUNT_OF (data.ncs_));
test_put_data (data, np, std::ostreambuf_iterator<char>(&nsb),
nio, ' ', '\0');
rw_fatal (!nio.fail (), __FILE__, __LINE__,
"num_put<char>::put(...) failed for locale(%#s)",
data.locale_name_);
#ifndef _RWSTD_NO_WCHAR_T
const std::num_put<wchar_t> &wp =
std::use_facet<std::num_put<wchar_t> >(loc);
wio.imbue (loc);
wsb.pubsetp (data.wcs_, RW_COUNT_OF (data.wcs_));
test_put_data (data, wp, std::ostreambuf_iterator<wchar_t>(&wsb),
wio, L' ', L'\0');
rw_fatal (!wio.fail (), __FILE__, __LINE__,
"num_put<wchar_t>::put(...) failed for locale(%#s)",
data.locale_name_);
#endif // _RWSTD_NO_WCHAR_T
if (rw_opt_shared_locale)
data.locale_ = loc;
nlocales += 1;
}
catch (...) {
rw_warn (!rw_opt_locales, 0, __LINE__,
"failed to create locale(%#s)", name);
}
if (nlocales == maxinx || nlocales == std::size_t (opt_nlocales))
break;
}
// avoid divide by zero in thread if there are no locales to test
rw_fatal (nlocales != 0, 0, __LINE__,
"failed to create one or more usable locales!");
rw_info (0, 0, 0,
"testing std::num_get<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
rw_opt_nthreads, 1 != rw_opt_nthreads,
rw_opt_nloops, 1 != rw_opt_nloops,
nlocales, int (nlocales), "%#s", locales);
rw_info (0, 0, 0, "exercising std::num_get<char>");
test_char = true;
test_wchar = false;
// create and start a pool of threads and wait for them to finish
int result =
rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
rw_opt_nthreads, thread_func);
#ifndef _RWSTD_NO_WCHAR_T
rw_info (0, 0, 0, "exercising std::num_get<wchar_t>");
test_char = false;
test_wchar = true;
// start a pool of threads to exercise wstring thread safety
result =
rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
rw_opt_nthreads, thread_func);
// exercise both the char and the wchar_t specializations
// at the same time
rw_info (0, 0, 0,
"exercising both std::num_get<char> and std::num_get<wchar_t>");
test_char = true;
test_wchar = true;
// start a pool of threads to exercise wstring thread safety
result =
rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
rw_opt_nthreads, thread_func);
#endif // _RWSTD_NO_WCHAR_T
return result;
}
/**************************************************************************/
int main (int argc, char *argv [])
{
#ifdef _RWSTD_REENTRANT
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
rw_opt_nthreads = rw_get_cpus ();
if (rw_opt_nthreads < 2)
rw_opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.num.get",
"thread safety", run_test,
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // must be provided
"|-shared-locale# ",
&rw_opt_nloops,
int (MAX_THREADS),
&rw_opt_nthreads,
&opt_nlocales,
&rw_opt_setlocales,
&rw_opt_shared_locale);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,468 @@
/************************************************************************
*
* 22.locale.num.put.mt.cpp
*
* test exercising the thread safety of the num_put facet
*
* $Id: 22.locale.num.put.mt.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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.
*
**************************************************************************/
#include <ios> // for ios
#include <iterator> // for ostreambuf_iterator
#include <locale> // for locale, num_put
#include <cstring> // for strlen()
#include <rw_locale.h>
#include <rw_thread.h> // for rw_get_processors (), rw_thread_pool()
#include <driver.h>
#include <valcmp.h>
#define MAX_THREADS 32
#define MAX_LOOPS 100000
// default number of threads (will be adjusted to the number
// of processors/cores later)
int opt_nthreads = 1;
// the number of times each thread should iterate
int opt_nloops = MAX_LOOPS;
#if !defined (_RWSTD_OS_HP_UX) || defined (_ILP32)
// number of locales to use
int opt_nlocales = MAX_THREADS;
#else // HP-UX in LP64 mode
// work around an inefficiency (small cache size?) on HP-UX
// in LP64 mode (see STDCXX-812)
int opt_nlocales = 10;
#endif // HP-UX 32/64 bit mode
// should all threads share the same set of locale objects instead
// of creating their own?
int opt_shared_locale;
/**************************************************************************/
// array of locale names to use for testing
static const char*
locales [MAX_THREADS];
// number of locale names in the array
static std::size_t
nlocales;
struct MyNumData {
enum { BufferSize = 32 };
enum PutId {
put_bool,
put_long,
put_ulong,
#ifndef _RWSTD_NO_LONG_LONG
put_llong,
put_ullong,
#endif // _RWSTD_NO_LONG_LONG
put_dbl,
#ifndef _RWSTD_NO_LONG_DOUBLE
put_ldbl,
#endif // _RWSTD_NO_LONG_DOUBLE
put_ptr,
put_max
};
// name of the locale the data corresponds to
const char* locale_name_;
// optionally set to the named locale for threads to share
std::locale locale_;
// the value that we will be formatting
double value_;
// the type of the data we put
PutId type_;
// holds the narrow/wide character representation of value_ and
// the number of used 'charT' in each buffer.
char ncs_ [BufferSize];
#ifndef _RWSTD_NO_WCHAR_T
wchar_t wcs_ [BufferSize];
#endif // _RWSTD_NO_WCHAR_T
} my_num_data [MAX_THREADS];
/**************************************************************************/
template <class charT, class Traits>
struct MyIos: std::basic_ios<charT, Traits>
{
MyIos () {
this->init (0);
}
};
template <class charT, class Traits>
struct MyStreambuf: std::basic_streambuf<charT, Traits>
{
typedef std::basic_streambuf<charT, Traits> Base;
MyStreambuf ()
: Base () {
}
void pubsetp (charT *pbeg, std::streamsize n) {
this->setp (pbeg, pbeg + n);
}
};
template <class charT, class Traits>
void
put_data (const MyNumData &data,
const std::num_put<charT> &np,
const std::ostreambuf_iterator<charT, Traits> &iter,
std::basic_ios<charT, Traits> &io,
charT fill,
charT term)
{
switch (data.type_) {
case MyNumData::put_bool:
*np.put (iter, io, fill,
data.value_ < 1.f) = term;
break;
case MyNumData::put_long:
*np.put (iter, io, fill,
(long)data.value_) = term;
break;
case MyNumData::put_ulong:
*np.put (iter, io, fill,
(unsigned long)data.value_) = term;
break;
#ifndef _RWSTD_NO_LONG_LONG
case MyNumData::put_llong:
*np.put (iter, io, fill,
(_RWSTD_LONG_LONG)data.value_) = term;
break;
case MyNumData::put_ullong:
*np.put (iter, io, fill,
(unsigned _RWSTD_LONG_LONG)data.value_) = term;
break;
#endif // _RWSTD_NO_LONG_LONG
case MyNumData::put_dbl:
*np.put (iter, io, fill,
(double)data.value_) = term;
break;
#ifndef _RWSTD_NO_LONG_DOUBLE
case MyNumData::put_ldbl:
*np.put (iter, io, fill,
(long double)data.value_) = term;
break;
#endif // _RWSTD_NO_LONG_DOUBLE
case MyNumData::put_ptr:
*np.put (iter, io, fill,
(const void*)&data.value_) = term;
break;
case MyNumData::put_max:
// avoid enumeration value `put_max' not handled in switch
// this case should never happen
break;
}
}
extern "C" {
bool test_char; // exercise num_put<char>
bool test_wchar; // exercise num_put<wchar_t>
static void*
thread_func (void*)
{
char ncs [MyNumData::BufferSize];
MyIos<char, std::char_traits<char> > nio;
MyStreambuf<char, std::char_traits<char> > nsb;
nio.rdbuf (&nsb);
#ifndef _RWSTD_NO_WCHAR_T
wchar_t wcs [MyNumData::BufferSize];
MyIos<wchar_t, std::char_traits<wchar_t> > wio;
MyStreambuf<wchar_t, std::char_traits<wchar_t> > wsb;
wio.rdbuf (&wsb);
#endif // _RWSTD_NO_WCHAR_T
for (int i = 0; i != opt_nloops; ++i) {
// fill in the value and results for this locale
const MyNumData& data = my_num_data [i % nlocales];
// construct a named locale and imbue it in the ios object
// so that the locale is used not only by the num_put facet
const std::locale loc =
opt_shared_locale ? data.locale_
: std::locale (data.locale_name_);
if (test_char) {
// exercise the narrow char specialization of the facet
const std::num_put<char> &np =
std::use_facet<std::num_put<char> >(loc);
nio.imbue (loc);
nsb.pubsetp (ncs, RW_COUNT_OF (ncs));
put_data (data, np, std::ostreambuf_iterator<char>(&nsb),
nio, ' ', '\0');
RW_ASSERT (!nio.fail ());
RW_ASSERT (!rw_strncmp (ncs, data.ncs_));
}
// both specializations may be tested at the same time
if (test_wchar) {
// exercise the wide char specialization of the facet
#ifndef _RWSTD_NO_WCHAR_T
const std::num_put<wchar_t> &wp =
std::use_facet<std::num_put<wchar_t> >(loc);
wio.imbue (loc);
wsb.pubsetp (wcs, RW_COUNT_OF (wcs));
put_data (data, wp, std::ostreambuf_iterator<wchar_t>(&wsb),
wio, L' ', L'\0');
RW_ASSERT (!wio.fail ());
RW_ASSERT (!rw_strncmp (wcs, data.wcs_));
#endif // _RWSTD_NO_WCHAR_T
}
}
return 0;
}
} // extern "C"
/**************************************************************************/
static int
run_test (int, char**)
{
MyIos<char, std::char_traits<char> > nio;
MyStreambuf<char, std::char_traits<char> > nsb;
nio.rdbuf (&nsb);
#ifndef _RWSTD_NO_WCHAR_T
MyIos<wchar_t, std::char_traits<wchar_t> > wio;
MyStreambuf<wchar_t, std::char_traits<wchar_t> > wsb;
wio.rdbuf (&wsb);
#endif // _RWSTD_NO_WCHAR_T
// find all installed locales for which setlocale(LC_ALL) succeeds
const char* const locale_list =
rw_opt_locales ? rw_opt_locales : rw_locales (_RWSTD_LC_ALL);
const std::size_t maxinx = RW_COUNT_OF (locales);
for (const char *name = locale_list;
*name;
name += std::strlen (name) + 1) {
const std::size_t inx = nlocales;
locales [inx] = name;
// fill in the value and results for this locale
MyNumData& data = my_num_data [nlocales];
data.locale_name_ = name;
try {
const std::locale loc (data.locale_name_);
data.value_ = nlocales & 1 ? -1 * nlocales : nlocales;
data.type_ = MyNumData::PutId (nlocales % MyNumData::put_max);
// format data into buffers
const std::num_put<char> &np =
std::use_facet<std::num_put<char> >(loc);
nio.imbue (loc);
nsb.pubsetp (data.ncs_, RW_COUNT_OF (data.ncs_));
put_data (data, np, std::ostreambuf_iterator<char>(&nsb),
nio, ' ', '\0');
rw_fatal (!nio.fail (), __FILE__, __LINE__,
"num_put<char>::put(...) failed for locale(%#s)",
data.locale_name_);
#ifndef _RWSTD_NO_WCHAR_T
const std::num_put<wchar_t> &wp =
std::use_facet<std::num_put<wchar_t> >(loc);
wio.imbue (loc);
wsb.pubsetp (data.wcs_, RW_COUNT_OF (data.wcs_));
put_data (data, wp, std::ostreambuf_iterator<wchar_t>(&wsb),
wio, L' ', L'\0');
rw_fatal (!wio.fail (), __FILE__, __LINE__,
"num_put<wchar_t>::put(...) failed for locale(%#s)",
data.locale_name_);
#endif // _RWSTD_NO_WCHAR_T
if (opt_shared_locale)
data.locale_ = loc;
nlocales += 1;
}
catch (...) {
rw_warn (!rw_opt_locales, 0, __LINE__,
"failed to create locale(%#s)", name);
}
if (nlocales == maxinx || nlocales == std::size_t (opt_nlocales))
break;
}
// avoid divide by zero in thread if there are no locales to test
rw_fatal (nlocales != 0, 0, __LINE__,
"failed to create one or more usable locales!");
rw_info (0, 0, 0,
"testing std::num_put<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
opt_nthreads, 1 != opt_nthreads,
opt_nloops, 1 != opt_nloops,
nlocales, int (nlocales), "%#s", locales);
rw_info (0, 0, 0, "exercising std::num_put<char>");
test_char = true;
test_wchar = false;
// create and start a pool of threads and wait for them to finish
int result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
#ifndef _RWSTD_NO_WCHAR_T
rw_info (0, 0, 0, "exercising std::num_put<wchar_t>");
test_char = false;
test_wchar = true;
// start a pool of threads to exercise wstring thread safety
result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
// exercise both the char and the wchar_t specializations
// at the same time
rw_info (0, 0, 0,
"exercising both std::num_put<char> and std::num_put<wchar_t>");
test_char = true;
test_wchar = true;
// start a pool of threads to exercise wstring thread safety
result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
#endif // _RWSTD_NO_WCHAR_T
return result;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
#ifdef _RWSTD_REENTRANT
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
opt_nthreads = rw_get_cpus ();
if (opt_nthreads < 2)
opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.num.put",
"thread safety", run_test,
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // must be provided
"|-shared-locale# ",
&opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
&opt_nlocales,
&rw_opt_setlocales,
&opt_shared_locale);
}

View File

@@ -0,0 +1,399 @@
/************************************************************************
*
* 22.locale.numpunct.cpp
*
* test exercising the std::numpunct facet
*
* $Id: 22.locale.numpunct.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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.
*
**************************************************************************/
#include <rw/_defs.h>
#if defined (__IBMCPP__) && !defined (_RWSTD_NO_IMPLICIT_INCLUSION)
// Disable implicit inclusion to work around
// a limitation in IBM's VisualAge 5.0.2.0 (see PR#26959)
# define _RWSTD_NO_IMPLICIT_INCLUSION
#endif
#include <clocale> // for struct lconv, setlocale()
#include <cstdio> // for sprintf()
#include <cstdlib> // for getenv()
#include <cstring> // for strcmp()
#include <locale>
#include <driver.h>
#include <environ.h>
#include <rw_locale.h>
/**************************************************************************/
template <class charT>
void run_test (charT*);
template <class charT>
void check_decimal_point (charT, const char*, const std::locale*);
template <class charT>
void check_thousands_sep (charT, const char*, const std::locale*);
template <class charT>
void check_grouping (charT, const char*, const std::string&, const std::locale*);
template <class charT>
void check_falsename (const std::basic_string<charT>&,
const char*, const std::locale*);
template <class charT>
void check_truename (const std::basic_string<charT>&,
const char*, const std::locale*);
template <class charT>
bool check_numpunct (charT, const char*, const char*, const std::locale*);
/**************************************************************************/
template <class charT>
void run_test (charT, const char *tname)
{
rw_info (0, 0, __LINE__, "classic \"C\" locale");
// create a copy of the classic ("C") locale
std::locale *loc = new std::locale (std::locale::classic ());
// verify (at compile time) that _byname facets can be used
// to specialize use_facet() and has_facet()
typedef std::numpunct_byname<charT> NumpunctByname;
if (_STD_HAS_FACET (NumpunctByname, *loc))
_STD_USE_FACET (NumpunctByname, *loc);
// verify values as per 7.4 of C89, and 7.11, p2 of C99
check_decimal_point (charT ('.'), tname, loc);
// verify 22.2.3.1.2, p2
check_thousands_sep (charT (','), tname, loc);
check_grouping (charT (), tname, "", loc);
const charT fn[] = { 'f', 'a', 'l', 's', 'e', '\0' };
const charT tn[] = { 't', 'r', 'u', 'e', '\0' };
check_falsename (std::basic_string<charT>(fn), tname, loc);
check_truename (std::basic_string<charT>(tn), tname, loc);
delete loc;
loc = 0;
//////////////////////////////////////////////////////////////////
// verify that the facet can be safely used on its own, without
// first having to be installed in a locale and retrieved using
// use_facet
check_decimal_point (charT ('.'), tname, loc);
check_thousands_sep (charT (','), tname, loc);
check_grouping (charT (), tname, "", loc);
check_falsename (std::basic_string<charT>(fn), tname, loc);
check_truename (std::basic_string<charT>(tn), tname, loc);
//////////////////////////////////////////////////////////////////
// exercise the native locale (affected by the environment
// variables LANG, LC_ALL, LC_NUMERIC, etc.)
check_numpunct (charT (), tname, "", loc); // native locale
// the name of the first non-C (and non-POSIX) locale
const char *first_non_c = 0;
// exercise named locales (including "C" and "POSIX")
for (const char* s = rw_locales (); *s; s += std::strlen (s) + 1) {
if (check_numpunct (charT (), tname, s, loc))
if ( !first_non_c
&& std::strcmp ("C", s)
&& std::strcmp ("POSIX", s))
first_non_c = s;
}
// verify that numpunct behaves correctly when LC_ALL is set
// to the name of the (non-C, non-POSIX) locale
char envvar [80];
std::sprintf (envvar, "LC_ALL=%s", first_non_c);
rw_putenv (envvar);
check_numpunct (charT (), tname, "", loc);
}
/**************************************************************************/
char widen (char, const char *s)
{
return *s;
}
#ifndef _RWSTD_NO_WCHAR_T
wchar_t widen (wchar_t, const char *s)
{
wchar_t wc = 0;
# ifndef _RWSTD_NO_MBTOWC
const int n = s && *s ? std::mbtowc (&wc, s, std::strlen (s)) : 0;
# else // if defined (_RWSTD_NO_MBTOWC)
const int n = 1;
wc = s ? wchar_t (_RWSTD_STATIC_CAST (unsigned char, *s)) : 0;
# endif // _RWSTD_NO_MBTOWC
return n > 0 ? wc : n ? -1 : 0;
}
#endif // _RWSTD_NO_WCHAR_T
template <class charT>
bool check_numpunct (charT,
const char *tname,
const char *locname,
const std::locale *loc)
{
// (try to) set the global C locale
const char *tmploc = std::setlocale (LC_ALL, locname);
if (!tmploc)
return false;
// future setlocale() calls may change tmploc's value, so make a copy
// (fixed-size char buf is clunky but avoids memory-leak potential)
char locnamebuf [1024];
RW_ASSERT ((std::strlen (tmploc) + 1) < sizeof locnamebuf);
std::strcpy (locnamebuf, tmploc);
_TRY {
rw_info (0, 0, __LINE__,
"locale (%s) -> \"%s\"; LANG=%s, "
"LC_ALL=%s, LC_NUMERIC=%s",
locname, loc,
std::getenv ("LANG"),
std::getenv ("LC_ALL"),
std::getenv ("LC_NUMERIC"));
// get a pointer to lconv
const std::lconv *plconv = std::localeconv ();
if (!plconv)
return false;
// copy important data; the contents of *plconv may
// be overwritten by the call sto setlocale() below
// note that decimal_point at al may be multbyte character
// strings that need to be widened according to the rules
// of the same locale
const charT decimal_point = widen (charT (), plconv->decimal_point);
const charT thousands_sep = widen (charT (), plconv->thousands_sep);
const std::string grouping =
plconv->grouping ? plconv->grouping : "";
// reset to default locale given by LC_LANG
std::setlocale (LC_ALL, "");
loc = new std::locale (locname);
// check that newly constructed locale matches
if ( 'C' == locnamebuf [0] && '\0' == locnamebuf [1]
|| 'C' == locname [0] && '\0' == locname [1]
|| *loc == std::locale::classic ()) {
// follow requirements in 22.2.3.1.2. p1, 2, and 3
check_decimal_point (charT ('.'), tname, loc);
check_thousands_sep (charT (','), tname, loc);
check_grouping (charT (), tname, "", loc);
}
else {
// cast to prevent sign extension between (signed) char and wchar_t
// tmp guards against possibly passing along a "(nil)" pointer
check_decimal_point (decimal_point, tname, loc);
check_thousands_sep (thousands_sep, tname, loc);
check_grouping (charT (), tname, grouping.c_str (), loc);
}
// FIXME: exercise falsename() and truename() in named locales
delete loc;
loc = 0;
}
_CATCH (...) {
return false;
}
return true;
}
/**************************************************************************/
template <class charT>
void check_decimal_point (charT expect,
const char *tname,
const std::locale *loc)
{
typedef std::numpunct<charT> Punct;
typedef std::char_traits<charT> Traits;
const charT c = loc ?
_STD_USE_FACET (Punct, *loc).decimal_point ()
: Punct ().decimal_point ();
rw_assert (Traits::eq (c, expect), 0, __LINE__,
"numpunct<%s>::decimal_point() == %{#lc}, got %{#lc}",
tname, expect, c);
}
/**************************************************************************/
template <class charT>
void check_thousands_sep (charT expect,
const char *tname,
const std::locale *loc)
{
typedef std::numpunct<charT> Punct;
typedef std::char_traits<charT> Traits;
const charT c = loc ?
_STD_USE_FACET (Punct, *loc).thousands_sep ()
: Punct ().thousands_sep ();
rw_assert (Traits::eq (c, expect), 0, __LINE__,
"numpunct<%s>::thousands_sep() == %{#lc}, got %{#lc}",
tname, expect, c);
}
/**************************************************************************/
template <class charT>
void check_grouping (charT,
const char *tname,
const std::string &expect,
const std::locale *loc)
{
typedef std::numpunct<charT> Punct;
const std::string s = loc ?
_STD_USE_FACET (Punct, *loc).grouping ()
: Punct ().grouping ();
if ( s != expect
&& s.size () != expect.size () && s.size () && expect.size ()) {
// if the grouping is not exactly the same as the expected result,
// verify that the actual grouping is equivalent to the expected
// one, e.g., that "\003\003" is equivalent to "\003"
const std::string *lng = s.size () > expect.size () ? &expect : &s;
const std::string *shrt = s.size () < expect.size () ? &expect : &s;
std::size_t i = shrt->size () - 1;
for ( ; i != lng->size (); ++i)
if ((*shrt) [shrt->size () - 1] != (*lng)[i])
break;
rw_assert (i == lng->size (), 0, __LINE__,
"numpunct<%s>::grouping() equivalent to %{#S}, got %{#S}",
tname, &expect, &s);
}
else
rw_assert (s == expect, 0, __LINE__,
"numpunct<%s>::grouping() == %{#S}, got %{#S}",
tname, &expect, &s);
}
/**************************************************************************/
template <class charT>
void check_falsename (const std::basic_string<charT> &expect,
const char *tname,
const std::locale *loc)
{
typedef std::numpunct<charT> Punct;
const std::basic_string<charT> s = loc ?
_STD_USE_FACET (Punct, *loc).falsename ()
: Punct ().falsename ();
const int char_size = int (sizeof (charT));
rw_assert (s == expect, 0, __LINE__,
"numpunct<%s>::falsename() == %{#*S}, got %{#*S}",
tname, char_size, &expect, char_size, &s);
}
/**************************************************************************/
template <class charT>
void check_truename (const std::basic_string<charT> &expect,
const char *tname,
const std::locale *loc)
{
typedef std::numpunct<charT> Punct;
const std::basic_string<charT> s = loc ?
_STD_USE_FACET (Punct, *loc).truename ()
: Punct ().truename ();
const int char_size = int (sizeof (charT));
rw_assert (s == expect, 0, __LINE__,
"numpunct<%s>::truename() == %{#*S}, got %{#*S}",
tname, char_size, &expect, char_size, &s);
}
/**************************************************************************/
static int
run_test (int, char**)
{
run_test (char (), "char");
#ifndef _RWSTD_WCHAR_T
run_test (wchar_t (), "wchar_t");
#endif // _RWSTD_WCHAR_T
return 0;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
return rw_test (argc, argv, __FILE__,
"lib.locale.numpunct",
"", run_test,
"",
(void*)0);
}

View File

@@ -0,0 +1,335 @@
/************************************************************************
*
* 22.locale.numpunct.mt.cpp
*
* test exercising the thread safety of the numpunct facet
*
* $Id: 22.locale.numpunct.mt.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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.
*
**************************************************************************/
#include <locale> // for locale, numpunct
#include <clocale> // for lconv, localeconv()
#include <cstdlib> // for mbstowcs()
#include <cstring> // for size_t, strcpy()
#include <rw_locale.h>
#include <rw_thread.h>
#include <driver.h>
#include <valcmp.h>
// maximum number of threads allowed by the command line interface
#define MAX_THREADS 32
// default number of threads (will be adjusted to the number
// of processors/cores later)
int opt_nthreads = 1;
// the number of times each thread should iterate (unless specified
// otherwise on the command line)
int rw_opt_nloops = 200000;
#if !defined (_RWSTD_OS_HP_UX) || defined (_ILP32)
// number of locales to use
int opt_nlocales = MAX_THREADS;
#else // HP-UX in LP64 mode
// work around an inefficiency (small cache size?) on HP-UX
// in LP64 mode (see STDCXX-812)
int opt_nlocales = 10;
#endif // HP-UX 32/64 bit mode
// should all threads share the same set of locale objects instead
// of creating their own?
int opt_shared_locale;
/**************************************************************************/
// array of locale names to use for testing
static const char*
locales [MAX_THREADS];
// number of locale names in the array
static std::size_t
nlocales;
/**************************************************************************/
struct NumPunctData
{
const char* locale_name_;
std::locale locale_;
std::string grouping_;
char decimal_point_;
char thousands_sep_;
std::string truename_;
std::string falsename_;
#ifndef _RWSTD_NO_WCHAR_T
wchar_t wdecimal_point_;
wchar_t wthousands_sep_;
std::wstring wtruename_;
std::wstring wfalsename_;
#endif // _RWSTD_NO_WCHAR_T
} punct_data [MAX_THREADS];
extern "C" {
bool test_char; // exercise num_put<char>
bool test_wchar; // exercise num_put<wchar_t>
static void*
thread_func (void*)
{
for (int i = 0; i != rw_opt_nloops; ++i) {
const std::size_t inx = std::size_t (i) % nlocales;
const NumPunctData& data = punct_data[inx];
// construct a named locale
const std::locale loc =
opt_shared_locale ? data.locale_
: std::locale (data.locale_name_);
if (test_char) {
// exercise the narrow char specialization of the facet
const std::numpunct<char> &np =
std::use_facet<std::numpunct<char> >(loc);
const char dp = np.decimal_point ();
const char ts = np.thousands_sep ();
const std::string grp = np.grouping ();
const std::string tn = np.truename ();
const std::string fn = np.falsename ();
RW_ASSERT (dp == data.decimal_point_);
RW_ASSERT (ts == data.thousands_sep_);
RW_ASSERT (0 == rw_strncmp (grp.c_str (),
data.grouping_.c_str ()));
RW_ASSERT (0 == rw_strncmp (tn.c_str (),
data.truename_.c_str ()));
RW_ASSERT (0 == rw_strncmp (fn.c_str (),
data.falsename_.c_str ()));
}
// both specializations may be tested at the same time
if (test_wchar) {
// exercise the wide char specialization of the facet
#ifndef _RWSTD_NO_WCHAR_T
const std::numpunct<wchar_t> &wp =
std::use_facet<std::numpunct<wchar_t> >(loc);
const wchar_t dp = wp.decimal_point ();
const wchar_t ts = wp.thousands_sep ();
const std::string grp = wp.grouping ();
const std::wstring tn = wp.truename ();
const std::wstring fn = wp.falsename ();
RW_ASSERT (dp == data.wdecimal_point_);
RW_ASSERT (ts == data.wthousands_sep_);
RW_ASSERT (0 == rw_strncmp (grp.c_str (),
data.grouping_.c_str ()));
RW_ASSERT (0 == rw_strncmp (tn.c_str (),
data.wtruename_.c_str ()));
RW_ASSERT (0 == rw_strncmp (fn.c_str (),
data.wfalsename_.c_str ()));
#endif // _RWSTD_NO_WCHAR_T
}
}
return 0;
}
} // extern "C"
/**************************************************************************/
static int
run_test (int, char**)
{
// find all installed locales for which setlocale(LC_ALL) succeeds
const char* const locale_list =
rw_opt_locales ? rw_opt_locales : rw_locales (_RWSTD_LC_ALL);
const std::size_t maxinx = sizeof punct_data / sizeof *punct_data;
// iterate over locales, initializing a global punct_data array
for (const char *name = locale_list;
*name;
name += std::strlen (name) +1) {
const std::size_t inx = nlocales;
locales [inx] = name;
NumPunctData& data = punct_data [inx];
try {
std::locale loc(name);
data.locale_name_ = name;
const std::numpunct<char> &np =
std::use_facet<std::numpunct<char> >(loc);
data.grouping_ = np.grouping ();
data.decimal_point_ = np.decimal_point ();
data.thousands_sep_ = np.thousands_sep ();
data.truename_ = np.truename ();
data.falsename_ = np.falsename ();
#ifndef _RWSTD_NO_WCHAR_T
const std::numpunct<wchar_t> &wp =
std::use_facet<std::numpunct<wchar_t> >(loc);
data.wdecimal_point_ = wp.decimal_point ();
data.wthousands_sep_ = wp.thousands_sep ();
data.wtruename_ = wp.truename ();
data.wfalsename_ = wp.falsename ();
#endif
if (opt_shared_locale)
data.locale_ = loc;
nlocales += 1;
}
catch (...) {
rw_warn (!rw_opt_locales, 0, __LINE__,
"failed to create locale(%#s)", name);
}
if (nlocales == maxinx || nlocales == std::size_t (opt_nlocales))
break;
}
// avoid divide by zero in thread if there are no locales to test
rw_fatal (nlocales != 0, 0, __LINE__,
"failed to create one or more usable locales!");
rw_info (0, 0, 0,
"testing std::numpunct<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
opt_nthreads, 1 != opt_nthreads,
rw_opt_nloops, 1 != rw_opt_nloops,
nlocales, int (nlocales), "%#s", locales);
rw_info (0, 0, 0, "exercising std::numpunct<char>");
test_char = true;
test_wchar = false;
// create and start a pool of threads and wait for them to finish
int result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
#ifndef _RWSTD_NO_WCHAR_T
rw_info (0, 0, 0, "exercising std::numpunct<wchar_t>");
test_char = false;
test_wchar = true;
// start a pool of threads to exercise the thread safety
// of the wchar_t specialization
result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
// exercise both the char and the wchar_t specializations
// at the same time
rw_info (0, 0, 0,
"exercising both std::numpunct<char> and std::numpunct<wchar_t>");
test_char = true;
test_wchar = true;
// start a pool of threads to exercise wstring thread safety
result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
#endif // _RWSTD_NO_WCHAR_T
return result;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
#ifdef _RWSTD_REENTRANT
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
opt_nthreads = rw_get_cpus ();
if (opt_nthreads < 2)
opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.numpunct",
"thread safety", run_test,
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // must be provided
"|-shared-locale# ",
&rw_opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
&opt_nlocales,
&rw_opt_setlocales,
&opt_shared_locale);
}

View File

@@ -0,0 +1,199 @@
/************************************************************************
*
* 22.locale.statics.mt.cpp
*
* test exercising the thread safety of [lib.locale.statics]
*
* $Id: 22.locale.statics.mt.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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 2007 Rogue Wave Software, Inc.
*
**************************************************************************/
#include <locale> // for locale
#include <cstring> // for strlen()
#include <rw_locale.h> // for rw_locales()
#include <rw_thread.h> // for rw_get_processors(), rw_thread_pool()
#include <driver.h> // for rw_test()
// maximum number of threads allowed by the command line interface
#define MAX_THREADS 16
// default number of threads (will be adjusted to the number
// of processors/cores later)
int opt_nthreads = 1;
// the number of times each thread should iterate (unless specified
// otherwise on the command line)
int opt_nloops = 20000;
int opt_classic;
int opt_global;
/**************************************************************************/
// array of locale objects to use for testing
static std::locale
locales [MAX_THREADS];
// number of locale names in the array
static std::size_t
nlocales;
/**************************************************************************/
extern "C" {
static void*
test_classic (void*)
{
static volatile int nthreads;
// cast nthreads to int& (see STDCXX-792)
// casting should be removed after fixing STDCXX-794
_RWSTD_ATOMIC_PREINCREMENT (_RWSTD_CONST_CAST (int&, nthreads), false);
// spin until all threads have been created in order to icrease
// the odds that at least two of them will hit the tested function
// (and the lazy one-time initialization done by it) at the same
// time
while (nthreads < opt_nthreads);
const std::locale classic (std::locale::classic ());
_RWSTD_UNUSED (classic);
return 0;
}
static void*
test_global (void*)
{
for (std::size_t i = 0; i != opt_nloops; ++i) {
const std::size_t inx = i % nlocales;
const std::locale last (std::locale::global (locales [inx]));
_RWSTD_UNUSED (last);
// FIXME: verify the consistency of the returned locale
// by making sure that it matches the locale passed to
// global() made by the last call to the function by
// the last thread
}
return 0;
}
} // extern "C"
/**************************************************************************/
static int
run_test (int, char**)
{
int result = 0;
if (rw_note (0 <= opt_classic, 0, __LINE__,
"std::locale::classic() test disabled")) {
rw_info (0, 0, 0,
"testing std::locale::classic() with %d thread%{?}s%{;}",
opt_nthreads, 1 != opt_nthreads);
// create and start a pool of threads and wait for them to finish
result = rw_thread_pool (0, std::size_t (opt_nthreads), 0,
test_classic, 0);
}
if (rw_note (0 <= opt_global, 0, __LINE__,
"std::locale::global(const std::locale&) test disabled")) {
// find all installed locales for which setlocale(LC_ALL) succeeds
const char* const locale_list =
rw_opt_locales ? rw_opt_locales : rw_locales (_RWSTD_LC_ALL);
const std::size_t maxinx = sizeof locales / sizeof *locales;
const char* locale_names [MAX_THREADS];
for (const char *name = locale_list;
*name;
name += std::strlen (name) + 1) {
locale_names [nlocales] = name;
locales [nlocales++] = std::locale (name);
if (nlocales == maxinx)
break;
}
rw_info (0, 0, 0,
"testing std::locale::global(const std::locale&) with "
"%d thread%{?}s%{;}, %d iteration%{?}s%{;} each, in "
"%zu locales { %{ .*A@} }",
opt_nthreads, 1 != opt_nthreads,
opt_nloops, 1 != opt_nloops,
nlocales, int (nlocales), "%#s", locale_names);
// create and start a pool of threads and wait for them to finish
result = rw_thread_pool (0, std::size_t (opt_nthreads), 0,
test_global, 0);
}
return result;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
#ifdef _RWSTD_REENTRANT
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
opt_nthreads = rw_get_cpus ();
if (opt_nthreads < 2)
opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.statics",
"thread safety",
run_test,
"|-classic~ "
"|-global~ "
"|-nloops#0 " // arg must be non-negative
"|-nthreads#0-* " // arg must be in [0, MAX_THREADS]
"|-locales= ", // argument must be provided
&opt_classic,
&opt_global,
&opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
&rw_opt_setlocales);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,527 @@
/************************************************************************
*
* 22.locale.time.get.mt.cpp
*
* test exercising the thread safety of the time_get facet
*
* $Id: 22.locale.time.get.mt.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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 2002-2007 Rogue Wave Software.
*
**************************************************************************/
#include <ios> // for ios
#include <iterator> // for ostreambuf_iterator
#include <locale> // for locale, time_put
#include <cstring> // for strlen ()
#include <ctime> // for tm
#include <rw_locale.h>
#include <rw_thread.h>
#include <driver.h> // for rw_assert ()
#include <valcmp.h> // for rw_strncmp ()
#define MAX_THREADS 32
#define MAX_LOOPS 100000
// default number of threads (will be adjusted to the number
// of processors/cores later)
int rw_opt_nthreads = 1;
// the number of times each thread should iterate
int rw_opt_nloops = 50000;
// number of locales to use
int rw_opt_nlocales = MAX_THREADS;
// should all threads share the same set of locale objects instead
// of creating their own?
int rw_opt_shared_locale;
/**************************************************************************/
// array of locale names to use for testing
static const char*
locales [MAX_THREADS];
// number of locale names in the array
static std::size_t
nlocales;
/**************************************************************************/
//
struct MyTimeData
{
enum { BufferSize = 64 };
// name of the locale the data corresponds to
const char* locale_name_;
// optionally set to the named locale for threads to share
std::locale locale_;
// the time struct used to generate strings below
std::tm time_;
// the type specifier
char format_;
// narrow representations of time_ given the
// locale_name_ and the format_
char ncs_ [BufferSize];
#ifndef _RWSTD_NO_WCHAR_T
// wide representations of time_
wchar_t wcs_ [BufferSize];
#endif // _RWSTD_NO_WCHAR_T
} my_time_data [MAX_THREADS];
template <class charT, class Traits>
struct MyIos: std::basic_ios<charT, Traits>
{
MyIos () {
this->init (0);
}
};
template <class charT, class Traits>
struct MyStreambuf: std::basic_streambuf<charT, Traits>
{
typedef std::basic_streambuf<charT, Traits> Base;
MyStreambuf ()
: Base () {
}
void pubsetg (const charT *gbeg, std::streamsize n) {
this->setg (_RWSTD_CONST_CAST (charT*, gbeg),
_RWSTD_CONST_CAST (charT*, gbeg),
_RWSTD_CONST_CAST (charT*, gbeg) + n);
}
void pubsetp (charT *pbeg, std::streamsize n) {
this->setp (pbeg, pbeg + n);
}
};
void verify_fields (const std::tm& a, const std::tm& b)
{
RW_ASSERT (a.tm_sec == b.tm_sec);
RW_ASSERT (a.tm_min == b.tm_min);
RW_ASSERT (a.tm_hour == b.tm_hour);
RW_ASSERT (a.tm_mday == b.tm_mday);
RW_ASSERT (a.tm_mon == b.tm_mon);
RW_ASSERT (a.tm_year == b.tm_year);
RW_ASSERT (a.tm_wday == b.tm_wday);
RW_ASSERT (a.tm_yday == b.tm_yday);
}
#define RW_ASSERT_FIELDS(a,b) verify_fields(a,b)
extern "C" {
bool test_char; // exercise time_get<char>
bool test_wchar; // exercise time_get<wchar_t>
static void*
thread_func (void*)
{
MyIos<char, std::char_traits<char> > nio;
MyStreambuf<char, std::char_traits<char> > nsb;
nio.rdbuf (&nsb);
#ifndef _RWSTD_NO_WCHAR_T
MyIos<wchar_t, std::char_traits<wchar_t> > wio;
MyStreambuf<wchar_t, std::char_traits<wchar_t> > wsb;
wio.rdbuf (&wsb);
#endif // _RWSTD_NO_WCHAR_T
std::ios_base::iostate state = std::ios_base::goodbit;
std::tm local;
for (int i = 0; i != rw_opt_nloops; ++i) {
// save the name of the locale
const MyTimeData& data = my_time_data [i % nlocales];
// construct a named locale, get a reference to the time_put
// facet from it and use it to format a random time value
// using a random conversion specifier
const std::locale loc =
rw_opt_shared_locale ? data.locale_
: std::locale (data.locale_name_);
if (test_char) {
// exercise the narrow char specialization of the facet
const std::time_get<char> &ng =
std::use_facet<std::time_get<char> >(loc);
nio.imbue (loc);
nsb.pubsetg (data.ncs_, RW_COUNT_OF (data.ncs_));
const std::istreambuf_iterator<char> iter (&nsb);
const std::istreambuf_iterator<char> end;
std::memset (&local, 0, sizeof local);
switch (data.format_) {
case 'X':
ng.get_time (iter, end, nio, state, &local);
break;
case 'x':
ng.get_date (iter, end, nio, state, &local);
break;
case 'a':
case 'A':
ng.get_weekday (iter, end, nio, state, &local);
break;
case 'b':
case 'B':
ng.get_monthname (iter, end, nio, state, &local);
break;
case 'y':
case 'Y':
ng.get_year (iter, end, nio, state, &local);
break;
default:
#ifndef _RWSTD_NO_EXT_TIME_GET
ng.get (iter, end, nio, state, &local, data.format_);
#endif // _RWSTD_NO_EXT_TIME_GET
break;
}
RW_ASSERT (! (state & std::ios_base::failbit));
RW_ASSERT_FIELDS (local, data.time_);
}
// both specializations may be tested at the same time
if (test_wchar) {
// exercise the wide char specialization of the facet
#ifndef _RWSTD_NO_WCHAR_T
const std::time_get<wchar_t> &wg =
std::use_facet<std::time_get<wchar_t> >(loc);
wio.imbue (loc);
wsb.pubsetg (data.wcs_, RW_COUNT_OF (data.wcs_));
const std::istreambuf_iterator<wchar_t> iter (&wsb);
const std::istreambuf_iterator<wchar_t> end;
std::memset (&local, 0, sizeof local);
switch (data.format_) {
case 'X':
wg.get_time (iter, end, wio, state, &local);
break;
case 'x':
wg.get_date (iter, end, wio, state, &local);
break;
case 'a':
case 'A':
wg.get_weekday (iter, end, wio, state, &local);
break;
case 'b':
case 'B':
wg.get_monthname (iter, end, wio, state, &local);
break;
case 'y':
case 'Y':
wg.get_year (iter, end, wio, state, &local);
break;
default:
#ifndef _RWSTD_NO_EXT_TIME_GET
wg.get (iter, end, wio, state, &local, data.format_);
#endif // _RWSTD_NO_EXT_TIME_GET
break;
}
RW_ASSERT (! (state & std::ios_base::failbit));
RW_ASSERT_FIELDS (local, data.time_);
#endif // _RWSTD_NO_WCHAR_T
}
}
return 0;
}
} // extern "C"
/**************************************************************************/
static int
run_test (int, char**)
{
MyIos<char, std::char_traits<char> > nio;
MyStreambuf<char, std::char_traits<char> > nsb;
nio.rdbuf (&nsb);
#ifndef _RWSTD_NO_WCHAR_T
MyIos<wchar_t, std::char_traits<wchar_t> > wio;
MyStreambuf<wchar_t, std::char_traits<wchar_t> > wsb;
wio.rdbuf (&wsb);
#endif // _RWSTD_NO_WCHAR_T
// find all installed locales for which setlocale (LC_ALL) succeeds
const char* const locale_list =
rw_opt_locales ? rw_opt_locales : rw_locales (_RWSTD_LC_ALL);
const std::size_t maxinx = RW_COUNT_OF (locales);
int j = 0;
for (const char* name = locale_list;
*name;
name += std::strlen (name) + 1) {
const std::size_t inx = nlocales;
locales [inx] = name;
// fill in the time and results for this locale
MyTimeData& data = my_time_data [inx];
data.locale_name_ = name;
// initialize tm with random but valid values
std::memset (&data.time_, 0, sizeof data.time_);
data.time_.tm_sec = ++j % 61;
data.time_.tm_min = ++j % 60;
data.time_.tm_hour = ++j % 12;
data.time_.tm_wday = ++j % 7;
data.time_.tm_mon = ++j % 12;
data.time_.tm_mday = ++j % 31;
data.time_.tm_yday = ++j % 366;
data.time_.tm_year = ++j;
#ifndef _RWSTD_NO_EXT_TIME_GET
// format specifiers that we can reliably parse
// get_weekday, get_monthname, get_date, get_time,
// get_year and the extension get.
const char formats [] = "aAbBCdhHjmMnRStTwxXyY";
#else
// formats that generate strings compatible with
// get_weekday, get_monthname, get_date, get_time
// and get_year.
const char formats [] = "aAbBxXyY";
#endif
// get the "random" data type used to generate representation
data.format_ = formats [nlocales % (sizeof formats - 1)];
try {
const std::locale loc (data.locale_name_);
const std::time_put<char> &np =
std::use_facet<std::time_put<char> >(loc);
const std::time_get<char> &ng =
std::use_facet<std::time_get<char> >(loc);
std::ios::iostate state = std::ios::goodbit;
nio.imbue (loc);
// put the time representation on the stream
nsb.pubsetp (data.ncs_, RW_COUNT_OF (data.ncs_));
*np.put (std::ostreambuf_iterator<char>(&nsb), nio, ' ',
&data.time_, data.format_) = '\0';
rw_fatal (!nio.fail (), __FILE__, __LINE__,
"time_put<char>::put(...) failed for locale(%#s)",
data.locale_name_);
// read the data back out. this is what the thread
// is expected to do, and the result it should get.
nsb.pubsetg (data.ncs_, RW_COUNT_OF (data.ncs_));
const std::istreambuf_iterator<char> iter (&nsb);
const std::istreambuf_iterator<char> end;
std::memset (&data.time_, 0, sizeof data.time_);
switch (data.format_) {
case 'a':
case 'A':
ng.get_weekday (iter, end, nio, state, &data.time_);
break;
case 'b':
case 'B':
case 'h':
ng.get_monthname (iter, end, nio, state, &data.time_);
break;
case 'y':
case 'Y':
ng.get_year (iter, end, nio, state, &data.time_);
break;
case 'x':
ng.get_date (iter, end, nio, state, &data.time_);
break;
case 'X':
ng.get_time (iter, end, nio, state, &data.time_);
break;
default:
#ifndef _RWSTD_NO_EXT_TIME_GET
ng.get (iter, end, nio, state, &data.time_, data.format_);
#endif // _RWSTD_NO_EXT_TIME_GET
break;
}
// we couldn't read the data back, so don't use this locale
if (state & std::ios_base::failbit)
continue;
#ifndef _RWSTD_NO_WCHAR_T
const std::time_put<wchar_t> &wp =
std::use_facet<std::time_put<wchar_t> >(loc);
wio.imbue (loc);
wsb.pubsetp (data.wcs_, RW_COUNT_OF (data.wcs_));
*wp.put (std::ostreambuf_iterator<wchar_t>(&wsb),
wio, L' ', &data.time_, data.format_) = L'\0';
rw_fatal (!wio.fail (), __FILE__, __LINE__,
"time_put<wchar_t>::put(...) failed for locale(%#s)",
data.locale_name_);
#endif // _RWSTD_NO_WCHAR_T
if (rw_opt_shared_locale)
data.locale_ = loc;
nlocales += 1;
}
catch (...) {
rw_warn (!rw_opt_locales, 0, __LINE__,
"failed to create locale(%#s)", name);
}
if (nlocales == maxinx || nlocales == std::size_t (rw_opt_nlocales))
break;
}
// avoid divide by zero in thread if there are no locales to test
rw_fatal (nlocales != 0, 0, __LINE__,
"failed to create one or more usable locales!");
rw_info (0, 0, 0,
"testing std::time_get<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
rw_opt_nthreads, 1 != rw_opt_nthreads,
rw_opt_nloops, 1 != rw_opt_nloops,
nlocales, int (nlocales), "%#s", locales);
rw_info (0, 0, 0, "exercising std::time_get<char>");
test_char = true;
test_wchar = false;
// create and start a pool of threads and wait for them to finish
int result =
rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
rw_opt_nthreads, thread_func);
#ifndef _RWSTD_NO_WCHAR_T
rw_info (0, 0, 0, "exercising std::time_get<wchar_t>");
test_char = false;
test_wchar = true;
// start a pool of threads to exercise wstring thread safety
result =
rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
rw_opt_nthreads, thread_func);
// exercise both the char and the wchar_t specializations
// at the same time
rw_info (0, 0, 0,
"exercising both std::time_get<char> and std::time_get<wchar_t>");
test_char = true;
test_wchar = true;
// start a pool of threads to exercise wstring thread safety
result =
rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
rw_opt_nthreads, thread_func);
#endif // _RWSTD_NO_WCHAR_T
return result;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
#ifdef _RWSTD_REENTRANT
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
rw_opt_nthreads = rw_get_cpus ();
if (rw_opt_nthreads < 2)
rw_opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.time.get",
"thread safety", run_test,
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // must be provided
"|-shared-locale# ",
&rw_opt_nloops,
int (MAX_THREADS),
&rw_opt_nthreads,
&rw_opt_nlocales,
&rw_opt_setlocales,
&rw_opt_shared_locale);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,405 @@
/************************************************************************
*
* 22.locale.time.put.mt.cpp
*
* test exercising the thread safety of the time_put facet
*
* $Id: 22.locale.time.put.mt.cpp 648752 2008-04-16 17:01:56Z faridz $
*
***************************************************************************
*
* 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 2002-2007 Rogue Wave Software.
*
**************************************************************************/
#include <ios> // for ios
#include <iterator> // for ostreambuf_iterator
#include <locale> // for locale, time_put
#include <cstring> // for strlen ()
#include <ctime> // for tm
#include <rw_locale.h>
#include <rw_thread.h>
#include <driver.h> // for rw_assert ()
#include <valcmp.h> // for rw_strncmp ()
#define MAX_THREADS 32
#define MAX_LOOPS 100000
// default number of threads (will be adjusted to the number
// of processors/cores later)
int opt_nthreads = 1;
// the number of times each thread should iterate
int opt_nloops = MAX_LOOPS;
#if !defined (_RWSTD_OS_HP_UX) || defined (_ILP32)
// number of locales to use
int opt_nlocales = MAX_THREADS;
#else // HP-UX in LP64 mode
// work around an inefficiency (small cache size?) on HP-UX
// in LP64 mode (see STDCXX-812)
int opt_nlocales = 10;
#endif // HP-UX 32/64 bit mode
// should all threads share the same set of locale objects instead
// of creating their own?
int opt_shared_locale;
/**************************************************************************/
// array of locale names to use for testing
static const char*
locales [MAX_THREADS];
// number of locale names in the array
static std::size_t
nlocales;
/**************************************************************************/
//
struct MyTimeData
{
enum { BufferSize = 64 };
// name of the locale the data corresponds to
const char* locale_name_;
// optionally set to the named locale for threads to share
std::locale locale_;
// the time struct used to generate strings below
std::tm time_;
// the format specifier
char format_;
// narrow representations of time_ given the
// locale_name_ and the format_
char ncs_ [BufferSize];
#ifndef _RWSTD_NO_WCHAR_T
// wide representations of time_
wchar_t wcs_ [BufferSize];
#endif // _RWSTD_NO_WCHAR_T
} my_time_data [MAX_THREADS];
template <class charT, class Traits>
struct MyIos: std::basic_ios<charT, Traits>
{
MyIos () {
this->init (0);
}
};
template <class charT, class Traits>
struct MyStreambuf: std::basic_streambuf<charT, Traits>
{
typedef std::basic_streambuf<charT, Traits> Base;
MyStreambuf ()
: Base () {
}
void pubsetp (charT *pbeg, std::streamsize n) {
this->setp (pbeg, pbeg + n);
}
};
extern "C" {
bool test_char; // exercise time_put<char>
bool test_wchar; // exercise time_put<wchar_t>
static void*
thread_func (void*)
{
char ncs [MyTimeData::BufferSize];
MyIos<char, std::char_traits<char> > nio;
MyStreambuf<char, std::char_traits<char> > nsb;
nio.rdbuf (&nsb);
#ifndef _RWSTD_NO_WCHAR_T
wchar_t wcs [MyTimeData::BufferSize];
MyIos<wchar_t, std::char_traits<wchar_t> > wio;
MyStreambuf<wchar_t, std::char_traits<wchar_t> > wsb;
wio.rdbuf (&wsb);
#endif // _RWSTD_NO_WCHAR_T
for (int i = 0; i != opt_nloops; ++i) {
// save the name of the locale
const MyTimeData& data = my_time_data [i % nlocales];
// construct a named locale, get a reference to the time_put
// facet from it and use it to format a random time value
// using a random conversion specifier
const std::locale loc =
opt_shared_locale ? data.locale_
: std::locale (data.locale_name_);
if (test_char) {
// exercise the narrow char specialization of the facet
const std::time_put<char> &tp =
std::use_facet<std::time_put<char> >(loc);
nio.imbue (loc);
nsb.pubsetp (ncs, RW_COUNT_OF (ncs));
// format time using provided format specifier
*tp.put (std::ostreambuf_iterator<char>(&nsb),
nio, ' ', &data.time_, data.format_) = '\0';
RW_ASSERT (!nio.fail ());
RW_ASSERT (!rw_strncmp(ncs, data.ncs_));
}
// both specializations may be tested at the same time
if (test_wchar) {
// exercise the wide char specialization of the facet
#ifndef _RWSTD_NO_WCHAR_T
const std::time_put<wchar_t> &wp =
std::use_facet<std::time_put<wchar_t> >(loc);
wio.imbue (loc);
wsb.pubsetp (wcs, RW_COUNT_OF (wcs));
*wp.put (std::ostreambuf_iterator<wchar_t>(&wsb),
wio, L' ', &data.time_, data.format_) = L'\0';
RW_ASSERT (!wio.fail ());
RW_ASSERT (!rw_strncmp(wcs, data.wcs_));
#endif // _RWSTD_NO_WCHAR_T
}
}
return 0;
}
} // extern "C"
/**************************************************************************/
static int
run_test (int, char**)
{
MyIos<char, std::char_traits<char> > nio;
MyStreambuf<char, std::char_traits<char> > nsb;
nio.rdbuf (&nsb);
#ifndef _RWSTD_NO_WCHAR_T
MyIos<wchar_t, std::char_traits<wchar_t> > wio;
MyStreambuf<wchar_t, std::char_traits<wchar_t> > wsb;
wio.rdbuf (&wsb);
#endif // _RWSTD_NO_WCHAR_T
// find all installed locales for which setlocale (LC_ALL) succeeds
const char* const locale_list =
rw_opt_locales ? rw_opt_locales : rw_locales (_RWSTD_LC_ALL);
const std::size_t maxinx = RW_COUNT_OF (locales);
int j = 0;
for (const char* name = locale_list;
*name;
name += std::strlen (name) + 1) {
const std::size_t inx = nlocales;
locales [inx] = name;
// fill in the time and results for this locale
MyTimeData& data = my_time_data [inx];
data.locale_name_ = name;
// initialize tm with random but valid values
data.time_.tm_sec = ++j % 61;
data.time_.tm_min = ++j % 60;
data.time_.tm_hour = ++j % 12;
data.time_.tm_wday = ++j % 7;
data.time_.tm_mon = ++j % 12;
data.time_.tm_mday = ++j % 31;
data.time_.tm_yday = ++j % 366;
data.time_.tm_year = ++j;
const char cvtspecs[] = "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%";
// get the "random" conversion specifier used to generate
// the result string
data.format_ = cvtspecs [nlocales % (sizeof cvtspecs - 1)];
try {
const std::locale loc (data.locale_name_);
const std::time_put<char> &np =
std::use_facet<std::time_put<char> >(loc);
nio.imbue (loc);
nsb.pubsetp (data.ncs_, RW_COUNT_OF (data.ncs_));
*np.put (std::ostreambuf_iterator<char>(&nsb),
nio, ' ', &data.time_, data.format_) = '\0';
rw_fatal (!nio.fail (), __FILE__, __LINE__,
"time_put<char>::put(..., %c) "
"failed for locale(%#s)",
data.format_, data.locale_name_);
#ifndef _RWSTD_NO_WCHAR_T
const std::time_put<wchar_t> &wp =
std::use_facet<std::time_put<wchar_t> >(loc);
wio.imbue (loc);
wsb.pubsetp (data.wcs_, RW_COUNT_OF (data.wcs_));
*wp.put (std::ostreambuf_iterator<wchar_t>(&wsb),
wio, L' ', &data.time_, data.format_) = L'\0';
rw_fatal (!wio.fail (), __FILE__, __LINE__,
"time_put<wchar_t>::put(..., %c) "
"failed for locale(%#s)",
data.format_, data.locale_name_);
#endif // _RWSTD_NO_WCHAR_T
if (opt_shared_locale)
data.locale_ = loc;
nlocales += 1;
}
catch (...) {
rw_warn (!rw_opt_locales, 0, __LINE__,
"failed to create locale(%#s)", name);
}
if (nlocales == maxinx || nlocales == std::size_t (opt_nlocales))
break;
}
// avoid divide by zero in thread if there are no locales to test
rw_fatal (nlocales != 0, 0, __LINE__,
"failed to create one or more usable locales!");
rw_info (0, 0, 0,
"testing std::time_put<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
opt_nthreads, 1 != opt_nthreads,
opt_nloops, 1 != opt_nloops,
nlocales, int (nlocales), "%#s", locales);
rw_info (0, 0, 0, "exercising std::time_put<char>");
test_char = true;
test_wchar = false;
// create and start a pool of threads and wait for them to finish
int result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
#ifndef _RWSTD_NO_WCHAR_T
rw_info (0, 0, 0, "exercising std::time_put<wchar_t>");
test_char = false;
test_wchar = true;
// start a pool of threads to exercise wstring thread safety
result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
// exercise both the char and the wchar_t specializations
// at the same time
rw_info (0, 0, 0,
"exercising both std::time_put<char> and std::time_put<wchar_t>");
test_char = true;
test_wchar = true;
// start a pool of threads to exercise wstring thread safety
result =
rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
opt_nthreads, thread_func);
#endif // _RWSTD_NO_WCHAR_T
return result;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
#ifdef _RWSTD_REENTRANT
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
opt_nthreads = rw_get_cpus ();
if (opt_nthreads < 2)
opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.time.put",
"thread safety", run_test,
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // must be provided
"|-shared-locale# ",
&opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
&opt_nlocales,
&rw_opt_setlocales,
&opt_shared_locale);
}