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