1 package org.simantics.datatypes.literal;
\r
3 import java.util.UUID;
\r
5 import org.simantics.databoard.Bindings;
\r
6 import org.simantics.databoard.binding.Binding;
\r
7 import org.simantics.databoard.util.Bean;
\r
10 public class GUID extends Bean {
\r
12 public static final Binding BINDING = Bindings.getBindingUnchecked(GUID.class);
\r
14 public long mostSignificant;
\r
15 public long leastSignificant;
\r
17 public GUID(long mostSignificant, long leastSignificant) {
\r
19 this.mostSignificant = mostSignificant;
\r
20 this.leastSignificant = leastSignificant;
\r
23 public static GUID invalid() {
\r
24 return new GUID(0, 0);
\r
27 public static GUID invalid2() {
\r
28 return new GUID(0, 1);
\r
31 public boolean isInvalid() {
\r
32 return mostSignificant == 0 && leastSignificant == 0;
\r
35 public static GUID random() {
\r
36 UUID random = UUID.randomUUID();
\r
37 return new GUID(random.getMostSignificantBits(), random.getLeastSignificantBits());
\r
40 public String indexString() {
\r
41 StringBuilder b = new StringBuilder();
\r
42 b.append(Long.toHexString(mostSignificant));
\r
44 b.append(Long.toHexString(leastSignificant));
\r
45 return b.toString();
\r
48 public static GUID parseIndexString(String indexString) {
\r
49 String[] parts = indexString.split("_");
\r
50 if(parts.length != 2) throw new IllegalArgumentException();
\r
51 Long mostSignificant = parseUnsignedLong(parts[0].toUpperCase(), 16);
\r
52 Long leastSignificant = parseUnsignedLong(parts[1], 16);
\r
53 return new GUID(mostSignificant, leastSignificant);
\r
57 * Parses the string argument as an unsigned {@code long} in the
\r
58 * radix specified by the second argument. An unsigned integer
\r
59 * maps the values usually associated with negative numbers to
\r
60 * positive numbers larger than {@code MAX_VALUE}.
\r
62 * The characters in the string must all be digits of the
\r
63 * specified radix (as determined by whether {@link
\r
64 * java.lang.Character#digit(char, int)} returns a nonnegative
\r
65 * value), except that the first character may be an ASCII plus
\r
66 * sign {@code '+'} ({@code '\u005Cu002B'}). The resulting
\r
67 * integer value is returned.
\r
69 * <p>An exception of type {@code NumberFormatException} is
\r
70 * thrown if any of the following situations occurs:
\r
72 * <li>The first argument is {@code null} or is a string of
\r
75 * <li>The radix is either smaller than
\r
76 * {@link java.lang.Character#MIN_RADIX} or
\r
77 * larger than {@link java.lang.Character#MAX_RADIX}.
\r
79 * <li>Any character of the string is not a digit of the specified
\r
80 * radix, except that the first character may be a plus sign
\r
81 * {@code '+'} ({@code '\u005Cu002B'}) provided that the
\r
82 * string is longer than length 1.
\r
84 * <li>The value represented by the string is larger than the
\r
85 * largest unsigned {@code long}, 2<sup>64</sup>-1.
\r
90 * @param s the {@code String} containing the unsigned integer
\r
91 * representation to be parsed
\r
92 * @param radix the radix to be used while parsing {@code s}.
\r
93 * @return the unsigned {@code long} represented by the string
\r
94 * argument in the specified radix.
\r
95 * @throws NumberFormatException if the {@code String}
\r
96 * does not contain a parsable {@code long}.
\r
99 public static long parseUnsignedLong(String s, int radix)
\r
100 throws NumberFormatException {
\r
102 throw new NumberFormatException("null");
\r
105 int len = s.length();
\r
107 char firstChar = s.charAt(0);
\r
108 if (firstChar == '-') {
\r
110 NumberFormatException(String.format("Illegal leading minus sign " +
\r
111 "on unsigned string %s.", s));
\r
113 if (len <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits
\r
114 (radix == 10 && len <= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits
\r
115 return Long.parseLong(s, radix);
\r
118 // No need for range checks on len due to testing above.
\r
119 long first = Long.parseLong(s.substring(0, len - 1), radix);
\r
120 int second = Character.digit(s.charAt(len - 1), radix);
\r
122 throw new NumberFormatException("Bad digit at end of " + s);
\r
124 long result = first * radix + second;
\r
125 if (compareUnsigned(result, first) < 0) {
\r
127 * The maximum unsigned value, (2^64)-1, takes at
\r
128 * most one more digit to represent than the
\r
129 * maximum signed value, (2^63)-1. Therefore,
\r
130 * parsing (len - 1) digits will be appropriately
\r
131 * in-range of the signed parsing. In other
\r
132 * words, if parsing (len -1) digits overflows
\r
133 * signed parsing, parsing len digits will
\r
134 * certainly overflow unsigned parsing.
\r
136 * The compareUnsigned check above catches
\r
137 * situations where an unsigned overflow occurs
\r
138 * incorporating the contribution of the final
\r
141 throw new NumberFormatException(String.format("String value %s exceeds " +
\r
142 "range of unsigned long.", s));
\r
147 throw new NumberFormatException("For input string: \"" + s + "\"");
\r
152 * Compares two {@code long} values numerically treating the values
\r
155 * @param x the first {@code long} to compare
\r
156 * @param y the second {@code long} to compare
\r
157 * @return the value {@code 0} if {@code x == y}; a value less
\r
158 * than {@code 0} if {@code x < y} as unsigned values; and
\r
159 * a value greater than {@code 0} if {@code x > y} as
\r
163 public static int compareUnsigned(long x, long y) {
\r
164 return Long.compare(x + Long.MIN_VALUE, y + Long.MIN_VALUE);
\r