Coverage Report

Created: 2025-07-23 13:44

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