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