3480b938bc295186ee1f2235c363e962b68cf314
[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 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     Uint64(final long value) {
72         this.value = value;
73     }
74
75     protected Uint64(final Uint64 other) {
76         this.value = other.value;
77     }
78
79     private static Uint64 instanceFor(final long value) {
80         final int slot = (int)value;
81         if (slot < 0 || slot >= CACHE.length) {
82             for (Uint64 c : COMMON) {
83                 if (c.value == value) {
84                     return c;
85                 }
86             }
87
88             return LRU.getUnchecked(value);
89         }
90
91         Uint64 ret = CACHE[slot];
92         if (ret == null) {
93             synchronized (CACHE) {
94                 ret = CACHE[slot];
95                 if (ret == null) {
96                     ret = new Uint64(value);
97                     CACHE[slot] = ret;
98                 }
99             }
100         }
101
102         return ret;
103     }
104
105     public static Uint64 fromLongBits(final long bits) {
106         return instanceFor(bits);
107     }
108
109     public static Uint64 fromUnsignedLong(final UnsignedLong ulong) {
110         return instanceFor(ulong.longValue());
111     }
112
113     public static Uint64 valueOf(final byte byteVal) {
114         checkArgument(byteVal >= MIN_VALUE, "Negative values are not allowed");
115         return instanceFor(byteVal);
116     }
117
118     public static Uint64 valueOf(final short shortVal) {
119         checkArgument(shortVal >= MIN_VALUE, "Negative values are not allowed");
120         return instanceFor(shortVal);
121     }
122
123     public static Uint64 valueOf(final int intVal) {
124         checkArgument(intVal >= MIN_VALUE, "Value %s is outside of allowed range", intVal);
125         return instanceFor(intVal);
126     }
127
128     public static Uint64 valueOf(final long longVal) {
129         checkArgument(longVal >= MIN_VALUE, "Value %s is outside of allowed range", longVal);
130         return instanceFor(longVal);
131     }
132
133     public static Uint64 valueOf(final Uint8 uint) {
134         return instanceFor(uint.shortValue());
135     }
136
137     public static Uint64 valueOf(final Uint16 uint) {
138         return instanceFor(uint.intValue());
139     }
140
141     public static Uint64 valueOf(final Uint32 uint) {
142         return instanceFor(uint.longValue());
143     }
144
145     public static Uint64 valueOf(final String string) {
146         return valueOf(string, 10);
147     }
148
149     public static Uint64 valueOf(final String string, final int radix) {
150         return instanceFor(Long.parseUnsignedLong(string, radix));
151     }
152
153     public static Uint64 valueOf(final BigInteger bigInt) {
154         checkArgument(bigInt.signum() >= 0, "Negative values not allowed");
155         checkArgument(bigInt.bitLength() <= Long.SIZE, "Value %s is outside of allowed range", bigInt);
156
157         return instanceFor(bigInt.longValue());
158     }
159
160     @Override
161     public final int intValue() {
162         return (int)value;
163     }
164
165     @Override
166     public final long longValue() {
167         return value;
168     }
169
170     @Override
171     public final float floatValue() {
172         // TODO: ditch Guava
173         return UnsignedLong.fromLongBits(value).floatValue();
174     }
175
176     @Override
177     public final double doubleValue() {
178         // TODO: ditch Guava
179         return UnsignedLong.fromLongBits(value).doubleValue();
180     }
181
182     public final UnsignedLong toUnsignedLong() {
183         return UnsignedLong.fromLongBits(value);
184     }
185
186     @Override
187     @SuppressWarnings("checkstyle:parameterName")
188     public final int compareTo(final Uint64 o) {
189         return Long.compareUnsigned(value, o.value);
190     }
191
192     @Override
193     public final int hashCode() {
194         return Long.hashCode(value);
195     }
196
197     @Override
198     public final boolean equals(final Object obj) {
199         return this == obj || obj instanceof Uint64 && value == ((Uint64)obj).value;
200     }
201
202     @Override
203     public final String toString() {
204         return Long.toUnsignedString(value);
205     }
206
207     private Object readResolve() {
208         return instanceFor(value);
209     }
210 }