tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

status.h (14296B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 
      6 #ifndef LIB_JXL_BASE_STATUS_H_
      7 #define LIB_JXL_BASE_STATUS_H_
      8 
      9 // Error handling: Status return type + helper macros.
     10 
     11 #include <cstdarg>
     12 #include <cstdint>
     13 #include <cstdio>
     14 #include <cstdlib>
     15 #include <type_traits>
     16 #include <utility>
     17 
     18 #include "lib/jxl/base/common.h"
     19 #include "lib/jxl/base/compiler_specific.h"
     20 
     21 namespace jxl {
     22 
     23 // The Verbose level for the library
     24 #ifndef JXL_DEBUG_V_LEVEL
     25 #define JXL_DEBUG_V_LEVEL 0
     26 #endif  // JXL_DEBUG_V_LEVEL
     27 
     28 #ifdef USE_ANDROID_LOGGER
     29 #include <android/log.h>
     30 #define LIBJXL_ANDROID_LOG_TAG ("libjxl")
     31 inline void android_vprintf(const char* format, va_list args) {
     32  char* message = nullptr;
     33  int res = vasprintf(&message, format, args);
     34  if (res != -1) {
     35    __android_log_write(ANDROID_LOG_DEBUG, LIBJXL_ANDROID_LOG_TAG, message);
     36    free(message);
     37  }
     38 }
     39 #endif
     40 
     41 // Print a debug message on standard error or android logs. You should use the
     42 // JXL_DEBUG macro instead of calling Debug directly. This function returns
     43 // false, so it can be used as a return value in JXL_FAILURE.
     44 JXL_FORMAT(1, 2)
     45 inline JXL_NOINLINE bool Debug(const char* format, ...) {
     46  va_list args;
     47  va_start(args, format);
     48 #ifdef USE_ANDROID_LOGGER
     49  android_vprintf(format, args);
     50 #else
     51  vfprintf(stderr, format, args);
     52 #endif
     53  va_end(args);
     54  return false;
     55 }
     56 
     57 // Print a debug message on standard error if "enabled" is true. "enabled" is
     58 // normally a macro that evaluates to 0 or 1 at compile time, so the Debug
     59 // function is never called and optimized out in release builds. Note that the
     60 // arguments are compiled but not evaluated when enabled is false. The format
     61 // string must be a explicit string in the call, for example:
     62 //   JXL_DEBUG(JXL_DEBUG_MYMODULE, "my module message: %d", some_var);
     63 // Add a header at the top of your module's .cc or .h file (depending on whether
     64 // you have JXL_DEBUG calls from the .h as well) like this:
     65 //   #ifndef JXL_DEBUG_MYMODULE
     66 //   #define JXL_DEBUG_MYMODULE 0
     67 //   #endif JXL_DEBUG_MYMODULE
     68 #define JXL_DEBUG_TMP(format, ...) \
     69  ::jxl::Debug(("%s:%d: " format "\n"), __FILE__, __LINE__, ##__VA_ARGS__)
     70 
     71 #define JXL_DEBUG(enabled, format, ...)     \
     72  do {                                      \
     73    if (enabled) {                          \
     74      JXL_DEBUG_TMP(format, ##__VA_ARGS__); \
     75    }                                       \
     76  } while (0)
     77 
     78 // JXL_DEBUG version that prints the debug message if the global verbose level
     79 // defined at compile time by JXL_DEBUG_V_LEVEL is greater or equal than the
     80 // passed level.
     81 #if JXL_DEBUG_V_LEVEL > 0
     82 #define JXL_DEBUG_V(level, format, ...) \
     83  JXL_DEBUG(level <= JXL_DEBUG_V_LEVEL, format, ##__VA_ARGS__)
     84 #else
     85 #define JXL_DEBUG_V(level, format, ...)
     86 #endif
     87 
     88 #define JXL_WARNING(format, ...) \
     89  JXL_DEBUG(JXL_IS_DEBUG_BUILD, format, ##__VA_ARGS__)
     90 
     91 #if JXL_IS_DEBUG_BUILD
     92 // Exits the program after printing a stack trace when possible.
     93 JXL_NORETURN inline JXL_NOINLINE bool Abort() {
     94  JXL_PRINT_STACK_TRACE();
     95  JXL_CRASH();
     96 }
     97 #endif
     98 
     99 #if JXL_IS_DEBUG_BUILD
    100 #define JXL_DEBUG_ABORT(format, ...)                                   \
    101  do {                                                                 \
    102    if (JXL_DEBUG_ON_ABORT) {                                          \
    103      ::jxl::Debug(("%s:%d: JXL_DEBUG_ABORT: " format "\n"), __FILE__, \
    104                   __LINE__, ##__VA_ARGS__);                           \
    105    }                                                                  \
    106    ::jxl::Abort();                                                    \
    107  } while (0);
    108 #else
    109 #define JXL_DEBUG_ABORT(format, ...)
    110 #endif
    111 
    112 // Use this for code paths that are unreachable unless the code would change
    113 // to make it reachable, in which case it will print a warning and abort in
    114 // debug builds. In release builds no code is produced for this, so only use
    115 // this if this path is really unreachable.
    116 #if JXL_IS_DEBUG_BUILD
    117 #define JXL_UNREACHABLE(format, ...)                                          \
    118  (::jxl::Debug(("%s:%d: JXL_UNREACHABLE: " format "\n"), __FILE__, __LINE__, \
    119                ##__VA_ARGS__),                                               \
    120   ::jxl::Abort(), JXL_FAILURE(format, ##__VA_ARGS__))
    121 #else  // JXL_IS_DEBUG_BUILD
    122 #define JXL_UNREACHABLE(format, ...) \
    123  JXL_FAILURE("internal: " format, ##__VA_ARGS__)
    124 #endif
    125 
    126 // Only runs in debug builds (builds where NDEBUG is not
    127 // defined). This is useful for slower asserts that we want to run more rarely
    128 // than usual. These will run on asan, msan and other debug builds, but not in
    129 // opt or release.
    130 #if JXL_IS_DEBUG_BUILD
    131 #define JXL_DASSERT(condition)                                      \
    132  do {                                                              \
    133    if (!(condition)) {                                             \
    134      JXL_DEBUG(JXL_DEBUG_ON_ABORT, "JXL_DASSERT: %s", #condition); \
    135      ::jxl::Abort();                                               \
    136    }                                                               \
    137  } while (0)
    138 #else
    139 #define JXL_DASSERT(condition)
    140 #endif
    141 
    142 // A jxl::Status value from a StatusCode or Status which prints a debug message
    143 // when enabled.
    144 #define JXL_STATUS(status, format, ...)                                        \
    145  ::jxl::StatusMessage(::jxl::Status(status), "%s:%d: " format "\n", __FILE__, \
    146                       __LINE__, ##__VA_ARGS__)
    147 
    148 // Notify of an error but discard the resulting Status value. This is only
    149 // useful for debug builds or when building with JXL_CRASH_ON_ERROR.
    150 #define JXL_NOTIFY_ERROR(format, ...)                                      \
    151  (void)JXL_STATUS(::jxl::StatusCode::kGenericError, "JXL_ERROR: " format, \
    152                   ##__VA_ARGS__)
    153 
    154 // An error Status with a message. The JXL_STATUS() macro will return a Status
    155 // object with a kGenericError code, but the comma operator helps with
    156 // clang-tidy inference and potentially with optimizations.
    157 #define JXL_FAILURE(format, ...)                                              \
    158  ((void)JXL_STATUS(::jxl::StatusCode::kGenericError, "JXL_FAILURE: " format, \
    159                    ##__VA_ARGS__),                                           \
    160   ::jxl::Status(::jxl::StatusCode::kGenericError))
    161 
    162 // Always evaluates the status exactly once, so can be used for non-debug calls.
    163 // Returns from the current context if the passed Status expression is an error
    164 // (fatal or non-fatal). The return value is the passed Status.
    165 #define JXL_RETURN_IF_ERROR(status)                                       \
    166  do {                                                                    \
    167    ::jxl::Status jxl_return_if_error_status = (status);                  \
    168    if (!jxl_return_if_error_status) {                                    \
    169      (void)::jxl::StatusMessage(                                         \
    170          jxl_return_if_error_status,                                     \
    171          "%s:%d: JXL_RETURN_IF_ERROR code=%d: %s\n", __FILE__, __LINE__, \
    172          static_cast<int>(jxl_return_if_error_status.code()), #status);  \
    173      return jxl_return_if_error_status;                                  \
    174    }                                                                     \
    175  } while (0)
    176 
    177 // As above, but without calling StatusMessage. Intended for bundles (see
    178 // fields.h), which have numerous call sites (-> relevant for code size) and do
    179 // not want to generate excessive messages when decoding partial headers.
    180 #define JXL_QUIET_RETURN_IF_ERROR(status)                \
    181  do {                                                   \
    182    ::jxl::Status jxl_return_if_error_status = (status); \
    183    if (!jxl_return_if_error_status) {                   \
    184      return jxl_return_if_error_status;                 \
    185    }                                                    \
    186  } while (0)
    187 
    188 #if JXL_IS_DEBUG_BUILD
    189 // Debug: fatal check.
    190 #define JXL_ENSURE(condition)                     \
    191  do {                                            \
    192    if (!(condition)) {                           \
    193      ::jxl::Debug("JXL_ENSURE: %s", #condition); \
    194      ::jxl::Abort();                             \
    195    }                                             \
    196  } while (0)
    197 #else
    198 // Release: non-fatal check of condition. If false, just return an error.
    199 #define JXL_ENSURE(condition)                           \
    200  do {                                                  \
    201    if (!(condition)) {                                 \
    202      return JXL_FAILURE("JXL_ENSURE: %s", #condition); \
    203    }                                                   \
    204  } while (0)
    205 #endif
    206 
    207 enum class StatusCode : int32_t {
    208  // Non-fatal errors (negative values).
    209  kNotEnoughBytes = -1,
    210 
    211  // The only non-error status code.
    212  kOk = 0,
    213 
    214  // Fatal-errors (positive values)
    215  kGenericError = 1,
    216 };
    217 
    218 // Drop-in replacement for bool that raises compiler warnings if not used
    219 // after being returned from a function. Example:
    220 // Status LoadFile(...) { return true; } is more compact than
    221 // bool JXL_MUST_USE_RESULT LoadFile(...) { return true; }
    222 // In case of error, the status can carry an extra error code in its value which
    223 // is split between fatal and non-fatal error codes.
    224 class JXL_MUST_USE_RESULT Status {
    225 public:
    226  // We want implicit constructor from bool to allow returning "true" or "false"
    227  // on a function when using Status. "true" means kOk while "false" means a
    228  // generic fatal error.
    229  // NOLINTNEXTLINE(google-explicit-constructor)
    230  constexpr Status(bool ok)
    231      : code_(ok ? StatusCode::kOk : StatusCode::kGenericError) {}
    232 
    233  // NOLINTNEXTLINE(google-explicit-constructor)
    234  constexpr Status(StatusCode code) : code_(code) {}
    235 
    236  // We also want implicit cast to bool to check for return values of functions.
    237  // NOLINTNEXTLINE(google-explicit-constructor)
    238  constexpr operator bool() const { return code_ == StatusCode::kOk; }
    239 
    240  constexpr StatusCode code() const { return code_; }
    241 
    242  // Returns whether the status code is a fatal error.
    243  constexpr bool IsFatalError() const {
    244    return static_cast<int32_t>(code_) > 0;
    245  }
    246 
    247 private:
    248  StatusCode code_;
    249 };
    250 
    251 static constexpr Status OkStatus() { return Status(StatusCode::kOk); }
    252 
    253 // Helper function to create a Status and print the debug message or abort when
    254 // needed.
    255 inline JXL_FORMAT(2, 3) Status
    256    StatusMessage(const Status status, const char* format, ...) {
    257  // This block will be optimized out when JXL_IS_DEBUG_BUILD is disabled.
    258  if ((JXL_IS_DEBUG_BUILD && status.IsFatalError()) ||
    259      (JXL_DEBUG_ON_ALL_ERROR && !status)) {
    260    va_list args;
    261    va_start(args, format);
    262 #ifdef USE_ANDROID_LOGGER
    263    android_vprintf(format, args);
    264 #else
    265    vfprintf(stderr, format, args);
    266 #endif
    267    va_end(args);
    268  }
    269 #if JXL_CRASH_ON_ERROR
    270  // JXL_CRASH_ON_ERROR means to Abort() only on non-fatal errors.
    271  if (status.IsFatalError()) {
    272    ::jxl::Abort();
    273  }
    274 #endif  // JXL_CRASH_ON_ERROR
    275  return status;
    276 }
    277 
    278 template <typename T>
    279 class JXL_MUST_USE_RESULT StatusOr {
    280  static_assert(!std::is_convertible<StatusCode, T>::value &&
    281                    !std::is_convertible<T, StatusCode>::value,
    282                "You cannot make a StatusOr with a type convertible from or to "
    283                "StatusCode");
    284  static_assert(std::is_move_constructible<T>::value &&
    285                    std::is_move_assignable<T>::value,
    286                "T must be move constructible and move assignable");
    287 
    288 public:
    289  // NOLINTNEXTLINE(google-explicit-constructor)
    290  StatusOr(StatusCode code) : code_(code) {
    291    JXL_DASSERT(code_ != StatusCode::kOk);
    292  }
    293 
    294  // NOLINTNEXTLINE(google-explicit-constructor)
    295  StatusOr(Status status) : StatusOr(status.code()) {}
    296 
    297  // NOLINTNEXTLINE(google-explicit-constructor)
    298  StatusOr(T&& value) : code_(StatusCode::kOk) {
    299    new (&storage_.data_) T(std::move(value));
    300  }
    301 
    302  StatusOr(StatusOr&& other) noexcept {
    303    if (other.ok()) {
    304      new (&storage_.data_) T(std::move(other.storage_.data_));
    305    }
    306    code_ = other.code_;
    307  }
    308 
    309  StatusOr& operator=(StatusOr&& other) noexcept {
    310    if (this == &other) return *this;
    311    if (ok() && other.ok()) {
    312      storage_.data_ = std::move(other.storage_.data_);
    313    } else if (other.ok()) {
    314      new (&storage_.data_) T(std::move(other.storage_.data_));
    315    } else if (ok()) {
    316      storage_.data_.~T();
    317    }
    318    code_ = other.code_;
    319    return *this;
    320  }
    321 
    322  StatusOr(const StatusOr&) = delete;
    323  StatusOr operator=(const StatusOr&) = delete;
    324 
    325  bool ok() const { return code_ == StatusCode::kOk; }
    326  Status status() const { return code_; }
    327 
    328  // Only call this if you are absolutely sure that `ok()` is true.
    329  // Never call this manually: rely on JXL_ASSIGN_OR.
    330  T value_() && {
    331    JXL_DASSERT(ok());
    332    return std::move(storage_.data_);
    333  }
    334 
    335  ~StatusOr() {
    336    if (code_ == StatusCode::kOk) {
    337      storage_.data_.~T();
    338    }
    339  }
    340 
    341 private:
    342  union Storage {
    343    char placeholder_;
    344    T data_;
    345    Storage() {}
    346    ~Storage() {}
    347  } storage_;
    348 
    349  StatusCode code_;
    350 };
    351 
    352 #define JXL_ASSIGN_OR_RETURN(lhs, statusor) \
    353  PRIVATE_JXL_ASSIGN_OR_RETURN_IMPL(        \
    354      JXL_JOIN(assign_or_return_temporary_variable, __LINE__), lhs, statusor)
    355 
    356 // NOLINTBEGIN(bugprone-macro-parentheses)
    357 #define PRIVATE_JXL_ASSIGN_OR_RETURN_IMPL(name, lhs, statusor) \
    358  auto name = statusor;                                        \
    359  JXL_RETURN_IF_ERROR(name.status());                          \
    360  lhs = std::move(name).value_();
    361 // NOLINTEND(bugprone-macro-parentheses)
    362 
    363 #define JXL_ASSIGN_OR_QUIT(lhs, statusor, message)                     \
    364  PRIVATE_JXL_ASSIGN_OR_QUIT_IMPL(                                     \
    365      JXL_JOIN(assign_or_temporary_variable, __LINE__), lhs, statusor, \
    366      message)
    367 
    368 // NOLINTBEGIN(bugprone-macro-parentheses)
    369 #define PRIVATE_JXL_ASSIGN_OR_QUIT_IMPL(name, lhs, statusor, message) \
    370  auto name = statusor;                                               \
    371  if (!name.ok()) {                                                   \
    372    QUIT(message);                                                    \
    373  }                                                                   \
    374  lhs = std::move(name).value_();
    375 // NOLINTEND(bugprone-macro-parentheses)
    376 
    377 }  // namespace jxl
    378 
    379 #endif  // LIB_JXL_BASE_STATUS_H_