Merge branch 'master' of ../controller
[yangtools.git] / common / util / src / main / java / org / opendaylight / yangtools / util / OptionalBoolean.java
1 /*
2  * Copyright (c) 2017 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.util;
9
10 import com.google.common.annotations.Beta;
11 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
12 import java.util.Optional;
13 import org.eclipse.jdt.annotation.NonNull;
14 import org.eclipse.jdt.annotation.Nullable;
15
16 /**
17  * Utility class for storing an optional boolean in a single byte value. This cuts down the memory requirement quite
18  * at very small computational cost.
19  *
20  * <p>
21  * Note: fields do not have to be explicitly initialized, as default initialization value for 'byte', 0, is used to
22  *       represent 'absent' condition.
23  *
24  * @author Robert Varga
25  */
26 @Beta
27 public final class OptionalBoolean {
28     private static final @NonNull Optional<Boolean> FALSE_OPTIONAL = Optional.of(Boolean.FALSE);
29     private static final @NonNull Optional<Boolean> TRUE_OPTIONAL = Optional.of(Boolean.TRUE);
30
31     private static final byte ABSENT = 0;
32     private static final byte FALSE = 1;
33     private static final byte TRUE = 2;
34
35     private OptionalBoolean() {
36         throw new UnsupportedOperationException();
37     }
38
39     /**
40      * Check if a field value has been set, just like {@link Optional#isPresent()}.
41      *
42      * @param value field value
43      * @return True if the value is set.
44      * @throws IllegalArgumentException if value is invalid
45      */
46     public static boolean isPresent(final byte value) {
47         switch (value) {
48             case ABSENT:
49                 return false;
50             case FALSE:
51             case TRUE:
52                 return true;
53             default:
54                 throw invalidValue(value);
55         }
56     }
57
58     /**
59      * Decode boolean from a field value, just like {@link Optional#get()}.
60      *
61      * @param value Field value
62      * @return Decoded boolean.
63      * @throws IllegalArgumentException if value is invalid
64      * @throws IllegalStateException if value has not been set
65      */
66     public static boolean get(final byte value) {
67         switch (value) {
68             case ABSENT:
69                 throw new IllegalStateException("Field has not been initialized");
70             case FALSE:
71                 return false;
72             case TRUE:
73                 return true;
74             default:
75                 throw invalidValue(value);
76         }
77     }
78
79     /**
80      * Encode a boolean to a field value, just like {@link Optional#of(Object)}.
81      *
82      * @param bool Boolean value.
83      * @return Field value.
84      */
85     public static byte of(final boolean bool) {
86         return bool ? TRUE : FALSE;
87     }
88
89     /**
90      * Convert a nullable {@link Boolean} into a field value, just like {@link Optional#ofNullable(Object)}.
91      *
92      * @param bool Boolean value.
93      * @return Field value.
94      */
95     public static byte ofNullable(final @Nullable Boolean bool) {
96         return bool == null ? ABSENT : of(bool.booleanValue());
97     }
98
99     /**
100      * Convert a field value to a nullable {@link Boolean}. Similar to {@code Optional.orElse(null)}.
101      *
102      * @param value Field value.
103      * @return Nullable Boolean.
104      */
105     @SuppressFBWarnings("NP_BOOLEAN_RETURN_NULL")
106     public static @Nullable Boolean toNullable(final byte value) {
107         switch (value) {
108             case ABSENT:
109                 return null;
110             case FALSE:
111                 return Boolean.FALSE;
112             case TRUE:
113                 return Boolean.TRUE;
114             default:
115                 throw invalidValue(value);
116         }
117     }
118
119     /**
120      * Convert an {@link Optional} {@link Boolean} into a field value.
121      *
122      * @param value Optional {@link Boolean}.
123      * @return Field value.
124      * @throws NullPointerException if value is null.
125      */
126     public static byte ofOptional(final Optional<Boolean> value) {
127         return ofNullable(value.orElse(null));
128     }
129
130     /**
131      * Convert a field value into an {@link Optional} {@link Boolean}.
132      *
133      * @param value Field value.
134      * @return Optional {@link Boolean}.
135      * @throws IllegalArgumentException if value is invalid.
136      */
137     public static @NonNull Optional<Boolean> toOptional(final byte value) {
138         switch (value) {
139             case ABSENT:
140                 return Optional.empty();
141             case FALSE:
142                 return FALSE_OPTIONAL;
143             case TRUE:
144                 return TRUE_OPTIONAL;
145             default:
146                 throw invalidValue(value);
147         }
148     }
149
150     /**
151      * Convert a field value into a String representation.
152      *
153      * @param value Field value.
154      * @return Boolean-compatible string, or "absent".
155      * @throws IllegalArgumentException if value is invalid.
156      */
157     public static @NonNull String toString(final byte value) {
158         switch (value) {
159             case ABSENT:
160                 return "absent";
161             case FALSE:
162                 return Boolean.toString(false);
163             case TRUE:
164                 return Boolean.toString(true);
165             default:
166                 throw invalidValue(value);
167         }
168     }
169
170     private static IllegalArgumentException invalidValue(final byte value) {
171         throw new IllegalArgumentException("Invalid field value " + value);
172     }
173 }