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