BUG-4661: Introduce Decimal64, Empty, Uint{8,16,32,64}
[yangtools.git] / yang / yang-common / src / main / java / org / opendaylight / yangtools / yang / common / Uint64.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 com.google.common.base.Preconditions.checkArgument;
11
12 import com.google.common.annotations.Beta;
13 import com.google.common.cache.CacheBuilder;
14 import com.google.common.cache.CacheLoader;
15 import com.google.common.cache.LoadingCache;
16 import com.google.common.primitives.UnsignedLong;
17 import java.math.BigInteger;
18 import org.opendaylight.yangtools.concepts.Immutable;
19
20 /**
21  * Dedicated type for YANG's 'type uint64' type.
22  *
23  * @author Robert Varga
24  */
25 @Beta
26 public final class Uint64 extends Number implements Comparable<Uint64>, Immutable {
27     private static final long serialVersionUID = 1L;
28     private static final long MIN_VALUE = 0;
29
30     /**
31      * Cache of first 256 values.
32      */
33     private static final Uint64[] CACHE = new Uint64[Uint8.MAX_VALUE];
34     /**
35      * Commonly encountered values.
36      */
37     private static final Uint64[] COMMON = {
38         new Uint64(Short.MAX_VALUE + 1L),
39         new Uint64(32768),
40         new Uint64(65535),
41         new Uint64(65536),
42         new Uint64(Integer.MAX_VALUE),
43         new Uint64(Integer.MAX_VALUE + 1L),
44         new Uint64(Long.MAX_VALUE),
45     };
46
47     /**
48      * Tunable weak LRU cache for other values. By default it holds {@value #DEFAULT_LRU_SIZE} entries. This can be
49      * changed via {@value #LRU_SIZE_PROPERTY} system property.
50      */
51     private static final int DEFAULT_LRU_SIZE = 1024;
52     private static final String LRU_SIZE_PROPERTY = "org.opendaylight.yangtools.yang.common.Uint64.LRU.size";
53     private static final int MAX_LRU_SIZE = 0xffffff;
54     private static final int LRU_SIZE;
55
56     static {
57         final int p = Integer.getInteger(LRU_SIZE_PROPERTY, DEFAULT_LRU_SIZE);
58         LRU_SIZE = p >= 0 ? Math.min(p, MAX_LRU_SIZE) : DEFAULT_LRU_SIZE;
59     }
60
61     private static final LoadingCache<Long, Uint64> LRU = CacheBuilder.newBuilder().weakValues().maximumSize(LRU_SIZE)
62             .build(new CacheLoader<Long, Uint64>() {
63                 @Override
64                 public Uint64 load(final Long key) {
65                     return new Uint64(key);
66                 }
67             });
68
69     private final long value;
70
71     private Uint64(final long value) {
72         this.value = value;
73     }
74
75     private static Uint64 instanceFor(final long value) {
76         final int slot = (int)value;
77         if (value < 0 || slot >= CACHE.length) {
78             for (Uint64 c : COMMON) {
79                 if (c.value == value) {
80                     return c;
81                 }
82             }
83
84             return LRU.getUnchecked(value);
85         }
86
87         Uint64 ret = CACHE[slot];
88         if (ret == null) {
89             synchronized (CACHE) {
90                 ret = CACHE[slot];
91                 if (ret == null) {
92                     ret = new Uint64(value);
93                     CACHE[slot] = ret;
94                 }
95             }
96         }
97
98         return ret;
99     }
100
101     public static Uint64 fromLongBits(final long bits) {
102         return instanceFor(bits);
103     }
104
105     public static Uint64 fromUnsignedLong(final UnsignedLong ulong) {
106         return instanceFor(ulong.longValue());
107     }
108
109     public static Uint64 valueOf(final byte byteVal) {
110         checkArgument(byteVal >= MIN_VALUE, "Negative values are not allowed");
111         return instanceFor(byteVal);
112     }
113
114     public static Uint64 valueOf(final short shortVal) {
115         checkArgument(shortVal >= MIN_VALUE, "Negative values are not allowed");
116         return instanceFor(shortVal);
117     }
118
119     public static Uint64 valueOf(final int intVal) {
120         checkArgument(intVal >= MIN_VALUE, "Value %s is outside of allowed range", intVal);
121         return instanceFor(intVal);
122     }
123
124     public static Uint64 valueOf(final long longVal) {
125         checkArgument(longVal >= MIN_VALUE, "Value %s is outside of allowed range", longVal);
126         return instanceFor(longVal);
127     }
128
129     public static Uint64 valueOf(final Uint8 uint) {
130         return instanceFor(uint.shortValue());
131     }
132
133     public static Uint64 valueOf(final Uint16 uint) {
134         return instanceFor(uint.intValue());
135     }
136
137     public static Uint64 valueOf(final Uint32 uint) {
138         return instanceFor(uint.longValue());
139     }
140
141     public static Uint64 valueOf(final String string) {
142         return valueOf(string, 10);
143     }
144
145     public static Uint64 valueOf(final String string, final int radix) {
146         return instanceFor(Long.parseUnsignedLong(string, radix));
147     }
148
149     public static Uint64 valueOf(final BigInteger bigInt) {
150         checkArgument(bigInt.signum() >= 0, "Negative values not allowed");
151         checkArgument(bigInt.bitLength() <= Long.SIZE, "Value %s is outside of allowed range", bigInt);
152
153         return instanceFor(bigInt.longValue());
154     }
155
156     @Override
157     public int intValue() {
158         return (int)value;
159     }
160
161     @Override
162     public long longValue() {
163         return value;
164     }
165
166     @Override
167     public float floatValue() {
168         // TODO: ditch Guava
169         return UnsignedLong.fromLongBits(value).floatValue();
170     }
171
172     @Override
173     public double doubleValue() {
174         // TODO: ditch Guava
175         return UnsignedLong.fromLongBits(value).doubleValue();
176     }
177
178     public UnsignedLong toUnsignedLong() {
179         return UnsignedLong.fromLongBits(value);
180     }
181
182     @Override
183     @SuppressWarnings("checkstyle:parameterName")
184     public int compareTo(final Uint64 o) {
185         return Long.compareUnsigned(value, o.value);
186     }
187
188     @Override
189     public int hashCode() {
190         return Long.hashCode(value);
191     }
192
193     @Override
194     public boolean equals(final Object obj) {
195         if (this == obj) {
196             return true;
197         }
198
199         return obj instanceof Uint64 && value == ((Uint64)obj).value;
200     }
201
202     @Override
203     public String toString() {
204         return Long.toUnsignedString(value);
205     }
206
207     private Object readResolve() {
208         return instanceFor(value);
209     }
210 }