1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.collections4.trie;
18
19 import java.io.Serializable;
20 import java.util.AbstractMap;
21 import java.util.Map;
22 import java.util.Objects;
23
24 import org.apache.commons.collections4.Trie;
25
26 /**
27 * This class provides some basic {@link Trie} functionality and
28 * utility methods for actual bitwise {@link Trie} implementations.
29 *
30 * @param <K> the type of the keys in this map
31 * @param <V> the type of the values in this map
32 * @since 4.0
33 */
34 public abstract class AbstractBitwiseTrie<K, V> extends AbstractMap<K, V>
35 implements Trie<K, V>, Serializable {
36
37 /**
38 * A basic implementation of {@link Entry}.
39 *
40 * @param <K> the type of the keys in this entry.
41 * @param <V> the type of the values in this entry.
42 */
43 abstract static class BasicEntry<K, V> implements Map.Entry<K, V>, Serializable {
44
45 private static final long serialVersionUID = -944364551314110330L;
46
47 /**
48 * The entry's key.
49 */
50 protected K key;
51
52 /**
53 * The entry's value.
54 */
55 protected V value;
56
57 BasicEntry(final K key) {
58 this.key = key;
59 }
60
61 BasicEntry(final K key, final V value) {
62 this.key = key;
63 this.value = value;
64 }
65
66 @Override
67 public boolean equals(final Object o) {
68 if (o == this) {
69 return true;
70 }
71 if (!(o instanceof Map.Entry)) {
72 return false;
73 }
74
75 final Map.Entry<?, ?> other = (Map.Entry<?, ?>) o;
76 if (compare(key, other.getKey())
77 && compare(value, other.getValue())) {
78 return true;
79 }
80 return false;
81 }
82
83 @Override
84 public K getKey() {
85 return key;
86 }
87
88 @Override
89 public V getValue() {
90 return value;
91 }
92
93 @Override
94 public int hashCode() {
95 return (getKey() == null ? 0 : getKey().hashCode()) ^
96 (getValue() == null ? 0 : getValue().hashCode());
97 }
98
99 /**
100 * Replaces the current key and value with the provided key & value.
101 *
102 * @param key The new key.
103 * @param value The new value.
104 * @return The previous value.
105 */
106 public V setKeyValue(final K key, final V value) {
107 this.key = key;
108 return setValue(value);
109 }
110
111 @Override
112 public V setValue(final V value) {
113 final V previous = this.value;
114 this.value = value;
115 return previous;
116 }
117
118 @Override
119 public String toString() {
120 return key + "=" + value;
121 }
122 }
123
124 private static final long serialVersionUID = 5826987063535505652L;
125
126 /**
127 * Delegates to {@link Objects#equals(Object, Object)}.
128 */
129 static boolean compare(final Object a, final Object b) {
130 return Objects.equals(a, b);
131 }
132
133 /**
134 * The {@link KeyAnalyzer} that's being used to build the PATRICIA {@link Trie}.
135 */
136 private final KeyAnalyzer<? super K> keyAnalyzer;
137
138 /**
139 * Constructs a new {@link Trie} using the given {@link KeyAnalyzer}.
140 *
141 * @param keyAnalyzer the {@link KeyAnalyzer} to use
142 */
143 protected AbstractBitwiseTrie(final KeyAnalyzer<? super K> keyAnalyzer) {
144 this.keyAnalyzer = Objects.requireNonNull(keyAnalyzer, "keyAnalyzer");
145 }
146
147 /**
148 * Utility method for calling {@link KeyAnalyzer#bitIndex(Object, int, int, Object, int, int)}.
149 */
150 final int bitIndex(final K key, final K foundKey) {
151 return keyAnalyzer.bitIndex(key, 0, lengthInBits(key), foundKey, 0, lengthInBits(foundKey));
152 }
153
154 /**
155 * Returns the number of bits per element in the key
156 *
157 * @see KeyAnalyzer#bitsPerElement()
158 */
159 final int bitsPerElement() {
160 return keyAnalyzer.bitsPerElement();
161 }
162
163 /**
164 * A utility method to cast keys. It actually doesn't cast anything. It's just fooling the compiler!
165 */
166 @SuppressWarnings("unchecked")
167 final K castKey(final Object key) {
168 return (K) key;
169 }
170
171 /**
172 * A utility method for calling {@link KeyAnalyzer#compare(Object, Object)}
173 */
174 final boolean compareKeys(final K key, final K other) {
175 if (key == null) {
176 return other == null;
177 }
178 if (other == null) {
179 return false;
180 }
181
182 return keyAnalyzer.compare(key, other) == 0;
183 }
184
185 /**
186 * Gets the {@link KeyAnalyzer} that constructed the {@link Trie}.
187 * @return the {@link KeyAnalyzer} used by this {@link Trie}
188 */
189 protected KeyAnalyzer<? super K> getKeyAnalyzer() {
190 return keyAnalyzer;
191 }
192
193 /**
194 * Returns whether or not the given bit on the key is set or false if the key is null.
195 *
196 * @see KeyAnalyzer#isBitSet(Object, int, int)
197 */
198 final boolean isBitSet(final K key, final int bitIndex, final int lengthInBits) {
199 if (key == null) { // root's might be null!
200 return false;
201 }
202 return keyAnalyzer.isBitSet(key, bitIndex, lengthInBits);
203 }
204
205 /**
206 * Returns the length of the given key in bits
207 *
208 * @see KeyAnalyzer#lengthInBits(Object)
209 */
210 final int lengthInBits(final K key) {
211 if (key == null) {
212 return 0;
213 }
214
215 return keyAnalyzer.lengthInBits(key);
216 }
217
218 @Override
219 public String toString() {
220 final StringBuilder buffer = new StringBuilder();
221 buffer.append("Trie[").append(size()).append("]={\n");
222 for (final Map.Entry<K, V> entry : entrySet()) {
223 buffer.append(" ").append(entry).append("\n");
224 }
225 buffer.append("}\n");
226 return buffer.toString();
227 }
228 }