Import atomix/{storage,utils}
[controller.git] / third-party / atomix / utils / src / main / java / io / atomix / utils / misc / Match.java
1 /*
2  * Copyright 2016-present Open Networking Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package io.atomix.utils.misc;
17
18 import java.util.Arrays;
19 import java.util.Objects;
20 import java.util.function.Function;
21
22 import static com.google.common.base.MoreObjects.toStringHelper;
23
24 /**
25  * Utility class for checking matching values.
26  *
27  * @param <T> type of value
28  */
29 public final class Match<T> {
30
31   public static final Match ANY = new Match<>();
32   public static final Match NULL = new Match<>(null, false);
33   public static final Match NOT_NULL = new Match<>(null, true);
34
35   private final boolean matchAny;
36   private final T value;
37   private final boolean negation;
38
39   /**
40    * Returns a Match that matches any value including null.
41    *
42    * @param <T> match type
43    * @return new instance
44    */
45   public static <T> Match<T> any() {
46     return ANY;
47   }
48
49   /**
50    * Returns a Match that matches null values.
51    *
52    * @param <T> match type
53    * @return new instance
54    */
55   public static <T> Match<T> ifNull() {
56     return NULL;
57   }
58
59   /**
60    * Returns a Match that matches all non-null values.
61    *
62    * @param <T> match type
63    * @return new instance
64    */
65   public static <T> Match<T> ifNotNull() {
66     return NOT_NULL;
67   }
68
69   /**
70    * Returns a Match that only matches the specified value.
71    *
72    * @param value value to match
73    * @param <T>   match type
74    * @return new instance
75    */
76   public static <T> Match<T> ifValue(T value) {
77     return new Match<>(value, false);
78   }
79
80   /**
81    * Returns a Match that matches any value except the specified value.
82    *
83    * @param value value to not match
84    * @param <T>   match type
85    * @return new instance
86    */
87   public static <T> Match<T> ifNotValue(T value) {
88     return new Match<>(value, true);
89   }
90
91   private Match() {
92     matchAny = true;
93     negation = false;
94     value = null;
95   }
96
97   private Match(T value, boolean negation) {
98     matchAny = false;
99     this.value = value;
100     this.negation = negation;
101   }
102
103   /**
104    * Maps this instance to a Match of another type.
105    *
106    * @param mapper transformation function
107    * @param <V>    new match type
108    * @return new instance
109    */
110   public <V> Match<V> map(Function<T, V> mapper) {
111     if (matchAny) {
112       return any();
113     } else if (value == null) {
114       return negation ? ifNotNull() : ifNull();
115     } else {
116       return negation ? ifNotValue(mapper.apply(value)) : ifValue(mapper.apply(value));
117     }
118   }
119
120   /**
121    * Checks if this instance matches specified value.
122    *
123    * @param other other value
124    * @return true if matches; false otherwise
125    */
126   public boolean matches(T other) {
127     if (matchAny) {
128       return true;
129     } else if (other == null) {
130       return negation ? value != null : value == null;
131     } else {
132       if (value instanceof byte[]) {
133         boolean equal = Arrays.equals((byte[]) value, (byte[]) other);
134         return negation ? !equal : equal;
135       }
136       return negation ? !Objects.equals(value, other) : Objects.equals(value, other);
137     }
138   }
139
140   @Override
141   public int hashCode() {
142     return Objects.hash(matchAny, value, negation);
143   }
144
145   @Override
146   public boolean equals(Object other) {
147     if (!(other instanceof Match)) {
148       return false;
149     }
150     Match<T> that = (Match<T>) other;
151     return this.matchAny == that.matchAny
152         && Objects.equals(this.value, that.value)
153         && this.negation == that.negation;
154   }
155
156   @Override
157   public String toString() {
158     return toStringHelper(this)
159         .add("matchAny", matchAny)
160         .add("negation", negation)
161         .add("value", value)
162         .toString();
163   }
164 }