]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/classes/core/src/com/ibm/icu/impl/Norm2AllModes.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / classes / core / src / com / ibm / icu / impl / Norm2AllModes.java
1 /*\r
2 *******************************************************************************\r
3 *   Copyright (C) 2009-2010, International Business Machines\r
4 *   Corporation and others.  All Rights Reserved.\r
5 *******************************************************************************\r
6 */\r
7 package com.ibm.icu.impl;\r
8 \r
9 import java.io.IOException;\r
10 import java.io.InputStream;\r
11 import java.util.MissingResourceException;\r
12 \r
13 import com.ibm.icu.text.Normalizer;\r
14 import com.ibm.icu.text.Normalizer2;\r
15 \r
16 public final class Norm2AllModes {\r
17     // Public API dispatch via Normalizer2 subclasses -------------------------- ***\r
18 \r
19     // Normalizer2 implementation for the old UNORM_NONE.\r
20     public static final class NoopNormalizer2 extends Normalizer2 {\r
21         @Override\r
22         public StringBuilder normalize(CharSequence src, StringBuilder dest) {\r
23             if(dest!=src) {\r
24                 dest.setLength(0);\r
25                 return dest.append(src);\r
26             } else {\r
27                 throw new IllegalArgumentException();\r
28             }\r
29         }\r
30         @Override\r
31         public Appendable normalize(CharSequence src, Appendable dest) {\r
32             if(dest!=src) {\r
33                 try {\r
34                     return dest.append(src);\r
35                 } catch(IOException e) {\r
36                     throw new RuntimeException(e);  // Avoid declaring "throws IOException".\r
37                 }\r
38             } else {\r
39                 throw new IllegalArgumentException();\r
40             }\r
41         }\r
42         @Override\r
43         public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) {\r
44             if(first!=second) {\r
45                 return first.append(second);\r
46             } else {\r
47                 throw new IllegalArgumentException();\r
48             }\r
49         }\r
50         @Override\r
51         public StringBuilder append(StringBuilder first, CharSequence second) {\r
52             if(first!=second) {\r
53                 return first.append(second);\r
54             } else {\r
55                 throw new IllegalArgumentException();\r
56             }\r
57         }\r
58         @Override\r
59         public boolean isNormalized(CharSequence s) { return true; }\r
60         @Override\r
61         public Normalizer.QuickCheckResult quickCheck(CharSequence s) { return Normalizer.YES; }\r
62         @Override\r
63         public int spanQuickCheckYes(CharSequence s) { return s.length(); }\r
64         @Override\r
65         public boolean hasBoundaryBefore(int c) { return true; }\r
66         @Override\r
67         public boolean hasBoundaryAfter(int c) { return true; }\r
68         @Override\r
69         public boolean isInert(int c) { return true; }\r
70     }\r
71 \r
72     // Intermediate class:\r
73     // Has Normalizer2Impl and does boilerplate argument checking and setup.\r
74     public static abstract class Normalizer2WithImpl extends Normalizer2 {\r
75         public Normalizer2WithImpl(Normalizer2Impl ni) {\r
76             impl=ni;\r
77         }\r
78 \r
79         // normalize\r
80         @Override\r
81         public StringBuilder normalize(CharSequence src, StringBuilder dest) {\r
82             if(dest==src) {\r
83                 throw new IllegalArgumentException();\r
84             }\r
85             dest.setLength(0);\r
86             normalize(src, new Normalizer2Impl.ReorderingBuffer(impl, dest, src.length()));\r
87             return dest;\r
88         }\r
89         @Override\r
90         public Appendable normalize(CharSequence src, Appendable dest) {\r
91             if(dest==src) {\r
92                 throw new IllegalArgumentException();\r
93             }\r
94             Normalizer2Impl.ReorderingBuffer buffer=\r
95                 new Normalizer2Impl.ReorderingBuffer(impl, dest, src.length());\r
96             normalize(src, buffer);\r
97             buffer.flush();\r
98             return dest;\r
99         }\r
100         protected abstract void normalize(CharSequence src, Normalizer2Impl.ReorderingBuffer buffer);\r
101 \r
102         // normalize and append\r
103         @Override\r
104         public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) {\r
105             return normalizeSecondAndAppend(first, second, true);\r
106         }\r
107         @Override\r
108         public StringBuilder append(StringBuilder first, CharSequence second) {\r
109             return normalizeSecondAndAppend(first, second, false);\r
110         }\r
111         public StringBuilder normalizeSecondAndAppend(\r
112                 StringBuilder first, CharSequence second, boolean doNormalize) {\r
113             if(first==second) {\r
114                 throw new IllegalArgumentException();\r
115             }\r
116             normalizeAndAppend(\r
117                 second, doNormalize,\r
118                 new Normalizer2Impl.ReorderingBuffer(impl, first, first.length()+second.length()));\r
119             return first;\r
120         }\r
121         protected abstract void normalizeAndAppend(\r
122                 CharSequence src, boolean doNormalize, Normalizer2Impl.ReorderingBuffer buffer);\r
123 \r
124         // quick checks\r
125         @Override\r
126         public boolean isNormalized(CharSequence s) {\r
127             return s.length()==spanQuickCheckYes(s);\r
128         }\r
129         @Override\r
130         public Normalizer.QuickCheckResult quickCheck(CharSequence s) {\r
131             return isNormalized(s) ? Normalizer.YES : Normalizer.NO;\r
132         }\r
133 \r
134         public int getQuickCheck(int c) {\r
135             return 1;\r
136         }\r
137 \r
138         public final Normalizer2Impl impl;\r
139     }\r
140 \r
141     public static final class DecomposeNormalizer2 extends Normalizer2WithImpl {\r
142         public DecomposeNormalizer2(Normalizer2Impl ni) {\r
143             super(ni);\r
144         }\r
145 \r
146         @Override\r
147         protected void normalize(CharSequence src, Normalizer2Impl.ReorderingBuffer buffer) {\r
148             impl.decompose(src, 0, src.length(), buffer);\r
149         }\r
150         @Override\r
151         protected void normalizeAndAppend(\r
152                 CharSequence src, boolean doNormalize, Normalizer2Impl.ReorderingBuffer buffer) {\r
153             impl.decomposeAndAppend(src, doNormalize, buffer);\r
154         }\r
155         @Override\r
156         public int spanQuickCheckYes(CharSequence s) {\r
157             return impl.decompose(s, 0, s.length(), null);\r
158         }\r
159         @Override\r
160         public int getQuickCheck(int c) {\r
161             return impl.isDecompYes(impl.getNorm16(c)) ? 1 : 0;\r
162         }\r
163         @Override\r
164         public boolean hasBoundaryBefore(int c) { return impl.hasDecompBoundary(c, true); }\r
165         @Override\r
166         public boolean hasBoundaryAfter(int c) { return impl.hasDecompBoundary(c, false); }\r
167         @Override\r
168         public boolean isInert(int c) { return impl.isDecompInert(c); }\r
169     }\r
170 \r
171     public static final class ComposeNormalizer2 extends Normalizer2WithImpl {\r
172         public ComposeNormalizer2(Normalizer2Impl ni, boolean fcc) {\r
173             super(ni);\r
174             onlyContiguous=fcc;\r
175         }\r
176 \r
177         @Override\r
178         protected void normalize(CharSequence src, Normalizer2Impl.ReorderingBuffer buffer) {\r
179             impl.compose(src, 0, src.length(), onlyContiguous, true, buffer);\r
180         }\r
181         @Override\r
182         protected void normalizeAndAppend(\r
183                 CharSequence src, boolean doNormalize, Normalizer2Impl.ReorderingBuffer buffer) {\r
184             impl.composeAndAppend(src, doNormalize, onlyContiguous, buffer);\r
185         }\r
186 \r
187         @Override\r
188         public boolean isNormalized(CharSequence s) {\r
189             // 5: small destCapacity for substring normalization\r
190             return impl.compose(s, 0, s.length(),\r
191                                 onlyContiguous, false,\r
192                                 new Normalizer2Impl.ReorderingBuffer(impl, new StringBuilder(), 5));\r
193         }\r
194         @Override\r
195         public Normalizer.QuickCheckResult quickCheck(CharSequence s) {\r
196             int spanLengthAndMaybe=impl.composeQuickCheck(s, 0, s.length(), onlyContiguous, false);\r
197             if((spanLengthAndMaybe&1)!=0) {\r
198                 return Normalizer.MAYBE;\r
199             } else if((spanLengthAndMaybe>>>1)==s.length()) {\r
200                 return Normalizer.YES;\r
201             } else {\r
202                 return Normalizer.NO;\r
203             }\r
204         }\r
205         @Override\r
206         public int spanQuickCheckYes(CharSequence s) {\r
207             return impl.composeQuickCheck(s, 0, s.length(), onlyContiguous, true)>>>1;\r
208         }\r
209         @Override\r
210         public int getQuickCheck(int c) {\r
211             return impl.getCompQuickCheck(impl.getNorm16(c));\r
212         }\r
213         @Override\r
214         public boolean hasBoundaryBefore(int c) { return impl.hasCompBoundaryBefore(c); }\r
215         @Override\r
216         public boolean hasBoundaryAfter(int c) {\r
217             return impl.hasCompBoundaryAfter(c, onlyContiguous, false);\r
218         }\r
219         @Override\r
220         public boolean isInert(int c) {\r
221             return impl.hasCompBoundaryAfter(c, onlyContiguous, true);\r
222         }\r
223 \r
224         private final boolean onlyContiguous;\r
225     }\r
226 \r
227     public static final class FCDNormalizer2 extends Normalizer2WithImpl {\r
228         public FCDNormalizer2(Normalizer2Impl ni) {\r
229             super(ni);\r
230         }\r
231 \r
232         @Override\r
233         protected void normalize(CharSequence src, Normalizer2Impl.ReorderingBuffer buffer) {\r
234             impl.makeFCD(src, 0, src.length(), buffer);\r
235         }\r
236         @Override\r
237         protected void normalizeAndAppend(\r
238                 CharSequence src, boolean doNormalize, Normalizer2Impl.ReorderingBuffer buffer) {\r
239             impl.makeFCDAndAppend(src, doNormalize, buffer);\r
240         }\r
241         @Override\r
242         public int spanQuickCheckYes(CharSequence s) {\r
243             return impl.makeFCD(s, 0, s.length(), null);\r
244         }\r
245         @Override\r
246         public int getQuickCheck(int c) {\r
247             return impl.isDecompYes(impl.getNorm16(c)) ? 1 : 0;\r
248         }\r
249         @Override\r
250         public boolean hasBoundaryBefore(int c) { return impl.hasFCDBoundaryBefore(c); }\r
251         @Override\r
252         public boolean hasBoundaryAfter(int c) { return impl.hasFCDBoundaryAfter(c); }\r
253         @Override\r
254         public boolean isInert(int c) { return impl.isFCDInert(c); }\r
255     }\r
256 \r
257     // instance cache ---------------------------------------------------------- ***\r
258 \r
259     private Norm2AllModes(Normalizer2Impl ni) {\r
260         impl=ni;\r
261         comp=new ComposeNormalizer2(ni, false);\r
262         decomp=new DecomposeNormalizer2(ni);\r
263         fcd=new FCDNormalizer2(ni);\r
264         fcc=new ComposeNormalizer2(ni, true);\r
265     }\r
266 \r
267     public final Normalizer2Impl impl;\r
268     public final ComposeNormalizer2 comp;\r
269     public final DecomposeNormalizer2 decomp;\r
270     public final FCDNormalizer2 fcd;\r
271     public final ComposeNormalizer2 fcc;\r
272 \r
273     private static Norm2AllModes getInstanceFromSingleton(Norm2AllModesSingleton singleton) {\r
274         if(singleton.exception!=null) {\r
275             throw singleton.exception;\r
276         }\r
277         return singleton.allModes;\r
278     }\r
279     public static Norm2AllModes getNFCInstance() {\r
280         return getInstanceFromSingleton(NFCSingleton.INSTANCE);\r
281     }\r
282     public static Norm2AllModes getNFKCInstance() {\r
283         return getInstanceFromSingleton(NFKCSingleton.INSTANCE);\r
284     }\r
285     public static Norm2AllModes getNFKC_CFInstance() {\r
286         return getInstanceFromSingleton(NFKC_CFSingleton.INSTANCE);\r
287     }\r
288     // For use in properties APIs.\r
289     public static Normalizer2WithImpl getN2WithImpl(int index) {\r
290         switch(index) {\r
291         case 0: return getNFCInstance().decomp;  // NFD\r
292         case 1: return getNFKCInstance().decomp; // NFKD\r
293         case 2: return getNFCInstance().comp;    // NFC\r
294         case 3: return getNFKCInstance().comp;   // NFKC\r
295         default: return null;\r
296         }\r
297     }\r
298     public static Norm2AllModes getInstance(InputStream data, String name) {\r
299         if(data==null) {\r
300             Norm2AllModesSingleton singleton;\r
301             if(name.equals("nfc")) {\r
302                 singleton=NFCSingleton.INSTANCE;\r
303             } else if(name.equals("nfkc")) {\r
304                 singleton=NFKCSingleton.INSTANCE;\r
305             } else if(name.equals("nfkc_cf")) {\r
306                 singleton=NFKC_CFSingleton.INSTANCE;\r
307             } else {\r
308                 singleton=null;\r
309             }\r
310             if(singleton!=null) {\r
311                 if(singleton.exception!=null) {\r
312                     throw singleton.exception;\r
313                 }\r
314                 return singleton.allModes;\r
315             }\r
316         }\r
317         return cache.getInstance(name, data);\r
318     }\r
319     private static CacheBase<String, Norm2AllModes, InputStream> cache =\r
320         new SoftCache<String, Norm2AllModes, InputStream>() {\r
321             protected Norm2AllModes createInstance(String key, InputStream data) {\r
322                 if(data==null) {\r
323                     throw new MissingResourceException(\r
324                             "No Normalizer2 data name \""+key+"\" cached, and InputStream is null",\r
325                             "Normalizer2",\r
326                             key);\r
327                 }\r
328                 Normalizer2Impl impl=new Normalizer2Impl().load(data);\r
329                 return new Norm2AllModes(impl);\r
330             }\r
331         };\r
332 \r
333     public static final NoopNormalizer2 NOOP_NORMALIZER2=new NoopNormalizer2();\r
334     /**\r
335      * Gets the FCD normalizer, with the FCD data initialized.\r
336      * @return FCD normalizer\r
337      */\r
338     public static Normalizer2 getFCDNormalizer2() {\r
339         Norm2AllModes allModes=getNFCInstance();\r
340         allModes.impl.getFCDTrie();\r
341         return allModes.fcd;\r
342     }\r
343 \r
344     private static final class Norm2AllModesSingleton {\r
345         private Norm2AllModesSingleton(String name) {\r
346             try {\r
347                 Normalizer2Impl impl=new Normalizer2Impl().load(\r
348                         ICUResourceBundle.ICU_BUNDLE+"/"+name+".nrm");\r
349                 allModes=new Norm2AllModes(impl);\r
350             } catch(RuntimeException e) {\r
351                 exception=e;\r
352             }\r
353         }\r
354 \r
355         private Norm2AllModes allModes;\r
356         private RuntimeException exception;\r
357     }\r
358     private static final class NFCSingleton {\r
359         private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfc");\r
360     }\r
361     private static final class NFKCSingleton {\r
362         private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfkc");\r
363     }\r
364     private static final class NFKC_CFSingleton {\r
365         private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfkc_cf");\r
366     }\r
367 }\r