The Gaudi Framework  master (cc9a61f4)
Loading...
Searching...
No Matches
StatusCode.h
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2026 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
11#pragma once
12
13#include <boost/preprocessor/facilities/overload.hpp>
14#include <functional>
15#include <ostream>
16#include <type_traits>
17#include <utility>
18
19#include <GaudiKernel/Kernel.h>
20
21template <typename T>
22struct is_StatusCode_enum : std::false_type {};
23
60class
61#if !defined( __CLING__ )
62 [[nodiscard]]
63#endif
64 StatusCode final {
65public:
66 typedef unsigned long code_t;
67
68 enum class ErrorCode : code_t { FAILURE = 0, SUCCESS = 1, RECOVERABLE = 2 };
69
77 struct Category {
78 constexpr Category() noexcept = default;
79 virtual ~Category() {}
80
82 virtual const char* name() const = 0;
83
85 virtual std::string message( code_t code ) const { return "UNKNOWN(" + std::to_string( code ) + ")"; }
86
89 virtual bool isSuccess( code_t code ) const { return code == static_cast<code_t>( ErrorCode::SUCCESS ); }
90
92 virtual bool isRecoverable( code_t code ) const { return code == static_cast<code_t>( ErrorCode::RECOVERABLE ); }
93 };
94
96 static const Category& default_category() noexcept;
97
98 // Provide shorthands for default code values
99 constexpr const static auto SUCCESS = ErrorCode::SUCCESS;
100 constexpr const static auto FAILURE = ErrorCode::FAILURE;
101 constexpr const static auto RECOVERABLE = ErrorCode::RECOVERABLE;
102
104 StatusCode() = default;
105
107 template <typename T>
108 requires( is_StatusCode_enum<T>::value )
109 StatusCode( T sc ) noexcept : StatusCode{ static_cast<StatusCode::code_t>( sc ), is_StatusCode_enum<T>::instance } {}
110
112 explicit StatusCode( code_t code, const StatusCode::Category& cat ) noexcept : m_cat( &cat ), m_code( code ) {}
113
115 explicit StatusCode( code_t code ) noexcept : StatusCode( code, default_category() ) {}
116
117 bool isSuccess() const;
118 bool isFailure() const { return !isSuccess(); }
119 bool isRecoverable() const;
120
122 explicit operator bool() const { return isSuccess(); }
123
125 code_t getCode() const { return m_code; }
126
128 void ignore() const {}
129
150 template <typename F, typename... ARGS>
151 StatusCode andThen( F&& f, ARGS&&... args ) const {
152 if ( isFailure() ) return *this;
153 return i_invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
154 }
155
172 template <typename F, typename... ARGS>
173 StatusCode orElse( F&& f, ARGS&&... args ) const {
174 if ( isSuccess() ) return *this;
175 return i_invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
176 }
177
194 const StatusCode& orThrow( std::string_view message, std::string_view tag ) const {
195 if ( isFailure() ) i_doThrow( message, tag );
196 return *this;
197 }
198
203 const StatusCode& orThrow( std::string_view tag = "" ) const {
204 if ( isFailure() ) i_doThrow( message(), tag ); // make sure `message()` is only called on error path
205 return *this;
206 }
207
209 const StatusCode::Category& getCategory() const { return *m_cat; }
210
212 std::string message() const { return getCategory().message( m_code ); }
213
214 friend std::ostream& operator<<( std::ostream& s, const StatusCode& sc ) {
215 s << sc.message();
216 return s;
217 }
218
222 friend bool operator==( const StatusCode& lhs, const StatusCode& rhs );
223 friend bool operator!=( const StatusCode& lhs, const StatusCode& rhs ) { return !( lhs == rhs ); }
224
226 friend bool operator<( const StatusCode& lhs, const StatusCode& rhs ) {
227 return ( lhs.m_cat < rhs.m_cat || ( lhs.m_cat == rhs.m_cat && lhs.m_code < rhs.m_code ) );
228 }
229
231 StatusCode& operator&=( const StatusCode& rhs );
232 StatusCode& operator|=( const StatusCode& rhs );
233 //
235 friend StatusCode operator&( StatusCode lhs, const StatusCode& rhs ) { return lhs &= rhs; }
236
238 friend StatusCode operator|( StatusCode lhs, const StatusCode& rhs ) { return lhs |= rhs; }
239
241 friend bool& operator&=( bool& lhs, const StatusCode& sc ) { return lhs &= sc.isSuccess(); }
242
244 friend bool& operator|=( bool& lhs, const StatusCode& sc ) { return lhs |= sc.isSuccess(); }
245
246private:
249
250 ErrorCode default_value() const;
251
253 [[noreturn]] void i_doThrow( std::string_view message, std::string_view tag ) const;
254
256 template <typename... ARGS, std::invocable<ARGS...> F> // requires ( std::is_invocable_v<F, ARGS...> )
257 StatusCode i_invoke( F&& f, ARGS&&... args ) const {
258 if constexpr ( std::is_invocable_r_v<StatusCode, F, ARGS...> ) {
259 return std::invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
260 } else {
261 // static_assert( std::is_same_v<void,std::invoke_result_t<F,ARGS...>>); // how paranoid should this be?
262 std::invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
263 return *this;
264 }
265 }
266};
267
268/*
269 * Macros to declare/implement StatusCode enums/categories
270 */
271
274#define STATUSCODE_ENUM_DECL( ENUM ) \
275 template <> \
276 struct is_StatusCode_enum<ENUM> : std::true_type { \
277 static const StatusCode::Category& instance; \
278 };
279
283#define STATUSCODE_ENUM_IMPL( ... ) BOOST_PP_OVERLOAD( STATUSCODE_ENUM_IMPL_, __VA_ARGS__ )( __VA_ARGS__ )
284
285#define STATUSCODE_ENUM_IMPL_1( ENUM ) \
286 const StatusCode::Category& is_StatusCode_enum<ENUM>::instance = StatusCode::default_category();
287
288#define STATUSCODE_ENUM_IMPL_2( ENUM, CATEGORY ) \
289 const StatusCode::Category& is_StatusCode_enum<ENUM>::instance = CATEGORY{};
290
291// Declare the default StatusCode enum
293
294/*
295 * Inline methods
296 */
297
301
302inline bool StatusCode::isSuccess() const {
303 return ( m_code == static_cast<code_t>( ErrorCode::SUCCESS ) || m_cat->isSuccess( m_code ) );
304}
305
306inline bool StatusCode::isRecoverable() const { return m_cat->isRecoverable( m_code ); }
307
312
313inline bool operator==( const StatusCode& lhs, const StatusCode& rhs ) {
314 return ( lhs.m_code == rhs.m_code ) &&
317 ( lhs.m_cat == rhs.m_cat ) );
318}
319
321 // Ternary AND lookup matrix
322 static constexpr StatusCode::code_t AND[3][3] = { { 0, 0, 0 }, { 0, 1, 2 }, { 0, 2, 2 } };
323
325 StatusCode::code_t r = static_cast<StatusCode::code_t>( rhs.default_value() );
326 m_code = AND[l][r];
327 return *this;
328}
329
331 // Ternary OR lookup matrix
332 static constexpr StatusCode::code_t OR[3][3] = { { 0, 1, 2 }, { 1, 1, 1 }, { 2, 1, 2 } };
333
335 StatusCode::code_t r = static_cast<StatusCode::code_t>( rhs.default_value() );
336 m_code = OR[l][r];
337 return *this;
338}
#define STATUSCODE_ENUM_DECL(ENUM)
Declare an enum to be used as StatusCode value.
Definition StatusCode.h:274
bool operator==(const StatusCode &lhs, const StatusCode &rhs)
Definition StatusCode.h:313
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
friend bool & operator&=(bool &lhs, const StatusCode &sc)
Boolean AND assignment operator.
Definition StatusCode.h:241
StatusCode & operator|=(const StatusCode &rhs)
Ternary logic operator with RECOVERABLE being the "third" state.
Definition StatusCode.h:330
StatusCode orElse(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a failure result.
Definition StatusCode.h:173
friend bool & operator|=(bool &lhs, const StatusCode &sc)
Boolean OR assignment operator.
Definition StatusCode.h:244
ErrorCode default_value() const
Project onto the default StatusCode values.
Definition StatusCode.h:308
StatusCode(code_t code, const StatusCode::Category &cat) noexcept
Constructor from code_t and category (explicit conversion only).
Definition StatusCode.h:112
friend StatusCode operator&(StatusCode lhs, const StatusCode &rhs)
Ternary AND operator.
Definition StatusCode.h:235
StatusCode & operator&=(const StatusCode &rhs)
Ternary logic operator with RECOVERABLE being the "third" state.
Definition StatusCode.h:320
code_t m_code
The status code value.
Definition StatusCode.h:248
StatusCode()=default
Default constructor.
const StatusCode & orThrow(std::string_view tag="") const
Throw a GaudiException in case of failures.
Definition StatusCode.h:203
friend StatusCode operator|(StatusCode lhs, const StatusCode &rhs)
Ternary OR operator.
Definition StatusCode.h:238
bool isFailure() const
Definition StatusCode.h:118
static const Category & default_category() noexcept
Default Gaudi StatusCode category.
Definition StatusCode.h:298
StatusCode(code_t code) noexcept
Constructor from code_t in the default category (explicit conversion only).
Definition StatusCode.h:115
unsigned long code_t
type of StatusCode value
Definition StatusCode.h:66
StatusCode i_invoke(F &&f, ARGS &&... args) const
Helper to invoke a callable and return the resulting StatusCode or this, if the callable returns void...
Definition StatusCode.h:257
const StatusCode & orThrow(std::string_view message, std::string_view tag) const
Throw a GaudiException in case of failures.
Definition StatusCode.h:194
friend bool operator<(const StatusCode &lhs, const StatusCode &rhs)
Comparison (values are grouped by category first).
Definition StatusCode.h:226
std::string message() const
Description (or name) of StatusCode value.
Definition StatusCode.h:212
constexpr static const auto RECOVERABLE
Definition StatusCode.h:101
friend bool operator!=(const StatusCode &lhs, const StatusCode &rhs)
Definition StatusCode.h:223
StatusCode andThen(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a success result.
Definition StatusCode.h:151
const Category * m_cat
The status code category.
Definition StatusCode.h:247
friend std::ostream & operator<<(std::ostream &s, const StatusCode &sc)
Definition StatusCode.h:214
void i_doThrow(std::string_view message, std::string_view tag) const
Helper function to avoid circular dependency between GaudiException.h and StatusCode....
void ignore() const
Allow discarding a StatusCode without warning.
Definition StatusCode.h:128
bool isSuccess() const
Definition StatusCode.h:302
bool isRecoverable() const
Definition StatusCode.h:306
constexpr static const auto SUCCESS
Definition StatusCode.h:99
constexpr static const auto FAILURE
Definition StatusCode.h:100
const StatusCode::Category & getCategory() const
Retrieve category.
Definition StatusCode.h:209
code_t getCode() const
Retrieve value.
Definition StatusCode.h:125
The category assigned to a StatusCode.
Definition StatusCode.h:77
virtual bool isSuccess(code_t code) const
Is code considered success ?
Definition StatusCode.h:89
constexpr Category() noexcept=default
virtual std::string message(code_t code) const
Description for code within this category.
Definition StatusCode.h:85
virtual const char * name() const =0
Name of the category.
virtual bool isRecoverable(code_t code) const
Is code considered recoverable ?
Definition StatusCode.h:92