зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1648137 - Part 15: Record the source of a number part. r=platform-i18n-reviewers,nordzilla
Add `NumberPartSource` to `NumberPart` in preparation for part 18. Also changes the underlying type of `NumberPartType` to `int16_t` to ensure the size of `NumberPart` doesn't change on 32-bit platforms when adding `NumberPartSource`. (Note: `sizeof(NumberPart)` is 16 on 64-platforms with or without this change.) Differential Revision: https://phabricator.services.mozilla.com/D119755
This commit is contained in:
Родитель
52d6dde648
Коммит
982d8dbbbf
|
@ -189,11 +189,19 @@ TEST(IntlNumberFormat, FormatToParts)
|
|||
ASSERT_TRUE(res != nullptr);
|
||||
ASSERT_EQ(std::u16string_view(res), u"123.456,789");
|
||||
ASSERT_EQ(parts.length(), 5U);
|
||||
ASSERT_EQ(parts[0], (NumberPart{NumberPartType::Integer, 3}));
|
||||
ASSERT_EQ(parts[1], (NumberPart{NumberPartType::Group, 4}));
|
||||
ASSERT_EQ(parts[2], (NumberPart{NumberPartType::Integer, 7}));
|
||||
ASSERT_EQ(parts[3], (NumberPart{NumberPartType::Decimal, 8}));
|
||||
ASSERT_EQ(parts[4], (NumberPart{NumberPartType::Fraction, 11}));
|
||||
|
||||
// NumberFormat only ever produces number parts with NumberPartSource::Shared.
|
||||
|
||||
ASSERT_EQ(parts[0],
|
||||
(NumberPart{NumberPartType::Integer, NumberPartSource::Shared, 3}));
|
||||
ASSERT_EQ(parts[1],
|
||||
(NumberPart{NumberPartType::Group, NumberPartSource::Shared, 4}));
|
||||
ASSERT_EQ(parts[2],
|
||||
(NumberPart{NumberPartType::Integer, NumberPartSource::Shared, 7}));
|
||||
ASSERT_EQ(parts[3],
|
||||
(NumberPart{NumberPartType::Decimal, NumberPartSource::Shared, 8}));
|
||||
ASSERT_EQ(parts[4], (NumberPart{NumberPartType::Fraction,
|
||||
NumberPartSource::Shared, 11}));
|
||||
}
|
||||
|
||||
} // namespace intl
|
||||
|
|
|
@ -185,7 +185,7 @@ struct MOZ_STACK_CLASS NumberFormatOptions {
|
|||
} mRoundingPriority = RoundingPriority::Auto;
|
||||
};
|
||||
|
||||
enum class NumberPartType {
|
||||
enum class NumberPartType : int16_t {
|
||||
Compact,
|
||||
Currency,
|
||||
Decimal,
|
||||
|
@ -204,15 +204,18 @@ enum class NumberPartType {
|
|||
Unit,
|
||||
};
|
||||
|
||||
enum class NumberPartSource : int16_t { Shared, Start, End };
|
||||
|
||||
// Because parts fully partition the formatted string, we only track the
|
||||
// index of the end of each part -- the beginning is implicitly the last
|
||||
// part's end.
|
||||
struct NumberPart {
|
||||
NumberPartType type;
|
||||
NumberPartSource source;
|
||||
size_t endIndex;
|
||||
|
||||
bool operator==(const NumberPart& rhs) const {
|
||||
return type == rhs.type && endIndex == rhs.endIndex;
|
||||
return type == rhs.type && source == rhs.source && endIndex == rhs.endIndex;
|
||||
}
|
||||
bool operator!=(const NumberPart& rhs) const { return !(*this == rhs); }
|
||||
};
|
||||
|
|
|
@ -16,6 +16,7 @@ bool NumberFormatFields::append(NumberPartType type, int32_t begin,
|
|||
}
|
||||
|
||||
bool NumberFormatFields::toPartsVector(size_t overallLength,
|
||||
const NumberPartSourceMap& sourceMap,
|
||||
NumberPartVector& parts) {
|
||||
std::sort(fields_.begin(), fields_.end(),
|
||||
[](const NumberFormatField& left, const NumberFormatField& right) {
|
||||
|
@ -87,6 +88,8 @@ bool NumberFormatFields::toPartsVector(size_t overallLength,
|
|||
// The length of the overall formatted string.
|
||||
const uint32_t limit = 0;
|
||||
|
||||
NumberPartSourceMap sourceMap;
|
||||
|
||||
Vector<size_t, 4> enclosingFields;
|
||||
|
||||
void popEnclosingFieldsEndingAt(uint32_t end) {
|
||||
|
@ -109,13 +112,13 @@ bool NumberFormatFields::toPartsVector(size_t overallLength,
|
|||
if (index == len) {
|
||||
if (enclosingFields.length() > 0) {
|
||||
const auto& enclosing = fields[enclosingFields.popCopy()];
|
||||
*part = {enclosing.type, enclosing.end};
|
||||
*part = {enclosing.type, sourceMap.source(enclosing), enclosing.end};
|
||||
|
||||
// If additional enclosing fields end where this part ends,
|
||||
// pop them as well.
|
||||
popEnclosingFieldsEndingAt(part->endIndex);
|
||||
} else {
|
||||
*part = {NumberPartType::Literal, limit};
|
||||
*part = {NumberPartType::Literal, sourceMap.source(limit), limit};
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -134,11 +137,13 @@ bool NumberFormatFields::toPartsVector(size_t overallLength,
|
|||
// field or the end of the enclosing field, whichever is
|
||||
// earlier.
|
||||
const auto& enclosing = fields[enclosingFields.back()];
|
||||
*part = {enclosing.type, std::min(enclosing.end, current->begin)};
|
||||
*part = {enclosing.type, sourceMap.source(enclosing),
|
||||
std::min(enclosing.end, current->begin)};
|
||||
popEnclosingFieldsEndingAt(part->endIndex);
|
||||
} else {
|
||||
// If there's no enclosing field, the space is a literal.
|
||||
*part = {NumberPartType::Literal, current->begin};
|
||||
*part = {NumberPartType::Literal, sourceMap.source(current->begin),
|
||||
current->begin};
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -152,7 +157,7 @@ bool NumberFormatFields::toPartsVector(size_t overallLength,
|
|||
|
||||
// If the current field is last, the part extends to its end.
|
||||
if (++index == len) {
|
||||
*part = {current->type, current->end};
|
||||
*part = {current->type, sourceMap.source(*current), current->end};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -175,20 +180,21 @@ bool NumberFormatFields::toPartsVector(size_t overallLength,
|
|||
if (current->end <= next->begin) {
|
||||
// The next field begins after the current field ends. Therefore
|
||||
// the current part ends at the end of the current field.
|
||||
*part = {current->type, current->end};
|
||||
*part = {current->type, sourceMap.source(*current), current->end};
|
||||
popEnclosingFieldsEndingAt(part->endIndex);
|
||||
} else {
|
||||
// The current field encloses the next one. The current part
|
||||
// ends where the next field/part will start.
|
||||
*part = {current->type, next->begin};
|
||||
*part = {current->type, sourceMap.source(*current), next->begin};
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
PartGenerator(const FieldsVector& vec, uint32_t limit)
|
||||
: fields(vec), limit(limit), enclosingFields() {}
|
||||
PartGenerator(const FieldsVector& vec, uint32_t limit,
|
||||
const NumberPartSourceMap& sourceMap)
|
||||
: fields(vec), limit(limit), sourceMap(sourceMap), enclosingFields() {}
|
||||
|
||||
bool nextPart(bool* hasPart, NumberPart* part) {
|
||||
// There are no parts left if we've partitioned the entire string.
|
||||
|
@ -211,7 +217,7 @@ bool NumberFormatFields::toPartsVector(size_t overallLength,
|
|||
// Finally, generate the result array.
|
||||
size_t lastEndIndex = 0;
|
||||
|
||||
PartGenerator gen(fields_, overallLength);
|
||||
PartGenerator gen(fields_, overallLength, sourceMap);
|
||||
do {
|
||||
bool hasPart;
|
||||
NumberPart part;
|
||||
|
|
|
@ -24,6 +24,33 @@ struct NumberFormatField {
|
|||
: begin(begin), end(end), type(type) {}
|
||||
};
|
||||
|
||||
struct NumberPartSourceMap {
|
||||
struct Range {
|
||||
uint32_t begin = 0;
|
||||
uint32_t end = 0;
|
||||
};
|
||||
|
||||
// Begin and end position of the start range.
|
||||
Range start;
|
||||
|
||||
// Begin and end position of the end range.
|
||||
Range end;
|
||||
|
||||
NumberPartSource source(uint32_t endIndex) {
|
||||
if (start.begin < endIndex && endIndex <= start.end) {
|
||||
return NumberPartSource::Start;
|
||||
}
|
||||
if (end.begin < endIndex && endIndex <= end.end) {
|
||||
return NumberPartSource::End;
|
||||
}
|
||||
return NumberPartSource::Shared;
|
||||
}
|
||||
|
||||
NumberPartSource source(const NumberFormatField& field) {
|
||||
return source(field.end);
|
||||
}
|
||||
};
|
||||
|
||||
class NumberFormatFields {
|
||||
using FieldsVector = Vector<NumberFormatField, 16>;
|
||||
|
||||
|
@ -33,6 +60,12 @@ class NumberFormatFields {
|
|||
[[nodiscard]] bool append(NumberPartType type, int32_t begin, int32_t end);
|
||||
|
||||
[[nodiscard]] bool toPartsVector(size_t overallLength,
|
||||
NumberPartVector& parts) {
|
||||
return toPartsVector(overallLength, {}, parts);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool toPartsVector(size_t overallLength,
|
||||
const NumberPartSourceMap& sourceMap,
|
||||
NumberPartVector& parts);
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче