123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- // © 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 "unicode/ustring.h"
- #include "formattedval_impl.h"
- #include "number_types.h"
- #include "formatted_string_builder.h"
- #include "number_utils.h"
- #include "static_unicode_sets.h"
- #include "unicode/listformatter.h"
- U_NAMESPACE_BEGIN
- typedef FormattedStringBuilder::Field Field;
- FormattedValueStringBuilderImpl::FormattedValueStringBuilderImpl(Field numericField)
- : fNumericField(numericField) {
- }
- FormattedValueStringBuilderImpl::~FormattedValueStringBuilderImpl() {
- }
- UnicodeString FormattedValueStringBuilderImpl::toString(UErrorCode&) const {
- return fString.toUnicodeString();
- }
- UnicodeString FormattedValueStringBuilderImpl::toTempString(UErrorCode&) const {
- return fString.toTempUnicodeString();
- }
- Appendable& FormattedValueStringBuilderImpl::appendTo(Appendable& appendable, UErrorCode&) const {
- appendable.appendString(fString.chars(), fString.length());
- return appendable;
- }
- UBool FormattedValueStringBuilderImpl::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const {
- // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
- return nextPositionImpl(cfpos, fNumericField, status) ? true : false;
- }
- UBool FormattedValueStringBuilderImpl::nextFieldPosition(FieldPosition& fp, UErrorCode& status) const {
- int32_t rawField = fp.getField();
- if (rawField == FieldPosition::DONT_CARE) {
- return false;
- }
- if (rawField < 0 || rawField >= UNUM_FIELD_COUNT) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return false;
- }
- ConstrainedFieldPosition cfpos;
- cfpos.constrainField(UFIELD_CATEGORY_NUMBER, rawField);
- cfpos.setState(UFIELD_CATEGORY_NUMBER, rawField, fp.getBeginIndex(), fp.getEndIndex());
- if (nextPositionImpl(cfpos, kUndefinedField, status)) {
- fp.setBeginIndex(cfpos.getStart());
- fp.setEndIndex(cfpos.getLimit());
- return true;
- }
- // Special case: fraction should start after integer if fraction is not present
- if (rawField == UNUM_FRACTION_FIELD && fp.getEndIndex() == 0) {
- bool inside = false;
- int32_t i = fString.fZero;
- for (; i < fString.fZero + fString.fLength; i++) {
- if (isIntOrGroup(fString.getFieldPtr()[i]) || fString.getFieldPtr()[i] == Field(UFIELD_CATEGORY_NUMBER, UNUM_DECIMAL_SEPARATOR_FIELD)) {
- inside = true;
- } else if (inside) {
- break;
- }
- }
- fp.setBeginIndex(i - fString.fZero);
- fp.setEndIndex(i - fString.fZero);
- }
- return false;
- }
- void FormattedValueStringBuilderImpl::getAllFieldPositions(FieldPositionIteratorHandler& fpih,
- UErrorCode& status) const {
- ConstrainedFieldPosition cfpos;
- while (nextPositionImpl(cfpos, kUndefinedField, status)) {
- fpih.addAttribute(cfpos.getField(), cfpos.getStart(), cfpos.getLimit());
- }
- }
- void FormattedValueStringBuilderImpl::resetString() {
- fString.clear();
- spanIndicesCount = 0;
- }
- // Signal the end of the string using a field that doesn't exist and that is
- // different from kUndefinedField, which is used for "null field".
- static constexpr Field kEndField = Field(0xf, 0xf);
- bool FormattedValueStringBuilderImpl::nextPositionImpl(ConstrainedFieldPosition& cfpos, Field numericField, UErrorCode& /*status*/) const {
- int32_t fieldStart = -1;
- Field currField = kUndefinedField;
- bool prevIsSpan = false;
- int32_t nextSpanStart = -1;
- if (spanIndicesCount > 0) {
- int64_t si = cfpos.getInt64IterationContext();
- U_ASSERT(si <= spanIndicesCount);
- if (si < spanIndicesCount) {
- nextSpanStart = spanIndices[si].start;
- }
- if (si > 0) {
- prevIsSpan = cfpos.getCategory() == spanIndices[si-1].category
- && cfpos.getField() == spanIndices[si-1].spanValue;
- }
- }
- bool prevIsNumeric = false;
- if (numericField != kUndefinedField) {
- prevIsNumeric = cfpos.getCategory() == numericField.getCategory()
- && cfpos.getField() == numericField.getField();
- }
- bool prevIsInteger = cfpos.getCategory() == UFIELD_CATEGORY_NUMBER
- && cfpos.getField() == UNUM_INTEGER_FIELD;
- for (int32_t i = fString.fZero + cfpos.getLimit(); i <= fString.fZero + fString.fLength; i++) {
- Field _field = (i < fString.fZero + fString.fLength) ? fString.getFieldPtr()[i] : kEndField;
- // Case 1: currently scanning a field.
- if (currField != kUndefinedField) {
- if (currField != _field) {
- int32_t end = i - fString.fZero;
- // Grouping separators can be whitespace; don't throw them out!
- if (isTrimmable(currField)) {
- end = trimBack(i - fString.fZero);
- }
- if (end <= fieldStart) {
- // Entire field position is ignorable; skip.
- fieldStart = -1;
- currField = kUndefinedField;
- i--; // look at this index again
- continue;
- }
- int32_t start = fieldStart;
- if (isTrimmable(currField)) {
- start = trimFront(start);
- }
- cfpos.setState(currField.getCategory(), currField.getField(), start, end);
- return true;
- }
- continue;
- }
- // Special case: emit normalField if we are pointing at the end of spanField.
- if (i > fString.fZero && prevIsSpan) {
- int64_t si = cfpos.getInt64IterationContext() - 1;
- U_ASSERT(si >= 0);
- int32_t previ = i - spanIndices[si].length;
- U_ASSERT(previ >= fString.fZero);
- Field prevField = fString.getFieldPtr()[previ];
- if (prevField == Field(UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD)) {
- // Special handling for ULISTFMT_ELEMENT_FIELD
- if (cfpos.matchesField(UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD)) {
- fieldStart = i - fString.fZero - spanIndices[si].length;
- int32_t end = fieldStart + spanIndices[si].length;
- cfpos.setState(
- UFIELD_CATEGORY_LIST,
- ULISTFMT_ELEMENT_FIELD,
- fieldStart,
- end);
- return true;
- } else {
- prevIsSpan = false;
- }
- } else {
- // Re-wind, since there may be multiple fields in the span.
- i = previ;
- _field = prevField;
- }
- }
- // Special case: coalesce the INTEGER if we are pointing at the end of the INTEGER.
- if (cfpos.matchesField(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)
- && i > fString.fZero
- && !prevIsInteger
- && !prevIsNumeric
- && isIntOrGroup(fString.getFieldPtr()[i - 1])
- && !isIntOrGroup(_field)) {
- int j = i - 1;
- for (; j >= fString.fZero && isIntOrGroup(fString.getFieldPtr()[j]); j--) {}
- cfpos.setState(
- UFIELD_CATEGORY_NUMBER,
- UNUM_INTEGER_FIELD,
- j - fString.fZero + 1,
- i - fString.fZero);
- return true;
- }
- // Special case: coalesce NUMERIC if we are pointing at the end of the NUMERIC.
- if (numericField != kUndefinedField
- && cfpos.matchesField(numericField.getCategory(), numericField.getField())
- && i > fString.fZero
- && !prevIsNumeric
- && fString.getFieldPtr()[i - 1].isNumeric()
- && !_field.isNumeric()) {
- // Re-wind to the beginning of the field and then emit it
- int32_t j = i - 1;
- for (; j >= fString.fZero && fString.getFieldPtr()[j].isNumeric(); j--) {}
- cfpos.setState(
- numericField.getCategory(),
- numericField.getField(),
- j - fString.fZero + 1,
- i - fString.fZero);
- return true;
- }
- // Check for span field
- if (!prevIsSpan && (
- _field == Field(UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD) ||
- i - fString.fZero == nextSpanStart)) {
- int64_t si = cfpos.getInt64IterationContext();
- if (si >= spanIndicesCount) {
- break;
- }
- UFieldCategory spanCategory = spanIndices[si].category;
- int32_t spanValue = spanIndices[si].spanValue;
- int32_t length = spanIndices[si].length;
- cfpos.setInt64IterationContext(si + 1);
- if (si + 1 < spanIndicesCount) {
- nextSpanStart = spanIndices[si + 1].start;
- }
- if (length == 0) {
- // ICU-21871: Don't return fields on empty spans
- i--;
- continue;
- }
- if (cfpos.matchesField(spanCategory, spanValue)) {
- fieldStart = i - fString.fZero;
- int32_t end = fieldStart + length;
- cfpos.setState(
- spanCategory,
- spanValue,
- fieldStart,
- end);
- return true;
- } else if (_field == Field(UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD)) {
- // Special handling for ULISTFMT_ELEMENT_FIELD
- if (cfpos.matchesField(UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD)) {
- fieldStart = i - fString.fZero;
- int32_t end = fieldStart + length;
- cfpos.setState(
- UFIELD_CATEGORY_LIST,
- ULISTFMT_ELEMENT_FIELD,
- fieldStart,
- end);
- return true;
- } else {
- // Failed to match; jump ahead
- i += length - 1;
- // goto loopend
- }
- }
- }
- // Special case: skip over INTEGER; will be coalesced later.
- else if (_field == Field(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)) {
- _field = kUndefinedField;
- }
- // No field starting at this position.
- else if (_field.isUndefined() || _field == kEndField) {
- // goto loopend
- }
- // No SpanField
- else if (cfpos.matchesField(_field.getCategory(), _field.getField())) {
- fieldStart = i - fString.fZero;
- currField = _field;
- }
- // loopend:
- prevIsSpan = false;
- prevIsNumeric = false;
- prevIsInteger = false;
- }
- U_ASSERT(currField == kUndefinedField);
- // Always set the position to the end so that we don't revisit previous sections
- cfpos.setState(
- cfpos.getCategory(),
- cfpos.getField(),
- fString.fLength,
- fString.fLength);
- return false;
- }
- void FormattedValueStringBuilderImpl::appendSpanInfo(UFieldCategory category, int32_t spanValue, int32_t start, int32_t length, UErrorCode& status) {
- if (U_FAILURE(status)) { return; }
- U_ASSERT(spanIndices.getCapacity() >= spanIndicesCount);
- if (spanIndices.getCapacity() == spanIndicesCount) {
- if (!spanIndices.resize(spanIndicesCount * 2, spanIndicesCount)) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- }
- spanIndices[spanIndicesCount] = {category, spanValue, start, length};
- spanIndicesCount++;
- }
- void FormattedValueStringBuilderImpl::prependSpanInfo(UFieldCategory category, int32_t spanValue, int32_t start, int32_t length, UErrorCode& status) {
- if (U_FAILURE(status)) { return; }
- U_ASSERT(spanIndices.getCapacity() >= spanIndicesCount);
- if (spanIndices.getCapacity() == spanIndicesCount) {
- if (!spanIndices.resize(spanIndicesCount * 2, spanIndicesCount)) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- }
- for (int32_t i = spanIndicesCount - 1; i >= 0; i--) {
- spanIndices[i+1] = spanIndices[i];
- }
- spanIndices[0] = {category, spanValue, start, length};
- spanIndicesCount++;
- }
- bool FormattedValueStringBuilderImpl::isIntOrGroup(Field field) {
- return field == Field(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)
- || field == Field(UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD);
- }
- bool FormattedValueStringBuilderImpl::isTrimmable(Field field) {
- return field != Field(UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD)
- && field.getCategory() != UFIELD_CATEGORY_LIST;
- }
- int32_t FormattedValueStringBuilderImpl::trimBack(int32_t limit) const {
- return unisets::get(unisets::DEFAULT_IGNORABLES)->spanBack(
- fString.getCharPtr() + fString.fZero,
- limit,
- USET_SPAN_CONTAINED);
- }
- int32_t FormattedValueStringBuilderImpl::trimFront(int32_t start) const {
- return start + unisets::get(unisets::DEFAULT_IGNORABLES)->span(
- fString.getCharPtr() + fString.fZero + start,
- fString.fLength - start,
- USET_SPAN_CONTAINED);
- }
- U_NAMESPACE_END
- #endif /* #if !UCONFIG_NO_FORMATTING */
|