File indexing completed on 2025-09-18 09:13:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef GAUDIKERNEL_STATUSCODE_H
0012 #define GAUDIKERNEL_STATUSCODE_H
0013
0014 #include <boost/preprocessor/facilities/overload.hpp>
0015 #include <functional>
0016 #include <ostream>
0017 #include <type_traits>
0018 #include <utility>
0019
0020 #include <GaudiKernel/Kernel.h>
0021
0022 template <typename T>
0023 struct is_StatusCode_enum : std::false_type {};
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061 class
0062 #if !defined( __CLING__ )
0063 [[nodiscard]]
0064 #endif
0065 StatusCode final {
0066 public:
0067 typedef unsigned long code_t;
0068
0069 enum class ErrorCode : code_t { FAILURE = 0, SUCCESS = 1, RECOVERABLE = 2 };
0070
0071
0072
0073
0074
0075
0076
0077
0078 struct Category {
0079 constexpr Category() noexcept = default;
0080 virtual ~Category() {}
0081
0082
0083 virtual const char* name() const = 0;
0084
0085
0086 virtual std::string message( code_t code ) const { return "UNKNOWN(" + std::to_string( code ) + ")"; }
0087
0088
0089
0090 virtual bool isSuccess( code_t code ) const { return code == static_cast<code_t>( ErrorCode::SUCCESS ); }
0091
0092
0093 virtual bool isRecoverable( code_t code ) const { return code == static_cast<code_t>( ErrorCode::RECOVERABLE ); }
0094 };
0095
0096
0097 static const Category& default_category() noexcept;
0098
0099
0100 constexpr const static auto SUCCESS = ErrorCode::SUCCESS;
0101 constexpr const static auto FAILURE = ErrorCode::FAILURE;
0102 constexpr const static auto RECOVERABLE = ErrorCode::RECOVERABLE;
0103
0104
0105 StatusCode() = default;
0106
0107
0108 template <typename T>
0109 requires( is_StatusCode_enum<T>::value )
0110 StatusCode( T sc ) noexcept : StatusCode{ static_cast<StatusCode::code_t>( sc ), is_StatusCode_enum<T>::instance } {}
0111
0112
0113 explicit StatusCode( code_t code, const StatusCode::Category& cat ) noexcept : m_cat( &cat ), m_code( code ) {}
0114
0115
0116 explicit StatusCode( code_t code ) noexcept : StatusCode( code, default_category() ) {}
0117
0118
0119 StatusCode( const StatusCode& rhs ) noexcept = default;
0120
0121
0122 StatusCode( StatusCode&& rhs ) noexcept = default;
0123
0124
0125 ~StatusCode() = default;
0126
0127 StatusCode& operator=( const StatusCode& rhs ) noexcept = default;
0128
0129 bool isSuccess() const;
0130 bool isFailure() const { return !isSuccess(); }
0131 bool isRecoverable() const;
0132
0133
0134 explicit operator bool() const { return isSuccess(); }
0135
0136
0137 code_t getCode() const { return m_code; }
0138
0139
0140 const StatusCode& ignore() const { return *this; }
0141 StatusCode& ignore() { return *this; }
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163 template <typename F, typename... ARGS>
0164 StatusCode andThen( F&& f, ARGS&&... args ) const {
0165 if ( isFailure() ) return *this;
0166 return i_invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
0167 }
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185 template <typename F, typename... ARGS>
0186 StatusCode orElse( F&& f, ARGS&&... args ) const {
0187 if ( isSuccess() ) return *this;
0188 return i_invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
0189 }
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207 const StatusCode& orThrow( std::string_view message, std::string_view tag ) const {
0208 if ( isFailure() ) i_doThrow( message, tag );
0209 return *this;
0210 }
0211
0212
0213
0214
0215
0216 const StatusCode& orThrow( std::string_view tag = "" ) const {
0217 if ( isFailure() ) i_doThrow( message(), tag );
0218 return *this;
0219 }
0220
0221
0222 const StatusCode::Category& getCategory() const { return *m_cat; }
0223
0224
0225 std::string message() const { return getCategory().message( m_code ); }
0226
0227 friend std::ostream& operator<<( std::ostream& s, const StatusCode& sc ) {
0228 s << sc.message();
0229 return s;
0230 }
0231
0232
0233
0234
0235 friend bool operator==( const StatusCode& lhs, const StatusCode& rhs );
0236 friend bool operator!=( const StatusCode& lhs, const StatusCode& rhs ) { return !( lhs == rhs ); }
0237
0238
0239 friend bool operator<( const StatusCode& lhs, const StatusCode& rhs ) {
0240 return ( lhs.m_cat < rhs.m_cat || ( lhs.m_cat == rhs.m_cat && lhs.m_code < rhs.m_code ) );
0241 }
0242
0243
0244 StatusCode& operator&=( const StatusCode& rhs );
0245 StatusCode& operator|=( const StatusCode& rhs );
0246
0247
0248 friend StatusCode operator&( StatusCode lhs, const StatusCode& rhs ) { return lhs &= rhs; }
0249
0250
0251 friend StatusCode operator|( StatusCode lhs, const StatusCode& rhs ) { return lhs |= rhs; }
0252
0253
0254 friend bool& operator&=( bool& lhs, const StatusCode& sc ) { return lhs &= sc.isSuccess(); }
0255
0256
0257 friend bool& operator|=( bool& lhs, const StatusCode& sc ) { return lhs |= sc.isSuccess(); }
0258
0259 private:
0260 const Category* m_cat{ &default_category() };
0261 code_t m_code{ static_cast<code_t>( ErrorCode::SUCCESS ) };
0262
0263 ErrorCode default_value() const;
0264
0265
0266 [[noreturn]] void i_doThrow( std::string_view message, std::string_view tag ) const;
0267
0268
0269 template <typename... ARGS, std::invocable<ARGS...> F>
0270 StatusCode i_invoke( F&& f, ARGS&&... args ) const {
0271 if constexpr ( std::is_invocable_r_v<StatusCode, F, ARGS...> ) {
0272 return std::invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
0273 } else {
0274
0275 std::invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
0276 return *this;
0277 }
0278 }
0279 };
0280
0281
0282
0283
0284
0285
0286
0287 #define STATUSCODE_ENUM_DECL( ENUM ) \
0288 template <> \
0289 struct is_StatusCode_enum<ENUM> : std::true_type { \
0290 static const StatusCode::Category& instance; \
0291 };
0292
0293
0294
0295
0296 #define STATUSCODE_ENUM_IMPL( ... ) BOOST_PP_OVERLOAD( STATUSCODE_ENUM_IMPL_, __VA_ARGS__ )( __VA_ARGS__ )
0297
0298 #define STATUSCODE_ENUM_IMPL_1( ENUM ) \
0299 const StatusCode::Category& is_StatusCode_enum<ENUM>::instance = StatusCode::default_category();
0300
0301 #define STATUSCODE_ENUM_IMPL_2( ENUM, CATEGORY ) \
0302 const StatusCode::Category& is_StatusCode_enum<ENUM>::instance = CATEGORY{};
0303
0304
0305 STATUSCODE_ENUM_DECL( StatusCode::ErrorCode )
0306
0307
0308
0309
0310
0311 inline const StatusCode::Category& StatusCode::default_category() noexcept {
0312 return is_StatusCode_enum<StatusCode::ErrorCode>::instance;
0313 }
0314
0315 inline bool StatusCode::isSuccess() const {
0316 return ( m_code == static_cast<code_t>( ErrorCode::SUCCESS ) || m_cat->isSuccess( m_code ) );
0317 }
0318
0319 inline bool StatusCode::isRecoverable() const { return m_cat->isRecoverable( m_code ); }
0320
0321 inline StatusCode::ErrorCode StatusCode::default_value() const {
0322 auto r = isSuccess() ? ErrorCode::SUCCESS : ( isRecoverable() ? ErrorCode::RECOVERABLE : ErrorCode::FAILURE );
0323 return r;
0324 }
0325
0326 inline bool operator==( const StatusCode& lhs, const StatusCode& rhs ) {
0327 return ( lhs.m_code == rhs.m_code ) &&
0328 ( lhs.m_code == static_cast<StatusCode::code_t>( StatusCode::ErrorCode::SUCCESS ) ||
0329 lhs.m_code == static_cast<StatusCode::code_t>( StatusCode::ErrorCode::FAILURE ) ||
0330 ( lhs.m_cat == rhs.m_cat ) );
0331 }
0332
0333 inline StatusCode& StatusCode::operator&=( const StatusCode& rhs ) {
0334
0335 static constexpr StatusCode::code_t AND[3][3] = { { 0, 0, 0 }, { 0, 1, 2 }, { 0, 2, 2 } };
0336
0337 StatusCode::code_t l = static_cast<StatusCode::code_t>( default_value() );
0338 StatusCode::code_t r = static_cast<StatusCode::code_t>( rhs.default_value() );
0339 m_code = AND[l][r];
0340 return *this;
0341 }
0342
0343 inline StatusCode& StatusCode::operator|=( const StatusCode& rhs ) {
0344
0345 static constexpr StatusCode::code_t OR[3][3] = { { 0, 1, 2 }, { 1, 1, 1 }, { 2, 1, 2 } };
0346
0347 StatusCode::code_t l = static_cast<StatusCode::code_t>( default_value() );
0348 StatusCode::code_t r = static_cast<StatusCode::code_t>( rhs.default_value() );
0349 m_code = OR[l][r];
0350 return *this;
0351 }
0352
0353 #endif