Attached is a patch to enhance the time_put facet mt test. Threads verify that the values they put compare equal to those put in the primary thread.
2007-08-07 Travis Vitek <[EMAIL PROTECTED]> * 22.locale.time.put.mt.cpp (MyIos, MyStreambuf, MyTimeData): Added structures to simplify testing. (run_test): Build table of in/outputs for verification in test threads. (thread_func): Assert that data written matches expected.
Index: 22.locale.time.put.mt.cpp =================================================================== --- 22.locale.time.put.mt.cpp (revision 562577) +++ 22.locale.time.put.mt.cpp (working copy) @@ -32,7 +32,7 @@ #include <iterator> // for ostreambuf_iterator #include <locale> // for locale, time_put -#include <cstring> // for strlen() +#include <cstring> // for strlen () #include <ctime> // for tm #include <rw_locale.h> @@ -60,76 +60,124 @@ static std::size_t nlocales; -/**************************************************************************/ +struct MyTimeData +{ + enum { BufferSize = 64 }; -extern "C" { + // name of the locale the data corresponds to + const char* locale_name_; -bool test_char; // exercise time_put<char> -bool test_wchar; // exercise time_put<wchar_t> + // optinally set to the named locale for threads to share + std::locale locale_; + // the time struct used to generate strings below + std::tm time_; -static void* -thread_func (void*) + // the format specifier + char format_; + + // narrow representations of time_ given the + // locale_name_ and the format_ + char ncs_ [BufferSize]; + std::char_traits<char>::off_type nlen_; + +#ifndef _RWSTD_NO_WCHAR_T + + // wide representations of time_ + wchar_t wcs_ [BufferSize]; + std::char_traits<wchar_t>::off_type wlen_; + +#endif // _RWSTD_NO_WCHAR_T + +} my_time_data [MAX_THREADS]; + + +/**************************************************************************/ + +template <class charT, class Traits> +struct MyIos: std::basic_ios<charT, Traits> { - std::tm tmb = std::tm (); + MyIos () { + this->init (0); + } +}; - const char cvtspecs[] = "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%"; +template <class charT, class Traits> +struct MyStreambuf: std::basic_streambuf<charT, Traits> +{ + typedef std::basic_streambuf<charT, Traits> Base; - // 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; + MyStreambuf () + : Base () { + } -#ifndef _RWSTD_NO_WCHAR_T + void pubsetp (charT *pbeg, charT *pend) { + this->setp (pbeg, pend); + } - struct WideBuf: std::wstreambuf { - int_type overflow (int_type c) { return c; } - } wsb; + charT* pubpbase () const { + return pbase (); + } -#endif // _RWSTD_NO_WCHAR_T + charT* pubpptr () const { + return pptr (); + } - struct Ios: std::ios { - Ios () { this->init (0); } - } io; + charT* pubepptr () const { + return epptr (); + } +}; - int j = 0; +#define countof(x) (sizeof (x) / sizeof (*x)) - for (int i = 0; i != rw_opt_nloops; ++i, ++j) { +extern "C" { - // initialize tm with random but valid values - tmb.tm_sec = ++j % 61; - tmb.tm_min = ++j % 60; - tmb.tm_min = ++j % 60; - tmb.tm_wday = ++j % 7; - tmb.tm_mon = ++j % 12; - tmb.tm_year = ++j; +bool test_char; // exercise time_put<char> +bool test_wchar; // exercise time_put<wchar_t> - // generate a "random" conversion specifier from the set - // of valid specifiers recognized by the facet to exercise - // all (or most) code paths - const char cvt = cvtspecs [i % (sizeof cvtspecs - 1)]; +static void* +thread_func (void*) +{ + char ncs [MyTimeData::BufferSize]; + MyIos<char, std::char_traits<char> > nio; + MyStreambuf<char, std::char_traits<char> > 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; +#endif // _RWSTD_NO_WCHAR_T + + for (int i = 0; i != rw_opt_nloops; ++i) { + // save the name of the locale - const char* const locale_name = locales [i % nlocales]; + 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 (locale_name); + const std::locale loc (data.locale_name_); if (test_char) { // exercise the narrow char specialization of the facet + // should this be hoisted out of the loop? const std::time_put<char> &tp = std::use_facet<std::time_put<char> >(loc); - // format a "random" but valid tm value using the random - // format specifier - tp.put (std::ostreambuf_iterator<char>(&sb), - io, ' ', &tmb, cvt); + // assign data buffer to streambuf + nsb.pubsetp (ncs, ncs + countof (ncs)); + // format time using provided format specifier + tp.put (std::ostreambuf_iterator<char>(&nsb), + nio, ' ', &data.time_, data.format_); + + const std::char_traits<char>::off_type nlen = + nsb.pubpptr() - nsb.pubpbase(); + + RW_ASSERT (nlen == data.nlen_ && + !memcmp (data.ncs_, ncs, nlen)); } // both specializations may be tested at the same time @@ -139,14 +187,23 @@ #ifndef _RWSTD_NO_WCHAR_T + // should this be hoisted out of the loop? const std::time_put<wchar_t> &wtp = std::use_facet<std::time_put<wchar_t> >(loc); + wsb.pubsetp (wcs, wcs + countof (wcs)); + wtp.put (std::ostreambuf_iterator<wchar_t>(&wsb), - io, L' ', &tmb, cvt); + wio, L' ', &data.time_, data.format_); -#endif // _RWSTD_NO_WCHAR_T + const std::char_traits<wchar_t>::off_type wlen = + wsb.pubpptr() - wsb.pubpbase(); + RW_ASSERT (wlen == data.wlen_ && + !memcmp (data.wcs_, wcs, wlen)); + +#endif // _RWSTD_NO_WCHAR_T + } } @@ -160,19 +217,91 @@ static int run_test (int, char**) { - // find all installed locales for which setlocale(LC_ALL) succeeds + 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) { - locales [nlocales++] = name; + const char cvtspecs [] = "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%"; + int j = 0; + for (const char const *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[nlocales]; + data.locale_name_ = name; + + try { + const std::locale loc (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; + + // get the "random" conversion specifier used to generate + // the result string + data.format_ = cvtspecs [nlocales % (sizeof cvtspecs - 1)]; + + const std::time_put<char> &np = + std::use_facet<std::time_put<char> >(loc); + + nsb.pubsetp (data.ncs_, data.ncs_ + countof (data.ncs_)); + + np.put (std::ostreambuf_iterator<char>(&nsb), + nio, ' ', &data.time_, data.format_); + + data.nlen_ = nsb.pubpptr() - nsb.pubpbase(); + +#ifndef _RWSTD_NO_WCHAR_T + + const std::time_put<wchar_t> &wp = + std::use_facet<std::time_put<wchar_t> >(loc); + + wsb.pubsetp (data.wcs_, data.wcs_ + countof (data.wcs_)); + + wp.put (std::ostreambuf_iterator<wchar_t>(&wsb), + wio, L' ', &data.time_, data.format_); + + data.wlen_ = wsb.pubpptr() - wsb.pubpbase(); + +#endif // _RWSTD_NO_WCHAR_T + + } catch (...) { + // skip over bad locale + } + + nlocales += 1; + if (nlocales == maxinx) break; } + // avoid divide by zero in thread if there are no locales to test + if (nlocales < 1) { + 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%{;}, " "%zu iteration%{?}s%{;} each, in locales { %{ [EMAIL PROTECTED] }",