lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lmi] Stream cast problems with trailing spaces and more


From: Greg Chicares
Subject: Re: [lmi] Stream cast problems with trailing spaces and more
Date: Wed, 29 Jan 2020 16:45:29 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.3.0

On 2020-01-29 15:08, Vadim Zeitlin wrote:
> On Wed, 29 Jan 2020 14:29:38 +0000 Greg Chicares <address@hidden> wrote:
> 
> GC> >  BTW, now that we use C++17, I'd seriously consider defining a couple of
> GC> > custom literal operators for calendar_date, that would allow us to write
> GC> > 2440588_jdn or even 19700101_ymd instead of 
> calendar_date(jdn_t(2440588)).
> GC> 
> GC> I think user-defined literals are like specialized kitchen gadgets--e.g.,
> GC> cherry-pitters or strawberry-hullers. If you need to remove the pits from
> GC> ten kilograms of cherries, a specialized tool might be a good investment.
> GC> But for ten grams of cherries, the benefit isn't enough to justify the
> GC> cost of learning to use it. I think our time is better spent elsewhere
> GC> in this case.
> 
>  I just think using 19700101_ymd is much more clear than using "2440588",
> so it's not so much about saving time as about making the code easier to
> read. I wouldn't mind using
> 
>       ,LastBillDate(1970, 1, 1)
> 
> neither.

Clearer, yes, of course; but unfortunately that's a syntax error,
because the datum is of type tnr_date, not calendar_date.

We already have
    enum
        {gregorian_epoch_jdn = 2361222
        ,last_yyyy_date_jdn  = 5373484
etc., and we could add
        ,unix_epoch          = 2440588
but that value is used nowhere else, so such a change doesn't clearly
reduce total complexity.

Given that "2440588" is a hapax legomenon, this:
      ,ListBillDate                   {"2440588"} // Assume no inforce <19700101
seems good enough--making it prettier doesn't seem worth the trouble.

> GC> > GC> Please take a look at how I changed that (once I push the commit).
> GC> > 
> GC> >  I'll have a look at the commit once it's done and will test it with 
> clang
> GC> > and MSVC.
> GC> 
> GC> Thanks--I'm not using those tools, so I might have again make a mistake
> GC> that's not readily visible with gcc.
> 
>  I didn't have time to really look into this yet, but the new test fails
> with clang:
> 
> ???? test failed: Caught exception
>     'converting 'INF' from type 'char const*' to type 'double'.'
>   when
>     '^Output failed'
>   was expected.
> [file stream_cast_test.cpp, line 85]

That's interesting. The exception is supposed to be a particular string like
  "Input failed "
or
  "Output failed "
prepended to a generic string like
  "converting $(VARIABLE) from type $(TYPE0) to type $(TYPE1)."
Here, somehow none of the particular initial strings was written.
I'm almost tempted to consider making a change like this:

         err << "Unconverted data remains ";
         }
     else
         {
-        ; // Nothing left to do.
+        err << "Unexpected failure ";
         }

but that provides only symptomatic relief and we really want to fix the
root cause.

>   Speed tests...
>   stream_cast:
> 
> ???? uncaught exception: std::runtime_error: converting '2.71828' from type 
> 'double' to type 'std::__1::basic_string<char, std::__1::char_traits<char>, 
> std::__1::allocator<char> >'.

That would arise here:

    static double const e {2.718281828459045};
    auto f0 = [] {for(int n = 0; n < 1000; ++n) stream_cast<std::string>(e);};
    auto f1 = [] {for(int n = 0; n < 1000; ++n) streamlined<std::string>(e);};
    std::cout
        << "\n  Speed tests..."
        << "\n  stream_cast: " << TimeAnAliquot(f0)
        << "\n  streamlined: " << TimeAnAliquot(f1)
        << std::endl
        ;

Is it the case that f0 and f1 both fail? I'm thinking that f1 should succeed
because it's the venerable ancient idiom, and f0 should succeed because I've
now made it behave the same way as f1, but clearly I'm mistaken somewhere.

>  The cause of the first problem seems relatively clear, but I'm not sure if
> it's a libc++ defect or not.

It's not at all clear to me. What do you see that I don't?

>  I don't understand at all why does the second problem happens in
> assay_speed() however. And this one also happens with MSVC (with almost
> exactly the same, except for the different full name of std::string, error
> message). I'll look into it later, but I just already wanted to let you
> know about these problems in case you immediately see something I don't.

The symptoms seem the same, so I think there's something wrong with my
latest changes. Both INF and Euler's number seem to cause failure; e
should work if the code is right, and as for INF, I did (quickly) read
something in the Standard that led me to believe that an infinity would
induce "Output failed" here:

    else if(!(interpreter >> result))
        {
        err << "Output failed ";
        }

because...well, I can't find the reason now, upon rereading the Standard.

Anyway, let me say what I was trying to accomplish.
    if(!(interpreter << from))
and
    else if(!(interpreter >> result))
seem like independent failure conditions that ought to be reported
specifically, so I tried to write unit-test code that would induce failure
in each one. In each case, I implemented the first idea I had that seemed
to work.

If you see better ways to induce these specific failures, please let me
know. OTOH, if there's no simple, portable way to elicit these specific
diagnostic exceptions, then maybe that means it's a mistake to strive for
such specificity...in which case the simple classic

    if
        (  !(interpreter << from)
        || !(interpreter >> result)
        || !(interpreter >> std::ws).eof()
        )
        {
        throw ...

is only damaged by my attempts to improve it.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]