PageRenderTime 77ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/saxonB/net/sf/saxon/value/IntegerValue.java

https://bitbucket.org/dmwelch/phdxnat_pipeline
Java | 367 lines | 169 code | 48 blank | 150 comment | 46 complexity | b8b005b32cb0e7bbbc7bda5ba686541b MD5 | raw file
  1. package net.sf.saxon.value;
  2. import net.sf.saxon.type.*;
  3. import net.sf.saxon.trans.Err;
  4. import net.sf.saxon.om.StandardNames;
  5. import net.sf.saxon.trans.XPathException;
  6. import java.math.BigInteger;
  7. /**
  8. * This class represents the XPath built-in type xs:integer. It is used for all
  9. * subtypes of xs:integer, other than user-defined subtypes. There are two implementations
  10. * of IntegerValue: {@link Int64Value}, which accommodates values up to 2^63, and
  11. * {@link BigIntegerValue}, which accommodates unlimited-length integers.
  12. */
  13. public abstract class IntegerValue extends NumericValue {
  14. // static {
  15. // BuiltInAtomicType.init();
  16. // }
  17. /**
  18. * IntegerValue representing the value -1
  19. */
  20. public static final Int64Value MINUS_ONE = new Int64Value(-1);
  21. /**
  22. * IntegerValue representing the value zero
  23. */
  24. public static final Int64Value ZERO = new Int64Value(0);
  25. /**
  26. * IntegerValue representing the value +1
  27. */
  28. public static final Int64Value PLUS_ONE = new Int64Value(+1);
  29. /**
  30. * Array of small integer values
  31. */
  32. public static final Int64Value[] SMALL_INTEGERS = {
  33. ZERO,
  34. PLUS_ONE,
  35. new Int64Value(2),
  36. new Int64Value(3),
  37. new Int64Value(4),
  38. new Int64Value(5),
  39. new Int64Value(6),
  40. new Int64Value(7),
  41. new Int64Value(8),
  42. new Int64Value(9),
  43. new Int64Value(10),
  44. new Int64Value(11),
  45. new Int64Value(12),
  46. new Int64Value(13),
  47. new Int64Value(14),
  48. new Int64Value(15),
  49. new Int64Value(16),
  50. new Int64Value(17),
  51. new Int64Value(18),
  52. new Int64Value(19),
  53. new Int64Value(20)
  54. };
  55. /**
  56. * IntegerValue representing the maximum value for a long
  57. */
  58. public static final Int64Value MAX_LONG = new Int64Value(Long.MAX_VALUE);
  59. /**
  60. * IntegerValue representing the minimum value for a long
  61. */
  62. public static final Int64Value MIN_LONG = new Int64Value(Long.MIN_VALUE);
  63. /**
  64. * Static data identifying the min and max values for each built-in subtype of xs:integer.
  65. * This is a sequence of triples, each holding the fingerprint of the type, the minimum
  66. * value, and the maximum value. The special value NO_LIMIT indicates that there is no
  67. * minimum (or no maximum) for this type. The special value MAX_UNSIGNED_LONG represents the
  68. * value 2^64-1
  69. */
  70. private static long NO_LIMIT = -9999;
  71. private static long MAX_UNSIGNED_LONG = -9998;
  72. private static long[] ranges = {
  73. // arrange so the most frequently used types are near the start
  74. StandardNames.XS_INTEGER, NO_LIMIT, NO_LIMIT,
  75. StandardNames.XS_LONG, Long.MIN_VALUE, Long.MAX_VALUE,
  76. StandardNames.XS_INT, Integer.MIN_VALUE, Integer.MAX_VALUE,
  77. StandardNames.XS_SHORT, Short.MIN_VALUE, Short.MAX_VALUE,
  78. StandardNames.XS_BYTE, Byte.MIN_VALUE, Byte.MAX_VALUE,
  79. StandardNames.XS_NON_NEGATIVE_INTEGER, 0, NO_LIMIT,
  80. StandardNames.XS_POSITIVE_INTEGER, 1, NO_LIMIT,
  81. StandardNames.XS_NON_POSITIVE_INTEGER, NO_LIMIT, 0,
  82. StandardNames.XS_NEGATIVE_INTEGER, NO_LIMIT, -1,
  83. StandardNames.XS_UNSIGNED_LONG, 0, MAX_UNSIGNED_LONG,
  84. StandardNames.XS_UNSIGNED_INT, 0, 4294967295L,
  85. StandardNames.XS_UNSIGNED_SHORT, 0, 65535,
  86. StandardNames.XS_UNSIGNED_BYTE, 0, 255};
  87. /**
  88. * Factory method: makes either an Int64Value or a BigIntegerValue depending on the value supplied
  89. * @param value the supplied integer value
  90. * @return the value as a BigIntegerValue or Int64Value as appropriate
  91. */
  92. public static IntegerValue makeIntegerValue(BigInteger value) {
  93. if (value.compareTo(BigIntegerValue.MAX_LONG) > 0 || value.compareTo(BigIntegerValue.MIN_LONG) < 0) {
  94. return new BigIntegerValue(value);
  95. } else {
  96. return Int64Value.makeIntegerValue(value.longValue());
  97. }
  98. }
  99. /**
  100. * This class allows subtypes of xs:integer to be held, as well as xs:integer values.
  101. * This method sets the required type label. Note that this method modifies the value in situ.
  102. * @param type the subtype of integer required
  103. * @param validate true if validation is required, false if the caller warrants that the value
  104. * is valid for the subtype
  105. * @return null if the operation succeeds, or a ValidationException if the value is out of range
  106. */
  107. public abstract ValidationFailure convertToSubType(BuiltInAtomicType type, boolean validate);
  108. /**
  109. * This class allows subtypes of xs:integer to be held, as well as xs:integer values.
  110. * This method sets the required type label. Note that this method modifies the value in situ.
  111. * @param type the subtype of integer required
  112. * @return null if the operation succeeds, or a ValidationException if the value is out of range
  113. */
  114. public abstract ValidationFailure validateAgainstSubType(BuiltInAtomicType type);
  115. /**
  116. * Check that a value is in range for the specified subtype of xs:integer
  117. *
  118. * @param value the value to be checked
  119. * @param type the required item type, a subtype of xs:integer
  120. * @return true if successful, false if value is out of range for the subtype
  121. */
  122. public static boolean checkRange(long value, BuiltInAtomicType type) {
  123. int fp = type.getFingerprint();
  124. for (int i = 0; i < ranges.length; i += 3) {
  125. if (ranges[i] == fp) {
  126. long min = ranges[i+1];
  127. if (min != NO_LIMIT && value < min) {
  128. return false;
  129. }
  130. long max = ranges[i+2];
  131. return (max == NO_LIMIT || max == MAX_UNSIGNED_LONG || value <= max);
  132. }
  133. }
  134. throw new IllegalArgumentException(
  135. "No range information found for integer subtype " + type.getDescription());
  136. }
  137. /**
  138. * Check that a BigInteger is within the required range for a given integer subtype.
  139. * This method is expensive, so it should not be used unless the BigInteger is outside the range of a long.
  140. * @param big the supplied BigInteger
  141. * @param type the derived type (a built-in restriction of xs:integer) to check the value against
  142. * @return true if the value is within the range for the derived type
  143. */
  144. public static boolean checkBigRange(BigInteger big, BuiltInAtomicType type) {
  145. for (int i = 0; i < ranges.length; i += 3) {
  146. if (ranges[i] == type.getFingerprint()) {
  147. long min = ranges[i+1];
  148. if (min != NO_LIMIT && BigInteger.valueOf(min).compareTo(big) > 0) {
  149. return false;
  150. }
  151. long max = ranges[i+2];
  152. if (max == NO_LIMIT) {
  153. return true;
  154. } else if (max == MAX_UNSIGNED_LONG) {
  155. return BigIntegerValue.MAX_UNSIGNED_LONG.compareTo(big) >= 0;
  156. } else {
  157. return BigInteger.valueOf(max).compareTo(big) >= 0;
  158. }
  159. }
  160. }
  161. throw new IllegalArgumentException(
  162. "No range information found for integer subtype " + type.getDescription());
  163. }
  164. /**
  165. * Static factory method to convert strings to integers.
  166. * @param s CharSequence representing the string to be converted
  167. * @return either an Int64Value or a BigIntegerValue representing the value of the String, or
  168. * a ValidationFailure encapsulating an Exception if the value cannot be converted.
  169. */
  170. public static ConversionResult stringToInteger(CharSequence s) {
  171. int len = s.length();
  172. int start = 0;
  173. int last = len - 1;
  174. while (start < len && s.charAt(start) <= 0x20) {
  175. start++;
  176. }
  177. while (last > start && s.charAt(last) <= 0x20) {
  178. last--;
  179. }
  180. if (start > last) {
  181. return numericError("Cannot convert zero-length string to an integer");
  182. }
  183. if (last - start < 16) {
  184. // for short numbers, we do the conversion ourselves, to avoid throwing unnecessary exceptions
  185. boolean negative = false;
  186. long value = 0;
  187. int i=start;
  188. if (s.charAt(i) == '+') {
  189. i++;
  190. } else if (s.charAt(i) == '-') {
  191. negative = true;
  192. i++;
  193. }
  194. if (i > last) {
  195. return numericError("Cannot convert string " + Err.wrap(s, Err.VALUE) +
  196. " to integer: no digits after the sign");
  197. }
  198. while (i <= last) {
  199. char d = s.charAt(i++);
  200. if (d >= '0' && d <= '9') {
  201. value = 10*value + (d-'0');
  202. } else {
  203. return numericError("Cannot convert string " + Err.wrap(s, Err.VALUE) + " to an integer");
  204. }
  205. }
  206. return Int64Value.makeIntegerValue((negative ? -value : value));
  207. } else {
  208. // for longer numbers, rely on library routines
  209. try {
  210. CharSequence t = Whitespace.trimWhitespace(s);
  211. if (t.charAt(0) == '+') {
  212. t = t.subSequence(1, t.length());
  213. }
  214. if (t.length() < 16) {
  215. return new Int64Value(Long.parseLong(t.toString()));
  216. } else {
  217. return new BigIntegerValue(new BigInteger(t.toString()));
  218. }
  219. } catch (NumberFormatException err) {
  220. return numericError("Cannot convert string " + Err.wrap(s, Err.VALUE) + " to an integer");
  221. }
  222. }
  223. }
  224. /**
  225. * Helper method to handle errors converting a string to a number
  226. * @param message error message
  227. * @return a ValidationFailure encapsulating an Exception describing the error
  228. */
  229. private static ValidationFailure numericError(String message) {
  230. ValidationFailure err = new ValidationFailure(message);
  231. err.setErrorCode("FORG0001");
  232. return err;
  233. }
  234. /**
  235. * Determine the primitive type of the value. This delivers the same answer as
  236. * getItemType().getPrimitiveItemType(). The primitive types are
  237. * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration,
  238. * and xs:untypedAtomic. For external objects, the result is AnyAtomicType.
  239. */
  240. public BuiltInAtomicType getPrimitiveType() {
  241. return BuiltInAtomicType.INTEGER;
  242. }
  243. /**
  244. * Determine whether the value is a whole number, that is, whether it compares
  245. * equal to some integer
  246. *
  247. * @return always true for this implementation
  248. */
  249. public boolean isWholeNumber() {
  250. return true;
  251. }
  252. /**
  253. * Add another integer
  254. * @param other the other integer
  255. * @return the result of the addition
  256. */
  257. public abstract IntegerValue plus(IntegerValue other);
  258. /**
  259. * Subtract another integer
  260. * @param other the other integer
  261. * @return the result of the subtraction
  262. */
  263. public abstract IntegerValue minus(IntegerValue other);
  264. /**
  265. * Multiply by another integer
  266. * @param other the other integer
  267. * @return the result of the multiplication
  268. */
  269. public abstract IntegerValue times(IntegerValue other);
  270. /**
  271. * Divide by another integer
  272. * @param other the other integer
  273. * @return the result of the division
  274. * @throws XPathException if the other integer is zero
  275. */
  276. public abstract NumericValue div(IntegerValue other) throws XPathException;
  277. /**
  278. * Take modulo another integer
  279. * @param other the other integer
  280. * @return the result of the modulo operation (the remainder)
  281. * @throws XPathException if the other integer is zero
  282. */
  283. public abstract IntegerValue mod(IntegerValue other) throws XPathException;
  284. /**
  285. * Integer divide by another integer
  286. * @param other the other integer
  287. * @return the result of the integer division
  288. * @throws XPathException if the other integer is zero
  289. */
  290. public abstract IntegerValue idiv(IntegerValue other) throws XPathException;
  291. /**
  292. * Get the value as a BigInteger
  293. * @return the value, as a BigInteger
  294. */
  295. public abstract BigInteger asBigInteger();
  296. /**
  297. * Get the signum of an int
  298. * @param i the int
  299. * @return -1 if the integer is negative, 0 if it is zero, +1 if it is positive
  300. */
  301. protected static int signum(int i) {
  302. return (i >> 31) | (-i >>> 31);
  303. }
  304. }
  305. //
  306. // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
  307. // you may not use this file except in compliance with the License. You may obtain a copy of the
  308. // License at http://www.mozilla.org/MPL/
  309. //
  310. // Software distributed under the License is distributed on an "AS IS" basis,
  311. // WITHOUT WARRANTY OF ANY KIND, either express or implied.
  312. // See the License for the specific language governing rights and limitations under the License.
  313. //
  314. // The Original Code is: all this file
  315. //
  316. // The Initial Developer of the Original Code is Michael H. Kay.
  317. //
  318. // Contributor(s):
  319. //