From stdcxx-commits-return-1483-apmail-incubator-stdcxx-commits-archive=incubator.apache.org@incubator.apache.org Wed Jun 27 22:19:53 2007 Return-Path: Delivered-To: apmail-incubator-stdcxx-commits-archive@www.apache.org Received: (qmail 14370 invoked from network); 27 Jun 2007 22:19:53 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 27 Jun 2007 22:19:53 -0000 Received: (qmail 90409 invoked by uid 500); 27 Jun 2007 22:19:56 -0000 Delivered-To: apmail-incubator-stdcxx-commits-archive@incubator.apache.org Received: (qmail 90387 invoked by uid 500); 27 Jun 2007 22:19:56 -0000 Mailing-List: contact stdcxx-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: stdcxx-dev@incubator.apache.org Delivered-To: mailing list stdcxx-commits@incubator.apache.org Received: (qmail 90376 invoked by uid 99); 27 Jun 2007 22:19:56 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 27 Jun 2007 15:19:56 -0700 X-ASF-Spam-Status: No, hits=-99.5 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 27 Jun 2007 15:19:52 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id E05031A981A; Wed, 27 Jun 2007 15:19:31 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r551354 - /incubator/stdcxx/trunk/tests/localization/22.locale.moneypunct.mt.cpp Date: Wed, 27 Jun 2007 22:19:31 -0000 To: stdcxx-commits@incubator.apache.org From: sebor@apache.org X-Mailer: svnmailer-1.1.0 Message-Id: <20070627221931.E05031A981A@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: sebor Date: Wed Jun 27 15:19:30 2007 New Revision: 551354 URL: http://svn.apache.org/viewvc?view=rev&rev=551354 Log: 2007-06-27 Martin Sebor * 22.locale.moneypunct.mt.cpp: Rewrote so as not to rely on localeconv but retrieve the "master" data from the C++ locale instead instead. (thread_loop_body): Factored out the body of thread_func here. (get_format): Removed. (rw_opt_nloops): Reduced from 2000000 to 10000 and set to the number of tested locales in non-reentrant configurations to speed things up. (rw_opt_setlocales): Callback function to process --locales option. (main): Set rw_opt_nthreads to rw_get_cpus() in thread-safe configs. (--locale=): New command line option to specify the names of locales to test. Modified: incubator/stdcxx/trunk/tests/localization/22.locale.moneypunct.mt.cpp Modified: incubator/stdcxx/trunk/tests/localization/22.locale.moneypunct.mt.cpp URL: http://svn.apache.org/viewvc/incubator/stdcxx/trunk/tests/localization/22.locale.moneypunct.mt.cpp?view=diff&rev=551354&r1=551353&r2=551354 ============================================================================== --- incubator/stdcxx/trunk/tests/localization/22.locale.moneypunct.mt.cpp (original) +++ incubator/stdcxx/trunk/tests/localization/22.locale.moneypunct.mt.cpp Wed Jun 27 15:19:30 2007 @@ -29,9 +29,8 @@ #include // for ios #include // for locale, moneypunct -#include // for lconv, localeconv() -#include // for mbstowcs() -#include // for size_t, strcpy() +#include // for mbstowcs(), size_t +#include // for strcpy() #include #include @@ -42,17 +41,16 @@ // maximum number of threads allowed by the command line interface #define MAX_THREADS 32 - -#ifdef _RWSTD_REENTRANT -int rw_opt_nthreads = 4; -#else // if !defined (_RWSTD_REENTRANT) -// in non-threaded builds use just one thread +// default number of threads (will be adjusted to the number +// of processors/cores later) int rw_opt_nthreads = 1; -#endif // _RWSTD_REENTRANT -// the number of times each thread should iterate (unless specified -// otherwise on the command line) -int rw_opt_nloops = 200000; +// 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; /**************************************************************************/ @@ -97,147 +95,154 @@ } punct_data [MAX_THREADS]; - -extern "C" { +/**************************************************************************/ bool test_char; // exercise num_put bool test_wchar; // exercise num_put - -static void* -thread_func (void*) +static void +thread_loop_body (std::size_t i) { - for (int i = 0; i != rw_opt_nloops; ++i) { + const std::size_t inx = std::size_t (i) % (nlocales ? nlocales : 1); - const std::size_t inx = std::size_t (i) % nlocales; + const MoneypunctData* const data = punct_data + inx; - const MoneypunctData* const data = punct_data + inx; + // construct a named locale + const std::locale loc (data->locale_name_); - // 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 Punct; + + const Punct &mp = std::use_facet(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_)); - if (test_char) { - // exercise the narrow char, local specialization of the facet - - typedef std::moneypunct Punct; - - const Punct &mp = std::use_facet(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)); + } - 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 - if (test_char) { - // exercise the narrow char, international specialization + typedef std::moneypunct Punct; - typedef std::moneypunct Punct; + const Punct &mp = std::use_facet(loc); - const Punct &mp = std::use_facet(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_)); - 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 (!std::memcmp (&pfm, data->int_pos_format_, 4)); + RW_ASSERT (!std::memcmp (&nfm, data->int_neg_format_, 4)); + } - 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_)); + // both specializations may be tested at the same time - RW_ASSERT (!std::memcmp (&pfm, data->int_pos_format_, 4)); - RW_ASSERT (!std::memcmp (&nfm, data->int_neg_format_, 4)); - } +#ifndef _RWSTD_NO_WCHAR_T - // both specializations may be tested at the same time + if (test_wchar) { + // exercise the wide char, local specialization of the facet -#ifndef _RWSTD_NO_WCHAR_T + typedef std::moneypunct Punct; - if (test_wchar) { - // exercise the wide char, local specialization of the facet + const Punct &mp = std::use_facet(loc); - typedef std::moneypunct Punct; + const char dp = mp.decimal_point (); + const char 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_)); - const Punct &mp = std::use_facet(loc); + RW_ASSERT (!std::memcmp (&pfm, data->pos_format_, 4)); + RW_ASSERT (!std::memcmp (&nfm, data->neg_format_, 4)); + } - const char dp = mp.decimal_point (); - const char 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 (); + if (test_wchar) { + // exercise the wide char, international specialization - 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_)); + typedef std::moneypunct Punct; - RW_ASSERT (!std::memcmp (&pfm, data->pos_format_, 4)); - RW_ASSERT (!std::memcmp (&nfm, data->neg_format_, 4)); - } + const Punct &mp = std::use_facet(loc); - if (test_wchar) { - // exercise the wide char, international specialization + const char dp = mp.decimal_point (); + const char 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_)); - typedef std::moneypunct Punct; + RW_ASSERT (!std::memcmp (&pfm, data->int_pos_format_, 4)); + RW_ASSERT (!std::memcmp (&nfm, data->int_neg_format_, 4)); + } - const Punct &mp = std::use_facet(loc); +#endif // _RWSTD_NO_WCHAR_T - const char dp = mp.decimal_point (); - const char 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)); - } +extern "C" { -#endif // _RWSTD_NO_WCHAR_T +static void* +thread_func (void*) +{ + for (int i = 0; i != rw_opt_nloops; ++i) { + thread_loop_body (std::size_t (i)); } return 0; @@ -247,154 +252,16 @@ /**************************************************************************/ -static void -get_format (MoneypunctData *pdata, const std::lconv *pconv) -{ - // code copied from src/punct.cpp - - enum { - // for syntactic convenience - 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 pat[] = { - - // 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. - - // +-------- cs_precedes - // |+----- sep_by_space - // ||+-- sign_posn - // ||| - // VVV .... - 1 $ . // pattern - /* 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\1\4\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" - }; - - std::size_t inx; - - inx = std::size_t (pconv->p_cs_precedes) * (3U * 5U) - + std::size_t (pconv->p_sep_by_space) * 5U - + std::size_t (pconv->p_sign_posn); - - if (inx < sizeof pat / sizeof *pat) - std::memcpy (pdata->pos_format_, pat + inx, sizeof *pat); - else - std::memset (pdata->pos_format_, none, sizeof *pat); - - inx = std::size_t (pconv->n_cs_precedes) * (3U * 5U) - + std::size_t (pconv->n_sep_by_space) * 5U - + std::size_t (pconv->n_sign_posn); - - if (inx < sizeof pat / sizeof *pat) - std::memcpy (pdata->neg_format_, pat + inx, sizeof *pat); - else - std::memset (pdata->neg_format_, none, sizeof *pat); - - -#ifndef _RWSTD_NO_LCONV_INT_FMAT - - inx = std::size_t (pconv->int_p_cs_precedes) * (3U * 5U) - + std::size_t (pconv->int_p_sep_by_space) * 5U - + std::size_t (pconv->int_p_sign_posn); - - if (inx < sizeof pat / sizeof *pat) - std::memcpy (pdata->int_pos_format_, pat + inx, sizeof *pat); - else - std::memset (pdata->int_pos_format_, none, sizeof *pat); - - inx = std::size_t (pconv->int_n_cs_precedes) * (3U * 5U) - + std::size_t (pconv->int_n_sep_by_space) * 5U - + std::size_t (pconv->int_n_sign_posn); - - if (inx < sizeof pat / sizeof *pat) - memcpy (pdata->int_neg_format_, pat + inx, sizeof *pat); - else - memset (pdata->int_neg_format_, none, sizeof *pat); - - std::strcpy (pdata->int_curr_symbol_, pconv->int_curr_symbol); - - pdata->int_frac_digits_ = pconv->int_frac_digits; - -#else // if defined (_RWSTD_NO_LCONV_INT_FMAT) - - std::strcpy (pdata->int_curr_symbol_, pconv->curr_symbol); - - pdata->int_frac_digits_ = pconv->frac_digits; - -#endif // _RWSTD_NO_LCONV_INT_FMAT - -} +static char* +rw_opt_locales; static int run_test (int, char**) { - // get a NUL-separated list of names of installed locales - char* const locale_list = rw_locales (); + // find all installed locales for which setlocale(LC_ALL) succeeds + 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]; @@ -404,76 +271,144 @@ // iterate over locales, initializing a global punct_data array for (char *name = locale_list; *name; name += std::strlen (name) + 1) { - const std::size_t inx = nlocales; + std::locale loc; - // set LC_NUMERIC and LC_CTYPE to be able to use mbstowcs() - if (std::setlocale (LC_ALL, name)) { + MoneypunctData* const pdata = punct_data + nlocales; - const std::lconv* const pconv = std::localeconv (); - MoneypunctData* const pdata = punct_data + inx; + pdata->locale_name_ = name; + locales [nlocales] = name; - locales [inx] = pdata->locale_name_ = name; + try { + loc = std::locale (name); - // assign just the first character of the (potentially) - // multibyte decimal_point and thousands_sep (C++ locale - // can't deal with more) - pdata->decimal_point_ = *pconv->mon_decimal_point; - pdata->thousands_sep_ = *pconv->mon_thousands_sep; + typedef std::moneypunct Punct; + + const Punct &mp = std::use_facet(loc); - pdata->frac_digits_ = pconv->frac_digits; + 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 Punct; + + const Punct &mp = std::use_facet(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 (); - // simply copy the narrow grouping, currency symbols, - // and signs - std::strcpy (pdata->grouping_, pconv->mon_grouping); - std::strcpy (pdata->curr_symbol_, pconv->currency_symbol); - std::strcpy (pdata->negative_sign_, pconv->negative_sign); - std::strcpy (pdata->positive_sign_, pconv->positive_sign); - std::strcpy (pdata->grouping_, pconv->mon_grouping); + pdata->int_frac_digits_ = fd; - get_format (pdata, pconv); + 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_WCHAR_T +#ifndef _RWSTD_NO_WCHAR_T - wchar_t tmp [2]; + try { + typedef std::moneypunct Punct; - // convert multibyte decimal point and thousands separator - // to wide characters (assumes they are single character - // each -- C++ locale can't handle more) - std::mbstowcs (tmp, pconv->mon_decimal_point, 2); - pdata->wdecimal_point_ = tmp [0]; + const Punct &mp = std::use_facet(loc); - std::mbstowcs (tmp, pconv->mon_thousands_sep, 2); - pdata->wthousands_sep_ = tmp [0]; + 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; + } - const std::size_t n = - sizeof pdata->wcurr_symbol_ / sizeof (wchar_t); + try { + typedef std::moneypunct Punct; - std::mbstowcs (pdata->wcurr_symbol_, pdata->curr_symbol_, n); - std::mbstowcs (pdata->wnegative_sign_, pdata->negative_sign_, n); - std::mbstowcs (pdata->wpositive_sign_, pdata->positive_sign_, n); + const Punct &mp = std::use_facet(loc); - std::mbstowcs (pdata->wint_curr_symbol_, - pdata->int_curr_symbol_, - n); + const std::wstring cur = mp.curr_symbol (); + const std::wstring pos = mp.positive_sign (); + const std::wstring neg = mp.negative_sign (); -#endif // _RWSTD_WCHAR_T + typedef std::wstring::traits_type Traits; - ++nlocales; + 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; } - // reset the global locale - std::setlocale (LC_ALL, "C"); + // 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 with %d thread%{?}s%{;}, " - "%zu iteration%{?}s%{;} each, in locales { %{ .*A@} }", + "%zu iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }", rw_opt_nthreads, 1 != rw_opt_nthreads, rw_opt_nloops, 1 != rw_opt_nloops, - int (nlocales), "%#s", locales); + nlocales, int (nlocales), "%#s", locales); rw_info (0, 0, 0, "exercising std::moneypunct"); @@ -529,14 +464,54 @@ /**************************************************************************/ +static int +rw_opt_setlocales (int argc, char* argv[]) +{ + RW_ASSERT (0 < argc && argv [0]); + + rw_opt_locales = std::strchr (argv [0], '='); + + if (rw_opt_locales) { + + const std::size_t len = std::strlen (++rw_opt_locales); + char* const locale_names = new char [len + 2]; + + locale_names [len + 1] = '\0'; + + std::memcpy (locale_names, rw_opt_locales, len); + + rw_opt_locales = locale_names; + + for (char *next = rw_opt_locales; ; ) { + next = std::strpbrk (next, ", "); + if (next) + *next++ = '\0'; + else + break; + } + } + + return 0; +} + + int main (int argc, char *argv[]) { +#ifdef _RWSTD_REENTRANT + + // set nthreads to the number of processors by default + rw_opt_nthreads = rw_get_cpus (); + +#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] + "|-nthreads#0-*" // must be in [0, MAX_THREADS] + "|-locales=", // must be provided &rw_opt_nloops, int (MAX_THREADS), - &rw_opt_nthreads); + &rw_opt_nthreads, + &rw_opt_setlocales); }