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