text: // Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
  //  This source code is licensed under both the GPLv2 (found in the
  //  COPYING file in the root directory) and Apache 2.0 License
  //  (found in the LICENSE.Apache file in the root directory).
  // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file. See the AUTHORS file for names of contributors.
  //
  // A Status encapsulates the result of an operation.  It may indicate success,
  // or it may indicate an error with an associated error message.
  //
  // 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.
  
  #ifndef STORAGE_ROCKSDB_INCLUDE_STATUS_H_
  #define STORAGE_ROCKSDB_INCLUDE_STATUS_H_
  
  #include <string>
  #include "rocksdb/slice.h"
  
  namespace rocksdb {
  
  class Status {
   public:
    // Create a success status.
    Status() : code_(kOk), subcode_(kNone), state_(nullptr) {}
    ~Status() { delete[] state_; }
  
    // Copy the specified status.
    Status(const Status& s);
    Status& operator=(const Status& s);
    Status(Status&& s)
  #if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900))
        noexcept
  #endif
        ;
    Status& operator=(Status&& s)
  #if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900))
        noexcept
  #endif
        ;
    bool operator==(const Status& rhs) const;
    bool operator!=(const Status& rhs) const;
  
    enum Code {
      kOk = 0,
      kNotFound = 1,
      kCorruption = 2,
      kNotSupported = 3,
      kInvalidArgument = 4,
      kIOError = 5,
      kMergeInProgress = 6,
      kIncomplete = 7,
      kShutdownInProgress = 8,
      kTimedOut = 9,
      kAborted = 10,
      kBusy = 11,
      kExpired = 12,
      kTryAgain = 13,
      kCompactionTooLarge = 14
    };
  
    Code code() const { return code_; }
  
    enum SubCode {
      kNone = 0,
      kMutexTimeout = 1,
      kLockTimeout = 2,
      kLockLimit = 3,
      kNoSpace = 4,
      kDeadlock = 5,
      kStaleFile = 6,
      kMemoryLimit = 7,
      kMaxSubCode
    };
  
    SubCode subcode() const { return subcode_; }
  
    // Returns a C style string indicating the message of the Status
    const char* getState() const { return state_; }
  
    // Return a success status.
    static Status OK() { return Status(); }
  
    // Return error status of an appropriate type.
    static Status NotFound(const Slice& msg, const Slice& msg2 = Slice()) {
      return Status(kNotFound, msg, msg2);
    }
    // Fast path for not found without malloc;
    static Status NotFound(SubCode msg = kNone) { return Status(kNotFound, msg); }
  
    static Status Corruption(const Slice& msg, const Slice& msg2 = Slice()) {
      return Status(kCorruption, msg, msg2);
    }
    static Status Corruption(SubCode msg = kNone) {
      return Status(kCorruption, msg);
    }
  
    static Status NotSupported(const Slice& msg, const Slice& msg2 = Slice()) {
      return Status(kNotSupported, msg, msg2);
    }
    static Status NotSupported(SubCode msg = kNone) {
      return Status(kNotSupported, msg);
    }
  
    static Status InvalidArgument(const Slice& msg, const Slice& msg2 = Slice()) {
      return Status(kInvalidArgument, msg, msg2);
    }
    static Status InvalidArgument(SubCode msg = kNone) {
      return Status(kInvalidArgument, msg);
    }
  
    static Status IOError(const Slice& msg, const Slice& msg2 = Slice()) {
      return Status(kIOError, msg, msg2);
    }
    static Status IOError(SubCode msg = kNone) { return Status(kIOError, msg); }
  
    static Status MergeInProgress(const Slice& msg, const Slice& msg2 = Slice()) {
      return Status(kMergeInProgress, msg, msg2);
    }
    static Status MergeInProgress(SubCode msg = kNone) {
      return Status(kMergeInProgress, msg);
    }
  
    static Status Incomplete(const Slice& msg, const Slice& msg2 = Slice()) {
      return Status(kIncomplete, msg, msg2);
    }
    static Status Incomplete(SubCode msg = kNone) {
      return Status(kIncomplete, msg);
    }
  
    static Status ShutdownInProgress(SubCode msg = kNone) {
      return Status(kShutdownInProgress, msg);
    }
    static Status ShutdownInProgress(const Slice& msg,
                                     const Slice& msg2 = Slice()) {
      return Status(kShutdownInProgress, msg, msg2);
    }
    static Status Aborted(SubCode msg = kNone) { return Status(kAborted, msg); }
    static Status Aborted(const Slice& msg, const Slice& msg2 = Slice()) {
      return Status(kAborted, msg, msg2);
    }
  
    static Status Busy(SubCode msg = kNone) { return Status(kBusy, msg); }
    static Status Busy(const Slice& msg, const Slice& msg2 = Slice()) {
      return Status(kBusy, msg, msg2);
    }
  
    static Status TimedOut(SubCode msg = kNone) { return Status(kTimedOut, msg); }
    static Status TimedOut(const Slice& msg, const Slice& msg2 = Slice()) {
      return Status(kTimedOut, msg, msg2);
    }
  
    static Status Expired(SubCode msg = kNone) { return Status(kExpired, msg); }
    static Status Expired(const Slice& msg, const Slice& msg2 = Slice()) {
      return Status(kExpired, msg, msg2);
    }
  
    static Status TryAgain(SubCode msg = kNone) { return Status(kTryAgain, msg); }
    static Status TryAgain(const Slice& msg, const Slice& msg2 = Slice()) {
      return Status(kTryAgain, msg, msg2);
    }
  
    static Status CompactionTooLarge(SubCode msg = kNone) {
      return Status(kCompactionTooLarge, msg);
    }
    static Status CompactionTooLarge(const Slice& msg,
                                     const Slice& msg2 = Slice()) {
      return Status(kCompactionTooLarge, msg, msg2);
    }
  
    static Status NoSpace() { return Status(kIOError, kNoSpace); }
    static Status NoSpace(const Slice& msg, const Slice& msg2 = Slice()) {
      return Status(kIOError, kNoSpace, msg, msg2);
    }
  
    static Status MemoryLimit() { return Status(kAborted, kMemoryLimit); }
    static Status MemoryLimit(const Slice& msg, const Slice& msg2 = Slice()) {
      return Status(kAborted, kMemoryLimit, msg, msg2);
    }
  
    // Returns true iff the status indicates success.
    bool ok() const { return code() == kOk; }
  
    // Returns true iff the status indicates a NotFound error.
    bool IsNotFound() const { return code() == kNotFound; }
  
    // Returns true iff the status indicates a Corruption error.
    bool IsCorruption() const { return code() == kCorruption; }
  
    // Returns true iff the status indicates a NotSupported error.
    bool IsNotSupported() const { return code() == kNotSupported; }
  
    // Returns true iff the status indicates an InvalidArgument error.
    bool IsInvalidArgument() const { return code() == kInvalidArgument; }
  
    // Returns true iff the status indicates an IOError.
    bool IsIOError() const { return code() == kIOError; }
  
    // Returns true iff the status indicates an MergeInProgress.
    bool IsMergeInProgress() const { return code() == kMergeInProgress; }
  
    // Returns true iff the status indicates Incomplete
    bool IsIncomplete() const { return code() == kIncomplete; }
  
    // Returns true iff the status indicates Shutdown In progress
    bool IsShutdownInProgress() const { return code() == kShutdownInProgress; }
  
    bool IsTimedOut() const { return code() == kTimedOut; }
  
    bool IsAborted() const { return code() == kAborted; }
  
    bool IsLockLimit() const {
      return code() == kAborted && subcode() == kLockLimit;
    }
  
    // Returns true iff the status indicates that a resource is Busy and
    // temporarily could not be acquired.
    bool IsBusy() const { return code() == kBusy; }
  
    bool IsDeadlock() const { return code() == kBusy && subcode() == kDeadlock; }
  
    // Returns true iff the status indicated that the operation has Expired.
    bool IsExpired() const { return code() == kExpired; }
  
    // Returns true iff the status indicates a TryAgain error.
    // This usually means that the operation failed, but may succeed if
    // re-attempted.
    bool IsTryAgain() const { return code() == kTryAgain; }
  
    // Returns true iff the status indicates the proposed compaction is too large
    bool IsCompactionTooLarge() const { return code() == kCompactionTooLarge; }
  
    // Returns true iff the status indicates a NoSpace error
    // This is caused by an I/O error returning the specific "out of space"
    // error condition. Stricto sensu, an NoSpace error is an I/O error
    // with a specific subcode, enabling users to take the appropriate action
    // if needed
    bool IsNoSpace() const {
      return (code() == kIOError) && (subcode() == kNoSpace);
    }
  
    // Returns true iff the status indicates a memory limit error.  There may be
    // cases where we limit the memory used in certain operations (eg. the size
    // of a write batch) in order to avoid out of memory exceptions.
    bool IsMemoryLimit() const {
      return (code() == kAborted) && (subcode() == kMemoryLimit);
    }
  
    // Return a string representation of this status suitable for printing.
    // Returns the string "OK" for success.
    std::string ToString() const;
  
   private:
    // A nullptr state_ (which is always the case for OK) means the message
    // is empty.
    // of the following form:
    //    state_[0..3] == length of message
    //    state_[4..]  == message
    Code code_;
    SubCode subcode_;
    const char* state_;
  
    static const char* msgs[static_cast<int>(kMaxSubCode)];
  
    explicit Status(Code _code, SubCode _subcode = kNone)
        : code_(_code), subcode_(_subcode), state_(nullptr) {}
  
    Status(Code _code, SubCode _subcode, const Slice& msg, const Slice& msg2);
    Status(Code _code, const Slice& msg, const Slice& msg2)
        : Status(_code, kNone, msg, msg2) {}
  
    static const char* CopyState(const char* s);
  };
  
  inline Status::Status(const Status& s) : code_(s.code_), subcode_(s.subcode_) {
    state_ = (s.state_ == nullptr) ? nullptr : CopyState(s.state_);
  }
  inline Status& 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 (this != &s) {
      code_ = s.code_;
      subcode_ = s.subcode_;
      delete[] state_;
      state_ = (s.state_ == nullptr) ? nullptr : CopyState(s.state_);
    }
    return *this;
  }
  
  inline Status::Status(Status&& s)
  #if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900))
      noexcept
  #endif
      : Status() {
    *this = std::move(s);
  }
  
  inline Status& Status::operator=(Status&& s)
  #if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900))
      noexcept
  #endif
  {
    if (this != &s) {
      code_ = std::move(s.code_);
      s.code_ = kOk;
      subcode_ = std::move(s.subcode_);
      s.subcode_ = kNone;
      delete[] state_;
      state_ = nullptr;
      std::swap(state_, s.state_);
    }
    return *this;
  }
  
  inline bool Status::operator==(const Status& rhs) const {
    return (code_ == rhs.code_);
  }
  
  inline bool Status::operator!=(const Status& rhs) const {
    return !(*this == rhs);
  }
  
  }  // namespace rocksdb
  
  #endif  // STORAGE_ROCKSDB_INCLUDE_STATUS_H_
  