File indexing completed on 2025-01-18 09:57:43
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 __cplusplus >= 201703L && !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, typename = std::enable_if_t<is_StatusCode_enum<T>::value>>
0109 StatusCode( T sc ) noexcept : StatusCode{ static_cast<StatusCode::code_t>( sc ), is_StatusCode_enum<T>::instance } {}
0110
0111
0112 explicit StatusCode( code_t code, const StatusCode::Category& cat ) noexcept : m_cat( &cat ), m_code( code ) {}
0113
0114
0115 explicit StatusCode( code_t code ) noexcept : StatusCode( code, default_category() ) {}
0116
0117
0118 StatusCode( const StatusCode& rhs ) noexcept = default;
0119
0120
0121 StatusCode( StatusCode&& rhs ) noexcept = default;
0122
0123
0124 ~StatusCode() = default;
0125
0126 StatusCode& operator=( const StatusCode& rhs ) noexcept = default;
0127
0128 bool isSuccess() const;
0129 bool isFailure() const { return !isSuccess(); }
0130 bool isRecoverable() const;
0131
0132
0133 explicit operator bool() const { return isSuccess(); }
0134
0135
0136 code_t getCode() const { return m_code; }
0137
0138
0139 const StatusCode& ignore() const { return *this; }
0140 StatusCode& ignore() { return *this; }
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162 template <typename F, typename... ARGS>
0163 StatusCode andThen( F&& f, ARGS&&... args ) const {
0164 if ( isFailure() ) return *this;
0165 return i_invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
0166 }
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184 template <typename F, typename... ARGS>
0185 StatusCode orElse( F&& f, ARGS&&... args ) const {
0186 if ( isSuccess() ) return *this;
0187 return i_invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
0188 }
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206 const StatusCode& orThrow( std::string_view message, std::string_view tag ) const {
0207 if ( isFailure() ) i_doThrow( message, tag );
0208 return *this;
0209 }
0210
0211
0212
0213
0214
0215 const StatusCode& orThrow( std::string_view tag = "" ) const {
0216 if ( isFailure() ) i_doThrow( message(), tag );
0217 return *this;
0218 }
0219
0220
0221 const StatusCode::Category& getCategory() const { return *m_cat; }
0222
0223
0224 std::string message() const { return getCategory().message( m_code ); }
0225
0226 friend std::ostream& operator<<( std::ostream& s, const StatusCode& sc ) {
0227 s << sc.message();
0228 return s;
0229 }
0230
0231
0232
0233
0234 friend bool operator==( const StatusCode& lhs, const StatusCode& rhs );
0235 friend bool operator!=( const StatusCode& lhs, const StatusCode& rhs ) { return !( lhs == rhs ); }
0236
0237
0238 friend bool operator<( const StatusCode& lhs, const StatusCode& rhs ) {
0239 return ( lhs.m_cat < rhs.m_cat || ( lhs.m_cat == rhs.m_cat && lhs.m_code < rhs.m_code ) );
0240 }
0241
0242
0243 StatusCode& operator&=( const StatusCode& rhs );
0244 StatusCode& operator|=( const StatusCode& rhs );
0245
0246
0247 friend StatusCode operator&( StatusCode lhs, const StatusCode& rhs ) { return lhs &= rhs; }
0248
0249
0250 friend StatusCode operator|( StatusCode lhs, const StatusCode& rhs ) { return lhs |= rhs; }
0251
0252
0253 friend bool& operator&=( bool& lhs, const StatusCode& sc ) { return lhs &= sc.isSuccess(); }
0254
0255
0256 friend bool& operator|=( bool& lhs, const StatusCode& sc ) { return lhs |= sc.isSuccess(); }
0257
0258 private:
0259 const Category* m_cat{ &default_category() };
0260 code_t m_code{ static_cast<code_t>( ErrorCode::SUCCESS ) };
0261
0262 ErrorCode default_value() const;
0263
0264
0265 [[noreturn]] void i_doThrow( std::string_view message, std::string_view tag ) const;
0266
0267
0268 template <typename F, typename... ARGS, typename = std::enable_if_t<std::is_invocable_v<F, ARGS...>>>
0269 StatusCode i_invoke( F&& f, ARGS&&... args ) const {
0270 if constexpr ( std::is_invocable_r_v<StatusCode, F, ARGS...> ) {
0271 return std::invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
0272 } else {
0273
0274 std::invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
0275 return *this;
0276 }
0277 }
0278 };
0279
0280
0281
0282
0283
0284
0285
0286 #define STATUSCODE_ENUM_DECL( ENUM ) \
0287 template <> \
0288 struct is_StatusCode_enum<ENUM> : std::true_type { \
0289 static const StatusCode::Category& instance; \
0290 };
0291
0292
0293
0294
0295 #define STATUSCODE_ENUM_IMPL( ... ) BOOST_PP_OVERLOAD( STATUSCODE_ENUM_IMPL_, __VA_ARGS__ )( __VA_ARGS__ )
0296
0297 #define STATUSCODE_ENUM_IMPL_1( ENUM ) \
0298 const StatusCode::Category& is_StatusCode_enum<ENUM>::instance = StatusCode::default_category();
0299
0300 #define STATUSCODE_ENUM_IMPL_2( ENUM, CATEGORY ) \
0301 const StatusCode::Category& is_StatusCode_enum<ENUM>::instance = CATEGORY{};
0302
0303
0304 STATUSCODE_ENUM_DECL( StatusCode::ErrorCode )
0305
0306
0307
0308
0309
0310 inline const StatusCode::Category& StatusCode::default_category() noexcept {
0311 return is_StatusCode_enum<StatusCode::ErrorCode>::instance;
0312 }
0313
0314 inline bool StatusCode::isSuccess() const {
0315 return ( m_code == static_cast<code_t>( ErrorCode::SUCCESS ) || m_cat->isSuccess( m_code ) );
0316 }
0317
0318 inline bool StatusCode::isRecoverable() const { return m_cat->isRecoverable( m_code ); }
0319
0320 inline StatusCode::ErrorCode StatusCode::default_value() const {
0321 auto r = isSuccess() ? ErrorCode::SUCCESS : ( isRecoverable() ? ErrorCode::RECOVERABLE : ErrorCode::FAILURE );
0322 return r;
0323 }
0324
0325 inline bool operator==( const StatusCode& lhs, const StatusCode& rhs ) {
0326 return ( lhs.m_code == rhs.m_code ) &&
0327 ( lhs.m_code == static_cast<StatusCode::code_t>( StatusCode::ErrorCode::SUCCESS ) ||
0328 lhs.m_code == static_cast<StatusCode::code_t>( StatusCode::ErrorCode::FAILURE ) ||
0329 ( lhs.m_cat == rhs.m_cat ) );
0330 }
0331
0332 inline StatusCode& StatusCode::operator&=( const StatusCode& rhs ) {
0333
0334 static constexpr StatusCode::code_t AND[3][3] = { { 0, 0, 0 }, { 0, 1, 2 }, { 0, 2, 2 } };
0335
0336 StatusCode::code_t l = static_cast<StatusCode::code_t>( default_value() );
0337 StatusCode::code_t r = static_cast<StatusCode::code_t>( rhs.default_value() );
0338 m_code = AND[l][r];
0339 return *this;
0340 }
0341
0342 inline StatusCode& StatusCode::operator|=( const StatusCode& rhs ) {
0343
0344 static constexpr StatusCode::code_t OR[3][3] = { { 0, 1, 2 }, { 1, 1, 1 }, { 2, 1, 2 } };
0345
0346 StatusCode::code_t l = static_cast<StatusCode::code_t>( default_value() );
0347 StatusCode::code_t r = static_cast<StatusCode::code_t>( rhs.default_value() );
0348 m_code = OR[l][r];
0349 return *this;
0350 }
0351
0352 #endif