Attached is a patch to enhance the num_put facet mt test. Threads verify that the values they put compare equal to those put in the primary thread.
2007-08-10 Travis Vitek <[EMAIL PROTECTED]> * 22.locale.num.put.mt.cpp(MyIos, MyStreambuf, MyNumData): Added structures to simplify testing. (run_test): Build a table of in/outputs for verification in thest threads. (thread_func): Assert the data written matches expected (main): Add command line options for specifying number of locales, locale names, and locale usage.
Index: 22.locale.num.put.mt.cpp =================================================================== --- 22.locale.num.put.mt.cpp (revision 564268) +++ 22.locale.num.put.mt.cpp (working copy) @@ -35,19 +35,25 @@ #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 -// 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 number of times each thread should iterate (unless specified -// otherwise on the command line) -int rw_opt_nloops = 200000; +// the number of times each thread should iterate +int rw_opt_nloops = MAX_LOOPS; +// 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 @@ -58,150 +64,129 @@ static std::size_t nlocales; -/**************************************************************************/ -extern "C" { +struct MyNumData { -bool test_char; // exercise num_put<char> -bool test_wchar; // exercise num_put<wchar_t> + enum { BufferSize = 32 }; + // name of the locale the data corresponds to + const char* locale_name_; -static void* -thread_func (void*) -{ - // dummy streambuf-derived object the doesn't do anything - // but allows ostreambuf_iterator to "think" it can write - // to it - struct NarrowBuf: std::streambuf { - int_type overflow (int_type c) { return c; } - } sb; + // optionally set to the named locale for threads to share + std::locale locale_; -#ifndef _RWSTD_NO_WCHAR_T + // the value that we will be formatting + int value_; - struct WideBuf: std::wstreambuf { - int_type overflow (int_type c) { return c; } - } wb; + // holds the narrow/wide character representation of value_ and + // the number of used 'charT' in each buffer. + struct result { + char ncs_ [BufferSize]; + std::char_traits<char>::off_type nlen_; -#endif // _RWSTD_NO_WCHAR_T + wchar_t wcs_ [BufferSize]; + std::char_traits<wchar_t>::off_type wlen_; + }; - struct Ios: std::ios { - Ios () { this->init (0); } - } io; + result bool_; + result long_; + result ulong_; + result llong_; + result ullong_; + result double_; + result ldouble_; + result pointer_; - const std::ios::fmtflags baseflags[] = { - std::ios::oct, - std::ios::dec, - std::ios::hex - }; +} my_num_data [MAX_THREADS]; - const std::ios::fmtflags fmtflags[] = { - std::ios::showpos, - std::ios::showpoint, - std::ios::fixed, - std::ios::scientific - }; - const std::ios::fmtflags adjustflags[] = { - std::ios::internal, - std::ios::left, - std::ios::right - }; +/**************************************************************************/ - for (int i = 0; i != rw_opt_nloops; ++i) { +template <class charT, class Traits> +struct MyIos: std::basic_ios<charT, Traits> +{ + MyIos () { + this->init (0); + } +}; - // save the name of the locale - const char* const locale_name = locales [i % nlocales]; +template <class charT, class Traits> +struct MyStreambuf: std::basic_streambuf<charT, Traits> +{ + typedef std::basic_streambuf<charT, Traits> Base; - // 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); - io.imbue (loc); + MyStreambuf () + : Base () { + } - enum PutId { - put_bool, - put_long, - put_ulong, + void pubsetp (charT *pbeg, std::streamsize n) { + this->setp (pbeg, pbeg + n); + } +}; -#ifndef _RWSTD_NO_LONG_LONG - put_llong, - put_ullong, +#define countof(x) (sizeof (x) / sizeof (*x)) -#endif // _RWSTD_NO_LONG_LONG +extern "C" { - put_dbl, - put_ldbl, - put_ptr, - put_max - }; +bool test_char; // exercise num_put<char> +bool test_wchar; // exercise num_put<wchar_t> - const std::ios::fmtflags base = - baseflags [i % (sizeof baseflags / sizeof *baseflags)]; - const std::ios::fmtflags fmt = - fmtflags [i % (sizeof baseflags / sizeof *baseflags)]; +static void* +thread_func (void*) +{ + char ncs [MyNumData::BufferSize]; + MyIos<char, std::char_traits<char> > nio; + MyStreambuf<char, std::char_traits<char> > nsb; - const std::ios::fmtflags adjust = - adjustflags [i % (sizeof baseflags / sizeof *baseflags)]; +#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; +#endif // _RWSTD_NO_WCHAR_T - io.flags (base | fmt | adjust); + for (int i = 0; i != rw_opt_nloops; ++i) { - io.width (i % 16); + // fill in the value and results for this locale + const MyNumData& data = my_num_data [i % nlocales]; - // exercise postive and negative values - const int ival = i & 1 ? -i : i; - + // 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_put<char> &np = std::use_facet<std::num_put<char> >(loc); - const std::ostreambuf_iterator<char> iter (&sb); + nio.imbue (loc); - switch (i % put_max) { - case put_bool: - if (i & 2) - io.setf (std::ios::boolalpha); - else - io.unsetf (std::ios::boolalpha); - - np.put (iter, io, ' ', bool (ival)); - break; +#define TEST(sb, buf, cmp, io, p, fill, valueT, val, charT) \ + sb.pubsetp (buf, countof (buf)); \ + io.rdbuf (&sb); \ + *p.put (std::ostreambuf_iterator<charT>(&sb), \ + io, fill, (valueT)(val)) = charT (); \ + RW_ASSERT (!io.fail ()); \ + RW_ASSERT (!rw_strncmp (buf, cmp)); - case put_long: - np.put (iter, io, ' ', long (ival)); - break; +#define TEST_N(o, t, v) \ + TEST(nsb, ncs, o.ncs_, nio, np, ' ', t, v, char) - case put_ulong: - np.put (iter, io, ' ', (unsigned long)ival); - break; - + TEST_N (data.bool_, bool, data.value_ != 0); + TEST_N (data.long_, long, data.value_); + TEST_N (data.ulong_, unsigned long, data.value_); #ifndef _RWSTD_NO_LONG_LONG - - case put_llong: - np.put (iter, io, ' ', (_RWSTD_LONG_LONG)ival); - break; - -#endif // _RWSTD_NO_LONG_LONG - - case put_ullong: - np.put (iter, io, ' ', (unsigned _RWSTD_LONG_LONG)ival); - break; - - case put_dbl: - np.put (iter, io, ' ', double (ival)); - break; - - case put_ldbl: - np.put (iter, io, ' ', (long double)ival); - break; - - case put_ptr: - np.put (iter, io, ' ', (void*)ival); - break; - } + TEST_N (data.llong_,_RWSTD_LONG_LONG, data.value_); + TEST_N (data.ullong_, unsigned _RWSTD_LONG_LONG, data.value_); +#endif // _RWSTD_NO_LONG_LONG + TEST_N (data.double_, double, data.value_); +#ifndef _RWSTD_NO_LONG_DOUBLE + TEST_N (data.ldouble_, long double, data.value_); +#endif // _RWSTD_NO_LONG_DOUBLE + TEST_N (data.pointer_, void*, data.value_); } // both specializations may be tested at the same time @@ -209,51 +194,29 @@ if (test_wchar) { // exercise the wide char specialization of the facet -#ifndef _RWSTD_NO_WCHAR_T - - const std::num_put<wchar_t> &np = + const std::num_put<wchar_t> &wp = std::use_facet<std::num_put<wchar_t> >(loc); - const std::ostreambuf_iterator<wchar_t> iter (&wb); + wio.imbue (loc); - switch (i % put_max) { - case put_bool: - np.put (iter, io, L' ', bool (ival)); - break; +#define TEST_W(o, t, v) \ + TEST(wsb, wcs, o.wcs_, wio, wp, L' ', t, v, wchar_t) - case put_long: - np.put (iter, io, L' ', long (ival)); - break; +#ifndef _RWSTD_NO_WCHAR_T - case put_ulong: - np.put (iter, io, L' ', (unsigned long)ival); - break; - -#ifndef _RWSTD_NO_LONG_LONG - - case put_llong: - np.put (iter, io, L' ', (_RWSTD_LONG_LONG)ival); - break; - - case put_ullong: - np.put (iter, io, L' ', (unsigned _RWSTD_LONG_LONG)ival); - break; - -#endif // _RWSTD_NO_LONG_LONG - - case put_dbl: - np.put (iter, io, L' ', double (ival)); - break; - - case put_ldbl: - np.put (iter, io, L' ', (long double)ival); - break; - - case put_ptr: - np.put (iter, io, L' ', (void*)ival); - break; - } - + TEST_W (data.bool_, bool, data.value_ != 0); + TEST_W (data.long_, long, data.value_); + TEST_W (data.ulong_, unsigned long, data.value_); +#ifndef _RWSTD_WO_LONG_LONG + TEST_W (data.llong_,_RWSTD_LONG_LONG, data.value_); + TEST_W (data.ullong_, unsigned _RWSTD_LONG_LONG, data.value_); +#endif // _RWSTD_WO_LONG_LONG + TEST_W (data.double_, double, data.value_); +#ifndef _RWSTD_WO_LONG_DOUBLE + TEST_W (data.ldouble_, long double, data.value_); +#endif // _RWSTD_WO_LONG_DOUBLE + TEST_W (data.pointer_, void*, data.value_); + #endif // _RWSTD_NO_WCHAR_T } @@ -266,23 +229,126 @@ /**************************************************************************/ + static int run_test (int, char**) { + MyIos<char, std::char_traits<char> > nio; + MyStreambuf<char, std::char_traits<char> > nsb; + +#ifndef _RWSTD_NO_WCHAR_T + MyIos<wchar_t, std::char_traits<wchar_t> > wio; + MyStreambuf<wchar_t, std::char_traits<wchar_t> > 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 = sizeof locales / sizeof *locales; + const std::size_t maxinx = countof (locales); - for (const char *name = locale_list; *name; name += std::strlen (name) +1) { + const char* const possible_locale_options[] = { + locale_list, "C\0", 0 + }; - locales [nlocales++] = name; + for (int p = 0; possible_locale_options[p]; ++p) { - if (nlocales == maxinx) - break; + for (const char *name = possible_locale_options[p]; + *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; + + // format data into buffers + const std::num_put<char> &np = + std::use_facet<std::num_put<char> >(loc); + + nio.imbue (loc); + +#define SETUP(sb, buf, io, p, fill, valueT, val, charT, loc) \ + sb.pubsetp (buf, countof (buf)); \ + io.rdbuf (&sb); \ + *p.put (std::ostreambuf_iterator<charT>(&sb), \ + io, fill, (valueT)(val)) = charT (); \ + rw_assert (!io.fail (), __FILE__, __LINE__, \ + "num_put<%s>::put(..., %s (%d)) " \ + "failed for locale(%#s)", \ + #charT, #valueT, val, loc); + +#define SETUP_N(o, t, v) \ + SETUP(nsb, o.ncs_, nio, np, ' ', t, v, char, name) + + SETUP_N (data.bool_, bool, data.value_ != 0); + SETUP_N (data.long_, long, data.value_); + SETUP_N (data.ulong_, unsigned long, data.value_); +#ifndef _RWSTD_NO_LONG_LONG + SETUP_N (data.llong_,_RWSTD_LONG_LONG, data.value_); + SETUP_N (data.ullong_, unsigned _RWSTD_LONG_LONG, data.value_); +#endif // _RWSTD_NO_LONG_LONG + SETUP_N (data.double_, double, data.value_); +#ifndef _RWSTD_NO_LONG_DOUBLE + SETUP_N (data.ldouble_, long double, data.value_); +#endif // _RWSTD_NO_LONG_DOUBLE + SETUP_N (data.pointer_, void*, data.value_); + +#ifndef _RWSTD_NO_WCHAR_T + + const std::num_put<wchar_t> &wp = + std::use_facet<std::num_put<wchar_t> >(loc); + + wio.imbue (loc); + +#define SETUP_W(o, t, v) \ + SETUP(wsb, o.wcs_, wio, wp, L' ', t, v, wchar_t, name) + + SETUP_W (data.bool_, bool, data.value_ != 0); + SETUP_W (data.long_, long, data.value_); + SETUP_W (data.ulong_, unsigned long, data.value_); +#ifndef _RWSTD_NO_LONG_LONG + SETUP_W (data.llong_,_RWSTD_LONG_LONG, data.value_); + SETUP_W (data.ullong_, unsigned _RWSTD_LONG_LONG, data.value_); +#endif // _RWSTD_NO_LONG_LONG + SETUP_W (data.double_, double, data.value_); +#ifndef _RWSTD_NO_LONG_DOUBLE + SETUP_W (data.ldouble_, long double, data.value_); +#endif // _RWSTD_NO_LONG_DOUBLE + SETUP_W (data.pointer_, void*, data.value_); + +#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; + } + + if (nlocales != 0) { + break; // found at least one locale + } } + // 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%{;}, " "%zu iteration%{?}s%{;} each, in locales { %{ [EMAIL PROTECTED] }", @@ -357,11 +423,15 @@ 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] - "|-locales=", // must be provided + "|-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_setlocales); + &rw_opt_nlocales, + &rw_opt_setlocales, + &rw_opt_shared_locale); }