liuxiaolong
2021-07-20 58d904a328c0d849769b483e901a0be9426b8209
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#ifndef BOOST_NUMERIC_CHECKED_RESULT
#define BOOST_NUMERIC_CHECKED_RESULT
 
//  Copyright (c) 2012 Robert Ramey
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
 
// contains operations for doing checked aritmetic on NATIVE
// C++ types.
#include <cassert>
#include <type_traits> // is_convertible
#include "exception.hpp"
 
namespace boost {
namespace safe_numerics {
 
template<typename R>
struct checked_result {
    const safe_numerics_error m_e;
    const union {
        R m_r;
        char const * m_msg;
    };
    
    // don't permit construction without initial value;
    checked_result() = delete;
 
    // note: I implemented the following non-default copy and move
    // constructors because I thought I needed to do this in order
    // to make them constexpr.  Turns out though that doing this creates
    // a syntax error because the assignment results in error due
    // to assignment "outside of object lifetime".  I think this could
    // be addressed by replacing the anonymous union above with a
    // named union.  This would create some syntax changes which would
    // ripple through some parts of th program.  So for now, we'll just
    // rely on the default copy and move constructors.
    #if 0
    // copy constructor
    constexpr /*explicit*/ checked_result(const checked_result & r) noexpect :
        m_e(r.m_e)
    {
        if(safe_numerics_error::success == r.m_e)
            m_r = r.m_r;
        else
            m_msg = r.m_msg;
    }
 
    // move constructor
    constexpr /*explicit*/ checked_result(checked_result && r) noexcept :
        m_e(r.m_e)
    {
        if(safe_numerics_error::success == r.m_e)
            m_r = r.m_r;
        else
            m_msg = r.m_msg;
    }
    #endif
 
    checked_result(const checked_result & r) = default;
    checked_result(checked_result && r) = default;
    
    constexpr /*explicit*/ checked_result(const R & r) noexcept :
        m_e(safe_numerics_error::success),
        m_r(r)
    {}
 
    constexpr /*explicit*/ checked_result(
        const safe_numerics_error & e,
        const char * msg = ""
    )  noexcept :
        m_e(e),
        m_msg(msg)
    {
        assert(m_e != safe_numerics_error::success);
    }
 
    // permit construct from another checked result type
    template<typename T>
    constexpr /*explicit*/ checked_result(const checked_result<T> & t) noexcept :
        m_e(t.m_e)
    {
        static_assert(
            std::is_convertible<T, R>::value,
            "T must be convertible to R"
        );
        if(safe_numerics_error::success == t.m_e)
            m_r = t.m_r;
        else
            m_msg = t.m_msg;
    }
 
    constexpr bool exception() const {
        return m_e != safe_numerics_error::success;
    }
 
    // accesors
    constexpr operator R() const  noexcept{
        // don't assert here.  Let the library catch these errors
        // assert(! exception());
        return m_r;
    }
    
    constexpr operator safe_numerics_error () const  noexcept{
        // note that this is a legitimate operation even when
        // the operation was successful - it will return success
        return m_e;
    }
    constexpr operator const char *() const  noexcept{
        assert(exception());
        return m_msg;
    }
 
    // disallow assignment
    checked_result & operator=(const checked_result &) = delete;
};
 
template <class R>
class make_checked_result {
public:
    template<safe_numerics_error E>
    constexpr static checked_result<R> invoke(
        char const * const & m
    ) noexcept {
        return checked_result<R>(E, m);
    }
};
 
} // safe_numerics
} // boost
 
#endif  // BOOST_NUMERIC_CHECKED_RESULT