001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.collections4.trie; 018 019import java.io.Serializable; 020import java.util.AbstractMap; 021import java.util.Map; 022import java.util.Map.Entry; 023 024import org.apache.commons.collections4.Trie; 025 026/** 027 * This class provides some basic {@link Trie} functionality and 028 * utility methods for actual bitwise {@link Trie} implementations. 029 * 030 * @since 4.0 031 * @version $Id: AbstractBitwiseTrie.html 972421 2015-11-14 20:00:04Z tn $ 032 */ 033public abstract class AbstractBitwiseTrie<K, V> extends AbstractMap<K, V> 034 implements Trie<K, V>, Serializable { 035 036 private static final long serialVersionUID = 5826987063535505652L; 037 038 /** 039 * The {@link KeyAnalyzer} that's being used to build the PATRICIA {@link Trie}. 040 */ 041 private final KeyAnalyzer<? super K> keyAnalyzer; 042 043 /** 044 * Constructs a new {@link Trie} using the given {@link KeyAnalyzer}. 045 * 046 * @param keyAnalyzer the {@link KeyAnalyzer} to use 047 */ 048 protected AbstractBitwiseTrie(final KeyAnalyzer<? super K> keyAnalyzer) { 049 if (keyAnalyzer == null) { 050 throw new NullPointerException("keyAnalyzer"); 051 } 052 053 this.keyAnalyzer = keyAnalyzer; 054 } 055 056 /** 057 * Returns the {@link KeyAnalyzer} that constructed the {@link Trie}. 058 * @return the {@link KeyAnalyzer} used by this {@link Trie} 059 */ 060 protected KeyAnalyzer<? super K> getKeyAnalyzer() { 061 return keyAnalyzer; 062 } 063 064 @Override 065 public String toString() { 066 final StringBuilder buffer = new StringBuilder(); 067 buffer.append("Trie[").append(size()).append("]={\n"); 068 for (final Map.Entry<K, V> entry : entrySet()) { 069 buffer.append(" ").append(entry).append("\n"); 070 } 071 buffer.append("}\n"); 072 return buffer.toString(); 073 } 074 075 /** 076 * A utility method to cast keys. It actually doesn't cast anything. It's just fooling the compiler! 077 */ 078 @SuppressWarnings("unchecked") 079 final K castKey(final Object key) { 080 return (K) key; 081 } 082 083 /** 084 * Returns the length of the given key in bits 085 * 086 * @see KeyAnalyzer#lengthInBits(Object) 087 */ 088 final int lengthInBits(final K key) { 089 if (key == null) { 090 return 0; 091 } 092 093 return keyAnalyzer.lengthInBits(key); 094 } 095 096 /** 097 * Returns the number of bits per element in the key 098 * 099 * @see KeyAnalyzer#bitsPerElement() 100 */ 101 final int bitsPerElement() { 102 return keyAnalyzer.bitsPerElement(); 103 } 104 105 /** 106 * Returns whether or not the given bit on the key is set or false if the key is null. 107 * 108 * @see KeyAnalyzer#isBitSet(Object, int, int) 109 */ 110 final boolean isBitSet(final K key, final int bitIndex, final int lengthInBits) { 111 if (key == null) { // root's might be null! 112 return false; 113 } 114 return keyAnalyzer.isBitSet(key, bitIndex, lengthInBits); 115 } 116 117 /** 118 * Utility method for calling {@link KeyAnalyzer#bitIndex(Object, int, int, Object, int, int)}. 119 */ 120 final int bitIndex(final K key, final K foundKey) { 121 return keyAnalyzer.bitIndex(key, 0, lengthInBits(key), foundKey, 0, lengthInBits(foundKey)); 122 } 123 124 /** 125 * An utility method for calling {@link KeyAnalyzer#compare(Object, Object)} 126 */ 127 final boolean compareKeys(final K key, final K other) { 128 if (key == null) { 129 return other == null; 130 } else if (other == null) { 131 return false; 132 } 133 134 return keyAnalyzer.compare(key, other) == 0; 135 } 136 137 /** 138 * Returns true if both values are either null or equal. 139 */ 140 static boolean compare(final Object a, final Object b) { 141 return a == null ? b == null : a.equals(b); 142 } 143 144 /** 145 * A basic implementation of {@link Entry}. 146 */ 147 abstract static class BasicEntry<K, V> implements Map.Entry<K, V>, Serializable { 148 149 private static final long serialVersionUID = -944364551314110330L; 150 151 protected K key; 152 153 protected V value; 154 155 public BasicEntry(final K key) { 156 this.key = key; 157 } 158 159 public BasicEntry(final K key, final V value) { 160 this.key = key; 161 this.value = value; 162 } 163 164 /** 165 * Replaces the current key and value with the provided key & value. 166 */ 167 public V setKeyValue(final K key, final V value) { 168 this.key = key; 169 return setValue(value); 170 } 171 172 public K getKey() { 173 return key; 174 } 175 176 public V getValue() { 177 return value; 178 } 179 180 public V setValue(final V value) { 181 final V previous = this.value; 182 this.value = value; 183 return previous; 184 } 185 186 @Override 187 public int hashCode() { 188 return (getKey() == null ? 0 : getKey().hashCode()) ^ 189 (getValue() == null ? 0 : getValue().hashCode()); 190 } 191 192 @Override 193 public boolean equals(final Object o) { 194 if (o == this) { 195 return true; 196 } else if (!(o instanceof Map.Entry)) { 197 return false; 198 } 199 200 final Map.Entry<?, ?> other = (Map.Entry<?, ?>)o; 201 if (compare(key, other.getKey()) 202 && compare(value, other.getValue())) { 203 return true; 204 } 205 return false; 206 } 207 208 @Override 209 public String toString() { 210 return key + "=" + value; 211 } 212 } 213}