]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/formattedval_iterimpl.cpp
ICU-64232.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / formattedval_iterimpl.cpp
diff --git a/icuSources/i18n/formattedval_iterimpl.cpp b/icuSources/i18n/formattedval_iterimpl.cpp
new file mode 100644 (file)
index 0000000..75328fa
--- /dev/null
@@ -0,0 +1,176 @@
+// © 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 */