2019-02-05 02:45:56 +00:00
|
|
|
// © 2018 and later: Unicode, Inc. and others.
|
|
|
|
// License & terms of use: http://www.unicode.org/copyright.html
|
|
|
|
|
|
|
|
#include "unicode/utypes.h"
|
|
|
|
|
|
|
|
#if !UCONFIG_NO_FORMATTING
|
|
|
|
|
|
|
|
// This file contains one implementation of FormattedValue.
|
|
|
|
// Other independent implementations should go into their own cpp file for
|
|
|
|
// better dependency modularization.
|
|
|
|
|
|
|
|
#include "formattedval_impl.h"
|
2019-02-11 23:53:31 +00:00
|
|
|
#include "putilimp.h"
|
2019-02-05 02:45:56 +00:00
|
|
|
|
|
|
|
U_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
|
|
|
|
FormattedValueFieldPositionIteratorImpl::FormattedValueFieldPositionIteratorImpl(
|
|
|
|
int32_t initialFieldCapacity,
|
|
|
|
UErrorCode& status)
|
|
|
|
: fFields(initialFieldCapacity * 4, status) {
|
|
|
|
}
|
|
|
|
|
|
|
|
FormattedValueFieldPositionIteratorImpl::~FormattedValueFieldPositionIteratorImpl() = default;
|
|
|
|
|
|
|
|
UnicodeString FormattedValueFieldPositionIteratorImpl::toString(
|
|
|
|
UErrorCode&) const {
|
|
|
|
return fString;
|
|
|
|
}
|
|
|
|
|
|
|
|
UnicodeString FormattedValueFieldPositionIteratorImpl::toTempString(
|
|
|
|
UErrorCode&) const {
|
2019-02-05 06:24:00 +00:00
|
|
|
// The alias must point to memory owned by this object;
|
|
|
|
// fastCopyFrom doesn't do this when using a stack buffer.
|
|
|
|
return UnicodeString(TRUE, fString.getBuffer(), fString.length());
|
2019-02-05 02:45:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Appendable& FormattedValueFieldPositionIteratorImpl::appendTo(
|
|
|
|
Appendable& appendable,
|
|
|
|
UErrorCode&) const {
|
|
|
|
appendable.appendString(fString.getBuffer(), fString.length());
|
|
|
|
return appendable;
|
|
|
|
}
|
|
|
|
|
|
|
|
UBool FormattedValueFieldPositionIteratorImpl::nextPosition(
|
|
|
|
ConstrainedFieldPosition& cfpos,
|
|
|
|
UErrorCode&) const {
|
|
|
|
U_ASSERT(fFields.size() % 4 == 0);
|
|
|
|
int32_t numFields = fFields.size() / 4;
|
2019-02-21 03:38:58 +00:00
|
|
|
int32_t i = static_cast<int32_t>(cfpos.getInt64IterationContext());
|
2019-02-05 02:45:56 +00:00
|
|
|
for (; i < numFields; i++) {
|
|
|
|
UFieldCategory category = static_cast<UFieldCategory>(fFields.elementAti(i * 4));
|
|
|
|
int32_t field = fFields.elementAti(i * 4 + 1);
|
|
|
|
if (cfpos.matchesField(category, field)) {
|
|
|
|
int32_t start = fFields.elementAti(i * 4 + 2);
|
|
|
|
int32_t limit = fFields.elementAti(i * 4 + 3);
|
|
|
|
cfpos.setState(category, field, start, limit);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cfpos.setInt64IterationContext(i == numFields ? i : i + 1);
|
|
|
|
return i < numFields;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FieldPositionIteratorHandler FormattedValueFieldPositionIteratorImpl::getHandler(
|
|
|
|
UErrorCode& status) {
|
|
|
|
return FieldPositionIteratorHandler(&fFields, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FormattedValueFieldPositionIteratorImpl::appendString(
|
|
|
|
UnicodeString string,
|
|
|
|
UErrorCode& status) {
|
|
|
|
if (U_FAILURE(status)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
fString.append(string);
|
|
|
|
// Make the string NUL-terminated
|
|
|
|
if (fString.getTerminatedBuffer() == nullptr) {
|
|
|
|
status = U_MEMORY_ALLOCATION_ERROR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-02-11 23:53:31 +00:00
|
|
|
void FormattedValueFieldPositionIteratorImpl::addOverlapSpans(
|
|
|
|
UFieldCategory spanCategory,
|
|
|
|
int8_t firstIndex,
|
|
|
|
UErrorCode& status) {
|
|
|
|
// In order to avoid fancy data structures, this is an O(N^2) algorithm,
|
|
|
|
// which should be fine for all real-life applications of this function.
|
|
|
|
int32_t s1a = INT32_MAX;
|
|
|
|
int32_t s1b = 0;
|
|
|
|
int32_t s2a = INT32_MAX;
|
|
|
|
int32_t s2b = 0;
|
|
|
|
int32_t numFields = fFields.size() / 4;
|
|
|
|
for (int32_t i = 0; i<numFields; i++) {
|
|
|
|
int32_t field1 = fFields.elementAti(i * 4 + 1);
|
|
|
|
for (int32_t j = i + 1; j<numFields; j++) {
|
|
|
|
int32_t field2 = fFields.elementAti(j * 4 + 1);
|
|
|
|
if (field1 != field2) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Found a duplicate
|
|
|
|
s1a = uprv_min(s1a, fFields.elementAti(i * 4 + 2));
|
|
|
|
s1b = uprv_max(s1b, fFields.elementAti(i * 4 + 3));
|
|
|
|
s2a = uprv_min(s2a, fFields.elementAti(j * 4 + 2));
|
|
|
|
s2b = uprv_max(s2b, fFields.elementAti(j * 4 + 3));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (s1a != INT32_MAX) {
|
|
|
|
// Success: add the two span fields
|
|
|
|
fFields.addElement(spanCategory, status);
|
|
|
|
fFields.addElement(firstIndex, status);
|
|
|
|
fFields.addElement(s1a, status);
|
|
|
|
fFields.addElement(s1b, status);
|
|
|
|
fFields.addElement(spanCategory, status);
|
|
|
|
fFields.addElement(1 - firstIndex, status);
|
|
|
|
fFields.addElement(s2a, status);
|
|
|
|
fFields.addElement(s2b, status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FormattedValueFieldPositionIteratorImpl::sort() {
|
|
|
|
// Use bubble sort, O(N^2) but easy and no fancy data structures.
|
|
|
|
int32_t numFields = fFields.size() / 4;
|
|
|
|
while (true) {
|
|
|
|
bool isSorted = true;
|
|
|
|
for (int32_t i=0; i<numFields-1; i++) {
|
|
|
|
int32_t categ1 = fFields.elementAti(i*4 + 0);
|
|
|
|
int32_t field1 = fFields.elementAti(i*4 + 1);
|
|
|
|
int32_t start1 = fFields.elementAti(i*4 + 2);
|
|
|
|
int32_t limit1 = fFields.elementAti(i*4 + 3);
|
|
|
|
int32_t categ2 = fFields.elementAti(i*4 + 4);
|
|
|
|
int32_t field2 = fFields.elementAti(i*4 + 5);
|
|
|
|
int32_t start2 = fFields.elementAti(i*4 + 6);
|
|
|
|
int32_t limit2 = fFields.elementAti(i*4 + 7);
|
|
|
|
int64_t comparison = 0;
|
|
|
|
if (start1 != start2) {
|
|
|
|
// Higher start index -> higher rank
|
|
|
|
comparison = start2 - start1;
|
|
|
|
} else if (limit1 != limit2) {
|
|
|
|
// Higher length (end index) -> lower rank
|
|
|
|
comparison = limit1 - limit2;
|
|
|
|
} else if (categ1 != categ2) {
|
|
|
|
// Higher field category -> lower rank
|
|
|
|
comparison = categ1 - categ2;
|
|
|
|
} else if (field1 != field2) {
|
|
|
|
// Higher field -> higher rank
|
|
|
|
comparison = field2 - field1;
|
|
|
|
}
|
|
|
|
if (comparison < 0) {
|
|
|
|
// Perform a swap
|
|
|
|
isSorted = false;
|
|
|
|
fFields.setElementAt(categ2, i*4 + 0);
|
|
|
|
fFields.setElementAt(field2, i*4 + 1);
|
|
|
|
fFields.setElementAt(start2, i*4 + 2);
|
|
|
|
fFields.setElementAt(limit2, i*4 + 3);
|
|
|
|
fFields.setElementAt(categ1, i*4 + 4);
|
|
|
|
fFields.setElementAt(field1, i*4 + 5);
|
|
|
|
fFields.setElementAt(start1, i*4 + 6);
|
|
|
|
fFields.setElementAt(limit1, i*4 + 7);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isSorted) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-02-05 02:45:56 +00:00
|
|
|
U_NAMESPACE_END
|
|
|
|
|
|
|
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|