Migrate RFC references to rfc-editor.org
[yangtools.git] / common / yang-common / src / main / java / org / opendaylight / yangtools / yang / common / Uint32.java
1 /*
2  * Copyright (c) 2015 Pantheon Technologies s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.common;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.annotations.Beta;
13 import com.google.common.collect.Interner;
14 import com.google.common.collect.Interners;
15 import com.google.common.primitives.UnsignedInteger;
16 import java.io.Serial;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.opendaylight.yangtools.concepts.Either;
21
22 /**
23  * Dedicated type for YANG's 'type uint32' type.
24  *
25  * @author Robert Varga
26  */
27 @Beta
28 @NonNullByDefault
29 public class Uint32 extends Number implements CanonicalValue<Uint32> {
30     public static final class Support extends AbstractCanonicalValueSupport<Uint32> {
31         public Support() {
32             super(Uint32.class);
33         }
34
35         @Override
36         public Either<Uint32, CanonicalValueViolation> fromString(final String str) {
37             try {
38                 return Either.ofFirst(Uint32.valueOf(str));
39             } catch (IllegalArgumentException e) {
40                 return CanonicalValueViolation.variantOf(e);
41             }
42         }
43     }
44
45     private static final CanonicalValueSupport<Uint32> SUPPORT = new Support();
46     @Serial
47     private static final long serialVersionUID = 1L;
48     private static final long MAX_VALUE_LONG = 4294967295L;
49     private static final String MAX_VALUE_STR = "4294967295";
50
51     private static final String CACHE_SIZE_PROPERTY = "org.opendaylight.yangtools.yang.common.Uint32.cache.size";
52     private static final int DEFAULT_CACHE_SIZE = 256;
53
54     /**
55      * Tunable cache for values. By default it holds {@value #DEFAULT_CACHE_SIZE} entries. This can be
56      * changed via {@value #CACHE_SIZE_PROPERTY} system property.
57      */
58     private static final int CACHE_SIZE;
59
60     static {
61         final int p = Integer.getInteger(CACHE_SIZE_PROPERTY, DEFAULT_CACHE_SIZE);
62         CACHE_SIZE = p >= 0 ? Math.min(p, Integer.MAX_VALUE) : DEFAULT_CACHE_SIZE;
63     }
64
65     private static final @NonNull Uint32[] CACHE;
66
67     static {
68         final Uint32[] c = new Uint32[CACHE_SIZE];
69         for (int i = 0; i < c.length; ++i) {
70             c[i] = new Uint32(i);
71         }
72         CACHE = c;
73     }
74
75     private static final Interner<Uint32> INTERNER = Interners.newWeakInterner();
76
77     /**
78      * Value of {@code 0}.
79      */
80     public static final Uint32 ZERO = valueOf(0).intern();
81     /**
82      * Value of {@code 1}.
83      */
84     public static final Uint32 ONE = valueOf(1).intern();
85     /**
86      * Value of {@code 2}.
87      */
88     public static final Uint32 TWO = valueOf(2).intern();
89     /**
90      * Value of {@code 10}.
91      */
92     public static final Uint32 TEN = valueOf(10).intern();
93     /**
94      * Value of {@code 4294967295}.
95      */
96     public static final Uint32 MAX_VALUE = valueOf(MAX_VALUE_LONG).intern();
97
98     private final int value;
99
100     private Uint32(final int value) {
101         this.value = value;
102     }
103
104     protected Uint32(final Uint32 other) {
105         this(other.value);
106     }
107
108     private static Uint32 instanceFor(final int value) {
109         final long longSlot = Integer.toUnsignedLong(value);
110         return longSlot < CACHE.length ? CACHE[(int)longSlot] : new Uint32(value);
111     }
112
113     /**
114      * Returns an {@code Uint32} corresponding to a given bit representation. The argument is interpreted as an
115      * unsigned 32-bit value.
116      *
117      * @param bits unsigned bit representation
118      * @return A Uint32 instance
119      */
120     public static Uint32 fromIntBits(final int bits) {
121         return instanceFor(bits);
122     }
123
124     /**
125      * Returns an {@code Uint32} corresponding to a given {@code byteVal}. The inverse operation is
126      * {@link #byteValue()}.
127      *
128      * @param byteVal byte value
129      * @return A Uint32 instance
130      * @throws IllegalArgumentException if byteVal is less than zero
131      */
132     public static Uint32 valueOf(final byte byteVal) {
133         UintConversions.checkNonNegative(byteVal, MAX_VALUE_STR);
134         return instanceFor(byteVal);
135     }
136
137     /**
138      * Returns an {@code Uint32} corresponding to a given {@code shortVal}. The inverse operation is
139      * {@link #shortValue()}.
140      *
141      * @param shortVal short value
142      * @return A Uint32 instance
143      * @throws IllegalArgumentException if shortVal is less than zero
144      */
145     public static Uint32 valueOf(final short shortVal) {
146         UintConversions.checkNonNegative(shortVal, MAX_VALUE_STR);
147         return instanceFor(shortVal);
148     }
149
150     /**
151      * Returns an {@code Uint32} corresponding to a given {@code intVal}. The inverse operation is {@link #intValue()}.
152      *
153      * @param intVal int value
154      * @return A Uint32 instance
155      * @throws IllegalArgumentException if intVal is less than zero
156      */
157     public static Uint32 valueOf(final int intVal) {
158         UintConversions.checkNonNegative(intVal, MAX_VALUE_STR);
159         return instanceFor(intVal);
160     }
161
162     /**
163      * Returns an {@code Uint32} corresponding to a given {@code longVal}. The inverse operation is
164      * {@link #longValue()}.
165      *
166      * @param longVal long value
167      * @return A Uint8 instance
168      * @throws IllegalArgumentException if longVal is less than zero or greater than 4294967295
169      */
170     public static Uint32 valueOf(final long longVal) {
171         UintConversions.checkRange(longVal, MAX_VALUE_LONG);
172         return instanceFor((int)longVal);
173     }
174
175     /**
176      * Returns an {@code Uint32} corresponding to a given {@code uint}.
177      *
178      * @param uint Uint8 value
179      * @return A Uint32 instance
180      * @throws NullPointerException if uint is null
181      */
182     public static Uint32 valueOf(final Uint8 uint) {
183         return instanceFor(uint.shortValue());
184     }
185
186     /**
187      * Returns an {@code Uint32} corresponding to a given {@code uint}.
188      *
189      * @param uint Uint16 value
190      * @return A Uint32 instance
191      * @throws NullPointerException if uint is null
192      */
193     public static Uint32 valueOf(final Uint16 uint) {
194         return instanceFor(uint.intValue());
195     }
196
197     /**
198      * Returns an {@code Uint32} corresponding to a given {@code uint}.
199      *
200      * @param uint Uint64 value
201      * @return A Uint32 instance
202      * @throws NullPointerException if uint is null
203      * @throws IllegalArgumentException if uint is greater than 4294967295
204      */
205     public static Uint32 valueOf(final Uint64 uint) {
206         return valueOf(uint.longValue());
207     }
208
209     /**
210      * Returns an {@code Uint32} corresponding to a given {@code uint}.
211      *
212      * @param uint UnsignedInteger value
213      * @return A Uint32 instance
214      * @throws NullPointerException if uint is null
215      */
216     public static Uint32 valueOf(final UnsignedInteger uint) {
217         return instanceFor(uint.intValue());
218     }
219
220     /**
221      * Returns an {@code Uint32} holding the value of the specified {@code String}, parsed as an unsigned {@code long}
222      * value.
223      *
224      * @param string String to parse
225      * @return A Uint32 instance
226      * @throws NullPointerException if string is null
227      * @throws IllegalArgumentException if the parsed value is less than zero or greater than 4294967295
228      * @throws NumberFormatException if the string does not contain a parsable unsigned {@code long} value.
229      */
230     public static Uint32 valueOf(final String string) {
231         return valueOf(string, 10);
232     }
233
234     /**
235      * Returns an {@code Uint32} holding the value of the specified {@code String}, parsed as an unsigned {@code long}
236      * value.
237      *
238      * @param string String to parse
239      * @param radix Radix to use
240      * @return A Uint32 instance
241      * @throws NullPointerException if string is null
242      * @throws IllegalArgumentException if the parsed value is less than zero or greater than 4294967295
243      * @throws NumberFormatException if the string does not contain a parsable unsigned {@code long} value, or if the
244      *                               {@code radix} is outside of allowed range.
245      */
246     public static Uint32 valueOf(final String string, final int radix) {
247         return instanceFor(Integer.parseUnsignedInt(requireNonNull(string), radix));
248     }
249
250     /**
251      * Returns an {@code Uint32} corresponding to a given {@code byteVal} if it is representable. If the value is
252      * negative {@link #ZERO} will be returned.
253      *
254      * @param byteVal byte value
255      * @return A Uint32 instance
256      */
257     public static Uint32 saturatedOf(final byte byteVal) {
258         return byteVal <= 0 ? Uint32.ZERO : instanceFor(byteVal);
259     }
260
261     /**
262      * Returns an {@code Uint32} corresponding to a given {@code shortVal} if it is representable. If the value is
263      * negative {@link #ZERO} will be returned.
264      *
265      * @param shortVal short value
266      * @return A Uint32 instance
267      */
268     public static Uint32 saturatedOf(final short shortVal) {
269         return shortVal <= 0 ? Uint32.ZERO : instanceFor(shortVal);
270     }
271
272     /**
273      * Returns an {@code Uint32} corresponding to a given {@code intVal} if it is representable. If the value is
274      * negative {@link #ZERO} will be returned.
275      *
276      * @param intVal int value
277      * @return A Uint32 instance
278      */
279     public static Uint32 saturatedOf(final int intVal) {
280         return intVal <= 0 ? Uint32.ZERO : instanceFor(intVal);
281     }
282
283     /**
284      * Returns an {@code Uint32} corresponding to a given {@code longVal} if it is representable. If the value is
285      * negative {@link #ZERO} will be returned. If the value is greater than 4294967295, {@link #MAX_VALUE} will be
286      * returned.
287      *
288      * @param longVal long value
289      * @return A Uint32 instance
290      */
291     public static Uint32 saturatedOf(final long longVal) {
292         if (longVal <= 0) {
293             return Uint32.ZERO;
294         }
295         if (longVal >= MAX_VALUE_LONG) {
296             return Uint32.MAX_VALUE;
297         }
298         return instanceFor((int) longVal);
299     }
300
301     /**
302      * {@inheritDoc}
303      *
304      * <p>
305      * The inverse operation is {@link #fromIntBits(int)}. In case this value is greater than {@link Integer#MAX_VALUE},
306      * the returned value will be equal to {@code this - 2^32}.
307      */
308     @Override
309     public final int intValue() {
310         return value;
311     }
312
313     @Override
314     public final long longValue() {
315         return Integer.toUnsignedLong(value);
316     }
317
318     @Override
319     public final float floatValue() {
320         return longValue();
321     }
322
323     @Override
324     public final double doubleValue() {
325         return longValue();
326     }
327
328     @Override
329     @SuppressWarnings("checkstyle:parameterName")
330     public final int compareTo(final Uint32 o) {
331         return Integer.compareUnsigned(value, o.value);
332     }
333
334     @Override
335     public final String toCanonicalString() {
336         return Integer.toUnsignedString(value);
337     }
338
339     @Override
340     public final CanonicalValueSupport<Uint32> support() {
341         return SUPPORT;
342     }
343
344     /**
345      * Return an interned (shared) instance equivalent to this object. This may return the same object.
346      *
347      * @return A shared instance.
348      */
349     public final Uint32 intern() {
350         return value >= 0 && value < CACHE_SIZE ? this : INTERNER.intern(this);
351     }
352
353     /**
354      * Convert this value to a {@code long}.
355      *
356      * @return A long
357      */
358     public final long toJava() {
359         return longValue();
360     }
361
362     /**
363      * Convert this value to an {@link UnsignedInteger}.
364      *
365      * @return An UnsignedInteger instance
366      */
367     public final UnsignedInteger toGuava() {
368         return UnsignedInteger.fromIntBits(value);
369     }
370
371     /**
372      * Convert this value to a {@code Uint8}.
373      *
374      * @return A Uint8
375      * @throws IllegalArgumentException if this value is greater than 255.
376      */
377     public final Uint8 toUint8() {
378         return Uint8.valueOf(toJava());
379     }
380
381     /**
382      * Convert this value to a {@code Uint16}.
383      *
384      * @return A Uint16
385      * @throws IllegalArgumentException if this value is greater than 65535.
386      */
387     public final Uint16 toUint16() {
388         return Uint16.valueOf(toJava());
389     }
390
391     /**
392      * Convert this value to a {@code Uint64}.
393      *
394      * @return A Uint64
395      */
396     public final Uint64 toUint64() {
397         return Uint64.fromLongBits(longValue());
398     }
399
400     public final Uint8 toSaturatedUint8() {
401         return Uint8.saturatedOf(toJava());
402     }
403
404     public final Uint16 toSaturatedUint16() {
405         return Uint16.saturatedOf(toJava());
406     }
407
408     // FIXME: more saturated conversions
409
410     @Override
411     public final int hashCode() {
412         return Integer.hashCode(value);
413     }
414
415     @Override
416     public final boolean equals(final @Nullable Object obj) {
417         return this == obj || obj instanceof Uint32 other && value == other.value;
418     }
419
420     /**
421      * A slightly faster version of {@link #equals(Object)}.
422      *
423      * @param obj Uint32 object
424      * @return {@code true} if this object is the same as the obj argument; {@code false} otherwise.
425      */
426     public final boolean equals(final @Nullable Uint32 obj) {
427         return this == obj || obj != null && value == obj.value;
428     }
429
430     @Override
431     public final String toString() {
432         return toCanonicalString();
433     }
434
435     @Serial
436     private Object readResolve() {
437         return instanceFor(value);
438     }
439 }