Travis
-----Original Message-----
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]
}",