Bug 1737814 - Part 1: Add a AutoFormatResult class. r=platform-i18n-reviewers,anba,gregtatum

This AutoFormatResult class could be shared later by ListFormat.

Differential Revision: https://phabricator.services.mozilla.com/D129561
This commit is contained in:
Yoshi Cheng-Hao Huang 2021-11-01 14:23:22 +00:00
Родитель cf3a438f13
Коммит 24dcdf0726
4 изменённых файлов: 127 добавлений и 112 удалений

Просмотреть файл

@ -2,8 +2,6 @@
* 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/. */
#include "unicode/udateintervalformat.h"
#include "DateTimeFormatUtils.h"
#include "ScopedICUObject.h"
@ -72,63 +70,15 @@ DateIntervalFormat::~DateIntervalFormat() {
udtitvfmt_close(mDateIntervalFormat.GetMut());
}
AutoFormattedDateInterval::AutoFormattedDateInterval() {
mFormatted = udtitvfmt_openResult(&mError);
if (U_FAILURE(mError)) {
mFormatted = nullptr;
}
}
const UFormattedValue* AutoFormattedDateInterval::Value() const {
if (!IsValid()) {
return nullptr;
}
UErrorCode status = U_ZERO_ERROR;
const UFormattedValue* value = udtitvfmt_resultAsValue(mFormatted, &status);
if (U_FAILURE(status)) {
return nullptr;
}
return value;
}
Result<Span<const char16_t>, ICUError> AutoFormattedDateInterval::ToSpan()
const {
if (!IsValid()) {
return Err(GetError());
}
const UFormattedValue* value = Value();
if (!value) {
return Err(ICUError::InternalError);
}
UErrorCode status = U_ZERO_ERROR;
int32_t strLength;
const char16_t* str = ufmtval_getString(value, &strLength, &status);
if (U_FAILURE(status)) {
return Err(ToICUError(status));
}
return Span{str, AssertedCast<size_t>(strLength)};
}
AutoFormattedDateInterval::~AutoFormattedDateInterval() {
if (mFormatted) {
udtitvfmt_closeResult(mFormatted);
}
}
ICUResult DateIntervalFormat::TryFormatCalendar(
const Calendar& aStart, const Calendar& aEnd,
AutoFormattedDateInterval& aFormatted, bool* aPracticallyEqual) const {
MOZ_ASSERT(aFormatted.IsValid());
UErrorCode status = U_ZERO_ERROR;
udtitvfmt_formatCalendarToResult(
mDateIntervalFormat.GetConst(), aStart.GetUCalendar(),
aEnd.GetUCalendar(), aFormatted.GetUFormattedDateInterval(), &status);
udtitvfmt_formatCalendarToResult(mDateIntervalFormat.GetConst(),
aStart.GetUCalendar(), aEnd.GetUCalendar(),
aFormatted.GetFormatted(), &status);
if (U_FAILURE(status)) {
return Err(ToICUError(status));
@ -145,7 +95,7 @@ ICUResult DateIntervalFormat::TryFormatDateTime(
UErrorCode status = U_ZERO_ERROR;
udtitvfmt_formatToResult(mDateIntervalFormat.GetConst(), aStart, aEnd,
aFormatted.GetUFormattedDateInterval(), &status);
aFormatted.GetFormatted(), &status);
if (U_FAILURE(status)) {
return Err(ToICUError(status));
}

Просмотреть файл

@ -11,16 +11,16 @@
#include "mozilla/Span.h"
#include "mozilla/UniquePtr.h"
#include "unicode/udateintervalformat.h"
#include "unicode/utypes.h"
struct UDateIntervalFormat;
struct UFormattedDateInterval;
struct UFormattedValue;
namespace mozilla::intl {
class AutoFormattedDateInterval;
class Calendar;
using AutoFormattedDateInterval =
AutoFormattedResult<UFormattedDateInterval, udtitvfmt_openResult,
udtitvfmt_resultAsValue, udtitvfmt_closeResult>;
/**
* This component is a Mozilla-focused API for the date range formatting
* provided by ICU. This DateIntervalFormat class helps to format the range
@ -101,59 +101,6 @@ class DateIntervalFormat final {
ICUPointer<UDateIntervalFormat> mDateIntervalFormat =
ICUPointer<UDateIntervalFormat>(nullptr);
};
/**
* A RAII class to hold the formatted value of DateIntervalFormat.
*
* The caller will need to create this AutoFormattedDateInterval on the stack,
* and call IsValid() method to check if the native object
* (UFormattedDateInterval) has been created properly, and then passes this
* object to the methods of DateIntervalFormat.
* The result of the DateIntervalFormat's method will be stored in this object,
* the caller can use ToSpan() method to get the formatted string, or pass it
* to DateIntervalFormat::TryFormattedToParts to get the DateTimePart vector.
*
* The formatted value will be released once this class is destructed.
*/
class MOZ_RAII AutoFormattedDateInterval {
public:
AutoFormattedDateInterval();
~AutoFormattedDateInterval();
AutoFormattedDateInterval(const AutoFormattedDateInterval& other) = delete;
AutoFormattedDateInterval& operator=(const AutoFormattedDateInterval& other) =
delete;
AutoFormattedDateInterval(AutoFormattedDateInterval&& other) = delete;
AutoFormattedDateInterval& operator=(AutoFormattedDateInterval&& other) =
delete;
/**
* Check if the native UFormattedDateInterval was created successfully.
*/
bool IsValid() const { return !!mFormatted; }
/**
* Get error code if IsValid() returns false.
*/
ICUError GetError() const { return ToICUError(mError); }
/**
* Get the formatted result.
*/
Result<Span<const char16_t>, ICUError> ToSpan() const;
private:
friend class DateIntervalFormat;
UFormattedDateInterval* GetUFormattedDateInterval() const {
return mFormatted;
}
const UFormattedValue* Value() const;
UFormattedDateInterval* mFormatted = nullptr;
UErrorCode mError = U_ZERO_ERROR;
};
} // namespace mozilla::intl
#endif

Просмотреть файл

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/intl/ICU4CGlue.h"
#include "unicode/uformattedvalue.h"
namespace mozilla::intl {
@ -21,4 +22,17 @@ ICUResult ToICUResult(UErrorCode status) {
return Err(ToICUError(status));
}
// static
Result<Span<const char16_t>, ICUError> FormattedResult::ToSpanImpl(
const UFormattedValue* value) {
UErrorCode status = U_ZERO_ERROR;
int32_t strLength;
const char16_t* str = ufmtval_getString(value, &strLength, &status);
if (U_FAILURE(status)) {
return Err(ToICUError(status));
}
return Span{str, AssertedCast<size_t>(strLength)};
}
} // namespace mozilla::intl

Просмотреть файл

@ -29,6 +29,7 @@
#include <stdint.h>
#include <string_view>
struct UFormattedValue;
namespace mozilla::intl {
static inline const char* IcuLocale(const char* aLocale) {
@ -544,6 +545,109 @@ class AvailableLocalesEnumeration final {
Iterator end() const { return Iterator(mLocalesCount); }
};
/**
* A helper class to wrap calling ICU function in cpp file so we don't have to
* include the ICU header here.
*/
class FormattedResult {
protected:
static Result<Span<const char16_t>, ICUError> ToSpanImpl(
const UFormattedValue* value);
};
/**
* A RAII class to hold the formatted value of format result.
*
* The caller will need to create this AutoFormattedResult on the stack, with
* the following parameters:
* 1. Native ICU type.
* 2. An ICU function which opens the result.
* 3. An ICU function which can get the result as UFormattedValue.
* 4. An ICU function which closes the result.
*
* After the object is created, caller needs to call IsValid() method to check
* if the native object has been created properly, and then passes this
* object to other format interfaces.
* The format result will be stored in this object, the caller can use ToSpan()
* method to get the formatted string.
*
* The methods GetFormatted() and Value() are private methods since they expose
* native ICU types. If the caller wants to call these methods, the caller needs
* to register itself as a friend class in AutoFormattedResult.
*
* The formatted value and the native ICU object will be released once this
* class is destructed.
*/
template <typename T, T*(Open)(UErrorCode*),
const UFormattedValue*(GetValue)(const T*, UErrorCode*),
void(Close)(T*)>
class MOZ_RAII AutoFormattedResult : FormattedResult {
public:
AutoFormattedResult() {
mFormatted = Open(&mError);
if (U_FAILURE(mError)) {
mFormatted = nullptr;
}
}
~AutoFormattedResult() {
if (mFormatted) {
Close(mFormatted);
}
}
AutoFormattedResult(const AutoFormattedResult& other) = delete;
AutoFormattedResult& operator=(const AutoFormattedResult& other) = delete;
AutoFormattedResult(AutoFormattedResult&& other) = delete;
AutoFormattedResult& operator=(AutoFormattedResult&& other) = delete;
/**
* Check if the native UFormattedDateInterval was created successfully.
*/
bool IsValid() const { return !!mFormatted; }
/**
* Get error code if IsValid() returns false.
*/
ICUError GetError() const { return ToICUError(mError); }
/**
* Get the formatted result.
*/
Result<Span<const char16_t>, ICUError> ToSpan() const {
if (!IsValid()) {
return Err(GetError());
}
const UFormattedValue* value = Value();
if (!value) {
return Err(ICUError::InternalError);
}
return ToSpanImpl(value);
}
private:
friend class DateIntervalFormat;
T* GetFormatted() const { return mFormatted; }
const UFormattedValue* Value() const {
if (!IsValid()) {
return nullptr;
}
UErrorCode status = U_ZERO_ERROR;
const UFormattedValue* value = GetValue(mFormatted, &status);
if (U_FAILURE(status)) {
return nullptr;
}
return value;
};
T* mFormatted = nullptr;
UErrorCode mError = U_ZERO_ERROR;
};
} // namespace mozilla::intl
#endif /* intl_components_ICUUtils_h */