ADTF
Loading...
Searching...
No Matches
result_description_impl.h
Go to the documentation of this file.
1
15
16#ifndef A_UTIL_UTIL_RESULT_DETAIL_DESCRIPTION_IMPL_HEADER_INCLUDED
17#define A_UTIL_UTIL_RESULT_DETAIL_DESCRIPTION_IMPL_HEADER_INCLUDED
18
20
21// This comment keeps result_description_decl.h on top while clang-formatting
24
25#include <cassert>
26#include <new>
27
28namespace a_util {
29namespace result {
30namespace detail {
31template <typename DescriptionIntf>
33 const std::uint64_t value)
34{
35 // detailed result was allocated...
36 return (!isErrorCodeSet(value)) && // if the error code bit is not set, ...
37 0 != (value & error_code_bitmask); //... but other bits
38}
39
40template <typename DescriptionIntf>
42{
43 // the error code bit indicates whether only the error code is set
44 return error_code_bit == (value & error_code_bit);
45}
46
47template <typename DescriptionIntf>
49 const std::int32_t error_code) noexcept
50{
51 // highly optimized code to bypass the cast on negative error codes...
52 return (
53 // fit the error code to the first 32 bits
54 (static_cast<std::uint64_t>(error_code) & error_code_serialize_bitmask) |
55 // set the error code bit to the most significant bit
57}
58
59template <typename DescriptionIntf>
61 const std::uint64_t error_code) noexcept
62{
63 return static_cast<std::int32_t>(
64 // get rid of the error code bit
66 // convert error code to its original value
67 (error_code | error_code_deserialize_bitmask));
68}
69
70template <typename DescriptionIntf>
72 DescriptionIntf>::toInternalErrorPointer(const std::uint64_t error_code) noexcept
73{
74 return reinterpret_cast<const ReferenceCountedDescriptionType*>(error_code);
75}
76
77template <typename DescriptionIntf>
78inline ResultDescriptionTraits<DescriptionIntf>::~ResultDescriptionTraits()
79{
80 // check whether the internal representation remains binary compatible
81 // the calculation might be changed
82 using namespace std;
83 constexpr auto minus_one_representation = toInternalErrorCode(-1);
84 constexpr auto plus_one_representation = toInternalErrorCode(1);
85
86#if defined(__GNUC__) && ((__GNUC__ == 5) && (__GNUC_MINOR__ == 2))
87#pragma GCC diagnostic push
88#pragma GCC diagnostic ignored "-Wattributes"
89#endif // defined(__GNUC__) && ((__GNUC__ == 5) && (__GNUC_MINOR__ == 2))
90 constexpr auto min_val_representation =
91 toInternalErrorCode((numeric_limits<std::int32_t>::min)());
92 constexpr auto max_val_representation =
93 toInternalErrorCode((numeric_limits<std::int32_t>::max)());
94#if defined(__GNUC__) && ((__GNUC__ == 5) && (__GNUC_MINOR__ == 2))
95#pragma GCC diagnostic pop
96#endif // defined(__GNUC__) && ((__GNUC__ == 5) && (__GNUC_MINOR__ == 2))
97
98 // but these checks must not be changed!
99 // this is the original error code specification
100 // these checks exist to make sure refactoring the code does not change the original behavior
101 static_assert(0x8000000000000000 == error_code_bit, "error_code_bit must not be changed!");
102 static_assert(~0x8000000000000000 == error_code_bitmask,
103 "error_code_bitmask must not be changed!");
104 static_assert(0xFFFFFFFF00000000 == error_code_deserialize_bitmask,
105 "error_code_deserialize_bitmask must not be changed!");
106 static_assert(0xFFFFFFFF == error_code_serialize_bitmask,
107 "error_code_serialize_bitmask must not be changed!");
108 static_assert(0x80000000ffffffff == minus_one_representation,
109 "Calculation of internal error code representation must not be changed!");
110 static_assert(0x8000000000000001 == plus_one_representation,
111 "Calculation of internal error code representation must not be changed!");
112 static_assert(0x8000000080000000 == min_val_representation,
113 "Calculation of internal error code representation must not be changed!");
114 static_assert(0x800000007fffffff == max_val_representation,
115 "Calculation of internal error code representation must not be changed!");
116}
117
118template <typename DescriptionIntf>
119inline ResultDescription<DescriptionIntf>::ResultDescription() : _pointer_to_result_or_error_code{}
120{
121}
122
123template <typename DescriptionIntf>
125 : _pointer_to_result_or_error_code{}
126{
127 *this = other;
128}
129
130template <typename DescriptionIntf>
132 const ResultDescription& other)
133{
134 if (&other != this) {
135 if (TraitsType::isDetailedDescriptionSet(_pointer_to_result_or_error_code)) {
136 TraitsType::toInternalErrorPointer(_pointer_to_result_or_error_code)->removeReference();
137 }
138
139 _pointer_to_result_or_error_code = other._pointer_to_result_or_error_code;
140 if (TraitsType::isDetailedDescriptionSet(_pointer_to_result_or_error_code)) {
141 TraitsType::toInternalErrorPointer(_pointer_to_result_or_error_code)->addReference();
143 }
144 return *this;
146
147template <typename DescriptionIntf>
149 : _pointer_to_result_or_error_code{}
150{
151 std::swap(other._pointer_to_result_or_error_code, _pointer_to_result_or_error_code);
152}
153
154template <typename DescriptionIntf>
156 ResultDescription&& other)
157{
158 if (&other != this) {
159 if (TraitsType::isDetailedDescriptionSet(_pointer_to_result_or_error_code)) {
160 TraitsType::toInternalErrorPointer(_pointer_to_result_or_error_code)->removeReference();
161 }
162
163 _pointer_to_result_or_error_code = {};
164 std::swap(other._pointer_to_result_or_error_code, _pointer_to_result_or_error_code);
165 }
166 return *this;
167}
169template <typename DescriptionIntf>
171{
172 if (TraitsType::isDetailedDescriptionSet(_pointer_to_result_or_error_code)) {
173 TraitsType::toInternalErrorPointer(_pointer_to_result_or_error_code)->removeReference();
174 }
175 // DTOR is always compiled, so put the test here
176 static_assert(sizeof(std::uintptr_t) <= 8,
177 "ResultDescription pointers must always have a size of 8 Byte or less!");
178}
180template <typename DescriptionIntf> // class template parameter
181template <typename DescriptionImpl, typename... Args> // method template parameters
183ResultDescription<DescriptionIntf>::makeResultDescription(std::int32_t error_code, Args&&... args)
184{
185 // do not use std::nothrow overload, corresponding 'new'-operator can only be overloaded global
186 try {
188 // first parameter of the detailed description must be of type error code
189 const auto reference_counted_error_object =
190 new ReferenceCountedErrorType(error_code, std::forward<Args>(args)...);
191 SelfType result_description(*reference_counted_error_object);
192 if (TraitsType::isErrorCodeSet(result_description._pointer_to_result_or_error_code)) {
193 // not allowed, only create the error code (no assert in production code, only in debug)
194 reference_counted_error_object->removeReference();
195 assert((false) && "The MSB of the pointer to the heap allocated memory is set to 1, "
196 "but it is reserved for the error code bit. This is inplausible and "
197 "must not happen.");
198 }
199 else {
200 return result_description;
201 }
202 }
203 catch (const std::bad_alloc&) {
204 // operator new() failed to alloc
205 }
206
207 return SelfType::makeResultDescription(error_code);
208}
209
210template <typename DescriptionIntf>
211template <typename T>
212typename ResultDescription<DescriptionIntf>::SelfType ResultDescription<
213 DescriptionIntf>::makeResultDescription(const ::a_util::result::ResultInfo<T>&) noexcept
214{
216 SelfType result_description(uncounted_error);
217
218 // The address of the pointer must not occupy the MSB of the internal error, because the
219 // MSB is used to set the error code bit. In reality this should never happen.
220 if (!TraitsType::isErrorCodeSet(result_description._pointer_to_result_or_error_code)) {
221 return result_description;
222 }
223
225}
226
227template <typename DescriptionIntf>
229 std::int32_t error_code)
230{
231 // use the entire pointer for the error code and set the error code bit appropriately
232 // the user doesn't want to allocate space by calling this function, so just DON'T!
233 return SelfType(error_code);
234}
235
236template <typename DescriptionIntf>
238{
239 // make sure, detailed description instead of error code is set
240 if (TraitsType::isDetailedDescriptionSet(_pointer_to_result_or_error_code)) {
241 return &TraitsType::toInternalErrorPointer(_pointer_to_result_or_error_code)->getObject();
242 }
243 return nullptr;
244}
245
246template <typename DescriptionIntf>
248{
249 // only return the error code if only the error code was set!
250 if (TraitsType::isErrorCodeSet(_pointer_to_result_or_error_code)) {
251 return TraitsType::toExternalErrorCode(_pointer_to_result_or_error_code);
252 }
253 return 0;
254}
255
256template <typename DescriptionIntf>
258 std::int32_t error_code) noexcept
259 : _pointer_to_result_or_error_code(TraitsType::toInternalErrorCode(error_code))
260{
261}
262
263template <typename DescriptionIntf>
265 const ReferenceCountedObjectInterface<DescriptionIntf>& error_object) noexcept
266 : _pointer_to_result_or_error_code(reinterpret_cast<std::uintptr_t>(&error_object))
267{
268 static_assert(sizeof(std::uintptr_t) == sizeof(decltype(&error_object)),
269 "ResultDescription pointers must match the size of std::uintptr_t!");
270 assert((!TraitsType::isErrorCodeSet(_pointer_to_result_or_error_code)) &&
271 "The cast of the pointer to the internal error code set the MSB to 1, but it is "
272 "reserved for the error code bit. This is inplausible and must not happen.");
273 error_object.addReference();
274}
275
276template <typename T>
277inline bool operator==(const ResultDescription<T>& lhs, const ResultDescription<T>& rhs)
278{
279 // we put the tests inside this function so it will be available for all specializations
280 static_assert(sizeof(ResultDescription<T>) == 8, "Description type unsupported size!");
281
282 return lhs.getErrorCode() == rhs.getErrorCode() &&
284}
285
286template <typename T>
287inline bool operator!=(const ResultDescription<T>& lhs, const ResultDescription<T>& rhs)
288{
289 return !(lhs == rhs);
290}
291
292} // namespace detail
293} // namespace result
294} // namespace a_util
295
296#endif // A_UTIL_UTIL_RESULT_DETAIL_DESCRIPTION_IMPL_HEADER_INCLUDED
Definition reference_counted_object_intf.h:29
Default implementation of a reference counter.
Definition reference_counted_object.h:33
Wrapper for either a pointer to a detailed description object or simply a numeric error code.
Definition result_description_decl.h:111
std::int32_t getErrorCode() const
Definition result_description_impl.h:247
ResultDescription & operator=(const ResultDescription &other)
Definition result_description_impl.h:131
static SelfType makeResultDescription(std::int32_t error_code, Args &&... args)
Definition result_description_impl.h:183
ResultDescription()
CTOR.
Definition result_description_impl.h:119
~ResultDescription()
DTOR.
Definition result_description_impl.h:170
DescriptionIntf const * getDetailedDescription() const
Definition result_description_impl.h:237
ResultDescription< DescriptionIntf > SelfType
Self type.
Definition result_description_decl.h:115
Default implementation of a non-counting reference counter.
Definition reference_counted_object.h:104
Serves as namespace for result implementation details.
Definition result.h:22
bool operator==(const ResultDescription< T > &lhs, const ResultDescription< T > &rhs)
Definition result_description_impl.h:277
bool operator!=(const ResultDescription< T > &lhs, const ResultDescription< T > &rhs)
Definition result_description_impl.h:287
Serves as component for functionality handling error and return types.
Definition result.h:20
Serves as the root component, with common functionality documented in core functionality.
Definition base.h:24
static std::int32_t getCode()
Definition result_info_impl.h:42
Definition result_description_decl.h:32
static bool isDetailedDescriptionSet(std::uint64_t value)
Definition result_description_impl.h:32
static const std::uint64_t error_code_bit
The error code bit indicating whether only the error code (1) was set or not (0)
Definition result_description_decl.h:36
static constexpr std::uint64_t toInternalErrorCode(std::int32_t error_code) noexcept
Definition result_description_impl.h:48
static const std::uint64_t error_code_bitmask
The error code bitmask to mask out the error code bit.
Definition result_description_decl.h:38
static constexpr const ReferenceCountedDescriptionType * toInternalErrorPointer(std::uint64_t error_code) noexcept
Definition result_description_impl.h:72
ReferenceCountedObjectInterface< DescriptionIntf > ReferenceCountedDescriptionType
Reference counted error description type.
Definition result_description_decl.h:34
static constexpr std::int32_t toExternalErrorCode(std::uint64_t error_code) noexcept
Definition result_description_impl.h:60
static const std::uint64_t error_code_serialize_bitmask
The bitmask to serialize the error code to its internal representation.
Definition result_description_decl.h:40
static const std::uint64_t error_code_deserialize_bitmask
The bitmask to deserialize the internal error representation to its original value.
Definition result_description_decl.h:42
static bool isErrorCodeSet(std::uint64_t value)
Definition result_description_impl.h:41