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
15U_NAMESPACE_BEGIN
16
17
18FormattedValueFieldPositionIteratorImpl::FormattedValueFieldPositionIteratorImpl(
19 int32_t initialFieldCapacity,
20 UErrorCode& status)
21 : fFields(initialFieldCapacity * 4, status) {
22}
23
24FormattedValueFieldPositionIteratorImpl::~FormattedValueFieldPositionIteratorImpl() = default;
25
26UnicodeString FormattedValueFieldPositionIteratorImpl::toString(
27 UErrorCode&) const {
28 return fString;
29}
30
31UnicodeString 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
38Appendable& FormattedValueFieldPositionIteratorImpl::appendTo(
39 Appendable& appendable,
40 UErrorCode&) const {
41 appendable.appendString(fString.getBuffer(), fString.length());
42 return appendable;
43}
44
45UBool 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
66FieldPositionIteratorHandler FormattedValueFieldPositionIteratorImpl::getHandler(
67 UErrorCode& status) {
68 return FieldPositionIteratorHandler(&fFields, status);
69}
70
71void 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
86void 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
126void 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
174U_NAMESPACE_END
175
176#endif /* #if !UCONFIG_NO_FORMATTING */
177