GCC Code Coverage Report


Directory: src/gate/
File: src/gate/exceptions.hpp
Date: 2026-05-04 21:11:01
Exec Total Coverage
Lines: 74 95 77.9%
Functions: 87 106 82.1%
Branches: 13 36 36.1%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright (c) 2018-2026, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 /** @file
30 * @brief C++ exception base classes and utilities
31 * @ingroup gatecore_cpp
32 */
33
34 #ifndef GATE_EXECEPTIONS_HPP_INCLUDED
35 #define GATE_EXECEPTIONS_HPP_INCLUDED
36
37 #include "gate/gate_core_api.hpp"
38 #include "gate/gatetypes.hpp"
39 #include "gate/results.hpp"
40 #include "gate/memalloc.hpp"
41
42 namespace gate
43 {
44
45 /// @brief
46 class GATE_CORE_CPP_API Throwable
47 {
48 public:
49 virtual ~Throwable() noexcept;
50
51 virtual result_t getResult() const noexcept = 0;
52 virtual char const* getMessage() const noexcept = 0;
53 virtual char const* getSource() const noexcept = 0;
54 virtual int32_t getErrorCode() const noexcept = 0;
55
56 };
57
58
59
60 /// @brief
61 class GATE_CORE_CPP_API Error : public Throwable
62 {
63 public:
64 explicit Error(result_t result, char const* source = 0, int32_t errCode = 0) noexcept;
65 virtual ~Error() noexcept;
66
67 virtual result_t getResult() const noexcept;
68 virtual char const* getMessage() const noexcept;
69 virtual char const* getSource() const noexcept;
70 virtual int32_t getErrorCode() const noexcept;
71
72 private:
73 gate_error_info_t info;
74 };
75
76
77 /// @brief
78 class GATE_CORE_CPP_API Exception : public Throwable
79 {
80 public:
81 explicit Exception(result_t result, char const* msg = 0, char const* src = 0, int32_t errCode = 0) noexcept;
82 explicit Exception(exception_info_t const& xinfo);
83 virtual ~Exception() noexcept;
84
85 virtual result_t getResult() const noexcept;
86 virtual char const* getMessage() const noexcept;
87 virtual char const* getSource() const noexcept;
88 virtual int32_t getErrorCode() const noexcept;
89
90 private:
91 exception_info_t info;
92 };
93
94
95 /// @brief
96 class GATE_CORE_CPP_API ExceptionInfo : public exception_info_t
97 {
98 public:
99 ExceptionInfo();
100 ExceptionInfo(result_t result, int32_t errorCode, char const* source, char const* message);
101 ExceptionInfo(exception_info_t const& src);
102
103 bool_t failed() const noexcept;
104 bool_t succeeded() const noexcept;
105 void raise() const;
106 };
107
108
109 /// @brief
110 /// @param errObj
111 /// @return
112 GATEXX_ATTR_NORETURN GATE_CORE_CPP_API extern void raise(Error errObj);
113
114
115 /// @brief
116 /// @param resultCode
117 /// @param src
118 /// @param errCode
119 /// @return
120 GATEXX_ATTR_NORETURN GATE_CORE_CPP_API extern void raiseError(result_t resultCode, char const* src = 0, int32_t errCode = 0);
121
122 #define GATEXX_CHECK_ERROR(resultCode) do { if(GATE_FAILED(resultCode)) ::gate::raiseError(resultCode, GATE_CURRENT_FUNCTION_NAME, 0); } while(0)
123 #define GATEXX_RAISE_ERROR(resultCode) ::gate::raiseError(resultCode, GATE_CURRENT_FUNCTION_NAME, 0)
124
125
126 /// @brief
127 /// @param xcptObj
128 /// @return
129 GATEXX_ATTR_NORETURN GATE_CORE_CPP_API extern void raise(Exception xcptObj);
130
131
132 /// @brief
133 /// @param resultCode
134 /// @param msg
135 /// @param src
136 /// @param errCode
137 /// @return
138 GATEXX_ATTR_NORETURN GATE_CORE_CPP_API extern void raiseException(result_t resultCode, char const* msg = 0, char const* src = 0, int32_t errCode = 0);
139
140 #define GATEXX_CHECK_EXCEPTION(resultCode) do { if(GATE_FAILED(resultCode)) ::gate::raiseException(resultCode, 0, GATE_CURRENT_FUNCTION_NAME, 0); } while(0)
141 #define GATEXX_RAISE_EXCEPTION(resultCode, message, nativeErrorCode) ::gate::raiseException(resultCode, message, GATE_CURRENT_FUNCTION_NAME, nativeErrorCode)
142
143 #define GATEXX_RETHROW throw
144
145
146 /// @brief
147 /// @tparam T
148 template<class T>
149 class ErrorPublisher
150 {
151 public:
152 static void publish(T const& errObj, char const* source);
153 };
154
155 template<>
156 class ErrorPublisher<result_t>
157 {
158 public:
159 static void publish(result_t const& errType, char const* source)
160 {
161 raise(Error(errType, source));
162 }
163 };
164
165
166 /// @brief
167 /// @tparam T
168 template<class T>
169 class ExceptionPublisher
170 {
171 public:
172 static void publish(T const& errObj, char const* source);
173 };
174
175 template<>
176 class ExceptionPublisher<result_t>
177 {
178 public:
179 static void publish(result_t const& xcptType, char const* source)
180 {
181 raise(Exception(xcptType, 0, source));
182 }
183 };
184
185
186
187 /// @brief
188 /// @tparam T
189 /// @tparam ID
190 template<class T, class ID>
191 class ResultValue
192 {
193 public:
194 typedef ResultValue<T, ID> self_t;
195 typedef T item_t;
196 private:
197 item_t item;
198 public:
199
200 21 ResultValue(item_t const& src)
201 21 : item(src)
202 {
203 21 }
204 ResultValue(self_t const& src)
205 : item(src.item)
206 {
207 }
208 self_t& operator=(self_t const& src)
209 {
210 this->item = src.item;
211 return *this;
212 }
213 28 ~ResultValue()
214 {
215 28 }
216 item_t& get() noexcept
217 {
218 return this->item;
219 }
220 28 item_t const& get() const noexcept
221 {
222 28 return this->item;
223 }
224 };
225
226 struct ResultSuccessId {};
227 struct ResultErrorId {};
228
229
230 /// @brief
231 /// @tparam TRESULTTYPE
232 /// @param resultType
233 /// @return
234 template<class TRESULTTYPE>
235 19 ResultValue<TRESULTTYPE, ResultSuccessId> makeOk(TRESULTTYPE const& resultType)
236 {
237 19 return ResultValue<TRESULTTYPE, ResultSuccessId>(resultType);
238 }
239
240
241 /// @brief
242 /// @tparam TERRORTYPE
243 /// @param errType
244 /// @return
245 template<class TERRORTYPE>
246 1 ResultValue<TERRORTYPE, ResultErrorId> makeErr(TERRORTYPE const& errType)
247 {
248 1 return ResultValue<TERRORTYPE, ResultErrorId>(errType);
249 }
250
251
252 /// @brief
253 /// @param errCode
254 /// @return
255 GATE_CORE_CPP_API extern ResultValue<result_t, ResultErrorId> makeErr(result_t const& errCode);
256
257
258 /// @brief
259 /// @param errCode
260 /// @return
261 GATE_CORE_CPP_API extern ResultValue<result_t, ResultErrorId> makeErrResult(results::ResultType const& errCode);
262
263 struct Void {};
264
265
266 /// @brief
267 /// @tparam T
268 /// @tparam E
269 template<class T = Void, class E = result_t>
270 class Result
271 {
272 public:
273 typedef T value_t;
274 typedef E error_t;
275 typedef Result<T, E> self_t;
276
277 typedef ResultValue<T, ResultSuccessId> ResultSuccessType;
278 typedef ResultValue<E, ResultErrorId> ResultErrorType;
279 private:
280 value_t* ptrValue;
281 error_t* ptrError;
282 union
283 {
284 gate_c_maxalign_t dummy;
285 char valueContent[sizeof(value_t)];
286 char errorContent[sizeof(error_t)];
287 } content;
288
289 public:
290 123235 bool_t empty() const noexcept
291 {
292
2/4
✓ Branch 0 taken 61687 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 61687 times.
✗ Branch 3 not taken.
123235 return (this->ptrValue == NULL) && (this->ptrError == NULL);
293 }
294
295
296 void createValue()
297 {
298 if (!this->empty())
299 {
300 GATEXX_RAISE_ERROR(results::InvalidState);
301 }
302 else
303 {
304 value_t* ptrMem = reinterpret_cast<value_t*>(&this->content.valueContent[0]);
305 gate::constructType(ptrMem);
306 this->ptrValue = ptrMem;
307 }
308 }
309 122194 void createValue(value_t const& src)
310 {
311
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 61678 times.
122194 if (!this->empty())
312 {
313 GATEXX_RAISE_ERROR(results::InvalidState);
314 }
315 else
316 {
317 122194 value_t* ptrMem = reinterpret_cast<value_t*>(&this->content.valueContent[0]);
318 122194 gate::copyConstructType(ptrMem, src);
319 122194 this->ptrValue = ptrMem;
320 }
321 122194 }
322
323 void createError()
324 {
325 if (!this->empty())
326 {
327 GATEXX_RAISE_ERROR(results::InvalidState);
328 }
329 else
330 {
331 error_t* ptrMem = reinterpret_cast<error_t*>(&this->content.errorContent[0]);
332 gate::constructType(ptrMem);
333 this->ptrError = ptrMem;
334 }
335 }
336
337 18 void createError(error_t const& src)
338 {
339
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
18 if (!this->empty())
340 {
341 GATEXX_RAISE_ERROR(results::InvalidState);
342 }
343 else
344 {
345 18 error_t* ptrMem = reinterpret_cast<error_t*>(&this->content.errorContent[0]);
346 18 gate::copyConstructType(ptrMem, src);
347 18 this->ptrError = ptrMem;
348 }
349 18 }
350
351 61667 Result()
352 : ptrValue(NULL),
353 ptrError(NULL),
354 61667 content()
355 {
356 61667 }
357
358 19 Result(ResultSuccessType const& successType)
359 : ptrValue(NULL),
360 ptrError(NULL),
361 19 content()
362 {
363 19 this->createValue(successType.get());
364 19 }
365
366 4 Result(ResultErrorType const& errorType)
367 : ptrValue(NULL),
368 ptrError(NULL),
369 4 content()
370 {
371 4 this->createError(errorType.get());
372 4 }
373
374 Result(self_t const& src)
375 : ptrValue(NULL),
376 ptrError(NULL),
377 content()
378 {
379 if (src.hasValue())
380 {
381 this->createValue(src.value());
382 }
383 else if (src.hasError())
384 {
385 this->createError(src.error());
386 }
387 else
388 {
389 // An empty result is not allowed to be copied
390 GATEXX_RAISE_ERROR(results::InvalidState);
391 }
392 }
393
394 122229 void reset()
395 {
396
2/2
✓ Branch 0 taken 61678 times.
✓ Branch 1 taken 9 times.
122229 if (this->ptrValue)
397 {
398 122219 destructType(this->ptrValue);
399 122219 this->ptrValue = NULL;
400 }
401
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
10 else if (this->ptrError)
402 {
403 10 destructType(this->ptrError);
404 10 this->ptrError = NULL;
405 }
406 122229 }
407
408 6 self_t& operator=(self_t const& src)
409 {
410
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (this != &src)
411 {
412 6 this->reset();
413
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (src.hasValue())
414 {
415 6 this->createValue(src.value());
416 }
417 else if (src.hasError())
418 {
419 this->createError(src.error());
420 }
421 }
422 6 return *this;
423 }
424
425 122220 ~Result()
426 {
427 122220 this->reset();
428 122220 }
429
430 60524 bool_t hasValue() const noexcept
431 {
432 60524 return this->ptrValue != NULL;
433 }
434
435 120037 value_t& value() const noexcept
436 {
437
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60023 times.
120037 if (!this->ptrValue)
438 {
439 gate::panic(results::NullPointer, "Result<>::value()");
440 }
441 120037 return *this->ptrValue;
442 }
443
444 14 void checkError(char const* source) const
445 {
446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
14 if (this->ptrError)
447 {
448 ErrorPublisher<error_t>::publish(*this->ptrError, source);
449 }
450 14 }
451
452 void checkException(char const* source) const
453 {
454 if (this->ptrError)
455 {
456 ExceptionPublisher<error_t>::publish(*this->ptrError, source);
457 }
458 }
459
460 14 value_t& valueOrError() const
461 {
462 14 checkError("Result::valueOrError");
463 14 return value();
464 }
465
466 value_t& valueOrExcept() const
467 {
468 checkException("Result::valueOrExcept");
469 return value();
470 }
471
472 24 bool_t hasError() const noexcept
473 {
474 24 return this->ptrError != NULL;
475 }
476
477 2 error_t& error() const noexcept
478 {
479
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
2 if (!this->ptrError)
480 {
481 gate::panic(results::NullPointer, "Result<>::error()");
482 }
483 2 return *this->ptrError;
484 }
485
486 bool_t operator!() const noexcept
487 {
488 return !this->hasValue();
489 }
490 value_t& operator*() noexcept
491 {
492 return this->value();
493 }
494 value_t const& operator*() const noexcept
495 {
496 return this->value();
497 }
498 };
499
500 typedef Result<Void, result_t> VoidResult;
501
502
503
504 GATE_CORE_CPP_API extern VoidResult makeOk(void);
505
506
507
508 /// @brief
509 /// @tparam TRESULTTYPE
510 /// @param resultCode
511 /// @param resultType
512 /// @return
513 template<class TRESULTTYPE>
514 60516 Result<TRESULTTYPE, result_t> makeResult(result_t const& resultCode, TRESULTTYPE const& resultType)
515 {
516 60516 Result<TRESULTTYPE, result_t> ret;
517
1/2
✓ Branch 0 taken 60516 times.
✗ Branch 1 not taken.
60516 if (GATE_SUCCEEDED(resultCode))
518 {
519
1/2
✓ Branch 1 taken 60516 times.
✗ Branch 2 not taken.
60516 ret.createValue(resultType);
520 }
521 else
522 {
523 ret.createError(resultCode);
524 }
525 60516 return ret;
526 }
527
528 // NOTICE: Old compilers like OpenWATCOM cannot link templated ResultValue<E> into Result<T,E>.
529 // Therefore we need a makeErr() that provides the T-Result too.
530 template<class TRESULTTYPE>
531 Result<TRESULTTYPE, result_t> makeErr(result_t const& errorCode, TRESULTTYPE const& resultInfo)
532 {
533 Result<TRESULTTYPE, result_t> ret;
534 ret.createError(errorCode);
535 return ret;
536 }
537 template<class TRESULTTYPE>
538 Result<TRESULTTYPE, result_t> makeErr(results::ResultType const& errorCode, TRESULTTYPE const& resultInfo)
539 {
540 Result<TRESULTTYPE, result_t> ret;
541 ret.createError(static_cast<result_t>(errorCode));
542 return ret;
543 }
544
545
546 GATE_CORE_CPP_API extern Result<Void, result_t> makeResult(result_t const& resultCode);
547
548
549 #if defined(GATE_EXCEPTIONS_ADVANCED)
550
551 namespace exceptions
552 {
553
554 template<int RESULT>
555 class GATE_CORE_CPP_API ResultException : public Exception
556 {
557 public:
558 ResultException(char const* msg = 0, char const* src = 0, int32_t errCode = 0)
559 : Exception(RESULT, (msg ? msg : gate_result_text(RESULT)), src, errCode)
560 {
561 }
562 };
563
564
565 /* GENERIC ERRORS */
566 typedef ResultException<GATE_RESULT_ERROR> Error;
567 typedef ResultException<GATE_RESULT_FAILED> Failed;
568 typedef ResultException<GATE_RESULT_CANCELED> Canceled;
569 typedef ResultException<GATE_RESULT_INVALIDARG> InvalidArg;
570 typedef ResultException<GATE_RESULT_ACCESSDENIED> AccessDenied;
571 typedef ResultException<GATE_RESULT_PERMISSIONDENIED> PermissionDenied;
572 typedef ResultException<GATE_RESULT_NOTDEFINED> NotDefined;
573 typedef ResultException<GATE_RESULT_NOTAVAILABLE> NotAvailable;
574 typedef ResultException<GATE_RESULT_NOTIMPLEMENTED> NotImplemented;
575 typedef ResultException<GATE_RESULT_NOMATCH> NoMatch;
576 typedef ResultException<GATE_RESULT_NOTSUPPORTED> NotSupported;
577 typedef ResultException<GATE_RESULT_NOTREQUIRED> NotRequired;
578 typedef ResultException<GATE_RESULT_NOTREADY> NotReady;
579 typedef ResultException<GATE_RESULT_SECURITYBREACH> SecurityBreach;
580 typedef ResultException<GATE_RESULT_ALREADYEXISTS> AlreadyExists;
581 typedef ResultException<GATE_RESULT_INVALIDSTATE> InvalidState;
582
583 /* RESOURCE ACCESS ERRORS */
584 typedef ResultException<GATE_RESULT_OUTOFMEMORY> OutOfMemory;
585 typedef ResultException<GATE_RESULT_OUTOFRESOURCES> OutOfResources;
586 typedef ResultException<GATE_RESULT_OUTOFBOUNDS> OutOfBounds;
587 typedef ResultException<GATE_RESULT_NULLPOINTER> NullPointer;
588 typedef ResultException<GATE_RESULT_BADCAST> BadCast;
589 typedef ResultException<GATE_RESULT_ARITHMETICERROR> ArithmeticError;
590 typedef ResultException<GATE_RESULT_OVERFLOW> Overflow;
591 typedef ResultException<GATE_RESULT_UNDERFLOW> Underflow;
592 typedef ResultException<GATE_RESULT_LOCKED> Locked;
593 typedef ResultException<GATE_RESULT_TIMEOUT> Timeout;
594 typedef ResultException<GATE_RESULT_BADADDRESS> BadAddress;
595 typedef ResultException<GATE_RESULT_BLOCKED> Blocked;
596 typedef ResultException<GATE_RESULT_DEVICEERROR> DeviceError;
597
598 /* EXECUTION ERRORS */
599 typedef ResultException<GATE_RESULT_EXECUTIONFAILED> ExecutionFailed;
600 typedef ResultException<GATE_RESULT_EXECUTIONINTERRUPTED> ExecutionInterrupted;
601 typedef ResultException<GATE_RESULT_CRITICALERROR> CriticalError;
602 typedef ResultException<GATE_RESULT_UNKNOWNEXCEPTION> UnknownException;
603 typedef ResultException<GATE_RESULT_PRECONDITIONFAILED> PreconditionFailed;
604 typedef ResultException<GATE_RESULT_PREPARATIONFAILED> PreparationFailed;
605 typedef ResultException<GATE_RESULT_BADINSTRUCTION> BadInstruction;
606
607 /* DATA ERRORS */
608 typedef ResultException<GATE_RESULT_INVALIDHEADER> InvalidHeader;
609 typedef ResultException<GATE_RESULT_INVALIDDATA> InvalidData;
610 typedef ResultException<GATE_RESULT_INVALIDCONTENT> InvalidContent;
611 typedef ResultException<GATE_RESULT_INCORRECTSIZE> IncorrectSize;
612 typedef ResultException<GATE_RESULT_INCORRECTTYPE> IncorrectType;
613 typedef ResultException<GATE_RESULT_ENDOFSTREAM> EndOfStream;
614 typedef ResultException<GATE_RESULT_INVALIDINPUT> InvalidInput;
615 typedef ResultException<GATE_RESULT_INVALIDOUTPUT> InvalidOutput;
616 typedef ResultException<GATE_RESULT_BUFFERTOOSMALL> BufferTooSmall;
617 typedef ResultException<GATE_RESULT_NODATA> NoData;
618
619 /* PROGRAM ERRORS */
620 typedef ResultException<GATE_RESULT_APPLICATIONERROR> ApplicationError;
621 typedef ResultException<GATE_RESULT_LOGICALERROR> LogicalError;
622 typedef ResultException<GATE_RESULT_USERERROR> UserError;
623
624 /* UNSPECIFIED ERRORS */
625 typedef ResultException<GATE_RESULT_UNKNOWNERROR> UnknownError;
626
627 } // end of namespace exceptions
628 #endif
629
630
631 #if defined(GATEXX_NO_EXCEPTIONS)
632 // no exception handling (raising exceptions would panic/abort)
633 # define GATEXX_TRY_CATCHINFO(exceptionInfoRef, codeblock) \
634 do { \
635 codeblock ; \
636 exceptionInfoRef = ExceptionInfo(); \
637 } while(0);
638
639 # define GATEXX_TRY_IGNORE(codeblock) \
640 do { \
641 codeblock ; \
642 } while(0);
643
644 # define GATEXX_TRY_CATCHALL(trycode, catchcode) \
645 do { \
646 trycode ; \
647 } while(0);
648
649 #else
650 // catch exceptions with default try-catch
651
652 # define GATEXX_TRY_CATCHINFO(exceptionInfoRef, codeblock) \
653 try { \
654 codeblock ; \
655 exceptionInfoRef = ExceptionInfo(); \
656 } \
657 catch(...) { \
658 exceptionInfoRef = catchCurrentException(); \
659 }
660
661 # define GATEXX_TRY_IGNORE(codeblock) \
662 try { \
663 codeblock ; \
664 } \
665 catch(...) { }
666
667 # define GATEXX_TRY_CATCHALL(trycode, catchcode) \
668 try { \
669 trycode ; \
670 } catch (...) { \
671 catchcode ; \
672 }
673
674 #endif
675
676 } // end if namespace gate
677
678 #endif
679