1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 // © 2019 and later: Unicode, Inc. and others. 3 // License & terms of use: http://www.unicode.org/copyright.html#License 4 package ohos.global.icu.impl; 5 6 import java.text.AttributedCharacterIterator; 7 import java.text.AttributedString; 8 import java.text.FieldPosition; 9 import java.text.Format; 10 import java.util.List; 11 12 import ohos.global.icu.text.ConstrainedFieldPosition; 13 14 /** 15 * Implementation of FormattedValue based on FieldPositionIterator. 16 * 17 * In C++, this implements FormattedValue. In Java, it is a stateless 18 * collection of static functions to avoid having to use nested objects. 19 * @hide exposed on OHOS 20 */ 21 public class FormattedValueFieldPositionIteratorImpl { 22 23 /** Do not construct instances of this class */ FormattedValueFieldPositionIteratorImpl()24 private FormattedValueFieldPositionIteratorImpl() {} 25 26 /** Helper class to keep track of fields with values in Java */ 27 private static class FieldWithValue extends Format.Field { 28 private static final long serialVersionUID = -3850076447157793465L; 29 30 public final Format.Field field; 31 public final int value; 32 FieldWithValue(Format.Field field, int value)33 public FieldWithValue(Format.Field field, int value) { 34 super(field.toString()); 35 this.field = field; 36 this.value = value; 37 } 38 } 39 nextPosition(List<FieldPosition> attributes, ConstrainedFieldPosition cfpos)40 public static boolean nextPosition(List<FieldPosition> attributes, ConstrainedFieldPosition cfpos) { 41 int numFields = attributes.size(); 42 int i = (int) cfpos.getInt64IterationContext(); 43 for (; i < numFields; i++) { 44 FieldPosition fpos = attributes.get(i); 45 Format.Field field = fpos.getFieldAttribute(); 46 Object value = null; 47 if (field instanceof FieldWithValue) { 48 value = ((FieldWithValue) field).value; 49 field = ((FieldWithValue) field).field; 50 } 51 if (cfpos.matchesField(field, value)) { 52 int start = fpos.getBeginIndex(); 53 int limit = fpos.getEndIndex(); 54 cfpos.setState(field, value, start, limit); 55 break; 56 } 57 } 58 cfpos.setInt64IterationContext(i == numFields ? i : i + 1); 59 return i < numFields; 60 } 61 toCharacterIterator(CharSequence cs, List<FieldPosition> attributes)62 public static AttributedCharacterIterator toCharacterIterator(CharSequence cs, List<FieldPosition> attributes) { 63 AttributedString as = new AttributedString(cs.toString()); 64 65 // add attributes to the AttributedString 66 for (int i = 0; i < attributes.size(); i++) { 67 FieldPosition fp = attributes.get(i); 68 Format.Field field = fp.getFieldAttribute(); 69 Object value = field; 70 if (field instanceof FieldWithValue) { 71 value = ((FieldWithValue) field).value; 72 field = ((FieldWithValue) field).field; 73 } 74 as.addAttribute(field, value, fp.getBeginIndex(), fp.getEndIndex()); 75 } 76 77 // return the CharacterIterator from AttributedString 78 return as.getIterator(); 79 } 80 addOverlapSpans(List<FieldPosition> attributes, Format.Field spanField, int firstIndex)81 public static void addOverlapSpans(List<FieldPosition> attributes, Format.Field spanField, int firstIndex) { 82 // In order to avoid fancy data structures, this is an O(N^2) algorithm, 83 // which should be fine for all real-life applications of this function. 84 int s1a = Integer.MAX_VALUE; 85 int s1b = 0; 86 int s2a = Integer.MAX_VALUE; 87 int s2b = 0; 88 int numFields = attributes.size(); 89 for (int i = 0; i<numFields; i++) { 90 FieldPosition fp1 = attributes.get(i); 91 for (int j = i + 1; j<numFields; j++) { 92 FieldPosition fp2 = attributes.get(j); 93 if (fp1.getFieldAttribute() != fp2.getFieldAttribute()) { 94 continue; 95 } 96 // Found a duplicate 97 s1a = Math.min(s1a, fp1.getBeginIndex()); 98 s1b = Math.max(s1b, fp1.getEndIndex()); 99 s2a = Math.min(s2a, fp2.getBeginIndex()); 100 s2b = Math.max(s2b, fp2.getEndIndex()); 101 break; 102 } 103 } 104 if (s1a != Integer.MAX_VALUE) { 105 // Success: add the two span fields 106 FieldPosition newPos = new FieldPosition(new FieldWithValue(spanField, firstIndex)); 107 newPos.setBeginIndex(s1a); 108 newPos.setEndIndex(s1b); 109 attributes.add(newPos); 110 newPos = new FieldPosition(new FieldWithValue(spanField, 1 - firstIndex)); 111 newPos.setBeginIndex(s2a); 112 newPos.setEndIndex(s2b); 113 attributes.add(newPos); 114 } 115 } 116 sort(List<FieldPosition> attributes)117 public static void sort(List<FieldPosition> attributes) { 118 // Use bubble sort, O(N^2) but easy and no fancy data structures. 119 int numFields = attributes.size(); 120 while (true) { 121 boolean isSorted = true; 122 for (int i=0; i<numFields-1; i++) { 123 FieldPosition fp1 = attributes.get(i); 124 FieldPosition fp2 = attributes.get(i + 1); 125 long comparison = 0; 126 if (fp1.getBeginIndex() != fp2.getBeginIndex()) { 127 // Higher start index -> higher rank 128 comparison = fp2.getBeginIndex() - fp1.getBeginIndex(); 129 } else if (fp1.getEndIndex() != fp2.getEndIndex()) { 130 // Higher length (end index) -> lower rank 131 comparison = fp1.getEndIndex() - fp2.getEndIndex(); 132 } else if (fp1.getFieldAttribute() != fp2.getFieldAttribute()) { 133 // Span category -> lower rank 134 // Pick other orders arbitrarily 135 boolean fp1isSpan = fp1.getFieldAttribute() instanceof FieldWithValue; 136 boolean fp2isSpan = fp2.getFieldAttribute() instanceof FieldWithValue; 137 if (fp1isSpan && !fp2isSpan) { 138 comparison = 1; 139 } else if (fp2isSpan && !fp1isSpan) { 140 comparison = -1; 141 } else { 142 comparison = fp1.hashCode() - fp2.hashCode(); 143 } 144 } 145 if (comparison < 0) { 146 // Perform a swap 147 isSorted = false; 148 attributes.set(i, fp2); 149 attributes.set(i + 1, fp1); 150 } 151 } 152 if (isSorted) { 153 break; 154 } 155 } 156 } 157 } 158