Require scale for integral conversions and RoundingMode for float
[yangtools.git] / model / yang-model-ri / src / main / java / org / opendaylight / yangtools / yang / model / ri / type / NumberUtil.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.model.ri.type;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11
12 import com.google.common.collect.ImmutableMap;
13 import java.util.Comparator;
14 import java.util.function.Function;
15 import org.opendaylight.yangtools.yang.common.Decimal64;
16 import org.opendaylight.yangtools.yang.common.Uint16;
17 import org.opendaylight.yangtools.yang.common.Uint32;
18 import org.opendaylight.yangtools.yang.common.Uint64;
19 import org.opendaylight.yangtools.yang.common.Uint8;
20
21 final class NumberUtil {
22     private static final Comparator<Number> NUMBER_COMPARATOR = (o1, o2) -> {
23         checkArgument(o1.getClass().equals(o2.getClass()), "Incompatible Number classes %s and %s",
24             o1.getClass(), o2.getClass());
25
26         if (o1 instanceof Byte) {
27             return ((Byte)o1).compareTo((Byte) o2);
28         } else if (o1 instanceof Short) {
29             return ((Short)o1).compareTo((Short) o2);
30         } else if (o1 instanceof Integer) {
31             return ((Integer)o1).compareTo((Integer) o2);
32         } else if (o1 instanceof Long) {
33             return ((Long)o1).compareTo((Long) o2);
34         } else if (o1 instanceof Uint8) {
35             return ((Uint8)o1).compareTo((Uint8) o2);
36         } else if (o1 instanceof Uint16) {
37             return ((Uint16)o1).compareTo((Uint16) o2);
38         } else if (o1 instanceof Uint32) {
39             return ((Uint32)o1).compareTo((Uint32) o2);
40         } else if (o1 instanceof Uint64) {
41             return ((Uint64)o1).compareTo((Uint64) o2);
42         } else if (o1 instanceof Decimal64) {
43             return ((Decimal64)o1).compareTo((Decimal64) o2);
44         } else {
45             throw new IllegalArgumentException("Unsupported Number class " + o1.getClass());
46         }
47     };
48
49     private static final ImmutableMap<Class<? extends Number>, Function<Number, Number>> CONVERTERS;
50
51     static {
52         final ImmutableMap.Builder<Class<? extends Number>, Function<Number, Number>> b = ImmutableMap.builder();
53         b.put(Byte.class, input -> {
54             if (input instanceof Byte) {
55                 return input;
56             }
57
58             return Byte.valueOf(input.toString());
59         });
60         b.put(Short.class, input -> {
61             if (input instanceof Short) {
62                 return input;
63             }
64             if (input instanceof Byte) {
65                 return input.shortValue();
66             }
67
68             return Short.valueOf(input.toString());
69         });
70         b.put(Integer.class, input -> {
71             if (input instanceof Integer) {
72                 return input;
73             }
74             if (input instanceof Byte || input instanceof Short) {
75                 return input.intValue();
76             }
77
78             return Integer.valueOf(input.toString());
79         });
80         b.put(Long.class, input ->  {
81             if (input instanceof Long) {
82                 return input;
83             }
84             if (input instanceof Byte || input instanceof Short || input instanceof Integer) {
85                 return input.longValue();
86             }
87
88             return Long.valueOf(input.toString());
89         });
90         b.put(Decimal64.class, input -> {
91             if (input instanceof Decimal64) {
92                 return input;
93             }
94             if (input instanceof Byte || input instanceof Short || input instanceof Integer || input instanceof Long) {
95                 // FIXME: this is not right, as we need to know fraction-digits
96                 return Decimal64.valueOf(1, input.longValue());
97             }
98
99             return Decimal64.valueOf(input.toString());
100         });
101         b.put(Uint8.class, input -> {
102             if (input instanceof Uint8) {
103                 return input;
104             }
105             // FIXME: revise this
106             if (input instanceof Byte || input instanceof Short || input instanceof Integer || input instanceof Long
107                     || input instanceof Uint16 || input instanceof Uint32 || input instanceof Uint64) {
108                 return Uint8.valueOf(input.longValue());
109             }
110
111             return Uint8.valueOf(input.toString());
112         });
113         b.put(Uint16.class, input -> {
114             if (input instanceof Uint16) {
115                 return input;
116             }
117             // FIXME: revise this
118             if (input instanceof Byte || input instanceof Short || input instanceof Integer || input instanceof Long
119                     || input instanceof Uint8 || input instanceof Uint32 || input instanceof Uint64) {
120                 return Uint16.valueOf(input.longValue());
121             }
122
123             return Uint16.valueOf(input.toString());
124         });
125         b.put(Uint32.class, input -> {
126             if (input instanceof Uint32) {
127                 return input;
128             }
129             // FIXME: revise this
130             if (input instanceof Byte || input instanceof Short || input instanceof Integer || input instanceof Long
131                     || input instanceof Uint8 || input instanceof Uint16 || input instanceof Uint64) {
132                 return Uint32.valueOf(input.longValue());
133             }
134
135             return Uint32.valueOf(input.toString());
136         });
137         b.put(Uint64.class, input -> {
138             if (input instanceof Uint64) {
139                 return input;
140             }
141             // FIXME: revise this
142             if (input instanceof Byte || input instanceof Short || input instanceof Integer || input instanceof Long
143                     || input instanceof Uint8 || input instanceof Uint16 || input instanceof Uint32) {
144                 return Uint64.valueOf(input.longValue());
145             }
146
147             return Uint64.valueOf(input.toString());
148         });
149         CONVERTERS = b.build();
150     }
151
152     private NumberUtil() {
153         // Hidden on purpose
154     }
155
156     @SuppressWarnings("unchecked")
157     static <T extends Number> Function<Number, T> converterTo(final Class<T> clazz) {
158         return (Function<Number, T>) CONVERTERS.get(clazz);
159     }
160
161     static boolean isRangeCovered(final Number min, final Number max, final Number superMin, final Number superMax) {
162         return NumberUtil.NUMBER_COMPARATOR.compare(min, superMin) >= 0
163             && NumberUtil.NUMBER_COMPARATOR.compare(max, superMax) <= 0;
164     }
165 }