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 *      https://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.Comparator;
021
022import org.apache.commons.collections4.Trie;
023
024/**
025 * Defines the interface to analyze {@link Trie Trie} keys on a bit level.
026 * {@link KeyAnalyzer}'s methods return the length of the key in bits, whether or not a bit is set,
027 * and bits per element in the key.
028 * <p>
029 * Additionally, a method determines if a key is a prefix of another
030 * key and returns the bit index where one key is different from another
031 * key (if the key and found key are equal than the return value is
032 * {@link #EQUAL_BIT_KEY}).
033 * </p>
034 *
035 * @param <K> The type of objects that may be compared by this analyzer
036 * @since 4.0
037 */
038public abstract class KeyAnalyzer<K> implements Comparator<K>, Serializable {
039
040    /** Serialization version */
041    private static final long serialVersionUID = -20497563720380683L;
042
043    /**
044     * Returned by {@link #bitIndex(Object, int, int, Object, int, int)}
045     * if key's bits are all 0.
046     */
047    public static final int NULL_BIT_KEY = -1;
048
049    /**
050     * Returned by {@link #bitIndex(Object, int, int, Object, int, int)} if key and found key are equal.
051     * This is a very specific case and shouldn't happen on a regular basis.
052     */
053    public static final int EQUAL_BIT_KEY = -2;
054
055    /**
056     * Used to test a {@code bitIndex} in {@link #isOutOfBoundsIndex(int)}.
057     */
058    public static final int OUT_OF_BOUNDS_BIT_KEY = -3;
059
060    /**
061     * Returns true if bitIndex is a {@link KeyAnalyzer#EQUAL_BIT_KEY}.
062     */
063    static boolean isEqualBitKey(final int bitIndex) {
064        return bitIndex == EQUAL_BIT_KEY;
065    }
066
067    /**
068     * Returns true if bitIndex is a {@link KeyAnalyzer#NULL_BIT_KEY}.
069     */
070    static boolean isNullBitKey(final int bitIndex) {
071        return bitIndex == NULL_BIT_KEY;
072    }
073
074    /**
075     * Returns true if bitIndex is a {@link KeyAnalyzer#OUT_OF_BOUNDS_BIT_KEY}.
076     */
077    static boolean isOutOfBoundsIndex(final int bitIndex) {
078        return bitIndex == OUT_OF_BOUNDS_BIT_KEY;
079    }
080
081    /**
082     * Returns true if the given bitIndex is valid.
083     * Indices are considered valid if they're between 0 and {@link Integer#MAX_VALUE}
084     */
085    static boolean isValidBitIndex(final int bitIndex) {
086        return bitIndex >= 0;
087    }
088
089    /**
090     * Constructs a new instance.
091     */
092    public KeyAnalyzer() {
093        // empty
094    }
095
096    /**
097     * Returns the n-th different bit between key and other. This starts the comparison in
098     * key at 'offsetInBits' and goes for 'lengthInBits' bits, and compares to the other key starting
099     * at 'otherOffsetInBits' and going for 'otherLengthInBits' bits.
100     *
101     * @param key  The key to use
102     * @param offsetInBits  The bit offset in the key
103     * @param lengthInBits  The maximum key length in bits to use
104     * @param other  The other key to use
105     * @param otherOffsetInBits  The bit offset in the other key
106     * @param otherLengthInBits  The maximum key length in bits for the other key
107     * @return The bit index where the key and other first differ
108     */
109    public abstract int bitIndex(K key, int offsetInBits, int lengthInBits,
110                                 K other, int otherOffsetInBits, int otherLengthInBits);
111
112    /**
113     * Returns the number of bits per element in the key.
114     * This is only useful for variable-length keys, such as Strings.
115     *
116     * @return The number of bits per element
117     */
118    public abstract int bitsPerElement();
119
120    @Override
121    @SuppressWarnings("unchecked")
122    public int compare(final K o1, final K o2) {
123        if (o1 == null) {
124            return o2 == null ? 0 : -1;
125        }
126        if (o2 == null) {
127            return 1;
128        }
129
130        return ((Comparable<K>) o1).compareTo(o2);
131    }
132
133    /**
134     * Returns whether or not a bit is set.
135     *
136     * @param key  The key to check, may not be null
137     * @param bitIndex  The bit index to check
138     * @param lengthInBits  The maximum key length in bits to check
139     * @return {@code true} if the bit is set in the given key and
140     *   {@code bitIndex} &lt; {@code lengthInBits}, {@code false} otherwise.
141     */
142    public abstract boolean isBitSet(K key, int bitIndex, int lengthInBits);
143
144    /**
145     * Determines whether or not the given prefix (from offset to length) is a prefix of the given key.
146     *
147     * @param prefix  The prefix to check
148     * @param offsetInBits  The bit offset in the key
149     * @param lengthInBits  The maximum key length in bits to use
150     * @param key  The key to check
151     * @return {@code true} if this is a valid prefix for the given key
152     */
153    public abstract boolean isPrefix(K prefix, int offsetInBits, int lengthInBits, K key);
154
155    /**
156     * Returns the length of the Key in bits.
157     *
158     * @param key  The key
159     * @return The bit length of the key
160     */
161    public abstract int lengthInBits(K key);
162
163}