Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
143 lines (118 sloc) 4.33 KB
// Copyright (c) 2015 Baidu, Inc.
#ifndef BUTIL_STATUS_H
#define BUTIL_STATUS_H
#include <stdarg.h> // va_list
#include <stdlib.h> // free
#include <string> // std::string
#include <ostream> // std::ostream
#include "butil/strings/string_piece.h"
namespace butil {
// A Status encapsulates the result of an operation. It may indicate success,
// or it may indicate an error with an associated error message. It's suitable
// for passing status of functions with richer information than just error_code
// in exception-forbidden code. This utility is inspired by leveldb::Status.
//
// Multiple threads can invoke const methods on a Status without
// external synchronization, but if any of the threads may call a
// non-const method, all threads accessing the same Status must use
// external synchronization.
//
// Since failed status needs to allocate memory, you should be careful when
// failed status is frequent.
class Status {
public:
struct State {
int code;
unsigned size; // length of message string
unsigned state_size;
char message[0];
};
// Create a success status.
Status() : _state(NULL) { }
// Return a success status.
static Status OK() { return Status(); }
~Status() { reset(); }
// Create a failed status.
// error_text is formatted from `fmt' and following arguments.
Status(int code, const char* fmt, ...)
__attribute__ ((__format__ (__printf__, 3, 4)))
: _state(NULL) {
va_list ap;
va_start(ap, fmt);
set_errorv(code, fmt, ap);
va_end(ap);
}
Status(int code, const butil::StringPiece& error_msg) : _state(NULL) {
set_error(code, error_msg);
}
// Copy the specified status. Internal fields are deeply copied.
Status(const Status& s);
void operator=(const Status& s);
// Reset this status to be OK.
void reset();
// Reset this status to be failed.
// Returns 0 on success, -1 otherwise and internal fields are not changed.
int set_error(int code, const char* error_format, ...)
__attribute__ ((__format__ (__printf__, 3, 4)));
int set_error(int code, const butil::StringPiece& error_msg);
int set_errorv(int code, const char* error_format, va_list args);
// Returns true iff the status indicates success.
bool ok() const { return (_state == NULL); }
// Get the error code
int error_code() const {
return (_state == NULL) ? 0 : _state->code;
}
// Return a string representation of the status.
// Returns "OK" for success.
// NOTICE:
// * You can print a Status to std::ostream directly
// * if message contains '\0', error_cstr() will not be shown fully.
const char* error_cstr() const {
return (_state == NULL ? "OK" : _state->message);
}
butil::StringPiece error_data() const {
return (_state == NULL ? butil::StringPiece("OK", 2)
: butil::StringPiece(_state->message, _state->size));
}
std::string error_str() const;
void swap(butil::Status& other) { std::swap(_state, other._state); }
private:
// OK status has a NULL _state. Otherwise, _state is a State object
// converted from malloc().
State* _state;
static State* copy_state(const State* s);
};
inline Status::Status(const Status& s) {
_state = (s._state == NULL) ? NULL : copy_state(s._state);
}
inline int Status::set_error(int code, const char* msg, ...) {
va_list ap;
va_start(ap, msg);
const int rc = set_errorv(code, msg, ap);
va_end(ap);
return rc;
}
inline void Status::reset() {
free(_state);
_state = NULL;
}
inline void Status::operator=(const Status& s) {
// The following condition catches both aliasing (when this == &s),
// and the common case where both s and *this are ok.
if (_state == s._state) {
return;
}
if (s._state == NULL) {
free(_state);
_state = NULL;
} else {
set_error(s._state->code,
butil::StringPiece(s._state->message, s._state->size));
}
}
inline std::ostream& operator<<(std::ostream& os, const Status& st) {
// NOTE: don't use st.error_text() which is inaccurate if message has '\0'
return os << st.error_data();
}
} // namespace butil
#endif // BUTIL_STATUS_H
You can’t perform that action at this time.