Zero  0.1.0
w_rc.h
Go to the documentation of this file.
1 /*
2  * (c) Copyright 2014, Hewlett-Packard Development Company, LP
3  */
4 
5 #ifndef __W_RC_H
6 #define __W_RC_H
7 
49 #include <cstdint>
50 #include <memory.h> // for memcpy
51 #include <ostream> // for pretty-printing w_rc_t
52 #include <iostream> // for cout
53 #include <sstream> // for append
54 #include <cassert>
55 #include <cstdlib> // for abort
56 #include "w_error.h"
57 
62 const uint16_t MAX_RCT_STACK_DEPTH = 8;
63 
87 class w_rc_t {
88 public:
90  w_rc_t();
91 
100  explicit w_rc_t(w_error_codes error_code);
101 
112  w_rc_t(const char* filename, uint32_t linenum, w_error_codes error_code, const char* custom_message = nullptr);
113 
115  w_rc_t(const w_rc_t& other);
116 
118  w_rc_t(const w_rc_t& other, const char* filename, uint32_t linenum, const char* more_custom_message = nullptr);
119 
121  w_rc_t& operator=(w_rc_t const& other);
122 
124  ~w_rc_t();
125 
136  bool is_error() const;
137 
139  w_error_codes err_num() const;
140 
142  const char* get_message() const;
143 
145  const char* get_custom_message() const;
146 
148  void append_custom_message(const char* more_custom_message);
149 
151  uint16_t get_stack_depth() const;
152 
154  uint16_t get_linenum(uint16_t stack_index) const;
155 
157  const char* get_filename(uint16_t stack_index) const;
158 
160  void verify() const;
161 
166  void fatal() const;
167 
168 private:
169 
180 
183 
190  const char* _custom_message;
191 
200 
205  uint16_t _stack_depth;
206 
208  mutable bool _checked;
209 };
210 
211 typedef w_rc_t rc_t;
212 
213 inline std::ostream& operator<<(std::ostream& o, const w_rc_t& obj) {
214  if (obj.err_num() == w_error_ok) {
215  o << "No error";
216  } else {
217  o << w_error_name(obj.err_num()) << "(" << obj.err_num() << "):" << obj.get_message();
218  if (obj.get_custom_message() != nullptr) {
219  o << ":" << obj.get_custom_message();
220  }
221  for (uint16_t stack_index = 0; stack_index < obj.get_stack_depth(); ++stack_index) {
222  o << std::endl << " " << obj.get_filename(stack_index) << ":" << obj.get_linenum(stack_index);
223  }
224  if (obj.get_stack_depth() >= MAX_RCT_STACK_DEPTH) {
225  o << std::endl << " .. and more. Increase MAX_RCT_STACK_DEPTH to see full stacktraces";
226  }
227  }
228  return o;
229 }
230 
239 const w_rc_t RCOK;
240 
248 #define RC(e) w_rc_t(__FILE__, __LINE__, e)
249 
264 #define RC_AUGMENT(rc) w_rc_t(rc, __FILE__, __LINE__)
265 
275 #define RC_APPEND_MSG(rc, m) \
276 do { \
277  std::stringstream os; \
278  os m; \
279  rc.append_custom_message(os.str().c_str()); \
280 } while (0)
281 
287 #define W_RETURN_RC_MSG(e, m) \
288 do { \
289  w_rc_t __e(__FILE__, __LINE__, e); \
290  RC_APPEND_MSG(__e, m); \
291  return __e; \
292 } while (0)
293 
304 #define W_DO(x) \
305 do { \
306  w_rc_t __e(x); \
307  if (__e.is_error()) {return RC_AUGMENT(__e);} \
308 } while (0)
309 
318 #define W_DO_MSG(x, m) \
319 do { \
320  w_rc_t __e = (x); \
321  if (__e.is_error()) { \
322  RC_AUGMENT(__e); \
323  RC_APPEND_MSG(__e, m); \
324  return __e; \
325  } \
326 } while (0)
327 
349 #define W_COERCE(x) \
350 do { \
351  w_rc_t __e = (x); \
352  if (__e.is_error()) { \
353  __e = RC_AUGMENT(__e); \
354  __e.fatal(); \
355  } \
356 } while (0)
357 
363 #define W_COERCE_MSG(x, m) \
364 do { \
365  w_rc_t __em = (x); \
366  if (__em.is_error()) { \
367  __em = RC_AUGMENT(__em); \
368  RC_APPEND_MSG(__em, m); \
369  __em.fatal(); \
370  } \
371 } while (0)
372 
378 #define W_FATAL(e) W_COERCE(RC(e))
379 
385 #define W_FATAL_MSG(e, m) W_COERCE_MSG(RC(e), m)
386 
392 #define W_IGNORE(x) ((void) x.is_error())
393 
395  : _custom_message(nullptr),
397  _stack_depth(0),
398  _checked(true) {}
399 
400 inline w_rc_t::w_rc_t(w_error_codes error_code)
401  : _custom_message(nullptr),
402  _error_code(error_code),
403  _stack_depth(0),
404  _checked(false) {}
405 
406 inline w_rc_t::w_rc_t(const char* filename, uint32_t linenum, w_error_codes error_code, const char* custom_message)
407  : _custom_message(custom_message),
408  _error_code(error_code),
409  _stack_depth(1),
410  _checked(false) {
411  assert(error_code != w_error_ok);
412  _filenames[0] = filename;
413  _linenums[0] = linenum;
414 #if W_DEBUG_LEVEL >= 5
415  std::cout << "Error instantiated: " << *this << std::endl;
416 #endif //W_DEBUG_LEVEL>=3
417 }
418 
419 inline w_rc_t::w_rc_t(const w_rc_t& other) {
420  operator=(other);
421 }
422 
423 inline w_rc_t& w_rc_t::operator=(w_rc_t const& other) {
424  // Invariant: if w_error_ok, no more processing
425  if (other._error_code == w_error_ok) {
426  this->_error_code = w_error_ok;
427  return *this;
428  }
429 
430  // As we don't have any linked-list etc, mostly this is enough. Quick.
431  ::memcpy(this, &other, sizeof(w_rc_t)); // note, we take copy BEFORE mark other checked
432  other._checked = true;
433 
434  // except custom error message
435  if (other._custom_message != nullptr) {
436  // do NOT use strdup to make sure new/delete everywhere.
437  size_t len = ::strlen(other._custom_message);
438  char* copied = new char[len + 1]; // +1 for null terminator
439  this->_custom_message = copied;
440  ::memcpy(copied, other._custom_message, len + 1);
441  }
442  return *this;
443 }
444 
445 inline w_rc_t::w_rc_t(const w_rc_t& other, const char* filename, uint32_t linenum, const char* more_custom_message) {
446  // Invariant: if w_error_ok, no more processing
447  if (other._error_code == w_error_ok) {
448  this->_error_code = w_error_ok;
449  return;
450  }
451 
452  operator=(other);
453  // augment stacktrace
455  _filenames[_stack_depth] = filename;
456  _linenums[_stack_depth] = linenum;
457  ++_stack_depth;
458  }
459  // augment custom error message
460  if (more_custom_message != nullptr) {
461  append_custom_message(more_custom_message);
462  }
463 #if W_DEBUG_LEVEL >= 5
464  std::cout << "Error augmented: " << *this << std::endl;
465 #endif //W_DEBUG_LEVEL>=3
466 }
467 
468 inline w_rc_t::~w_rc_t() {
469  // Invariant: if w_error_ok, no more processing
470  if (_error_code == w_error_ok) {
471  return;
472  }
473 #if W_DEBUG_LEVEL > 0
474  // We output warning if some error code is not checked , but we don't do so in release mode.
475  verify();
476 #endif // W_DEBUG_LEVEL>0
477  if (_custom_message != nullptr) {
478  delete[] _custom_message;
479  _custom_message = nullptr;
480  }
481 }
482 
483 inline void w_rc_t::append_custom_message(const char* more_custom_message) {
484  // Invariant: if w_error_ok, no more processing
485  if (_error_code == w_error_ok) {
486  return;
487  }
488  // augment custom error message
489  size_t more_len = ::strlen(more_custom_message);
490  if (_custom_message != nullptr) {
491  // concat
492  size_t cur_len = ::strlen(_custom_message);
493  char* copied = new char[cur_len + more_len + 1];
494  _custom_message = copied;
495  ::memcpy(copied, _custom_message, cur_len);
496  ::memcpy(copied + cur_len, more_custom_message, more_len + 1);
497  } else {
498  // just put the new message
499  char* copied = new char[more_len + 1];
500  _custom_message = copied;
501  ::memcpy(copied, more_custom_message, more_len + 1);
502  }
503 }
504 
505 inline bool w_rc_t::is_error() const {
506  _checked = true;
507  return _error_code != w_error_ok;
508 }
509 
511  _checked = true;
512  return _error_code;
513 }
514 
515 inline const char* w_rc_t::get_message() const {
516  assert(_error_code < w_error_count);
517  return w_error_message(_error_code);
518 }
519 
520 inline const char* w_rc_t::get_custom_message() const {
521  // Invariant: if w_error_ok, no more processing
522  if (_error_code == w_error_ok) {
523  return nullptr;
524  }
525  return _custom_message;
526 }
527 
528 inline uint16_t w_rc_t::get_stack_depth() const {
529  // Invariant: if w_error_ok, no more processing
530  if (_error_code == w_error_ok) {
531  return 0;
532  }
533  return _stack_depth;
534 }
535 
536 inline uint16_t w_rc_t::get_linenum(uint16_t stack_index) const {
537  // Invariant: if w_error_ok, no more processing
538  if (_error_code == w_error_ok) {
539  return 0;
540  }
541  assert(stack_index < _stack_depth);
542  return _linenums[stack_index];
543 }
544 
545 inline const char* w_rc_t::get_filename(uint16_t stack_index) const {
546  // Invariant: if w_error_ok, no more processing
547  if (_error_code == w_error_ok) {
548  return nullptr;
549  }
550  assert(stack_index < _stack_depth);
551  return _filenames[stack_index];
552 }
553 
554 inline void w_rc_t::verify() const {
555  // Invariant: if w_error_ok, no more processing
556  if (_error_code == w_error_ok) {
557  return;
558  }
559  if (!_checked) {
560  std::cerr << "WARNING: Return value is not checked. w_rc_t must be checked before deallocation." << std::endl;
561  std::cerr << "Error detail:" << *this << std::endl;
562  }
563 }
564 
565 inline void w_rc_t::fatal() const {
566  // Invariant: if w_error_ok, no more processing
567  if (_error_code == w_error_ok) {
568  return;
569  }
570  std::cerr << "FATAL: Unexpected error happened. Will exit." << std::endl;
571  std::cerr << "Error detail:" << *this << std::endl;
572  assert(false);
573  std::cout.flush();
574  std::cerr.flush();
575  std::abort();
576 }
577 
578 #endif // __W_RC_H
~w_rc_t()
Definition: w_rc.h:468
w_error_codes err_num() const
Definition: w_rc.h:510
uint16_t _stack_depth
Current stack depth. Value 0 implies that we don&#39;t pass around stacktrace for this return code...
Definition: w_rc.h:205
const w_rc_t RCOK
Definition: w_rc.h:239
bool is_error() const
True if this return code is not RCOK or equivalent. This must be called for every w_rc_t before destr...
Definition: w_rc.h:505
uint16_t get_linenum(uint16_t stack_index) const
Definition: w_rc.h:536
w_rc_t()
Definition: w_rc.h:394
bool _checked
Whether someone already checked the error code of this object.
Definition: w_rc.h:208
const char * _filenames[MAX_RCT_STACK_DEPTH]
Filenames of stacktraces. This is deep-first, so _filenames[0] is where the w_rc_t was initially inst...
Definition: w_rc.h:179
void verify() const
Definition: w_rc.h:554
const char * get_custom_message() const
Definition: w_rc.h:520
const char * get_filename(uint16_t stack_index) const
Definition: w_rc.h:545
w_error_codes
Enum of error codes defined in w_error_xmacro.h.
Definition: w_error.h:43
Definition: w_error.h:45
w_error_codes _error_code
Integer error code.
Definition: w_rc.h:199
uint16_t get_stack_depth() const
Definition: w_rc.h:528
Return code for most functions and methods.
Definition: w_rc.h:87
w_rc_t rc_t
Definition: w_rc.h:211
uint16_t _linenums[MAX_RCT_STACK_DEPTH]
Line numbers of stacktraces.
Definition: w_rc.h:182
const char * _custom_message
Optional custom error message. We deep-copy this string if it&#39;s non-NULL. The reason why we don&#39;t use...
Definition: w_rc.h:190
std::ostream & operator<<(std::ostream &o, const w_rc_t &obj)
Definition: w_rc.h:213
void append_custom_message(const char *more_custom_message)
Definition: w_rc.h:483
const char * get_message() const
Definition: w_rc.h:515
void fatal() const
Fail catastrophically after describing the error. This is called from W_COERCE to handle an unexpecte...
Definition: w_rc.h:565
const uint16_t MAX_RCT_STACK_DEPTH
Constant to define maximum stack trace depth for w_rc_t.
Definition: w_rc.h:62
w_rc_t & operator=(w_rc_t const &other)
Definition: w_rc.h:423