formattedval_iterimpl.cpp (6245B)
1 // © 2018 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 4 #include "unicode/utypes.h" 5 6 #if !UCONFIG_NO_FORMATTING 7 8 // This file contains one implementation of FormattedValue. 9 // Other independent implementations should go into their own cpp file for 10 // better dependency modularization. 11 12 #include "formattedval_impl.h" 13 #include "putilimp.h" 14 15 U_NAMESPACE_BEGIN 16 17 18 FormattedValueFieldPositionIteratorImpl::FormattedValueFieldPositionIteratorImpl( 19 int32_t initialFieldCapacity, 20 UErrorCode& status) 21 : fFields(initialFieldCapacity * 4, status) { 22 } 23 24 FormattedValueFieldPositionIteratorImpl::~FormattedValueFieldPositionIteratorImpl() = default; 25 26 UnicodeString FormattedValueFieldPositionIteratorImpl::toString( 27 UErrorCode&) const { 28 return fString; 29 } 30 31 UnicodeString FormattedValueFieldPositionIteratorImpl::toTempString( 32 UErrorCode&) const { 33 // The alias must point to memory owned by this object; 34 // fastCopyFrom doesn't do this when using a stack buffer. 35 return UnicodeString(true, fString.getBuffer(), fString.length()); 36 } 37 38 Appendable& FormattedValueFieldPositionIteratorImpl::appendTo( 39 Appendable& appendable, 40 UErrorCode&) const { 41 appendable.appendString(fString.getBuffer(), fString.length()); 42 return appendable; 43 } 44 45 UBool FormattedValueFieldPositionIteratorImpl::nextPosition( 46 ConstrainedFieldPosition& cfpos, 47 UErrorCode&) const { 48 U_ASSERT(fFields.size() % 4 == 0); 49 int32_t numFields = fFields.size() / 4; 50 int32_t i = static_cast<int32_t>(cfpos.getInt64IterationContext()); 51 for (; i < numFields; i++) { 52 UFieldCategory category = static_cast<UFieldCategory>(fFields.elementAti(i * 4)); 53 int32_t field = fFields.elementAti(i * 4 + 1); 54 if (cfpos.matchesField(category, field)) { 55 int32_t start = fFields.elementAti(i * 4 + 2); 56 int32_t limit = fFields.elementAti(i * 4 + 3); 57 cfpos.setState(category, field, start, limit); 58 break; 59 } 60 } 61 cfpos.setInt64IterationContext(i == numFields ? i : i + 1); 62 return i < numFields; 63 } 64 65 66 FieldPositionIteratorHandler FormattedValueFieldPositionIteratorImpl::getHandler( 67 UErrorCode& status) { 68 return FieldPositionIteratorHandler(&fFields, status); 69 } 70 71 void FormattedValueFieldPositionIteratorImpl::appendString( 72 UnicodeString string, 73 UErrorCode& status) { 74 if (U_FAILURE(status)) { 75 return; 76 } 77 fString.append(string); 78 // Make the string NUL-terminated 79 if (fString.getTerminatedBuffer() == nullptr) { 80 status = U_MEMORY_ALLOCATION_ERROR; 81 return; 82 } 83 } 84 85 86 void FormattedValueFieldPositionIteratorImpl::addOverlapSpans( 87 UFieldCategory spanCategory, 88 int8_t firstIndex, 89 UErrorCode& status) { 90 // In order to avoid fancy data structures, this is an O(N^2) algorithm, 91 // which should be fine for all real-life applications of this function. 92 int32_t s1a = INT32_MAX; 93 int32_t s1b = 0; 94 int32_t s2a = INT32_MAX; 95 int32_t s2b = 0; 96 int32_t numFields = fFields.size() / 4; 97 for (int32_t i = 0; i<numFields; i++) { 98 int32_t field1 = fFields.elementAti(i * 4 + 1); 99 for (int32_t j = i + 1; j<numFields; j++) { 100 int32_t field2 = fFields.elementAti(j * 4 + 1); 101 if (field1 != field2) { 102 continue; 103 } 104 // Found a duplicate 105 s1a = uprv_min(s1a, fFields.elementAti(i * 4 + 2)); 106 s1b = uprv_max(s1b, fFields.elementAti(i * 4 + 3)); 107 s2a = uprv_min(s2a, fFields.elementAti(j * 4 + 2)); 108 s2b = uprv_max(s2b, fFields.elementAti(j * 4 + 3)); 109 break; 110 } 111 } 112 if (s1a != INT32_MAX) { 113 // Success: add the two span fields 114 fFields.addElement(spanCategory, status); 115 fFields.addElement(firstIndex, status); 116 fFields.addElement(s1a, status); 117 fFields.addElement(s1b, status); 118 fFields.addElement(spanCategory, status); 119 fFields.addElement(1 - firstIndex, status); 120 fFields.addElement(s2a, status); 121 fFields.addElement(s2b, status); 122 } 123 } 124 125 126 void FormattedValueFieldPositionIteratorImpl::sort() { 127 // Use bubble sort, O(N^2) but easy and no fancy data structures. 128 int32_t numFields = fFields.size() / 4; 129 while (true) { 130 bool isSorted = true; 131 for (int32_t i=0; i<numFields-1; i++) { 132 int32_t categ1 = fFields.elementAti(i*4 + 0); 133 int32_t field1 = fFields.elementAti(i*4 + 1); 134 int32_t start1 = fFields.elementAti(i*4 + 2); 135 int32_t limit1 = fFields.elementAti(i*4 + 3); 136 int32_t categ2 = fFields.elementAti(i*4 + 4); 137 int32_t field2 = fFields.elementAti(i*4 + 5); 138 int32_t start2 = fFields.elementAti(i*4 + 6); 139 int32_t limit2 = fFields.elementAti(i*4 + 7); 140 int64_t comparison = 0; 141 if (start1 != start2) { 142 // Higher start index -> higher rank 143 comparison = start2 - start1; 144 } else if (limit1 != limit2) { 145 // Higher length (end index) -> lower rank 146 comparison = limit1 - limit2; 147 } else if (categ1 != categ2) { 148 // Higher field category -> lower rank 149 comparison = categ1 - categ2; 150 } else if (field1 != field2) { 151 // Higher field -> higher rank 152 comparison = field2 - field1; 153 } 154 if (comparison < 0) { 155 // Perform a swap 156 isSorted = false; 157 fFields.setElementAt(categ2, i*4 + 0); 158 fFields.setElementAt(field2, i*4 + 1); 159 fFields.setElementAt(start2, i*4 + 2); 160 fFields.setElementAt(limit2, i*4 + 3); 161 fFields.setElementAt(categ1, i*4 + 4); 162 fFields.setElementAt(field1, i*4 + 5); 163 fFields.setElementAt(start1, i*4 + 6); 164 fFields.setElementAt(limit1, i*4 + 7); 165 } 166 } 167 if (isSorted) { 168 break; 169 } 170 } 171 } 172 173 174 U_NAMESPACE_END 175 176 #endif /* #if !UCONFIG_NO_FORMATTING */