Coverage Report

Created: 2024-09-23 09:09

src/zserio/CppRuntimeException.h
Line
Count
Source
1
#ifndef ZSERIO_CPP_RUNTIME_EXCEPTION_H_INC
2
#define ZSERIO_CPP_RUNTIME_EXCEPTION_H_INC
3
4
#include <array>
5
#include <exception>
6
#include <string>
7
#include <string_view>
8
#include <type_traits>
9
#include <vector>
10
11
#include "zserio/StringConvertUtil.h"
12
13
namespace zserio
14
{
15
16
/**
17
 * Exception thrown when an error within the Zserio C++ runtime library occurs.
18
 */
19
class CppRuntimeException : public std::exception
20
{
21
public:
22
    /**
23
     * Constructor.
24
     *
25
     * \param message Description of the error.
26
     */
27
    explicit CppRuntimeException(const char* message = "");
28
29
    /**
30
     * Method generated by default.
31
     * \{
32
     */
33
3.07k
    ~CppRuntimeException() override = default;
34
35
    CppRuntimeException(const CppRuntimeException& other) = default;
36
103
    CppRuntimeException& operator=(const CppRuntimeException& other) = default;
37
38
1.45k
    CppRuntimeException(CppRuntimeException&& other) = default;
39
2
    CppRuntimeException& operator=(CppRuntimeException&& other) = default;
40
    /**
41
     * \}
42
     */
43
44
    const char* what() const noexcept override;
45
46
    /**
47
     * Appends a message to the description.
48
     *
49
     * \param message Description of the error to append.
50
     */
51
    void append(const char* message);
52
53
    /**
54
     * Appends a message of a known length to the description.
55
     *
56
     * \param message Description of the error to append.
57
     * \param messageLen Length of the message.
58
     */
59
    void append(const char* message, size_t messageLen);
60
61
private:
62
    void appendImpl(std::string_view message);
63
64
    std::array<char, 512> m_buffer; // note fixed sized array is deeply copied on copy operations and it's OK
65
    size_t m_len = 0;
66
};
67
68
/**
69
 * Appends a message to the exception's description.
70
 *
71
 * \param exception Exception to modify.
72
 * \param message Description of the error to append.
73
 *
74
 * \return Reference to the exception to allow operator chaining.
75
 */
76
CppRuntimeException& operator<<(CppRuntimeException& exception, const char* message);
77
78
/**
79
 * Appends a bool value to the exception's description.
80
 *
81
 * \param exception Exception to modify.
82
 * \param value Bool value to append.
83
 *
84
 * \return Reference to the exception to allow operator chaining.
85
 */
86
CppRuntimeException& operator<<(CppRuntimeException& exception, bool value);
87
88
/**
89
 * Appends a float value to the exception's description.
90
 *
91
 * \param exception Exception to modify.
92
 * \param value Float value to append.
93
 *
94
 * \return Reference to the exception to allow operator chaining.
95
 */
96
CppRuntimeException& operator<<(CppRuntimeException& exception, float value);
97
98
/**
99
 * Appends a double value to the exception's description.
100
 *
101
 * \param exception Exception to modify.
102
 * \param value Double value to append.
103
 *
104
 * \return Reference to the exception to allow operator chaining.
105
 */
106
CppRuntimeException& operator<<(CppRuntimeException& exception, double value);
107
108
/**
109
 * Appends a string_view to the exception's description.
110
 *
111
 * \param exception Exception to modify.
112
 * \param value String view to append.
113
 *
114
 * \return Reference to the exception to allow operator chaining.
115
 */
116
CppRuntimeException& operator<<(CppRuntimeException& exception, std::string_view value);
117
118
/**
119
 * Appends an integral value to the exception's description.
120
 *
121
 * \param exception Exception to modify.
122
 * \param value Integral value to append.
123
 *
124
 * \return Reference to the exception to allow operator chaining.
125
 */
126
template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
127
CppRuntimeException& operator<<(CppRuntimeException& exception, T value)
128
3.57k
{
129
3.57k
    std::array<char, 24> buffer = {};
130
3.57k
    const char* stringValue = convertIntToString(buffer, value);
131
3.57k
    return exception << stringValue;
132
3.57k
}
133
134
/**
135
 * Appends a string value to the exception's description.
136
 *
137
 * \param exception Exception to modify.
138
 * \param value String value to append.
139
 *
140
 * \return Reference to the exception to allow operator chaining.
141
 */
142
template <typename ALLOC>
143
CppRuntimeException& operator<<(
144
        CppRuntimeException& exception, const std::basic_string<char, std::char_traits<char>, ALLOC>& value)
145
3
{
146
3
    exception.append(value.c_str(), value.size());
147
3
    return exception;
148
3
}
149
150
/**
151
 * Appends a vector value to the exception's description.
152
 *
153
 * \param exception Exception to modify.
154
 * \param value Vector value to append.
155
 *
156
 * \return Reference to the exception to allow operator chaining.
157
 */
158
template <typename T, typename ALLOC>
159
CppRuntimeException& operator<<(CppRuntimeException& exception, const std::vector<T, ALLOC>& value)
160
1
{
161
1
    return exception << "vector([...], " << value.size() << ")";
162
1
}
163
164
namespace detail
165
{
166
167
// inspired by C++ ostreams - see https://cplusplus.github.io/LWG/issue1203
168
// note that e.g. in gcc implementation of ostreams there are two constraints, but the second one:
169
//      typename = decltype(std::declval<EXCEPTION&>() << std::declval<const VALUE&>())
170
// is probably unnecessary and since it caused a compilation error in MSVC 2017 Conformance Mode,
171
// we intentionally skipped it (even though it was probably a compiler bug)
172
template <typename EXCEPTION, typename VALUE,
173
        typename = typename std::enable_if<std::is_base_of<CppRuntimeException, EXCEPTION>::value, int>::type>
174
using CppRuntimeExceptionRValueInsertion = EXCEPTION&&;
175
176
} // namespace detail
177
178
/**
179
 * Appends any value for which operator<< is implemented to the exception's description.
180
 *
181
 * Overload for rvalue to enable operator<< on a temporary object, .e.g. CppRuntimeException() << "value".
182
 * Moreover note that this overload preserves the concrete type of the exception!
183
 *
184
 * \param exception Exception to modify.
185
 * \param value Value to append.
186
 *
187
 * \return R-value reference to the original exception to allow operator chaining.
188
 */
189
template <typename CPP_RUNTIME_EXCEPTION, typename T>
190
detail::CppRuntimeExceptionRValueInsertion<CPP_RUNTIME_EXCEPTION, T> operator<<(
191
        CPP_RUNTIME_EXCEPTION&& exception, const T& value)
192
7.17k
{
193
7.17k
    exception << value;
194
7.17k
    return std::forward<CPP_RUNTIME_EXCEPTION>(exception);
195
7.17k
}
196
197
} // namespace zserio
198
199
#endif // ifndef ZSERIO_CPP_RUNTIME_EXCEPTION_H_INC