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);
 }

Reply via email to