summaryrefslogtreecommitdiffstats
path: root/intl/components/src/ICUError.h
diff options
context:
space:
mode:
Diffstat (limited to 'intl/components/src/ICUError.h')
-rw-r--r--intl/components/src/ICUError.h118
1 files changed, 118 insertions, 0 deletions
diff --git a/intl/components/src/ICUError.h b/intl/components/src/ICUError.h
new file mode 100644
index 0000000000..c3ef236210
--- /dev/null
+++ b/intl/components/src/ICUError.h
@@ -0,0 +1,118 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef intl_components_ICUError_h
+#define intl_components_ICUError_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/Result.h"
+
+#include <cstdint>
+#include <type_traits>
+
+namespace mozilla::intl {
+
+/**
+ * General purpose error type for operations that can result in an ICU error.
+ */
+enum class ICUError : uint8_t {
+ // Since we claim UnusedZero<ICUError>::value and
+ // HasFreeLSB<ICUError>::value == true below, we must only use positive,
+ // even enum values.
+
+ OutOfMemory = 2,
+ InternalError = 4,
+ OverflowError = 6,
+};
+
+/**
+ * Error type when a method call can only result in an internal ICU error.
+ */
+struct InternalError {
+ // Since we claim UnusedZero<InternalError>::value and
+ // HasFreeLSB<InternalError>::value == true below, we must only use positive,
+ // even enum values.
+ enum class ErrorKind : uint8_t { Unspecified = 2 };
+
+ const ErrorKind kind = ErrorKind::Unspecified;
+
+ constexpr InternalError() = default;
+
+ private:
+ friend struct mozilla::detail::UnusedZero<InternalError>;
+
+ constexpr MOZ_IMPLICIT InternalError(ErrorKind aKind) : kind(aKind) {}
+};
+
+} // namespace mozilla::intl
+
+namespace mozilla::detail {
+
+// Provide specializations for UnusedZero and HasFreeLSB to enable more
+// efficient packing for mozilla::Result. This also avoids having to include
+// the ResultVariant.h header.
+//
+// UnusedZero specialization:
+//
+// The UnusedZero specialization makes it possible to use CompactPair as the
+// underlying storage type for Result. For this optimization to work, it is
+// necessary that a distinct null-value is present for the error type. The
+// null-value represents the success case and must be different from all actual
+// error values.
+// This optimization can be easily enabled when the error type is a scoped enum.
+// No enum value must use zero as its value and UnusedZero must be specialized
+// through the helper struct UnusedZeroEnum.
+// For non-enum error types, a more complicated setup is necessary. The
+// UnusedZero specialization must implement all necessary interface methods
+// (i.e. `Inspect`, `Unwrap`, and `Store`) as well as all necessary constants
+// and types (i.e. `StorageType`, `value`, and `nullValue`).
+//
+// HasFreeLSB specialization:
+//
+// When the value and the error type are both providing specializations for
+// HasFreeLSB, Result uses an optimization to store both types within a single
+// storage location. This optimization uses the least significant bit as a tag
+// bit to mark the error case. And because the least significant bit is used for
+// tagging, it can't be used by the error type. That means for example when the
+// error type is an enum, all enum values must be even, because odd integer
+// values have the least significant bit set.
+// The actual HasFreeLSB specialization just needs to define `value` as a static
+// constant with the value `true`.
+
+template <>
+struct UnusedZero<mozilla::intl::ICUError>
+ : UnusedZeroEnum<mozilla::intl::ICUError> {};
+
+template <>
+struct UnusedZero<mozilla::intl::InternalError> {
+ using Error = mozilla::intl::InternalError;
+ using StorageType = std::underlying_type_t<Error::ErrorKind>;
+
+ static constexpr bool value = true;
+ static constexpr StorageType nullValue = 0;
+
+ static constexpr Error Inspect(const StorageType& aValue) {
+ return static_cast<Error::ErrorKind>(aValue);
+ }
+ static constexpr Error Unwrap(StorageType aValue) {
+ return static_cast<Error::ErrorKind>(aValue);
+ }
+ static constexpr StorageType Store(Error aValue) {
+ return static_cast<StorageType>(aValue.kind);
+ }
+};
+
+template <>
+struct HasFreeLSB<mozilla::intl::ICUError> {
+ static constexpr bool value = true;
+};
+
+template <>
+struct HasFreeLSB<mozilla::intl::InternalError> {
+ static constexpr bool value = true;
+};
+
+} // namespace mozilla::detail
+
+#endif