• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GENERATED SOURCE. DO NOT MODIFY. */
2 // © 2016 and later: Unicode, Inc. and others.
3 // License & terms of use: http://www.unicode.org/copyright.html#License
4 /*
5  *******************************************************************************
6  * Copyright (C) 1996-2015, Google, Inc., International Business Machines Corporation and
7  * others. All Rights Reserved.
8  *******************************************************************************
9  */
10 package ohos.global.icu.impl;
11 
12 import java.util.Collection;
13 import java.util.Comparator;
14 import java.util.Iterator;
15 import java.util.LinkedList;
16 import java.util.Map.Entry;
17 import java.util.Set;
18 import java.util.TreeMap;
19 import java.util.TreeSet;
20 
21 import ohos.global.icu.lang.CharSequences;
22 import ohos.global.icu.util.ICUException;
23 
24 /**
25  * @hide exposed on OHOS
26  */
27 @SuppressWarnings("deprecation")
28 public class StringRange {
29     private static final boolean DEBUG = false;
30 
31     /**
32      * @hide exposed on OHOS
33      */
34     public interface Adder {
35         /**
36          * @param start
37          * @param end   may be null, for adding single string
38          */
add(String start, String end)39         void add(String start, String end);
40     }
41 
42     public static final Comparator<int[]> COMPARE_INT_ARRAYS = new Comparator<int[]>() {
43         @Override
44         public int compare(int[] o1, int[] o2) {
45             int minIndex = Math.min(o1.length, o2.length);
46             for (int i = 0; i < minIndex; ++i) {
47                 int diff = o1[i] - o2[i];
48                 if (diff != 0) {
49                     return diff;
50                 }
51             }
52             return o1.length - o2.length;
53         }
54     };
55 
56     /**
57      * Compact the set of strings.
58      * @param source set of strings
59      * @param adder adds each pair to the output. See the {@link Adder} interface.
60      * @param shorterPairs use abc-d instead of abc-abd
61      * @param moreCompact use a more compact form, at the expense of more processing. If false, source must be sorted.
62      */
compact(Set<String> source, Adder adder, boolean shorterPairs, boolean moreCompact)63     public static void compact(Set<String> source, Adder adder, boolean shorterPairs, boolean moreCompact) {
64         if (!moreCompact) {
65             String start = null;
66             String end = null;
67             int lastCp = 0;
68             int prefixLen = 0;
69             for (String s : source) {
70                 if (start != null) { // We have something queued up
71                     if (s.regionMatches(0, start, 0, prefixLen)) {
72                         int currentCp = s.codePointAt(prefixLen);
73                         if (currentCp == 1+lastCp && s.length() == prefixLen + Character.charCount(currentCp)) {
74                             end = s;
75                             lastCp = currentCp;
76                             continue;
77                         }
78                     }
79                     // We failed to find continuation. Add what we have and restart
80                     adder.add(start, end == null ? null
81                         : !shorterPairs ? end
82                             : end.substring(prefixLen, end.length()));
83                 }
84                 // new possible range
85                 start = s;
86                 end = null;
87                 lastCp = s.codePointBefore(s.length());
88                 prefixLen = s.length() - Character.charCount(lastCp);
89             }
90             adder.add(start, end == null ? null
91                 : !shorterPairs ? end
92                     : end.substring(prefixLen, end.length()));
93         } else {
94             // not a fast algorithm, but ok for now
95             // TODO rewire to use the first (slower) algorithm to generate the ranges, then compact them from there.
96             // first sort by lengths
97             Relation<Integer,Ranges> lengthToArrays = Relation.of(new TreeMap<Integer,Set<Ranges>>(), TreeSet.class);
98             for (String s : source) {
99                 Ranges item = new Ranges(s);
100                 lengthToArrays.put(item.size(), item);
101             }
102             // then compact items of each length and emit compacted sets
103             for (Entry<Integer, Set<Ranges>> entry : lengthToArrays.keyValuesSet()) {
104                 LinkedList<Ranges> compacted = compact(entry.getKey(), entry.getValue());
105                 for (Ranges ranges : compacted) {
106                     adder.add(ranges.start(), ranges.end(shorterPairs));
107                 }
108             }
109         }
110     }
111 
112     /**
113      * Faster but not as good compaction. Only looks at final codepoint.
114      * @param source set of strings
115      * @param adder adds each pair to the output. See the {@link Adder} interface.
116      * @param shorterPairs use abc-d instead of abc-abd
117      */
compact(Set<String> source, Adder adder, boolean shorterPairs)118     public static void compact(Set<String> source, Adder adder, boolean shorterPairs) {
119         compact(source,adder,shorterPairs,false);
120     }
121 
compact(int size, Set<Ranges> inputRanges)122     private static LinkedList<Ranges> compact(int size, Set<Ranges> inputRanges) {
123         LinkedList<Ranges> ranges = new LinkedList<Ranges>(inputRanges);
124         for (int i = size-1; i >= 0; --i) {
125             Ranges last = null;
126             for (Iterator<Ranges> it = ranges.iterator(); it.hasNext();) {
127                 Ranges item = it.next();
128                 if (last == null) {
129                     last = item;
130                 } else if (last.merge(i, item)) {
131                     it.remove();
132                 } else {
133                     last = item; // go to next
134                 }
135             }
136         };
137         return ranges;
138     }
139 
140     static final class Range implements Comparable<Range>{
141         int min;
142         int max;
Range(int min, int max)143         public Range(int min, int max) {
144             this.min = min;
145             this.max = max;
146         }
147         @Override
equals(Object obj)148         public boolean equals(Object obj) {
149             return this == obj || (obj != null && obj instanceof Range && compareTo((Range)obj) == 0);
150         }
151         @Override
compareTo(Range that)152         public int compareTo(Range that) {
153             int diff = min - that.min;
154             if (diff != 0) {
155                 return diff;
156             }
157             return max - that.max;
158         }
159         @Override
hashCode()160         public int hashCode() {
161             return min * 37 + max;
162         }
163         @Override
toString()164         public String toString() {
165             StringBuilder result = new StringBuilder().appendCodePoint(min);
166             return min == max ? result.toString() : result.append('~').appendCodePoint(max).toString();
167         }
168     }
169 
170     static final class Ranges implements Comparable<Ranges> {
171         private final Range[] ranges;
Ranges(String s)172         public Ranges(String s) {
173             int[] array = CharSequences.codePoints(s);
174             ranges = new Range[array.length];
175             for (int i = 0; i < array.length; ++i) {
176                 ranges[i] = new Range(array[i], array[i]);
177             }
178         }
merge(int pivot, Ranges other)179         public boolean merge(int pivot, Ranges other) {
180            // We merge items if the pivot is adjacent, and all later ranges are equal.
181            for (int i = ranges.length-1; i >= 0; --i) {
182                if (i == pivot) {
183                    if (ranges[i].max != other.ranges[i].min-1) { // not adjacent
184                        return false;
185                    }
186                } else {
187                    if (!ranges[i].equals(other.ranges[i])) {
188                        return false;
189                    }
190                }
191            }
192            if (DEBUG) System.out.print("Merging: " + this + ", " + other);
193            ranges[pivot].max = other.ranges[pivot].max;
194            if (DEBUG) System.out.println(" => " + this);
195            return true;
196         }
197 
start()198         public String start() {
199             StringBuilder result = new StringBuilder();
200             for (int i = 0; i < ranges.length; ++i) {
201                 result.appendCodePoint(ranges[i].min);
202             }
203             return result.toString();
204         }
end(boolean mostCompact)205         public String end(boolean mostCompact) {
206             int firstDiff = firstDifference();
207             if (firstDiff == ranges.length) {
208                 return null;
209             }
210             StringBuilder result = new StringBuilder();
211             for (int i = mostCompact ? firstDiff : 0; i < ranges.length; ++i) {
212                 result.appendCodePoint(ranges[i].max);
213             }
214             return result.toString();
215         }
firstDifference()216         public int firstDifference() {
217             for (int i = 0; i < ranges.length; ++i) {
218                 if (ranges[i].min != ranges[i].max){
219                     return i;
220                 }
221             }
222             return ranges.length;
223         }
size()224         public Integer size() {
225             return ranges.length;
226         }
227         @Override
compareTo(Ranges other)228         public int compareTo(Ranges other) {
229             int diff = ranges.length - other.ranges.length;
230             if (diff != 0) {
231                 return diff;
232             }
233             for (int i = 0; i < ranges.length; ++i) {
234                 diff = ranges[i].compareTo(other.ranges[i]);
235                 if (diff != 0) {
236                     return diff;
237                 }
238             }
239             return 0;
240         }
241         @Override
toString()242         public String toString() {
243             String start = start();
244             String end = end(false);
245             return end == null ? start : start + "~" + end;
246         }
247     }
248 
expand(String start, String end, boolean requireSameLength, Collection<String> output)249     public static Collection<String> expand(String start, String end, boolean requireSameLength, Collection<String> output) {
250         if (start == null || end == null) {
251             throw new ICUException("Range must have 2 valid strings");
252         }
253         int[] startCps = CharSequences.codePoints(start);
254         int[] endCps = CharSequences.codePoints(end);
255         int startOffset = startCps.length - endCps.length;
256 
257         if (requireSameLength && startOffset != 0) {
258             throw new ICUException("Range must have equal-length strings");
259         } else if (startOffset < 0) {
260             throw new ICUException("Range must have start-length ≥ end-length");
261         } else if (endCps.length == 0) {
262             throw new ICUException("Range must have end-length > 0");
263         }
264 
265         StringBuilder builder = new StringBuilder();
266         for (int i = 0; i < startOffset; ++i) {
267             builder.appendCodePoint(startCps[i]);
268         }
269         add(0, startOffset, startCps, endCps, builder, output);
270         return output;
271     }
272 
add(int endIndex, int startOffset, int[] starts, int[] ends, StringBuilder builder, Collection<String> output)273     private static void add(int endIndex, int startOffset, int[] starts, int[] ends, StringBuilder builder, Collection<String> output) {
274         int start = starts[endIndex+startOffset];
275         int end = ends[endIndex];
276         if (start > end) {
277             throw new ICUException("Range must have xᵢ ≤ yᵢ for each index i");
278         }
279         boolean last = endIndex == ends.length - 1;
280         int startLen = builder.length();
281         for (int i = start; i <= end; ++i) {
282             builder.appendCodePoint(i);
283             if (last) {
284                 output.add(builder.toString());
285             } else {
286                 add(endIndex+1, startOffset, starts, ends, builder, output);
287             }
288             builder.setLength(startLen);
289         }
290     }
291 }
292