Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  v36r1 (3e2fb5a8)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
StatusCode.h
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2021 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 #ifndef GAUDIKERNEL_STATUSCODE_H
12 #define GAUDIKERNEL_STATUSCODE_H
13 
14 #include "boost/preprocessor/facilities/overload.hpp"
15 #include <functional>
16 #include <ostream>
17 #include <type_traits>
18 #include <utility>
19 
20 #include "GaudiKernel/Kernel.h"
21 
22 template <typename T>
24 
61 class
62 #if __cplusplus >= 201703L && !defined( __CLING__ )
63  [[nodiscard]]
64 #endif
65  StatusCode final {
66 public:
67  typedef unsigned long code_t;
68 
69  enum class ErrorCode : code_t { FAILURE = 0, SUCCESS = 1, RECOVERABLE = 2 };
70 
78  struct Category {
79  constexpr Category() noexcept = default;
80  virtual ~Category() {}
81 
83  virtual const char* name() const = 0;
84 
86  virtual std::string message( code_t code ) const { return "UNKNOWN(" + std::to_string( code ) + ")"; }
87 
90  virtual bool isSuccess( code_t code ) const { return code == static_cast<code_t>( ErrorCode::SUCCESS ); }
91 
93  virtual bool isRecoverable( code_t code ) const { return code == static_cast<code_t>( ErrorCode::RECOVERABLE ); }
94  };
95 
97  static const Category& default_category() noexcept;
98 
99  // Provide shorthands for default code values
100  constexpr const static auto SUCCESS = ErrorCode::SUCCESS;
101  constexpr const static auto FAILURE = ErrorCode::FAILURE;
102  constexpr const static auto RECOVERABLE = ErrorCode::RECOVERABLE;
103 
106 
108  template <typename T, typename = std::enable_if_t<is_StatusCode_enum<T>::value>>
109  StatusCode( T sc ) noexcept : StatusCode{static_cast<StatusCode::code_t>( sc ), is_StatusCode_enum<T>::instance} {}
110 
112  template <typename T, typename = std::enable_if_t<is_StatusCode_enum<T>::value>>
113  [[deprecated( "use StatusCode(T) instead" )]] StatusCode( T sc, bool ) noexcept : StatusCode{sc} {}
114 
116  explicit StatusCode( code_t code, const StatusCode::Category& cat ) noexcept : m_cat( &cat ), m_code( code ) {}
117 
119  [[deprecated( "use StatusCode(code_t, Category) instead" )]] explicit StatusCode(
120  code_t code, const StatusCode::Category& cat, bool ) noexcept
121  : StatusCode{code, cat} {}
122 
124  explicit StatusCode( code_t code ) noexcept : StatusCode( code, default_category() ) {}
125 
127  [[deprecated( "use StatusCode(code_t) instead" )]] explicit StatusCode( code_t code, bool ) noexcept
128  : StatusCode{code} {}
129 
131  StatusCode( const StatusCode& rhs ) noexcept = default;
132 
134  StatusCode( StatusCode && rhs ) noexcept = default;
135 
137  ~StatusCode() = default;
138 
139  StatusCode& operator=( const StatusCode& rhs ) noexcept = default;
140 
141  bool isSuccess() const;
142  bool isFailure() const { return !isSuccess(); }
143  bool isRecoverable() const;
144 
146  explicit operator bool() const { return isSuccess(); }
147 
149  code_t getCode() const { return m_code; }
150 
152  [[deprecated( "will be removed" )]] const StatusCode& setChecked( bool = true ) const { return *this; }
153  [[deprecated( "will be removed" )]] StatusCode& setChecked( bool = true ) { return *this; }
154 
156  const StatusCode& ignore() const { return *this; }
157  StatusCode& ignore() { return *this; }
158 
179  template <typename F, typename... ARGS>
180  StatusCode andThen( F && f, ARGS && ... args ) const {
181  if ( isFailure() ) return *this;
182  return i_invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
183  }
184 
201  template <typename F, typename... ARGS>
202  StatusCode orElse( F && f, ARGS && ... args ) const {
203  if ( isSuccess() ) return *this;
204  return i_invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
205  }
206 
223  const StatusCode& orThrow( std::string_view message, std::string_view tag ) const {
224  if ( isFailure() ) i_doThrow( message, tag );
225  return *this;
226  }
227 
232  const StatusCode& orThrow( std::string_view tag = "" ) const {
233  if ( isFailure() ) i_doThrow( message(), tag ); // make sure `message()` is only called on error path
234  return *this;
235  }
236 
238  [[deprecated( "will be removed" )]] bool checked() const { return true; }
239 
241  const StatusCode::Category& getCategory() const { return *m_cat; }
242 
244  std::string message() const { return getCategory().message( m_code ); }
245 
247  s << sc.message();
248  return s;
249  }
250 
254  friend bool operator==( const StatusCode& lhs, const StatusCode& rhs );
255  friend bool operator!=( const StatusCode& lhs, const StatusCode& rhs ) { return !( lhs == rhs ); }
256 
258  friend bool operator<( const StatusCode& lhs, const StatusCode& rhs ) {
259  return ( lhs.m_cat < rhs.m_cat || ( lhs.m_cat == rhs.m_cat && lhs.m_code < rhs.m_code ) );
260  }
261 
263  StatusCode& operator&=( const StatusCode& rhs );
264  StatusCode& operator|=( const StatusCode& rhs );
265  //
267  friend StatusCode operator&( StatusCode lhs, const StatusCode& rhs ) { return lhs &= rhs; }
268 
270  friend StatusCode operator|( StatusCode lhs, const StatusCode& rhs ) { return lhs |= rhs; }
271 
273  friend bool& operator&=( bool& lhs, const StatusCode& sc ) { return lhs &= sc.isSuccess(); }
274 
276  friend bool& operator|=( bool& lhs, const StatusCode& sc ) { return lhs |= sc.isSuccess(); }
277 
278  [[deprecated( "will be removed" )]] static GAUDI_API void enableChecking();
279  [[deprecated( "will be removed" )]] static GAUDI_API void disableChecking();
280  [[deprecated( "will be removed" )]] static GAUDI_API bool checkingEnabled();
281 
296  class [[deprecated( "will be removed" )]] ScopedDisableChecking{};
297 
298 private:
299  const Category* m_cat{&default_category()};
300  code_t m_code{static_cast<code_t>( ErrorCode::SUCCESS )};
301 
302  ErrorCode default_value() const;
303  void check();
304 
306  [[noreturn]] void i_doThrow( std::string_view message, std::string_view tag ) const;
307 
309  template <typename F, typename... ARGS, typename = std::enable_if_t<std::is_invocable_v<F, ARGS...>>>
310  StatusCode i_invoke( F && f, ARGS && ... args ) const {
311  if constexpr ( std::is_invocable_r_v<StatusCode, F, ARGS...> ) {
312  return std::invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
313  } else {
314  // static_assert( std::is_same_v<void,std::invoke_result_t<F,ARGS...>>); // how paranoid should this be?
315  std::invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
316  return *this;
317  }
318  }
319 };
320 
321 /*
322  * Macros to declare/implement StatusCode enums/categories
323  */
324 
327 #define STATUSCODE_ENUM_DECL( ENUM ) \
328  template <> \
329  struct is_StatusCode_enum<ENUM> : std::true_type { \
330  static const StatusCode::Category& instance; \
331  };
332 
336 #define STATUSCODE_ENUM_IMPL( ... ) BOOST_PP_OVERLOAD( STATUSCODE_ENUM_IMPL_, __VA_ARGS__ )( __VA_ARGS__ )
337 
338 #define STATUSCODE_ENUM_IMPL_1( ENUM ) \
339  const StatusCode::Category& is_StatusCode_enum<ENUM>::instance = StatusCode::default_category();
340 
341 #define STATUSCODE_ENUM_IMPL_2( ENUM, CATEGORY ) \
342  const StatusCode::Category& is_StatusCode_enum<ENUM>::instance = CATEGORY{};
343 
344 // Declare the default StatusCode enum
346 
347 /*
348  * Inline methods
349  */
350 
351 inline const StatusCode::Category& StatusCode::default_category() noexcept {
353 }
354 
355 inline bool StatusCode::isSuccess() const {
356  return ( m_code == static_cast<code_t>( ErrorCode::SUCCESS ) || m_cat->isSuccess( m_code ) );
357 }
358 
359 inline bool StatusCode::isRecoverable() const { return m_cat->isRecoverable( m_code ); }
360 
363  return r;
364 }
365 
366 inline bool operator==( const StatusCode& lhs, const StatusCode& rhs ) {
367  return ( lhs.m_code == rhs.m_code ) &&
368  ( lhs.m_code == static_cast<StatusCode::code_t>( StatusCode::ErrorCode::SUCCESS ) ||
370  ( lhs.m_cat == rhs.m_cat ) );
371 }
372 
374  // Ternary AND lookup matrix
375  static constexpr StatusCode::code_t AND[3][3] = {{0, 0, 0}, {0, 1, 2}, {0, 2, 2}};
376 
378  StatusCode::code_t r = static_cast<StatusCode::code_t>( rhs.default_value() );
379  m_code = AND[l][r];
380  return *this;
381 }
382 
384  // Ternary OR lookup matrix
385  static constexpr StatusCode::code_t OR[3][3] = {{0, 1, 2}, {1, 1, 1}, {2, 1, 2}};
386 
388  StatusCode::code_t r = static_cast<StatusCode::code_t>( rhs.default_value() );
389  m_code = OR[l][r];
390  return *this;
391 }
392 
393 #endif // GAUDIKERNEL_STATUSCODE_H
GaudiPython.Bindings.FAILURE
FAILURE
Definition: Bindings.py:71
StatusCode::getCategory
const StatusCode::Category & getCategory() const
Retrieve category (does not "check" the StatusCode)
Definition: StatusCode.h:241
StatusCode::ErrorCode::SUCCESS
@ SUCCESS
StatusCode::Category::Category
constexpr Category() noexcept=default
GaudiHive.precedence.message
message
Definition: precedence.py:21
StatusCode::isRecoverable
bool isRecoverable() const
Definition: StatusCode.h:359
std::false_type
StatusCode::i_invoke
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:310
std::string
STL class.
StatusCode::Category::isSuccess
virtual bool isSuccess(code_t code) const
Is code considered success ?
Definition: StatusCode.h:90
StatusCode::andThen
StatusCode andThen(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a success result.
Definition: StatusCode.h:180
StatusCode::orThrow
const StatusCode & orThrow(std::string_view message, std::string_view tag) const
Throw a GaudiException in case of failures.
Definition: StatusCode.h:223
StatusCode::isSuccess
bool isSuccess() const
Definition: StatusCode.h:355
StatusCode::checked
bool checked() const
Has the StatusCode been checked?
Definition: StatusCode.h:238
StatusCode::setChecked
StatusCode & setChecked(bool=true)
Definition: StatusCode.h:153
gaudirun.s
string s
Definition: gaudirun.py:328
StatusCode::operator|=
StatusCode & operator|=(const StatusCode &rhs)
Ternary logic operator with RECOVERABLE being the "third" state.
Definition: StatusCode.h:383
StatusCode::message
std::string message() const
Description (or name) of StatusCode value.
Definition: StatusCode.h:244
StatusCode::orElse
StatusCode orElse(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a failure result.
Definition: StatusCode.h:202
StatusCode::check
void check()
Do StatusCode check.
StatusCode::m_code
code_t m_code
The status code value.
Definition: StatusCode.h:300
StatusCode::operator!=
friend bool operator!=(const StatusCode &lhs, const StatusCode &rhs)
Definition: StatusCode.h:255
StatusCode::orThrow
const StatusCode & orThrow(std::string_view tag="") const
Throw a GaudiException in case of failures.
Definition: StatusCode.h:232
StatusCode::code_t
unsigned long code_t
type of StatusCode value
Definition: StatusCode.h:67
StatusCode::operator<
friend bool operator<(const StatusCode &lhs, const StatusCode &rhs)
Comparison (values are grouped by category first)
Definition: StatusCode.h:258
operator==
bool operator==(const StatusCode &lhs, const StatusCode &rhs)
Definition: StatusCode.h:366
StatusCode::StatusCode
StatusCode(T sc, bool) noexcept
Constructor from enum type (allowing implicit conversion)
Definition: StatusCode.h:113
gaudirun.default
default
Definition: gaudirun.py:181
StatusCode::operator&
friend StatusCode operator&(StatusCode lhs, const StatusCode &rhs)
Ternary AND operator.
Definition: StatusCode.h:267
StatusCode
Definition: StatusCode.h:65
StatusCode::Category
Definition: StatusCode.h:78
HistoDumpEx.r
r
Definition: HistoDumpEx.py:20
StatusCode::StatusCode
StatusCode(code_t code, const StatusCode::Category &cat) noexcept
Constructor from code_t and category (explicit conversion only)
Definition: StatusCode.h:116
std::ostream
STL class.
StatusCode::StatusCode
StatusCode(const StatusCode &rhs) noexcept=default
Copy constructor.
StatusCode::operator|
friend StatusCode operator|(StatusCode lhs, const StatusCode &rhs)
Ternary OR operator.
Definition: StatusCode.h:270
StatusCode::setChecked
const StatusCode & setChecked(bool=true) const
Check/uncheck StatusCode.
Definition: StatusCode.h:152
StatusCode::default_value
ErrorCode default_value() const
Project onto the default StatusCode values.
Definition: StatusCode.h:361
Gaudi::Tests::Histograms::CustomAxis::Category
Category
Definition: HistogramsTests.cpp:16
std::to_string
T to_string(T... args)
StatusCode::operator<<
friend std::ostream & operator<<(std::ostream &s, const StatusCode &sc)
Definition: StatusCode.h:246
StatusCode::operator&=
friend bool & operator&=(bool &lhs, const StatusCode &sc)
Boolean AND assignment operator.
Definition: StatusCode.h:273
StatusCode::operator&=
StatusCode & operator&=(const StatusCode &rhs)
Ternary logic operator with RECOVERABLE being the "third" state.
Definition: StatusCode.h:373
StatusCode::ScopedDisableChecking
Simple RAII class to ignore unchecked StatusCode instances in a scope.
Definition: StatusCode.h:296
StatusCode::m_cat
const Category * m_cat
The status code category.
Definition: StatusCode.h:299
StatusCode::operator|=
friend bool & operator|=(bool &lhs, const StatusCode &sc)
Boolean OR assignment operator.
Definition: StatusCode.h:276
StatusCode::ignore
const StatusCode & ignore() const
Allow discarding a StatusCode without warning.
Definition: StatusCode.h:156
StatusCode::isFailure
bool isFailure() const
Definition: StatusCode.h:142
StatusCode::ErrorCode
ErrorCode
Definition: StatusCode.h:69
StatusCode::ignore
StatusCode & ignore()
Definition: StatusCode.h:157
STATUSCODE_ENUM_DECL
#define STATUSCODE_ENUM_DECL(ENUM)
Declare an enum to be used as StatusCode value.
Definition: StatusCode.h:327
gaudirun.l
dictionary l
Definition: gaudirun.py:553
StatusCode::ErrorCode::RECOVERABLE
@ RECOVERABLE
gaudirun.args
args
Definition: gaudirun.py:319
std
STL namespace.
Kernel.h
StatusCode::operator=
StatusCode & operator=(const StatusCode &rhs) noexcept=default
StatusCode::StatusCode
StatusCode(code_t code) noexcept
Constructor from code_t in the default category (explicit conversion only)
Definition: StatusCode.h:124
StatusCode::ErrorCode::FAILURE
@ FAILURE
StatusCode::StatusCode
StatusCode(code_t code, bool) noexcept
Constructor from code_t and category (explicit conversion only)
Definition: StatusCode.h:127
StatusCode::getCode
code_t getCode() const
Retrieve value ("checks" the StatusCode)
Definition: StatusCode.h:149
StatusCode::StatusCode
StatusCode(StatusCode &&rhs) noexcept=default
Move constructor.
StatusCode::Category::name
virtual const char * name() const =0
Name of the category.
is_StatusCode_enum
Definition: StatusCode.h:23
bug_38882.SUCCESS
SUCCESS
Definition: bug_38882.py:23
StatusCode::~StatusCode
~StatusCode()=default
Destructor.
StatusCode::Category::isRecoverable
virtual bool isRecoverable(code_t code) const
Is code considered recoverable ?
Definition: StatusCode.h:93
StatusCode::StatusCode
StatusCode(code_t code, const StatusCode::Category &cat, bool) noexcept
Constructor from code_t in the default category (explicit conversion only)
Definition: StatusCode.h:119
GAUDI_API
#define GAUDI_API
Definition: Kernel.h:81
StatusCode::Category::message
virtual std::string message(code_t code) const
Description for code within this category.
Definition: StatusCode.h:86