stdcxx-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Martin Sebor <se...@roguewave.com>
Subject Re: [PATCH] Update test 22.locale.money.put.mt.cpp to validate results [take 2]
Date Mon, 13 Aug 2007 03:55:42 GMT
Travis Vitek wrote:
> Attached is a patch to enhance the money_put facet mt test. Threads
> verify that the values they put are equal to those put in the
> primary thread.

I'll hold off on committing this patch until we've decided how
to deal with the 22.locale.num.put.mt.cpp patch since many of
the issues are also applicable here.

Also, while you're enhancing this test (or at a later point in
a separate patch), it would be helpful to also extend the set of
"master" values to use to exercise the facet to those involving
the currency symbol.

Martin

> 
> 2007-08-10  Travis Vitek    <vitek@roguewave.com>
> 
>     * 22.locale.money.put.mt.cpp(MyIos, MyStreambuf, MyMoneyData)
>     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.
>     (main): Add
> 
> 
> ------------------------------------------------------------------------
> 
> Index: 22.locale.money.put.mt.cpp
> ===================================================================
> --- 22.locale.money.put.mt.cpp	(revision 564268)
> +++ 22.locale.money.put.mt.cpp	(working copy)
> @@ -30,15 +30,17 @@
>  #include <iterator>   // for ostreambuf_iterator
>  #include <locale>     // for locale, money_put
>  
> -#include <cstring>    // for strlen()
> +#include <cstring>    // for strlen ()
>  
>  #include <rw_locale.h>
>  #include <rw_thread.h>
> -#include <driver.h>
> +#include <driver.h>    // for rw_assert ()
> +#include <valcmp.h>    // for rw_strncmp ()
>  
>  
>  // maximum number of threads allowed by the command line interface
> -#define MAX_THREADS   32
> +#define MAX_THREADS      32
> +#define MAX_LOOPS    100000
>  
>  // default number of threads (will be adjusted to the number
>  // of processors/cores later)
> @@ -48,6 +50,13 @@
>  // otherwise on the command line)
>  int rw_opt_nloops = 100000;
>  
> +// 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
> @@ -60,97 +69,146 @@
>  
>  /**************************************************************************/
>  
> -extern "C" {
> +static const char n_money_vals[][20] = {
> +    "1", "12", "123", "1234", "12345", "123456", "1234567", "12345678",
> +    "-9", "-98", "-987", "-9876", "-98765", "-987654", "-9876543",
> +    "1.9", "-12.89", "123.789", "-1234.6789", "-12345.56789"
> +};
>  
> -bool test_char;    // exercise money_put<char>
> -bool test_wchar;   // exercise money_put<wchar_t>
> +#ifndef _RWSTD_NO_WCHAR_T
>  
> +static const wchar_t w_money_vals[][20] = {
> +    L"1", L"12", L"123", L"1234", L"12345", L"123456", L"1234567",
> +    L"-9", L"-98", L"-987", L"-9876", L"-98765", L"-987654", L"-9876543",
> +    L"1.9", L"-12.89", L"123.789", L"-1234.6789", L"-12345.56789"
> +};
>  
> -static void*
> -thread_func (void*)
> +#endif  // _RWSTD_NO_WCHAR_T
> +
> +//
> +struct MyMoneyData
>  {
> -    // 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;
> +    enum { BufferSize = 16 };
>  
> -    const char str_vals[][20] = {
> -        "1", "12", "123", "1234", "12345", "123456", "1234567", "12345678",
> -        "-9", "-98", "-987", "-9876", "-98765", "-987654", "-9876543",
> -        "1.9", "-12.89", "123.789", "-1234.6789", "-12345.56789"
> -    };
> +    // name of the locale the data corresponds to
> +    const char* locale_name_;
>  
> +    // optionally set to the named locale for threads to share
> +    std::locale locale_;
> +
> +    // international or domestic format flag
> +    bool intl_;
> +
> +    // the time struct used to generate strings below
> +    long double money_value_;
> +
> +    // index into string array [n,w]_money_vals
> +    unsigned n_money_index_;
> +    unsigned w_money_index_;
> +
> +    //
> +    struct Source {
> +
> +        // narrow representations of money_
> +        char ncs_ [BufferSize];
> +
>  #ifndef _RWSTD_NO_WCHAR_T
>  
> -    struct WideBuf: std::wstreambuf {
> -        int_type overflow (int_type c) { return c; }
> -    } wb;
> +        // wide representations of money_
> +        wchar_t wcs_ [BufferSize];
>  
> -    const wchar_t wstr_vals[][20] = {
> -        L"1", L"12", L"123", L"1234", L"12345", L"123456", L"1234567",
> -        L"-9", L"-98", L"-987", L"-9876", L"-98765", L"-987654", L"-9876543",
> -        L"1.9", L"-12.89", L"123.789", L"-1234.6789", L"-12345.56789"
> -    };
> +#endif // _RWSTD_NO_WCHAR_T
>  
> -#endif   // _RWSTD_NO_WCHAR_T
> +    } numeric_, string_;
>  
> -    struct Ios: std::ios {
> -        Ios () { this->init (0); }
> -    } io;
> +} my_money_data [MAX_THREADS];
>  
> -    for (int i = 0; i != rw_opt_nloops; ++i) {
>  
> -        // save the name of the locale
> -        const char* const locale_name = locales [i % nlocales];
> +template <class charT, class Traits>
> +struct MyIos: std::basic_ios<charT, Traits>
> +{
> +    MyIos () {
> +        this->init (0);
> +    }
> +};
>  
> -        // construct a named locale and imbue it in the ios object
> -        // so that the locale is used not only by the money_put facet
> -        // but also by the numpunct facet
> -        const std::locale loc (locale_name);
> -        io.imbue (loc);
>  
> -        enum PutId {
> -            put_ldbl,
> -            put_string,
> -            put_max
> -        };
> +template <class charT, class Traits>
> +struct MyStreambuf: std::basic_streambuf<charT, Traits>
> +{
> +    typedef std::basic_streambuf<charT, Traits> Base;
>  
> -        io.width (i % 16);
> +    MyStreambuf ()
> +        : Base () {
> +    }
>  
> -        // exercise postive and negative values
> -        long double ldval = i & 1 ? -i : i;
> +    void pubsetp (charT *pbeg, std::streamsize n) {
> +        this->setp (pbeg, pbeg + n);
> +    }
> +};
>  
> -        // add some random fractional digits
> -        if (i & 2)
> -            ldval += ldval / 3.14;
>  
> -        // exercise domestic formats every other iteration
> -        // and international formats the rest
> -        const bool intl = 0 == (i & 1);
> +#define countof(x) (sizeof (x) / sizeof (*x))
>  
> +extern "C" {
> +
> +bool test_char;    // exercise money_put<char>
> +bool test_wchar;   // exercise money_put<wchar_t>
> +
> +
> +static void*
> +thread_func (void*)
> +{
> +    char             ncs [MyMoneyData::BufferSize];
> +    MyIos<char, std::char_traits<char> >       nio;
> +    MyStreambuf<char, std::char_traits<char> > nsb;
> +
> +#ifndef _RWSTD_NO_WCHAR_T
> +    wchar_t                wcs [MyMoneyData::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 MyMoneyData& data = my_money_data [i % nlocales];
> +
> +        // construct a named locale, get a reference to the money_put
> +        // facet from it and use it to format a random money value
> +        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::money_put<char> &mp =
> +            const std::money_put<char> &np =
>                  std::use_facet<std::money_put<char> >(loc);
>  
> -            const std::ostreambuf_iterator<char> iter (&sb);
> +            nio.imbue (loc);
>  
> -            switch (i % put_max) {
> -            case put_ldbl:
> -                mp.put (iter, intl, io, ' ', ldval);
> -                break;
> +            // verify the conversion from double
> +            nsb.pubsetp (ncs, countof (ncs));
> +            nio.rdbuf (&nsb);
>  
> -            case put_string: {
> -                const char* const strval =
> -                    str_vals [i % sizeof str_vals / sizeof *str_vals];
> +            *np.put (std::ostreambuf_iterator<char>(&nsb),
> +                     data.intl_, nio, ' ', data.money_value_) = char();
>  
> -                mp.put (iter, intl, io, ' ', strval);
> -                break;
> -            }
> -            }
> +            RW_ASSERT (!nio.fail ());
> +            RW_ASSERT (!rw_strncmp(ncs, data.numeric_.ncs_));
> +
> +            // verify the conversion from string
> +            nsb.pubsetp (ncs, countof (ncs));
> +            nio.rdbuf (&nsb);
> +
> +            *np.put (std::ostreambuf_iterator<char>(&nsb),
> +                     data.intl_, nio, ' ',
> +                     n_money_vals [data.n_money_index_]) = char();
> +            
> +            RW_ASSERT (!nio.fail ());
> +            RW_ASSERT (!rw_strncmp(ncs, data.string_.ncs_));
> +
>          }
>  
>          // both specializations may be tested at the same time
> @@ -160,25 +218,32 @@
>  
>  #ifndef _RWSTD_NO_WCHAR_T
>  
> -            const std::money_put<wchar_t> &mp =
> +            const std::money_put<wchar_t> &wp =
>                  std::use_facet<std::money_put<wchar_t> >(loc);
>  
> -            const std::ostreambuf_iterator<wchar_t> iter (&wb);
> +            wio.imbue (loc);
>  
> -            switch (i % put_max) {
> -            case put_ldbl:
> -                mp.put (iter, intl, io, ' ', ldval);
> -                break;
> +            // verify the conversion from double
> +            wsb.pubsetp (wcs, countof (wcs));
> +            wio.rdbuf (&wsb);
>  
> -            case put_string: {
> -                const wchar_t* const strval =
> -                    wstr_vals [i % sizeof wstr_vals / sizeof *wstr_vals];
> +            *wp.put (std::ostreambuf_iterator<wchar_t>(&wsb),
> +                     data.intl_, wio, ' ', data.money_value_) = wchar_t();
> +            
> +            RW_ASSERT (!wio.fail ());
> +            RW_ASSERT (!rw_strncmp(wcs, data.numeric_.wcs_));
>  
> -                mp.put (iter, intl, io, ' ', strval);
> -                break;
> -            }
> -            }
> +            // verify the conversion from string
> +            wsb.pubsetp (wcs, countof (wcs));
> +            wio.rdbuf (&wsb);
>  
> +            *wp.put (std::ostreambuf_iterator<wchar_t>(&wsb),
> +                     data.intl_, wio, ' ',
> +                     w_money_vals [data.w_money_index_]) = wchar_t();
> +            
> +            RW_ASSERT (!wio.fail ());
> +            RW_ASSERT (!rw_strncmp(wcs, data.string_.wcs_));
> +
>  #endif   // _RWSTD_NO_WCHAR_T
>  
>          }
> @@ -194,19 +259,152 @@
>  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;
>  
> -    for (const char *name = locale_list; *name; name += std::strlen (name) +1) {
> -        locales [nlocales++] = name;
> +    const char* const possible_locale_options[] = {
> +        locale_list, "C\0", 0
> +    };
>  
> -        if (nlocales == maxinx)
> -            break;
> +    for (int p = 0; possible_locale_options[p]; ++p) {
> +
> +        for (const char* name = locale_list;
> +             *name;
> +             name += std::strlen (name) + 1) {
> +
> +            const std::size_t inx = nlocales;
> +            locales [inx] = name;
> +
> +            // fill in the money and results for this locale
> +            MyMoneyData& data = my_money_data [inx];
> +            data.locale_name_ = name;
> +
> +            try {
> +                const std::locale loc (data.locale_name_);
> +
> +                // initialize with random but valid values
> +
> +                data.money_value_ = inx;
> +                data.n_money_index_ = inx % countof (n_money_vals);
> +                data.w_money_index_ = inx % countof (w_money_vals);
> +
> +                // exercise domestic formats every other iteration
> +                // and international formats the rest
> +                data.intl_ = 0 == (inx & 1);
> +
> +                // exercise postive and negative values
> +                if (inx & 1)
> +                    data.money_value_ *= -1.;
> +
> +                // add some random fractional digits
> +                if (inx & 2)
> +                    data.money_value_ += data.money_value_ / 3.14;
> +
> +                const std::money_put<char> &np =
> +                    std::use_facet<std::money_put<char> >(loc);
> +
> +                nio.imbue (loc);
> +
> +                // write money from double
> +                nsb.pubsetp (data.numeric_.ncs_,
> +                             countof (data.numeric_.ncs_));
> +                nio.rdbuf (&nsb);
> +                
> +                *np.put (std::ostreambuf_iterator<char>(&nsb),
> +                         data.intl_, nio, ' ', data.money_value_) = char();
> +
> +                rw_assert (!nio.fail (), __FILE__, __LINE__,
> +                           "money_put<char>::put(..., %d, ..., %g) failed "
> +                           "for locale(%#s)",
> +                           data.intl_, data.money_value_, data.locale_name_);
> +                
> +                // write money from string
> +                nsb.pubsetp (data.string_.ncs_,
> +                             countof (data.string_.ncs_));
> +                nio.rdbuf (&nsb);
> +
> +                *np.put (std::ostreambuf_iterator<char>(&nsb),
> +                         data.intl_, nio, ' ',
> +                         n_money_vals [data.n_money_index_]) = char();
> +
> +                rw_assert (!nio.fail (), __FILE__, __LINE__,
> +                           "money_put<char>::put(..., %d, ..., '%s') "
> +                           "failed for locale(%#s)",
> +                           data.intl_, n_money_vals [data.n_money_index_],
> +                           data.locale_name_);
> +                
> +#ifndef _RWSTD_NO_WCHAR_T
> +
> +                const std::money_put<wchar_t> &wp =
> +                    std::use_facet<std::money_put<wchar_t> >(loc);
> +
> +                wio.imbue (loc);
> +
> +                // write money from double
> +                wsb.pubsetp (data.numeric_.wcs_,
> +                             countof (data.numeric_.wcs_));
> +                wio.rdbuf (&wsb);
> +
> +                *wp.put (std::ostreambuf_iterator<wchar_t>(&wsb),
> +                         data.intl_, wio, L' ', data.money_value_) = wchar_t();
> +
> +                rw_assert (!wio.fail (), __FILE__, __LINE__,
> +                           "money_put<wchar_t>::put(..., %d, ..., %g) "
> +                           "failed for locale(%#s)",
> +                           data.intl_, data.money_value_, data.locale_name_);
> +
> +                // write money from string
> +                wsb.pubsetp (data.string_.wcs_,
> +                             countof (data.string_.wcs_));
> +                wio.rdbuf (&wsb);
> +
> +                *wp.put (std::ostreambuf_iterator<wchar_t>(&wsb),
> +                         data.intl_, wio, L' ',
> +                         w_money_vals [data.w_money_index_]) = wchar_t();
> +
> +                rw_assert (!wio.fail (), __FILE__, __LINE__,
> +                           "money_put<wchar_t>::put(..., %d, ..., '%s') "
> +                           "failed for locale(%#s)",
> +                           data.intl_, w_money_vals [data.w_money_index_],
> +                           data.locale_name_);
> +
> +#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::money_put<charT> with %d thread%{?}s%{;}, "
>               "%zu iteration%{?}s%{;} each, in locales { %{ .*A@} }",
> @@ -220,7 +418,7 @@
>      test_wchar = false;
>  
>      // create and start a pool of threads and wait for them to finish
> -    int result =
> +    int result = 0;
>          rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
>  
>      rw_error (result == 0, 0, __LINE__,
> @@ -242,7 +440,7 @@
>                "rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
>                rw_opt_nthreads, thread_func);
>  
> -    // exercise bothe the char and the wchar_t specializations
> +    // exercise both the char and the wchar_t specializations
>      // at the same time
>  
>      rw_info (0, 0, 0,
> @@ -282,11 +480,15 @@
>      return rw_test (argc, argv, __FILE__,
>                      "lib.locale.money.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);
>  }


Mime
View raw message