Boost logo

Boost :

Subject: Re: [boost] [safe_numerics] One more review
From: Antony Polukhin (antoshkka_at_[hidden])
Date: 2017-03-11 19:24:54


2017-03-11 21:08 GMT+03:00 Robert Ramey via Boost <boost_at_[hidden]>:
> On 3/11/17 9:41 AM, Antony Polukhin via Boost wrote:
>>
>> 2017-03-11 20:22 GMT+03:00 Robert Ramey via Boost <boost_at_[hidden]>:
>>>
>>> On 3/11/17 7:52 AM, Steven Watanabe via Boost wrote:
>>>>
>>>>
>
>>>
>>> A simple extension to log such errors could be crafted from this idea and
>>> would make a great example on how to make one's own exception policy.
>>>
>>> What is missing from this idea?
>>
>>
>> State of the Policy is missing. In many cases it could be useful to
>> have a Policy with state to be able to get the UB info. This may be
>> useful for different try_* functions that must not throw, usually are
>> in hot path and rarely trigger UB:
>>
>> bool try_do(int x_native) noexcept {
>> bool was_an_error = false;
>> safe<int, native, lazy> x(x_native, &was_an_error);
>> // remembers that error was triggered in the `was_an_error` variable
>> ++x;
>> // ... other operations on `x`
>> // ...
>>
>> // `x` is bad, after comparison `y` is also bad
>> safe<int, native, lazy> y = x; // also copies pointer to
>> `was_an_error`
>> if (x < y) {
>> // ... other operations on `y`
>> }
>>
>> return was_an_error;
>> }
>
>
>
> template<class call_back>
> struct exception_logger {
> // implements ExceptionPolicy concept
> ...
> };
>
> what's the matter with the following?
>
> void handler(?){
> ... // log the error
> }
>
> bool try_do(int x_native) no_except {
> bool was_an_error = false
> safe<int, native, exception_logger> x{x_native};
> // handler logs error
> ++x;
> // other operations on x
> ...
> }
>
>>
>> Throwing and catching an exception in such function may affect
>> performance. Rewriting the whole function using functions from
>> include/checked.hpp may take a lot of effort and will make the
>> function harder to read.
>>
>> But this is more like a feature request, not a blocker to the library
>> acceptance. looks like they could be added later.
>
>
> Right - we're in serious jeopardy of scope creep. Consumer of all ambitious
> projects.
>
> Still, it's becoming clear that some enhancement of the ExceptionPolicy
> concept might create opportunities with little or no cost in conceptual
> integrity. We're open to modest specific suggestions.

Changes to deal with statefull policies are pretty small and could be
added any time later:

template<
    class Stored,
    Stored Min,
    Stored Max,
    class P, // promotion polic
    class E // exception policy
>
class safe_base
    : private P, private E /* empty base optimization will make sure
that safe_base size does not change for empty/stateless P and E */
{
    BOOST_CONCEPT_ASSERT((Integer<Stored>));
    BOOST_CONCEPT_ASSERT((PromotionPolicy<P>));
    BOOST_CONCEPT_ASSERT((ExceptionPolicy<E>));
    Stored m_t;

    // ...

    template<class T>
    constexpr /*explicit*/ safe_base(const T & t, P p = {}, E e = {});
/* added P and E as a parameters */

    // Added followin 4 functions:
    const E& exception_policy() const noexcept { return *this; }
    E& exception_policy() noexcept { return *this; }
    const P& promotion_policy() const noexcept { return *this; }
    P& promotion_policy() noexcept { return *this; }

    // looks like no other changes required
};

////////

Now the example becomes the following:

struct lazy {
    bool* was_an_error;

    void no_error(const char *) const noexcept { *was_an_error = true; }
    void uninitialized_error(const char *) const noexcept {
*was_an_error = true; }
    void overflow_error(const char *) const noexcept { *was_an_error = true; }
    void underflow_error(const char *) const noexcept { *was_an_error = true; }
    void range_error(const char *) const noexcept { *was_an_error = true; }
    void domain_error(const char *) const noexcept { *was_an_error = true; }

    bool is_error() const noexcept { return *was_an_error; }
};

bool try_do(int x_native) noexcept {
    bool was_an_error = false;
    safe<int, native, lazy> x(x_native, {}, lazy{&was_an_error});
    // remembers that error was triggered in the `was_an_error` variable
    ++x;
    // ... other operations on `x`
    // ...

    // `x` is bad, after comparison `y` is also bad
    safe<int, native, lazy> y = x; // also copies pointer to `was_an_error`
    if (x < y) {
        // ... other operations on `y`
        //
        // Also works well:
        return y.exception_policy().is_error();
    }

    return was_an_error;
}

-- 
Best regards,
Antony Polukhin

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk