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, International Business Machines Corporation and   *
7* others. All Rights Reserved.                                               *
8******************************************************************************
9*/
10
11package android.icu.impl.duration;
12
13import android.icu.impl.duration.impl.DataRecord.ETimeLimit;
14
15/**
16 * Represents an approximate duration in multiple TimeUnits.  Each unit,
17 * if set, has a count (which can be fractional and must be non-negative).
18 * In addition Period can either represent the duration as being into the past
19 * or future, and as being more or less than the defined value.
20 * <p>
21 * Use a PeriodFormatter to convert a Period to a String.
22 * <p>
23 * Periods are immutable.  Mutating operations return the new
24 * result leaving the original unchanged.
25 * <p>
26 * Example:<pre>
27 * Period p1 = Period.at(3, WEEK).and(2, DAY).inFuture();
28 * Period p2 = p1.and(12, HOUR);</pre>
29 * @hide Only a subset of ICU is exposed in Android
30 */
31public final class Period {
32  final byte timeLimit;
33  final boolean inFuture;
34  final int[] counts;
35
36  /**
37   * Constructs a Period representing a duration of
38   * count units extending into the past.
39   * @param count the number of units, must be non-negative
40   * @param unit the unit
41   * @return the new Period
42   */
43  public static Period at(float count, TimeUnit unit) {
44    checkCount(count);
45    return new Period(ETimeLimit.NOLIMIT, false, count, unit);
46  }
47
48  /**
49   * Constructs a Period representing a duration more than
50   * count units extending into the past.
51   * @param count the number of units. must be non-negative
52   * @param unit the unit
53   * @return the new Period
54   */
55  public static Period moreThan(float count, TimeUnit unit) {
56    checkCount(count);
57    return new Period(ETimeLimit.MT, false, count, unit);
58  }
59
60  /**
61   * Constructs a Period representing a duration
62   * less than count units extending into the past.
63   * @param count the number of units. must be non-negative
64   * @param unit the unit
65   * @return the new Period
66   */
67  public static Period lessThan(float count, TimeUnit unit) {
68    checkCount(count);
69    return new Period(ETimeLimit.LT, false, count, unit);
70  }
71
72  /**
73   * Set the given unit to have the given count.  Marks the
74   * unit as having been set.  This can be used to set
75   * multiple units, or to reset a unit to have a new count.
76   * This does <b>not</b> add the count to an existing count
77   * for this unit.
78   *
79   * @param count the number of units.  must be non-negative
80   * @param unit the unit
81   * @return the new Period
82   */
83  public Period and(float count, TimeUnit unit) {
84    checkCount(count);
85    return setTimeUnitValue(unit, count);
86  }
87
88  /**
89   * Mark the given unit as not being set.
90   *
91   * @param unit the unit to unset
92   * @return the new Period
93   */
94  public Period omit(TimeUnit unit) {
95    return setTimeUnitInternalValue(unit, 0);
96  }
97
98  /**
99   * Mark the duration as being at the defined duration.
100   *
101   * @return the new Period
102   */
103  public Period at() {
104    return setTimeLimit(ETimeLimit.NOLIMIT);
105  }
106
107  /**
108   * Mark the duration as being more than the defined duration.
109   *
110   * @return the new Period
111   */
112  public Period moreThan() {
113    return setTimeLimit(ETimeLimit.MT);
114  }
115
116  /**
117   * Mark the duration as being less than the defined duration.
118   *
119   * @return the new Period
120   */
121  public Period lessThan() {
122    return setTimeLimit(ETimeLimit.LT);
123  }
124
125  /**
126   * Mark the time as being in the future.
127   *
128   * @return the new Period
129   */
130  public Period inFuture() {
131    return setFuture(true);
132  }
133
134  /**
135   * Mark the duration as extending into the past.
136   *
137   * @return the new Period
138   */
139  public Period inPast() {
140    return setFuture(false);
141  }
142
143  /**
144   * Mark the duration as extending into the future if
145   * future is true, and into the past otherwise.
146   *
147   * @param future true if the time is in the future
148   * @return the new Period
149   */
150  public Period inFuture(boolean future) {
151    return setFuture(future);
152  }
153
154  /**
155   * Mark the duration as extending into the past if
156   * past is true, and into the future otherwise.
157   *
158   * @param past true if the time is in the past
159   * @return the new Period
160   */
161  public Period inPast(boolean past) {
162    return setFuture(!past);
163  }
164
165  /**
166   * Returns true if any unit is set.
167   * @return true if any unit is set
168   */
169  public boolean isSet() {
170    for (int i = 0; i < counts.length; ++i) {
171      if (counts[i] != 0) {
172        return true;
173      }
174    }
175    return false;
176  }
177
178  /**
179   * Returns true if the given unit is set.
180   * @param unit the unit to test
181   * @return true if the given unit is set.
182   */
183  public boolean isSet(TimeUnit unit) {
184    return counts[unit.ordinal] > 0;
185  }
186
187  /**
188   * Returns the count for the specified unit.  If the
189   * unit is not set, returns 0.
190   * @param unit the unit to test
191   * @return the count
192   */
193  public float getCount(TimeUnit unit) {
194    int ord = unit.ordinal;
195    if (counts[ord] == 0) {
196      return 0;
197    }
198    return (counts[ord] - 1)/1000f;
199  }
200
201  /**
202   * Returns true if this represents a
203   * duration into the future.
204   * @return true if this represents a
205   * duration into the future.
206   */
207  public boolean isInFuture() {
208    return inFuture;
209  }
210
211  /**
212   * Returns true if this represents a
213   * duration into the past
214   * @return true if this represents a
215   * duration into the past
216   */
217  public boolean isInPast  () {
218    return !inFuture;
219  }
220
221  /**
222   * Returns true if this represents a duration in
223   * excess of the defined duration.
224   * @return true if this represents a duration in
225   * excess of the defined duration.
226   */
227  public boolean isMoreThan() {
228    return timeLimit == ETimeLimit.MT;
229  }
230
231  /**
232   * Returns true if this represents a duration
233   * less than the defined duration.
234   * @return true if this represents a duration
235   * less than the defined duration.
236   */
237  public boolean isLessThan() {
238    return timeLimit == ETimeLimit.LT;
239  }
240
241  /**
242   * Returns true if rhs extends Period and
243   * the two Periods are equal.
244   * @param rhs the object to compare to
245   * @return true if rhs is a Period and is equal to this
246   */
247  @Override
248  public boolean equals(Object rhs) {
249    try {
250      return equals((Period)rhs);
251    }
252    catch (ClassCastException e) {
253      return false;
254    }
255  }
256
257  /**
258   * Returns true if the same units are defined with
259   * the same counts, both extend into the future or both into the
260   * past, and if the limits (at, more than, less than) are the same.
261   * Note that this means that a period of 1000ms and a period of 1sec
262   * will not compare equal.
263   *
264   * @param rhs the period to compare to
265   * @return true if the two periods are equal
266   */
267  public boolean equals(Period rhs) {
268    if (rhs != null &&
269        this.timeLimit == rhs.timeLimit &&
270        this.inFuture == rhs.inFuture) {
271      for (int i = 0; i < counts.length; ++i) {
272        if (counts[i] != rhs.counts[i]) {
273          return false;
274        }
275      }
276      return true;
277    }
278    return false;
279  }
280
281  /**
282   * Returns the hashCode.
283   * @return the hashCode
284   */
285  @Override
286public int hashCode() {
287    int hc = (timeLimit << 1) | (inFuture ? 1 : 0);
288    for (int i = 0; i < counts.length; ++i) {
289      hc = (hc << 2) ^ counts[i];
290    }
291    return hc;
292  }
293
294  /**
295   * Private constructor used by static factory methods.
296   */
297  private Period(int limit, boolean future, float count, TimeUnit unit) {
298    this.timeLimit = (byte) limit;
299    this.inFuture = future;
300    this.counts = new int[TimeUnit.units.length];
301    this.counts[unit.ordinal] = (int)(count * 1000) + 1;
302  }
303
304  /**
305   * Package private constructor used by setters and factory.
306   */
307  Period(int timeLimit, boolean inFuture, int[] counts) {
308    this.timeLimit = (byte) timeLimit;
309    this.inFuture = inFuture;
310    this.counts = counts;
311  }
312
313  /**
314   * Set the unit's internal value, converting from float to int.
315   */
316  private Period setTimeUnitValue(TimeUnit unit, float value) {
317    if (value < 0) {
318      throw new IllegalArgumentException("value: " + value);
319    }
320    return setTimeUnitInternalValue(unit, (int)(value * 1000) + 1);
321  }
322
323  /**
324   * Sets the period to have the provided value, 1/1000 of the
325   * unit plus 1.  Thus unset values are '0', 1' is the set value '0',
326   * 2 is the set value '1/1000', 3 is the set value '2/1000' etc.
327   * @param p the period to change
328   * @param value the int value as described above.
329   * @eturn the new Period object.
330   */
331  private Period setTimeUnitInternalValue(TimeUnit unit, int value) {
332    int ord = unit.ordinal;
333    if (counts[ord] != value) {
334      int[] newCounts = new int[counts.length];
335      for (int i = 0; i < counts.length; ++i) {
336        newCounts[i] = counts[i];
337      }
338      newCounts[ord] = value;
339      return new Period(timeLimit, inFuture, newCounts);
340    }
341    return this;
342  }
343
344  /**
345   * Sets whether this defines a future time.
346   * @param future true if the time is in the future
347   * @return  the new Period
348   */
349  private Period setFuture(boolean future) {
350    if (this.inFuture != future) {
351      return new Period(timeLimit, future, counts);
352    }
353    return this;
354  }
355
356  /**
357   * Sets whether this is more than, less than, or
358   * 'about' the specified time.
359   * @param limit the kind of limit
360   * @return the new Period
361   */
362  private Period setTimeLimit(byte limit) {
363    if (this.timeLimit != limit) {
364      return new Period(limit, inFuture, counts);
365
366    }
367    return this;
368  }
369
370  /**
371   * Validate count.
372   */
373  private static void checkCount(float count) {
374    if (count < 0) {
375      throw new IllegalArgumentException("count (" + count +
376                                         ") cannot be negative");
377    }
378  }
379}
380