summaryrefslogtreecommitdiff
path: root/lib/jxl/base/status.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/jxl/base/status.h')
-rw-r--r--lib/jxl/base/status.h125
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_