• 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) 2007-2011, International Business Machines Corporation and   *
7 * others. All Rights Reserved.                                               *
8 ******************************************************************************
9 */
10 
11 package ohos.global.icu.impl.duration;
12 
13 import java.util.TimeZone;
14 
15 import ohos.global.icu.impl.duration.impl.DataRecord;
16 import ohos.global.icu.impl.duration.impl.PeriodFormatterData;
17 import ohos.global.icu.impl.duration.impl.PeriodFormatterDataService;
18 
19 /**
20  * Default implementation of PeriodBuilderFactory.  This creates builders that
21  * use approximate durations.
22  */
23 class BasicPeriodBuilderFactory implements PeriodBuilderFactory {
24   private PeriodFormatterDataService ds;
25   private Settings settings;
26 
27   private static final short allBits = 0xff;
28 
BasicPeriodBuilderFactory(PeriodFormatterDataService ds)29   BasicPeriodBuilderFactory(PeriodFormatterDataService ds) {
30     this.ds = ds;
31     this.settings = new Settings();
32   }
33 
approximateDurationOf(TimeUnit unit)34   static long approximateDurationOf(TimeUnit unit) {
35     return TimeUnit.approxDurations[unit.ordinal];
36   }
37 
38   class Settings {
39     boolean inUse;
40     short uset = allBits;
41     TimeUnit maxUnit = TimeUnit.YEAR;
42     TimeUnit minUnit = TimeUnit.MILLISECOND;
43     int maxLimit;
44     int minLimit;
45     boolean allowZero = true;
46     boolean weeksAloneOnly;
47     boolean allowMillis = true;
48 
setUnits(int uset)49     Settings setUnits(int uset) {
50       if (this.uset == uset) {
51         return this;
52       }
53       Settings result = inUse ? copy() : this;
54 
55       result.uset = (short)uset;
56 
57       if ((uset & allBits) == allBits) {
58         result.uset = allBits;
59         result.maxUnit = TimeUnit.YEAR;
60         result.minUnit = TimeUnit.MILLISECOND;
61       } else {
62         int lastUnit = -1;
63         for (int i = 0; i < TimeUnit.units.length; ++i) {
64           if (0 != (uset & (1 << i))) {
65             if (lastUnit == -1) {
66               result.maxUnit = TimeUnit.units[i];
67             }
68             lastUnit = i;
69           }
70         }
71         if (lastUnit == -1) {
72             // currently empty, but this might be transient so no fail
73             result.minUnit = result.maxUnit = null;
74         } else {
75             result.minUnit = TimeUnit.units[lastUnit];
76         }
77       }
78 
79       return result;
80     }
81 
effectiveSet()82     short effectiveSet() {
83       if (allowMillis) {
84         return uset;
85       }
86       return (short)(uset & ~(1 << TimeUnit.MILLISECOND.ordinal));
87     }
88 
effectiveMinUnit()89     TimeUnit effectiveMinUnit() {
90         if (allowMillis || minUnit != TimeUnit.MILLISECOND) {
91             return minUnit;
92         }
93         // -1 to skip millisecond
94         for (int i = TimeUnit.units.length - 1; --i >= 0;) {
95             if (0 != (uset & (1 << i))) {
96                 return TimeUnit.units[i];
97             }
98         }
99         return TimeUnit.SECOND; // default for pathological case
100     }
101 
setMaxLimit(float maxLimit)102     Settings setMaxLimit(float maxLimit) {
103       int val = maxLimit <= 0 ? 0 : (int)(maxLimit*1000);
104       if (maxLimit == val) {
105         return this;
106       }
107       Settings result = inUse ? copy() : this;
108       result.maxLimit = val;
109       return result;
110     }
111 
setMinLimit(float minLimit)112     Settings setMinLimit(float minLimit) {
113       int val = minLimit <= 0 ? 0 : (int)(minLimit*1000);
114       if (minLimit == val) {
115         return this;
116       }
117       Settings result = inUse ? copy() : this;
118       result.minLimit = val;
119       return result;
120     }
121 
setAllowZero(boolean allow)122     Settings setAllowZero(boolean allow) {
123       if (this.allowZero == allow) {
124         return this;
125       }
126       Settings result = inUse ? copy() : this;
127       result.allowZero = allow;
128       return result;
129     }
130 
setWeeksAloneOnly(boolean weeksAlone)131     Settings setWeeksAloneOnly(boolean weeksAlone) {
132       if (this.weeksAloneOnly == weeksAlone) {
133         return this;
134       }
135       Settings result = inUse ? copy() : this;
136       result.weeksAloneOnly = weeksAlone;
137       return result;
138     }
139 
setAllowMilliseconds(boolean allowMillis)140     Settings setAllowMilliseconds(boolean allowMillis) {
141       if (this.allowMillis == allowMillis) {
142         return this;
143       }
144       Settings result = inUse ? copy() : this;
145       result.allowMillis = allowMillis;
146       return result;
147     }
148 
setLocale(String localeName)149     Settings setLocale(String localeName) {
150       PeriodFormatterData data = ds.get(localeName);
151       return this
152         .setAllowZero(data.allowZero())
153         .setWeeksAloneOnly(data.weeksAloneOnly())
154         .setAllowMilliseconds(data.useMilliseconds() != DataRecord.EMilliSupport.NO);
155     }
156 
setInUse()157     Settings setInUse() {
158       inUse = true;
159       return this;
160     }
161 
createLimited(long duration, boolean inPast)162     Period createLimited(long duration, boolean inPast) {
163       if (maxLimit > 0) {
164           long maxUnitDuration = approximateDurationOf(maxUnit);
165           if (duration * 1000 > maxLimit * maxUnitDuration) {
166               return Period.moreThan(maxLimit/1000f, maxUnit).inPast(inPast);
167           }
168       }
169 
170       if (minLimit > 0) {
171           TimeUnit emu = effectiveMinUnit();
172           long emud = approximateDurationOf(emu);
173           long eml = (emu == minUnit) ? minLimit :
174               Math.max(1000, (approximateDurationOf(minUnit) * minLimit) / emud);
175           if (duration * 1000 < eml * emud) {
176               return Period.lessThan(eml/1000f, emu).inPast(inPast);
177           }
178       }
179       return null;
180     }
181 
copy()182     public Settings copy() {
183         Settings result = new Settings();
184         result.inUse = inUse;
185         result.uset = uset;
186         result.maxUnit = maxUnit;
187         result.minUnit = minUnit;
188         result.maxLimit = maxLimit;
189         result.minLimit = minLimit;
190         result.allowZero = allowZero;
191         result.weeksAloneOnly = weeksAloneOnly;
192         result.allowMillis = allowMillis;
193         return result;
194     }
195   }
196 
197   @Override
setAvailableUnitRange(TimeUnit minUnit, TimeUnit maxUnit)198   public PeriodBuilderFactory setAvailableUnitRange(TimeUnit minUnit,
199                                                     TimeUnit maxUnit) {
200     int uset = 0;
201     for (int i = maxUnit.ordinal; i <= minUnit.ordinal; ++i) {
202         uset |= 1 << i;
203     }
204     if (uset == 0) {
205         throw new IllegalArgumentException("range " + minUnit + " to " + maxUnit + " is empty");
206     }
207     settings = settings.setUnits(uset);
208     return this;
209   }
210 
211   @Override
setUnitIsAvailable(TimeUnit unit, boolean available)212   public PeriodBuilderFactory setUnitIsAvailable(TimeUnit unit,
213                                                       boolean available) {
214     int uset = settings.uset;
215     if (available) {
216       uset |= 1 << unit.ordinal;
217     } else {
218       uset &= ~(1 << unit.ordinal);
219     }
220     settings = settings.setUnits(uset);
221     return this;
222   }
223 
224   @Override
setMaxLimit(float maxLimit)225   public PeriodBuilderFactory setMaxLimit(float maxLimit) {
226     settings = settings.setMaxLimit(maxLimit);
227     return this;
228   }
229 
230   @Override
setMinLimit(float minLimit)231   public PeriodBuilderFactory setMinLimit(float minLimit) {
232     settings = settings.setMinLimit(minLimit);
233     return this;
234   }
235 
236   @Override
setAllowZero(boolean allow)237   public PeriodBuilderFactory setAllowZero(boolean allow) {
238     settings = settings.setAllowZero(allow);
239     return this;
240   }
241 
242   @Override
setWeeksAloneOnly(boolean aloneOnly)243   public PeriodBuilderFactory setWeeksAloneOnly(boolean aloneOnly) {
244     settings = settings.setWeeksAloneOnly(aloneOnly);
245     return this;
246   }
247 
248   @Override
setAllowMilliseconds(boolean allow)249   public PeriodBuilderFactory setAllowMilliseconds(boolean allow) {
250     settings = settings.setAllowMilliseconds(allow);
251     return this;
252   }
253 
254   @Override
setLocale(String localeName)255   public PeriodBuilderFactory setLocale(String localeName) {
256     settings = settings.setLocale(localeName);
257     return this;
258   }
259 
260   @Override
setTimeZone(TimeZone timeZone)261   public PeriodBuilderFactory setTimeZone(TimeZone timeZone) {
262       // ignore this
263       return this;
264   }
265 
getSettings()266   private Settings getSettings() {
267     if (settings.effectiveSet() == 0) {
268       return null;
269     }
270     return settings.setInUse();
271   }
272 
273   /**
274    * Return a builder that represents relative time in terms of the single
275    * given TimeUnit
276    *
277    * @param unit the single TimeUnit with which to represent times
278    * @return a builder
279    */
280   @Override
getFixedUnitBuilder(TimeUnit unit)281   public PeriodBuilder getFixedUnitBuilder(TimeUnit unit) {
282     return FixedUnitBuilder.get(unit, getSettings());
283   }
284 
285   /**
286    * Return a builder that represents relative time in terms of the
287    * largest period less than or equal to the duration.
288    *
289    * @return a builder
290    */
291   @Override
getSingleUnitBuilder()292   public PeriodBuilder getSingleUnitBuilder() {
293     return SingleUnitBuilder.get(getSettings());
294   }
295 
296   /**
297    * Return a builder that formats the largest one or two periods,
298    * Starting with the largest period less than or equal to the duration.
299    * It formats two periods if the first period has a count &lt; 2
300    * and the next period has a count &gt;= 1.
301    *
302    * @return a builder
303    */
304   @Override
getOneOrTwoUnitBuilder()305   public PeriodBuilder getOneOrTwoUnitBuilder() {
306     return OneOrTwoUnitBuilder.get(getSettings());
307   }
308 
309   /**
310    * Return a builder that formats the given number of periods,
311    * starting with the largest period less than or equal to the
312    * duration.
313    *
314    * @return a builder
315    */
316   @Override
getMultiUnitBuilder(int periodCount)317   public PeriodBuilder getMultiUnitBuilder(int periodCount) {
318     return MultiUnitBuilder.get(periodCount, getSettings());
319   }
320 }
321 
322 abstract class PeriodBuilderImpl implements PeriodBuilder {
323 
324   protected BasicPeriodBuilderFactory.Settings settings;
325 
326   @Override
create(long duration)327   public Period create(long duration) {
328     return createWithReferenceDate(duration, System.currentTimeMillis());
329   }
330 
approximateDurationOf(TimeUnit unit)331   public long approximateDurationOf(TimeUnit unit) {
332     return BasicPeriodBuilderFactory.approximateDurationOf(unit);
333   }
334 
335   @Override
createWithReferenceDate(long duration, long referenceDate)336   public Period createWithReferenceDate(long duration, long referenceDate) {
337     boolean inPast = duration < 0;
338     if (inPast) {
339       duration = -duration;
340     }
341     Period ts = settings.createLimited(duration, inPast);
342     if (ts == null) {
343       ts = handleCreate(duration, referenceDate, inPast);
344       if (ts == null) {
345         ts = Period.lessThan(1, settings.effectiveMinUnit()).inPast(inPast);
346       }
347     }
348     return ts;
349   }
350 
351   @Override
352   public PeriodBuilder withTimeZone(TimeZone timeZone) {
353       // ignore the time zone
354       return this;
355   }
356 
357   @Override
358   public PeriodBuilder withLocale(String localeName) {
359     BasicPeriodBuilderFactory.Settings newSettings = settings.setLocale(localeName);
360     if (newSettings != settings) {
361       return withSettings(newSettings);
362     }
363     return this;
364   }
365 
366   protected abstract PeriodBuilder withSettings(BasicPeriodBuilderFactory.Settings settingsToUse);
367 
368   protected abstract Period handleCreate(long duration, long referenceDate,
369                                          boolean inPast);
370 
371   protected PeriodBuilderImpl(BasicPeriodBuilderFactory.Settings settings) {
372     this.settings = settings;
373   }
374 }
375 
376 class FixedUnitBuilder extends PeriodBuilderImpl {
377   private TimeUnit unit;
378 
379   public static FixedUnitBuilder get(TimeUnit unit, BasicPeriodBuilderFactory.Settings settingsToUse) {
380     if (settingsToUse != null && (settingsToUse.effectiveSet() & (1 << unit.ordinal)) != 0) {
381       return new FixedUnitBuilder(unit, settingsToUse);
382     }
383     return null;
384   }
385 
386   FixedUnitBuilder(TimeUnit unit, BasicPeriodBuilderFactory.Settings settings) {
387     super(settings);
388     this.unit = unit;
389   }
390 
391   @Override
392   protected PeriodBuilder withSettings(BasicPeriodBuilderFactory.Settings settingsToUse) {
393     return get(unit, settingsToUse);
394   }
395 
396   @Override
397   protected Period handleCreate(long duration, long referenceDate,
398                                 boolean inPast) {
399     if (unit == null) {
400       return null;
401     }
402     long unitDuration = approximateDurationOf(unit);
403     return Period.at((float)((double)duration/unitDuration), unit)
404         .inPast(inPast);
405   }
406 }
407 
408 class SingleUnitBuilder extends PeriodBuilderImpl {
409   SingleUnitBuilder(BasicPeriodBuilderFactory.Settings settings) {
410     super(settings);
411   }
412 
413   public static SingleUnitBuilder get(BasicPeriodBuilderFactory.Settings settings) {
414     if (settings == null) {
415       return null;
416     }
417     return new SingleUnitBuilder(settings);
418   }
419 
420   @Override
421   protected PeriodBuilder withSettings(BasicPeriodBuilderFactory.Settings settingsToUse) {
422     return SingleUnitBuilder.get(settingsToUse);
423   }
424 
425   @Override
426   protected Period handleCreate(long duration, long referenceDate,
427                                 boolean inPast) {
428     short uset = settings.effectiveSet();
429     for (int i = 0; i < TimeUnit.units.length; ++i) {
430       if (0 != (uset & (1 << i))) {
431         TimeUnit unit = TimeUnit.units[i];
432         long unitDuration = approximateDurationOf(unit);
433         if (duration >= unitDuration) {
434           return Period.at((float)((double)duration/unitDuration), unit)
435               .inPast(inPast);
436         }
437       }
438     }
439     return null;
440   }
441 }
442 
443 class OneOrTwoUnitBuilder extends PeriodBuilderImpl {
444   OneOrTwoUnitBuilder(BasicPeriodBuilderFactory.Settings settings) {
445     super(settings);
446   }
447 
448   public static OneOrTwoUnitBuilder get(BasicPeriodBuilderFactory.Settings settings) {
449     if (settings == null) {
450       return null;
451     }
452     return new OneOrTwoUnitBuilder(settings);
453   }
454 
455   @Override
456   protected PeriodBuilder withSettings(BasicPeriodBuilderFactory.Settings settingsToUse) {
457     return OneOrTwoUnitBuilder.get(settingsToUse);
458   }
459 
460   @Override
461   protected Period handleCreate(long duration, long referenceDate,
462                                 boolean inPast) {
463     Period period = null;
464     short uset = settings.effectiveSet();
465     for (int i = 0; i < TimeUnit.units.length; ++i) {
466       if (0 != (uset & (1 << i))) {
467         TimeUnit unit = TimeUnit.units[i];
468         long unitDuration = approximateDurationOf(unit);
469         if (duration >= unitDuration || period != null) {
470           double count = (double)duration/unitDuration;
471           if (period == null) {
472             if (count >= 2) {
473               period = Period.at((float)count, unit);
474               break;
475             }
476             period = Period.at(1, unit).inPast(inPast);
477             duration -= unitDuration;
478           } else {
479             if (count >= 1) {
480               period = period.and((float)count, unit);
481             }
482             break;
483           }
484         }
485       }
486     }
487     return period;
488   }
489 }
490 
491 class MultiUnitBuilder extends PeriodBuilderImpl {
492   private int nPeriods;
493 
494   MultiUnitBuilder(int nPeriods, BasicPeriodBuilderFactory.Settings settings) {
495     super(settings);
496     this.nPeriods = nPeriods;
497   }
498 
499   public static MultiUnitBuilder get(int nPeriods, BasicPeriodBuilderFactory.Settings settings) {
500     if (nPeriods > 0 && settings != null) {
501       return new MultiUnitBuilder(nPeriods, settings);
502     }
503     return null;
504   }
505 
506   @Override
507   protected PeriodBuilder withSettings(BasicPeriodBuilderFactory.Settings settingsToUse) {
508     return MultiUnitBuilder.get(nPeriods, settingsToUse);
509   }
510 
511   @Override
512   protected Period handleCreate(long duration, long referenceDate,
513                                 boolean inPast) {
514     Period period = null;
515     int n = 0;
516     short uset = settings.effectiveSet();
517     for (int i = 0; i < TimeUnit.units.length; ++i) {
518       if (0 != (uset & (1 << i))) {
519         TimeUnit unit = TimeUnit.units[i];
520         if (n == nPeriods) {
521           break;
522         }
523         long unitDuration = approximateDurationOf(unit);
524         if (duration >= unitDuration || n > 0) {
525           ++n;
526           double count = (double)duration / unitDuration;
527           if (n < nPeriods) {
528             count = Math.floor(count);
529             duration -= (long)(count * unitDuration);
530           }
531           if (period == null) {
532             period = Period.at((float)count, unit).inPast(inPast);
533           } else {
534             period = period.and((float)count, unit);
535           }
536         }
537       }
538     }
539     return period;
540   }
541 }
542 
543