Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
Exceptions.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4
5// Comment this in to turn on aggressive noisy DbgTrace in this module
6//#define Stroika_Foundation_Execution_Exceptions_USE_NOISY_TRACE_IN_THIS_MODULE_ 1
7
8#if Stroika_Foundation_Execution_Exceptions_USE_NOISY_TRACE_IN_THIS_MODULE_
11#endif
12
14
15 namespace Private_::SystemErrorExceptionPrivate_ {
16 Characters::String mkMsg_ (error_code errCode);
17 Characters::String mkCombinedMsg_ (error_code errCode, const Characters::String& message);
18
19 /*
20 * Shared by both TranslateException_ overloads - message is nullptr when the caller had none.
21 * The set of promotions implemented here is the one DOCUMENTED as guaranteed in Exceptions.h
22 * (@see ThrowError) - keep the two in sync.
23 */
24 void ThrowTranslatedExceptionIfNeeded_ (error_code errCode, const Characters::String* message = nullptr);
25 }
26
27 // forward declare for use below....to avoid #include of Thread.h
28 namespace Thread {
30 }
31
32 /*
33 ********************************************************************************
34 ******************************** ExceptionStringHelper *************************
35 ********************************************************************************
36 */
38 {
39 return fRawErrorMessage_;
40 }
42 {
43 EnsureBuilt_ ();
44 return fFullErrorMessage_;
45 }
46 inline optional<Containers::Stack<Activity<>>> ExceptionStringHelper::GetActivities () const
47 {
48 return fActivities_;
49 }
50 template <>
51 inline wstring ExceptionStringHelper::As () const
52 {
53 EnsureBuilt_ ();
54 return fFullErrorMessage_.As<wstring> ();
55 }
56 template <>
58 {
59 EnsureBuilt_ ();
60 return fFullErrorMessage_;
61 }
63 {
64 EnsureBuilt_ ();
65 return fSDKCharString_.c_str ();
66 }
67
68 /*
69 ********************************************************************************
70 ********************************** Exception ***********************************
71 ********************************************************************************
72 */
73 template <derived_from<exception> BASE_EXCEPTION>
74 inline Exception<BASE_EXCEPTION>::Exception (const Characters::String& reasonForError)
75 requires (default_initializable<BASE_EXCEPTION>)
76 : ExceptionStringHelper{reasonForError}
77 , inherited{}
78 {
79 }
80 template <derived_from<exception> BASE_EXCEPTION>
81 inline Exception<BASE_EXCEPTION>::Exception (const Characters::String& reasonForError)
82 requires (not default_initializable<BASE_EXCEPTION> and constructible_from<BASE_EXCEPTION, const char*>)
83 : ExceptionStringHelper{reasonForError}
84 , inherited{""} // BASE needs a what_arg; its value is irrelevant since what () is overridden
85 {
86 }
87 template <derived_from<exception> BASE_EXCEPTION>
88 template <typename... BASE_EXCEPTION_ARGS>
89 inline Exception<BASE_EXCEPTION>::Exception (const Characters::String& reasonForError, BASE_EXCEPTION_ARGS... baseExceptionArgs)
90 : ExceptionStringHelper{reasonForError}
91 , inherited{forward<BASE_EXCEPTION_ARGS> (baseExceptionArgs)...}
92 {
93 }
94 template <derived_from<exception> BASE_EXCEPTION>
95 const char* Exception<BASE_EXCEPTION>::what () const noexcept
96 {
97 return _PeekAtNarrowSDKString ();
98 }
99
100 /*
101 ********************************************************************************
102 ******************* RuntimeErrorException [[deprecated]] ***********************
103 ********************************************************************************
104 */
105 /**
106 * \deprecated Since Stroika v3.0d25 - say Execution::Exception<runtime_error>, or whichever std exception type you
107 * actually mean (Exception<logic_error>, Exception<out_of_range>, ...). Since v3.0d25
108 * Exception<> supplies the base's what_arg itself, so this added nothing but a name - and a
109 * misleading one whenever BASE_EXCEPTION was not in fact a runtime_error.
110 */
111 template <derived_from<exception> BASE_EXCEPTION = runtime_error>
112 class [[deprecated ("Since Stroika v3.0d25 - use Execution::Exception<runtime_error>")]] RuntimeErrorException
113 : public Exception<BASE_EXCEPTION> {
114 public:
115 RuntimeErrorException (const Characters::String& msg)
116 : Exception<BASE_EXCEPTION>{msg}
117 {
118 }
119 };
120
121 /*
122 ********************************************************************************
123 ******************************* NestedException ********************************
124 ********************************************************************************
125 */
126 inline NestedException::NestedException (const Characters::String& msg, const exception_ptr& basedOnException)
127 : Execution::Exception<runtime_error>{msg}
128 , fBasedOnException{basedOnException}
129 {
130 }
131
132 /*
133 ********************************************************************************
134 ***************************** SystemErrorException *****************************
135 ********************************************************************************
136 */
137 inline SystemErrorException::SystemErrorException (error_code errCode)
138 : SystemErrorException{errCode, Private_::SystemErrorExceptionPrivate_::mkMsg_ (errCode)}
139 {
140 }
141 inline SystemErrorException::SystemErrorException (error_code errCode, const Characters::String& message)
142 : inherited{Private_::SystemErrorExceptionPrivate_::mkCombinedMsg_ (errCode, message), errCode}
143 {
144 }
145 inline SystemErrorException::SystemErrorException (int ev, const std::error_category& ecat)
146 : SystemErrorException{error_code{ev, ecat}}
147 {
148 }
149 inline SystemErrorException::SystemErrorException (int ev, const std::error_category& ecat, const Characters::String& message)
150 : SystemErrorException{error_code{ev, ecat}, message}
151 {
152 }
153
154 /*
155 ********************************************************************************
156 ******************************** ThrowPOSIXErrNo *******************************
157 ********************************************************************************
158 */
159 inline void ThrowPOSIXErrNo (errno_t errNo)
160 {
161#if Stroika_Foundation_Execution_Exceptions_USE_NOISY_TRACE_IN_THIS_MODULE_
162 using namespace Characters::Literals;
163 Debug::TraceContextBumper tctx{"Execution::ThrowPOSIXErrNo", "{}"_f, errNo};
164#endif
165 Require (errNo != 0);
166#if qStroika_Platform_POSIX
167 error_code ec{errNo, system_category ()};
168#else
169 error_code ec{errNo, generic_category ()};
170#endif
171 ThrowError (ec);
172 }
173
174 /*
175 ********************************************************************************
176 ************************* ThrowPOSIXErrNoIfNegative ****************************
177 ********************************************************************************
178 */
179 template <typename INT_TYPE>
180 inline INT_TYPE ThrowPOSIXErrNoIfNegative (INT_TYPE returnCode)
181 {
182 if (returnCode < 0) [[unlikely]] {
183 ThrowPOSIXErrNo (errno);
184 }
185 return returnCode;
186 }
187
188 /*
189 ********************************************************************************
190 ******************************** ThrowSystemErrNo ******************************
191 ********************************************************************************
192 */
193 inline void ThrowSystemErrNo (int sysErr)
194 {
195#if Stroika_Foundation_Execution_Exceptions_USE_NOISY_TRACE_IN_THIS_MODULE_
196 using namespace Characters::Literals;
197 Debug::TraceContextBumper tctx{"Execution::ThrowSystemErrNo", "{}"_f, sysErr};
198#endif
199 Require (sysErr != 0);
200#if qStroika_Platform_Windows
201 ThrowError (error_code{sysErr, Platform::Windows::Win32_error_category ()}); // system_category (), plus what Microsoft's misses
202#else
203 ThrowError (error_code{sysErr, system_category ()});
204#endif
205 }
206
207 /*
208 ********************************************************************************
209 ************************************ ThrowError ********************************
210 ********************************************************************************
211 */
212 [[noreturn]] inline void ThrowError (error_code ec)
213 {
214 Require (ec != error_code{});
215 Private_::SystemErrorExceptionPrivate_::ThrowTranslatedExceptionIfNeeded_ (ec); // [[noreturn]] for the promoted conditions
217 }
218 [[noreturn]] inline void ThrowError (error_code ec, const Characters::String& message)
219 {
220 Require (ec != error_code{});
221 Private_::SystemErrorExceptionPrivate_::ThrowTranslatedExceptionIfNeeded_ (ec, &message); // [[noreturn]] for the promoted conditions
222 Throw (SystemErrorException{ec, message});
223 }
224 [[noreturn]] inline void ThrowError (errc ec)
225 {
226 Require (ec != errc{}); // errc has no zero enumerator, so errc{} is never a real error
227 ThrowError (make_error_code (ec));
228 }
229 [[noreturn]] inline void ThrowError (errc ec, const Characters::String& message)
230 {
231 Require (ec != errc{});
232 ThrowError (make_error_code (ec), message);
233 }
234
235 /*
236 ********************************************************************************
237 ****************************** ThrowSystemErrNo () *****************************
238 ********************************************************************************
239 */
240#if qStroika_Platform_POSIX or qStroika_Platform_Windows
241 [[noreturn]] inline void ThrowSystemErrNo ()
242 {
243#if qStroika_Platform_POSIX
244 ThrowSystemErrNo (errno);
245#elif qStroika_Platform_Windows
246 ThrowSystemErrNo (::GetLastError ());
247#endif
248 }
249#endif
250
251 /*
252 ********************************************************************************
253 ************************ Handle_ErrNoResultInterruption ************************
254 ********************************************************************************
255 */
256 template <typename CALL>
257 auto Handle_ErrNoResultInterruption (CALL call) -> decltype (call ())
258 {
259 decltype (call ()) ret; // intentionally uninitialized since always set at least once before read
260 do {
261 ret = call ();
263 } while (ret < 0 and errno == EINTR);
264 return ThrowPOSIXErrNoIfNegative (ret);
265 }
266
267 /*
268 ********************************************************************************
269 ****************************** ThrowPOSIXErrNoIfNull ***************************
270 ********************************************************************************
271 */
272 inline void ThrowPOSIXErrNoIfNull (void* returnValue)
273 {
274 if (returnValue == nullptr) [[unlikely]] {
275 ThrowPOSIXErrNo (errno);
276 }
277 }
278
279 /*
280 ********************************************************************************
281 ************************** TranslateExceptionToOptional ************************
282 ********************************************************************************
283 */
284 template <typename F>
285 inline auto TranslateExceptionToOptional (F&& f) -> optional<remove_cvref_t<invoke_result_t<F>>>
286 {
287 try {
288 return f ();
289 }
290 catch (...) {
291 //using namespace Characters::Literals;
292 //DbgTrace ("Mapping exception in TranslateExceptionToOptional to nullopt: {}"_f, current_exception ());
293 return nullopt;
294 }
295 }
296
297}
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
Exception<> is a replacement (subclass) for any std c++ exception class (e.g. the default 'std::excep...
Definition Exceptions.h:219
Exception()=delete
construct with just a message - BASE_EXCEPTION gets whatever it minimally needs.
virtual const char * what() const noexcept override
nonvirtual optional< Containers::Stack< Activity<> > > GetActivities() const
nonvirtual Characters::String GetBasicErrorMessage() const
nonvirtual Characters::String GetFullErrorMessage() const
nonvirtual const char * _PeekAtNarrowSDKString() const
void Throw(T &&e2Throw)
like the builtin C++ 'throw', but stamps in the current Activity context and does helpful,...
Definition Throw.inl:54
void ThrowPOSIXErrNo(errno_t errNo=errno)
treats argument errNo as a POSIX errno value, and calls ThrowError () with an error_code constructed ...
auto Handle_ErrNoResultInterruption(CALL call) -> decltype(call())
Handle UNIX EINTR system call behavior - fairly transparently - just effectively removes them from th...
void ThrowPOSIXErrNoIfNull(void *returnValue)
auto TranslateExceptionToOptional(F &&f) -> optional< remove_cvref_t< invoke_result_t< F > > >
void ThrowError(error_code ec)
throw a SystemErrorException with the given error_code - or std::bad_alloc for errc::not_enough_memor...
INT_TYPE ThrowPOSIXErrNoIfNegative(INT_TYPE returnCode)