diff options
Diffstat (limited to 'lib/jxl/base/status.h')
-rw-r--r-- | lib/jxl/base/status.h | 125 |
1 files changed, 116 insertions, 9 deletions
diff --git a/lib/jxl/base/status.h b/lib/jxl/base/status.h index 682f440..26390ad 100644 --- a/lib/jxl/base/status.h +++ b/lib/jxl/base/status.h @@ -13,6 +13,9 @@ #include <stdio.h> #include <stdlib.h> +#include <type_traits> +#include <utility> + #include "lib/jxl/base/compiler_specific.h" #include "lib/jxl/base/sanitizer_definitions.h" @@ -65,10 +68,10 @@ namespace jxl { #define JXL_DEBUG_V_LEVEL 0 #endif // JXL_DEBUG_V_LEVEL -// Pass -DJXL_DEBUG_ON_ABORT=0 to disable the debug messages on JXL_ASSERT, -// JXL_CHECK and JXL_ABORT. +// Pass -DJXL_DEBUG_ON_ABORT={0,1} to force disable/enable the debug messages on +// JXL_ASSERT, JXL_CHECK and JXL_ABORT. #ifndef JXL_DEBUG_ON_ABORT -#define JXL_DEBUG_ON_ABORT 1 +#define JXL_DEBUG_ON_ABORT JXL_DEBUG_ON_ERROR #endif // JXL_DEBUG_ON_ABORT // Print a debug message on standard error. You should use the JXL_DEBUG macro @@ -94,12 +97,14 @@ inline JXL_NOINLINE bool Debug(const char* format, ...) { // #ifndef JXL_DEBUG_MYMODULE // #define JXL_DEBUG_MYMODULE 0 // #endif JXL_DEBUG_MYMODULE -#define JXL_DEBUG(enabled, format, ...) \ - do { \ - if (enabled) { \ - ::jxl::Debug(("%s:%d: " format "\n"), __FILE__, __LINE__, \ - ##__VA_ARGS__); \ - } \ +#define JXL_DEBUG_TMP(format, ...) \ + ::jxl::Debug(("%s:%d: " format "\n"), __FILE__, __LINE__, ##__VA_ARGS__) + +#define JXL_DEBUG(enabled, format, ...) \ + do { \ + if (enabled) { \ + JXL_DEBUG_TMP(format, ##__VA_ARGS__); \ + } \ } while (0) // JXL_DEBUG version that prints the debug message if the global verbose level @@ -146,6 +151,21 @@ JXL_NORETURN inline JXL_NOINLINE bool Abort() { __FILE__, __LINE__, ##__VA_ARGS__), \ ::jxl::Abort()) +// Use this for code paths that are unreachable unless the code would change +// to make it reachable, in which case it will print a warning and abort in +// debug builds. In release builds no code is produced for this, so only use +// this if this path is really unreachable. +#define JXL_UNREACHABLE(format, ...) \ + do { \ + if (JXL_DEBUG_WARNING) { \ + ::jxl::Debug(("%s:%d: JXL_UNREACHABLE: " format "\n"), __FILE__, \ + __LINE__, ##__VA_ARGS__); \ + ::jxl::Abort(); \ + } else { \ + JXL_UNREACHABLE_BUILTIN; \ + } \ + } while (0) + // Does not guarantee running the code, use only for debug mode checks. #if JXL_ENABLE_ASSERT #define JXL_ASSERT(condition) \ @@ -297,6 +317,8 @@ class JXL_MUST_USE_RESULT Status { StatusCode code_; }; +static constexpr Status OkStatus() { return Status(StatusCode::kOk); } + // Helper function to create a Status and print the debug message or abort when // needed. inline JXL_FORMAT(2, 3) Status @@ -319,6 +341,91 @@ inline JXL_FORMAT(2, 3) Status return status; } +template <typename T> +class JXL_MUST_USE_RESULT StatusOr { + static_assert(!std::is_convertible<StatusCode, T>::value && + !std::is_convertible<T, StatusCode>::value, + "You cannot make a StatusOr with a type convertible from or to " + "StatusCode"); + static_assert(std::is_move_constructible<T>::value && + std::is_move_assignable<T>::value, + "T must be move constructible and move assignable"); + + public: + // NOLINTNEXTLINE(google-explicit-constructor) + StatusOr(StatusCode code) : code_(code) { + JXL_ASSERT(code_ != StatusCode::kOk); + } + + // NOLINTNEXTLINE(google-explicit-constructor) + StatusOr(Status status) : StatusOr(status.code()) {} + + // NOLINTNEXTLINE(google-explicit-constructor) + StatusOr(T&& value) : code_(StatusCode::kOk) { + new (&storage_.data_) T(std::move(value)); + } + + StatusOr(StatusOr&& other) noexcept { + if (other.ok()) { + new (&storage_.data_) T(std::move(other.storage_.data_)); + } + code_ = other.code_; + } + + StatusOr& operator=(StatusOr&& other) noexcept { + if (this == &other) return *this; + if (ok() && other.ok()) { + storage_.data_ = std::move(other.storage_.data_); + } else if (other.ok()) { + new (&storage_.data_) T(std::move(other.storage_.data_)); + } else if (ok()) { + storage_.data_.~T(); + } + code_ = other.code_; + return *this; + } + + StatusOr(const StatusOr&) = delete; + StatusOr operator=(const StatusOr&) = delete; + + bool ok() const { return code_ == StatusCode::kOk; } + Status status() const { return code_; } + + // Only call this if you are absolutely sure that `ok()` is true. + // Ideally, never call this manually and rely on JXL_ASSIGN_OR_RETURN. + T value() && { + JXL_ASSERT(ok()); + return std::move(storage_.data_); + } + + ~StatusOr() { + if (code_ == StatusCode::kOk) { + storage_.data_.~T(); + } + } + + private: + union Storage { + char placeholder_; + T data_; + Storage() {} + ~Storage() {} + } storage_; + + StatusCode code_; +}; + +#define JXL_ASSIGN_OR_RETURN(lhs, statusor) \ + PRIVATE_JXL_ASSIGN_OR_RETURN_IMPL( \ + assign_or_return_temporary_variable##__LINE__, lhs, statusor) + +// NOLINTBEGIN(bugprone-macro-parentheses) +#define PRIVATE_JXL_ASSIGN_OR_RETURN_IMPL(name, lhs, statusor) \ + auto name = statusor; \ + JXL_RETURN_IF_ERROR(name.status()); \ + lhs = std::move(name).value(); +// NOLINTEND(bugprone-macro-parentheses) + } // namespace jxl #endif // LIB_JXL_BASE_STATUS_H_ |