The Gaudi Framework  master (ff829712)
Loading...
Searching...
No Matches
StatusCode.h
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2025 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
118 StatusCode( const StatusCode& rhs ) noexcept = default;
119
121 StatusCode( StatusCode&& rhs ) noexcept = default;
122
124 ~StatusCode() = default;
125
126 StatusCode& operator=( const StatusCode& rhs ) noexcept = default;
127
128 bool isSuccess() const;
129 bool isFailure() const { return !isSuccess(); }
130 bool isRecoverable() const;
131
133 explicit operator bool() const { return isSuccess(); }
134
136 code_t getCode() const { return m_code; }
137
139 const StatusCode& ignore() const { return *this; }
140 StatusCode& ignore() { return *this; }
141
162 template <typename F, typename... ARGS>
163 StatusCode andThen( F&& f, ARGS&&... args ) const {
164 if ( isFailure() ) return *this;
165 return i_invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
166 }
167
184 template <typename F, typename... ARGS>
185 StatusCode orElse( F&& f, ARGS&&... args ) const {
186 if ( isSuccess() ) return *this;
187 return i_invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
188 }
189
206 const StatusCode& orThrow( std::string_view message, std::string_view tag ) const {
207 if ( isFailure() ) i_doThrow( message, tag );
208 return *this;
209 }
210
215 const StatusCode& orThrow( std::string_view tag = "" ) const {
216 if ( isFailure() ) i_doThrow( message(), tag ); // make sure `message()` is only called on error path
217 return *this;
218 }
219
221 const StatusCode::Category& getCategory() const { return *m_cat; }
222
224 std::string message() const { return getCategory().message( m_code ); }
225
226 friend std::ostream& operator<<( std::ostream& s, const StatusCode& sc ) {
227 s << sc.message();
228 return s;
229 }
230
234 friend bool operator==( const StatusCode& lhs, const StatusCode& rhs );
235 friend bool operator!=( const StatusCode& lhs, const StatusCode& rhs ) { return !( lhs == rhs ); }
236
238 friend bool operator<( const StatusCode& lhs, const StatusCode& rhs ) {
239 return ( lhs.m_cat < rhs.m_cat || ( lhs.m_cat == rhs.m_cat && lhs.m_code < rhs.m_code ) );
240 }
241
243 StatusCode& operator&=( const StatusCode& rhs );
244 StatusCode& operator|=( const StatusCode& rhs );
245 //
247 friend StatusCode operator&( StatusCode lhs, const StatusCode& rhs ) { return lhs &= rhs; }
248
250 friend StatusCode operator|( StatusCode lhs, const StatusCode& rhs ) { return lhs |= rhs; }
251
253 friend bool& operator&=( bool& lhs, const StatusCode& sc ) { return lhs &= sc.isSuccess(); }
254
256 friend bool& operator|=( bool& lhs, const StatusCode& sc ) { return lhs |= sc.isSuccess(); }
257
258private:
261
262 ErrorCode default_value() const;
263
265 [[noreturn]] void i_doThrow( std::string_view message, std::string_view tag ) const;
266
268 template <typename... ARGS, std::invocable<ARGS...> F> // requires ( std::is_invocable_v<F, ARGS...> )
269 StatusCode i_invoke( F&& f, ARGS&&... args ) const {
270 if constexpr ( std::is_invocable_r_v<StatusCode, F, ARGS...> ) {
271 return std::invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
272 } else {
273 // static_assert( std::is_same_v<void,std::invoke_result_t<F,ARGS...>>); // how paranoid should this be?
274 std::invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
275 return *this;
276 }
277 }
278};
279
280/*
281 * Macros to declare/implement StatusCode enums/categories
282 */
283
286#define STATUSCODE_ENUM_DECL( ENUM ) \
287 template <> \
288 struct is_StatusCode_enum<ENUM> : std::true_type { \
289 static const StatusCode::Category& instance; \
290 };
291
295#define STATUSCODE_ENUM_IMPL( ... ) BOOST_PP_OVERLOAD( STATUSCODE_ENUM_IMPL_, __VA_ARGS__ )( __VA_ARGS__ )
296
297#define STATUSCODE_ENUM_IMPL_1( ENUM ) \
298 const StatusCode::Category& is_StatusCode_enum<ENUM>::instance = StatusCode::default_category();
299
300#define STATUSCODE_ENUM_IMPL_2( ENUM, CATEGORY ) \
301 const StatusCode::Category& is_StatusCode_enum<ENUM>::instance = CATEGORY{};
302
303// Declare the default StatusCode enum
305
306/*
307 * Inline methods
308 */
309
313
314inline bool StatusCode::isSuccess() const {
315 return ( m_code == static_cast<code_t>( ErrorCode::SUCCESS ) || m_cat->isSuccess( m_code ) );
316}
317
318inline bool StatusCode::isRecoverable() const { return m_cat->isRecoverable( m_code ); }
319
324
325inline bool operator==( const StatusCode& lhs, const StatusCode& rhs ) {
326 return ( lhs.m_code == rhs.m_code ) &&
329 ( lhs.m_cat == rhs.m_cat ) );
330}
331
333 // Ternary AND lookup matrix
334 static constexpr StatusCode::code_t AND[3][3] = { { 0, 0, 0 }, { 0, 1, 2 }, { 0, 2, 2 } };
335
337 StatusCode::code_t r = static_cast<StatusCode::code_t>( rhs.default_value() );
338 m_code = AND[l][r];
339 return *this;
340}
341
343 // Ternary OR lookup matrix
344 static constexpr StatusCode::code_t OR[3][3] = { { 0, 1, 2 }, { 1, 1, 1 }, { 2, 1, 2 } };
345
347 StatusCode::code_t r = static_cast<StatusCode::code_t>( rhs.default_value() );
348 m_code = OR[l][r];
349 return *this;
350}
#define STATUSCODE_ENUM_DECL(ENUM)
Declare an enum to be used as StatusCode value.
Definition StatusCode.h:286
bool operator==(const StatusCode &lhs, const StatusCode &rhs)
Definition StatusCode.h:325
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
StatusCode(const StatusCode &rhs) noexcept=default
Copy constructor.
friend bool & operator&=(bool &lhs, const StatusCode &sc)
Boolean AND assignment operator.
Definition StatusCode.h:253
StatusCode & operator|=(const StatusCode &rhs)
Ternary logic operator with RECOVERABLE being the "third" state.
Definition StatusCode.h:342
StatusCode orElse(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a failure result.
Definition StatusCode.h:185
friend bool & operator|=(bool &lhs, const StatusCode &sc)
Boolean OR assignment operator.
Definition StatusCode.h:256
ErrorCode default_value() const
Project onto the default StatusCode values.
Definition StatusCode.h:320
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:247
StatusCode & operator&=(const StatusCode &rhs)
Ternary logic operator with RECOVERABLE being the "third" state.
Definition StatusCode.h:332
code_t m_code
The status code value.
Definition StatusCode.h:260
StatusCode()=default
Default constructor.
const StatusCode & orThrow(std::string_view tag="") const
Throw a GaudiException in case of failures.
Definition StatusCode.h:215
StatusCode & operator=(const StatusCode &rhs) noexcept=default
friend StatusCode operator|(StatusCode lhs, const StatusCode &rhs)
Ternary OR operator.
Definition StatusCode.h:250
bool isFailure() const
Definition StatusCode.h:129
static const Category & default_category() noexcept
Default Gaudi StatusCode category.
Definition StatusCode.h:310
const StatusCode & ignore() const
Allow discarding a StatusCode without warning.
Definition StatusCode.h:139
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:269
const StatusCode & orThrow(std::string_view message, std::string_view tag) const
Throw a GaudiException in case of failures.
Definition StatusCode.h:206
~StatusCode()=default
Destructor.
friend bool operator<(const StatusCode &lhs, const StatusCode &rhs)
Comparison (values are grouped by category first)
Definition StatusCode.h:238
std::string message() const
Description (or name) of StatusCode value.
Definition StatusCode.h:224
constexpr static const auto RECOVERABLE
Definition StatusCode.h:101
friend bool operator!=(const StatusCode &lhs, const StatusCode &rhs)
Definition StatusCode.h:235
StatusCode andThen(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a success result.
Definition StatusCode.h:163
const Category * m_cat
The status code category.
Definition StatusCode.h:259
StatusCode & ignore()
Definition StatusCode.h:140
friend std::ostream & operator<<(std::ostream &s, const StatusCode &sc)
Definition StatusCode.h:226
void i_doThrow(std::string_view message, std::string_view tag) const
Helper function to avoid circular dependency between GaudiException.h and StatusCode....
bool isSuccess() const
Definition StatusCode.h:314
StatusCode(StatusCode &&rhs) noexcept=default
Move constructor.
bool isRecoverable() const
Definition StatusCode.h:318
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:221
code_t getCode() const
Retrieve value.
Definition StatusCode.h:136
The category assigned to a StatusCode.
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