ICUError.h (4006B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifndef intl_components_ICUError_h 6 #define intl_components_ICUError_h 7 8 #include "mozilla/Attributes.h" 9 #include "mozilla/Result.h" 10 11 #include <cstdint> 12 #include <type_traits> 13 14 namespace mozilla::intl { 15 16 /** 17 * General purpose error type for operations that can result in an ICU error. 18 */ 19 enum class ICUError : uint8_t { 20 // Since we claim UnusedZero<ICUError>::value and 21 // HasFreeLSB<ICUError>::value == true below, we must only use positive, 22 // even enum values. 23 24 OutOfMemory = 2, 25 InternalError = 4, 26 OverflowError = 6, 27 }; 28 29 /** 30 * Error type when a method call can only result in an internal ICU error. 31 */ 32 struct InternalError { 33 // Since we claim UnusedZero<InternalError>::value and 34 // HasFreeLSB<InternalError>::value == true below, we must only use positive, 35 // even enum values. 36 enum class ErrorKind : uint8_t { Unspecified = 2 }; 37 38 const ErrorKind kind = ErrorKind::Unspecified; 39 40 constexpr InternalError() = default; 41 42 private: 43 friend struct mozilla::detail::UnusedZero<InternalError>; 44 45 constexpr MOZ_IMPLICIT InternalError(ErrorKind aKind) : kind(aKind) {} 46 }; 47 48 } // namespace mozilla::intl 49 50 namespace mozilla::detail { 51 52 // Provide specializations for UnusedZero and HasFreeLSB to enable more 53 // efficient packing for mozilla::Result. This also avoids having to include 54 // the ResultVariant.h header. 55 // 56 // UnusedZero specialization: 57 // 58 // The UnusedZero specialization makes it possible to use CompactPair as the 59 // underlying storage type for Result. For this optimization to work, it is 60 // necessary that a distinct null-value is present for the error type. The 61 // null-value represents the success case and must be different from all actual 62 // error values. 63 // This optimization can be easily enabled when the error type is a scoped enum. 64 // No enum value must use zero as its value and UnusedZero must be specialized 65 // through the helper struct UnusedZeroEnum. 66 // For non-enum error types, a more complicated setup is necessary. The 67 // UnusedZero specialization must implement all necessary interface methods 68 // (i.e. `Inspect`, `Unwrap`, and `Store`) as well as all necessary constants 69 // and types (i.e. `StorageType`, `value`, and `nullValue`). 70 // 71 // HasFreeLSB specialization: 72 // 73 // When the value and the error type are both providing specializations for 74 // HasFreeLSB, Result uses an optimization to store both types within a single 75 // storage location. This optimization uses the least significant bit as a tag 76 // bit to mark the error case. And because the least significant bit is used for 77 // tagging, it can't be used by the error type. That means for example when the 78 // error type is an enum, all enum values must be even, because odd integer 79 // values have the least significant bit set. 80 // The actual HasFreeLSB specialization just needs to define `value` as a static 81 // constant with the value `true`. 82 83 template <> 84 struct UnusedZero<mozilla::intl::ICUError> 85 : UnusedZeroEnum<mozilla::intl::ICUError> {}; 86 87 template <> 88 struct UnusedZero<mozilla::intl::InternalError> { 89 using Error = mozilla::intl::InternalError; 90 using StorageType = std::underlying_type_t<Error::ErrorKind>; 91 92 static constexpr bool value = true; 93 static constexpr StorageType nullValue = 0; 94 95 static constexpr Error Inspect(const StorageType& aValue) { 96 return static_cast<Error::ErrorKind>(aValue); 97 } 98 static constexpr Error Unwrap(StorageType aValue) { 99 return static_cast<Error::ErrorKind>(aValue); 100 } 101 static constexpr StorageType Store(Error aValue) { 102 return static_cast<StorageType>(aValue.kind); 103 } 104 }; 105 106 template <> 107 struct HasFreeLSB<mozilla::intl::ICUError> { 108 static constexpr bool value = true; 109 }; 110 111 template <> 112 struct HasFreeLSB<mozilla::intl::InternalError> { 113 static constexpr bool value = true; 114 }; 115 116 } // namespace mozilla::detail 117 118 #endif