The Gaudi Framework  v33r0 (d5ea422b)
StatusCode.h
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2019 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 StatusCode final {
62 public:
63  typedef unsigned long code_t;
64 
65  enum class ErrorCode : code_t { FAILURE = 0, SUCCESS = 1, RECOVERABLE = 2 };
66 
74  struct Category {
75  constexpr Category() noexcept = default;
76  virtual ~Category() {}
77 
79  virtual const char* name() const = 0;
80 
82  virtual std::string message( code_t code ) const { return "UNKNOWN(" + std::to_string( code ) + ")"; }
83 
86  virtual bool isSuccess( code_t code ) const { return code == static_cast<code_t>( ErrorCode::SUCCESS ); }
87 
89  virtual bool isRecoverable( code_t code ) const { return code == static_cast<code_t>( ErrorCode::RECOVERABLE ); }
90  };
91 
93  static const Category& default_category() noexcept;
94 
95  // Provide shorthands for default code values
96  constexpr const static auto SUCCESS = ErrorCode::SUCCESS;
97  constexpr const static auto FAILURE = ErrorCode::FAILURE;
98  constexpr const static auto RECOVERABLE = ErrorCode::RECOVERABLE;
99 
101  StatusCode() = default;
102 
104  template <typename T, typename = std::enable_if_t<is_StatusCode_enum<T>::value>>
105  StatusCode( T sc, bool checked = false ) noexcept {
106  *this = StatusCode( static_cast<StatusCode::code_t>( sc ), is_StatusCode_enum<T>::instance );
107  m_checked = checked;
108  }
109 
111  explicit StatusCode( code_t code, const StatusCode::Category& cat = default_category(),
112  bool checked = false ) noexcept
113  : m_cat( &cat ), m_code( code ), m_checked( checked ) {}
114 
116  explicit StatusCode( code_t code, bool checked ) noexcept : StatusCode( code, default_category(), checked ) {}
117 
119  StatusCode( const StatusCode& rhs ) noexcept : m_cat( rhs.m_cat ), m_code( rhs.m_code ), m_checked( rhs.m_checked ) {
120  rhs.m_checked = true;
121  }
122 
124  StatusCode( StatusCode&& rhs ) noexcept : m_cat( rhs.m_cat ), m_code( rhs.m_code ), m_checked( rhs.m_checked ) {
125  rhs.m_checked = true;
126  }
127 
130  if ( UNLIKELY( s_checking ) ) check();
131  }
132 
133  StatusCode& operator=( const StatusCode& rhs ) noexcept {
134  m_cat = rhs.m_cat;
135  m_code = rhs.m_code;
136  m_checked = std::exchange( rhs.m_checked, true );
137  return *this;
138  }
139 
140  bool isSuccess() const;
141  bool isFailure() const { return !isSuccess(); }
142  bool isRecoverable() const;
143 
145  explicit operator bool() const { return isSuccess(); }
146 
148  code_t getCode() const {
149  m_checked = true;
150  return m_code;
151  }
152 
154  const StatusCode& setChecked( bool checked = true ) const {
155  m_checked = checked;
156  return *this;
157  }
158  StatusCode& setChecked( bool checked = true ) {
159  m_checked = checked;
160  return *this;
161  }
162 
164  const StatusCode& ignore() const {
165  setChecked( true );
166  return *this;
167  }
169  setChecked( true );
170  return *this;
171  }
172 
193  template <typename F, typename... ARGS>
194  StatusCode andThen( F&& f, ARGS&&... args ) const {
195  if ( isFailure() ) return *this;
196  return i_invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
197  }
198 
215  template <typename F, typename... ARGS>
216  StatusCode orElse( F&& f, ARGS&&... args ) const {
217  if ( isSuccess() ) return *this;
218  return i_invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
219  }
220 
238  return orElse( &StatusCode::i_doThrow, this, std::move( message ), std::move( tag ) );
239  }
240 
242  bool checked() const { return m_checked; }
243 
245  const StatusCode::Category& getCategory() const { return *m_cat; }
246 
248  std::string message() const { return getCategory().message( m_code ); }
249 
251  s << sc.message();
252  return s;
253  }
254 
258  friend bool operator==( const StatusCode& lhs, const StatusCode& rhs );
259  friend bool operator!=( const StatusCode& lhs, const StatusCode& rhs ) { return !( lhs == rhs ); }
260 
262  friend bool operator<( const StatusCode& lhs, const StatusCode& rhs ) {
263  lhs.m_checked = true;
264  rhs.m_checked = true;
265  return ( lhs.m_cat < rhs.m_cat || ( lhs.m_cat == rhs.m_cat && lhs.m_code < rhs.m_code ) );
266  }
267 
269  StatusCode& operator&=( const StatusCode& rhs );
270  StatusCode& operator|=( const StatusCode& rhs );
271 
272  static GAUDI_API void enableChecking();
273  static GAUDI_API void disableChecking();
274  static GAUDI_API bool checkingEnabled();
275 
291  bool m_enabled;
292 
293  public:
296  }
299  }
300  };
301 
302 private:
304  code_t m_code{static_cast<code_t>( ErrorCode::SUCCESS )};
305  mutable bool m_checked{false};
306  static bool s_checking;
307 
308  ErrorCode default_value() const;
309  void check();
310 
312  void i_doThrow( std::string message, std::string tag ) const;
313 
315  template <typename F, typename... ARGS, typename = std::enable_if_t<std::is_invocable_v<F, ARGS...>>>
316  StatusCode i_invoke( F&& f, ARGS&&... args ) const {
317  if constexpr ( std::is_invocable_r_v<StatusCode, F, ARGS...> ) {
318  return std::invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
319  } else {
320  // static_assert( std::is_same_v<void,std::invoke_result_t<F,ARGS...>>); // how paranoid should this be?
321  std::invoke( std::forward<F>( f ), std::forward<ARGS>( args )... );
322  return *this;
323  }
324  }
325 };
326 
327 /*
328  * Macros to declare/implement StatusCode enums/categories
329  */
330 
333 #define STATUSCODE_ENUM_DECL( ENUM ) \
334  template <> \
335  struct is_StatusCode_enum<ENUM> : std::true_type { \
336  static const StatusCode::Category& instance; \
337  };
338 
342 #define STATUSCODE_ENUM_IMPL( ... ) BOOST_PP_OVERLOAD( STATUSCODE_ENUM_IMPL_, __VA_ARGS__ )( __VA_ARGS__ )
343 
344 #define STATUSCODE_ENUM_IMPL_1( ENUM ) \
345  const StatusCode::Category& is_StatusCode_enum<ENUM>::instance = StatusCode::default_category();
346 
347 #define STATUSCODE_ENUM_IMPL_2( ENUM, CATEGORY ) \
348  const StatusCode::Category& is_StatusCode_enum<ENUM>::instance = CATEGORY{};
349 
350 // Declare the default StatusCode enum
352 
353 /*
354  * Inline methods
355  */
356 
357 inline const StatusCode::Category& StatusCode::default_category() noexcept {
359 }
360 
361 inline bool StatusCode::isSuccess() const {
362  m_checked = true;
363  return ( m_code == static_cast<code_t>( ErrorCode::SUCCESS ) || m_cat->isSuccess( m_code ) );
364 }
365 
366 inline bool StatusCode::isRecoverable() const {
367  m_checked = true;
368  return m_cat->isRecoverable( m_code );
369 }
370 
372  bool save_checked = m_checked; // Preserve checked status
374  m_checked = save_checked;
375  return r;
376 }
377 
378 inline bool operator==( const StatusCode& lhs, const StatusCode& rhs ) {
379  lhs.m_checked = true;
380  rhs.m_checked = true;
381  return ( lhs.m_code == rhs.m_code ) &&
382  ( lhs.m_code == static_cast<StatusCode::code_t>( StatusCode::ErrorCode::SUCCESS ) ||
383  lhs.m_code == static_cast<StatusCode::code_t>( StatusCode::ErrorCode::FAILURE ) ||
384  ( lhs.m_cat == rhs.m_cat ) );
385 }
386 
388  // Ternary AND lookup matrix
389  static constexpr StatusCode::code_t AND[3][3] = {{0, 0, 0}, {0, 1, 2}, {0, 2, 2}};
390 
391  StatusCode::code_t l = static_cast<StatusCode::code_t>( default_value() );
392  StatusCode::code_t r = static_cast<StatusCode::code_t>( rhs.default_value() );
393  m_code = AND[l][r];
394  rhs.m_checked = true;
395  return *this;
396 }
397 
399  // Ternary OR lookup matrix
400  static constexpr StatusCode::code_t OR[3][3] = {{0, 1, 2}, {1, 1, 1}, {2, 1, 2}};
401 
402  StatusCode::code_t l = static_cast<StatusCode::code_t>( default_value() );
403  StatusCode::code_t r = static_cast<StatusCode::code_t>( rhs.default_value() );
404  m_code = OR[l][r];
405  rhs.m_checked = true;
406  return *this;
407 }
408 
410 inline StatusCode operator&( StatusCode lhs, const StatusCode& rhs ) { return lhs &= rhs; }
411 
413 inline StatusCode operator|( StatusCode lhs, const StatusCode& rhs ) { return lhs |= rhs; }
414 
416 inline bool& operator&=( bool& lhs, const StatusCode& sc ) { return lhs &= sc.isSuccess(); }
417 
419 inline bool& operator|=( bool& lhs, const StatusCode& sc ) { return lhs |= sc.isSuccess(); }
420 
421 #endif // GAUDIKERNEL_STATUSCODE_H
code_t getCode() const
Retrieve value ("checks" the StatusCode)
Definition: StatusCode.h:148
#define UNLIKELY(x)
Definition: Kernel.h:106
bool checked() const
Has the StatusCode been checked?
Definition: StatusCode.h:242
StatusCode operator|(StatusCode lhs, const StatusCode &rhs)
Ternary OR operator.
Definition: StatusCode.h:413
void check()
Do StatusCode check.
Definition: StatusCode.cpp:59
code_t m_code
The status code value.
Definition: StatusCode.h:304
friend bool operator<(const StatusCode &lhs, const StatusCode &rhs)
Comparison (values are grouped by category first)
Definition: StatusCode.h:262
bool m_checked
If the StatusCode has been checked.
Definition: StatusCode.h:305
The category assigned to a StatusCode.
Definition: StatusCode.h:74
constexpr static const auto RECOVERABLE
Definition: StatusCode.h:98
StatusCode & operator=(const StatusCode &rhs) noexcept
Definition: StatusCode.h:133
T to_string(T... args)
StatusCode(code_t code, const StatusCode::Category &cat=default_category(), bool checked=false) noexcept
Constructor from code_t in the default category (explicit conversion only)
Definition: StatusCode.h:111
constexpr static const auto SUCCESS
Definition: StatusCode.h:96
virtual const char * name() const =0
Name of the category.
STL namespace.
~StatusCode()
Destructor.
Definition: StatusCode.h:129
StatusCode(code_t code, bool checked) noexcept
Constructor from code_t and category (explicit conversion only)
Definition: StatusCode.h:116
static GAUDI_API void enableChecking()
Definition: StatusCode.cpp:53
StatusCode(const StatusCode &rhs) noexcept
Copy constructor.
Definition: StatusCode.h:119
static GAUDI_API bool checkingEnabled()
Definition: StatusCode.cpp:57
StatusCode & setChecked(bool checked=true)
Definition: StatusCode.h:158
StatusCode andThen(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a success result.
Definition: StatusCode.h:194
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:316
const StatusCode::Category & getCategory() const
Retrieve category (does not "check" the StatusCode)
Definition: StatusCode.h:245
virtual bool isSuccess(code_t code) const
Is code considered success ?
Definition: StatusCode.h:86
STL class.
friend std::ostream & operator<<(std::ostream &s, const StatusCode &sc)
Definition: StatusCode.h:250
StatusCode & ignore()
Definition: StatusCode.h:168
#define STATUSCODE_ENUM_DECL(ENUM)
Declare an enum to be used as StatusCode value.
Definition: StatusCode.h:333
virtual ~Category()
Definition: StatusCode.h:76
virtual std::string message(code_t code) const
Description for code within this category.
Definition: StatusCode.h:82
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:61
virtual bool isRecoverable(code_t code) const
Is code considered recoverable ?
Definition: StatusCode.h:89
friend bool operator!=(const StatusCode &lhs, const StatusCode &rhs)
Definition: StatusCode.h:259
static const Category & default_category() noexcept
Default Gaudi StatusCode category.
Definition: StatusCode.h:357
Simple RAII class to ignore unchecked StatusCode instances in a scope.
Definition: StatusCode.h:290
static bool s_checking
Global flag to control if StatusCode need to be checked.
Definition: StatusCode.h:306
bool isSuccess() const
Definition: StatusCode.h:361
T move(T... args)
std::string message() const
Description (or name) of StatusCode value.
Definition: StatusCode.h:248
dictionary l
Definition: gaudirun.py:543
StatusCode operator &(StatusCode lhs, const StatusCode &rhs)
Ternary AND operator.
Definition: StatusCode.h:410
bool operator==(const StatusCode &lhs, const StatusCode &rhs)
Definition: StatusCode.h:378
const StatusCode & ignore() const
Ignore/check StatusCode.
Definition: StatusCode.h:164
friend bool operator==(const StatusCode &lhs, const StatusCode &rhs)
Check if StatusCode value and category are the same.
Definition: StatusCode.h:378
StatusCode orThrow(std::string message, std::string tag) const
Throw a GaudiException in case of failures.
Definition: StatusCode.h:237
constexpr Category() noexcept=default
bool & operator|=(bool &lhs, const StatusCode &sc)
Boolean OR assignment operator.
Definition: StatusCode.h:419
string s
Definition: gaudirun.py:328
bool isRecoverable() const
Definition: StatusCode.h:366
constexpr static const auto FAILURE
Definition: StatusCode.h:97
static GAUDI_API void disableChecking()
Definition: StatusCode.cpp:55
StatusCode()=default
Default constructor.
bool isFailure() const
Definition: StatusCode.h:141
bool & operator&=(bool &lhs, const StatusCode &sc)
Boolean AND assignment operator.
Definition: StatusCode.h:416
StatusCode(StatusCode &&rhs) noexcept
Move constructor.
Definition: StatusCode.h:124
#define GAUDI_API
Definition: Kernel.h:81
STL class.
void i_doThrow(std::string message, std::string tag) const
Helper function to avoid circular dependency between GaudiException.h and StatusCode....
Definition: StatusCode.cpp:92
const StatusCode & setChecked(bool checked=true) const
Check/uncheck StatusCode.
Definition: StatusCode.h:154
ErrorCode default_value() const
Project onto the default StatusCode values.
Definition: StatusCode.h:371
const Category * m_cat
The status code category.
Definition: StatusCode.h:303
StatusCode & operator|=(const StatusCode &rhs)
Ternary logic operator with RECOVERABLE being the "third" state.
Definition: StatusCode.h:398
StatusCode & operator&=(const StatusCode &rhs)
Ternary logic operator with RECOVERABLE being the "third" state.
Definition: StatusCode.h:387
StatusCode orElse(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a failure result.
Definition: StatusCode.h:216
unsigned long code_t
type of StatusCode value
Definition: StatusCode.h:63