177 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			177 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
| // © 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"
 | |
| #include "putilimp.h"
 | |
| 
 | |
| 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 {
 | |
|     // 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());
 | |
| }
 | |
| 
 | |
| 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;
 | |
|     int32_t i = static_cast<int32_t>(cfpos.getInt64IterationContext());
 | |
|     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;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| 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;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| U_NAMESPACE_END
 | |
| 
 | |
| #endif /* #if !UCONFIG_NO_FORMATTING */
 |