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:
André Bargull 2021-08-24 09:34:51 +00:00
Родитель 52d6dde648
Коммит 982d8dbbbf
4 изменённых файлов: 67 добавлений и 17 удалений

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

@ -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);
};