/projects/eclipse_SDK-3.7.1/plugins/com.ibm.icu.source_4.4.2.v20110208/com/ibm/icu/impl/duration/BasicPeriodBuilderFactory.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus · Java · 514 lines · 405 code · 67 blank · 42 comment · 89 complexity · c5c9cf2c8bed93324728b9e1c70fce0f MD5 · raw file

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