001/*
002 * Copyright (c) 2015-2020, Oracle and/or its affiliates. All rights reserved.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.tribuo.util.infotheory.impl;
018
019import com.oracle.labs.mlrg.olcut.util.Pair;
020
021import java.util.ArrayList;
022
023/**
024 * A pair of things with a cached hashcode.
025 * <p>
026 * The cache is calculated on construction, and the objects inside the pair are thus expected to be immutable.
027 * If they aren't then the behaviour is undefined (and you shouldn't use this class).
028 * @param <T1> The type of the first object.
029 * @param <T2> The type of the second object.
030 */
031public class CachedPair<T1, T2> extends Pair<T1,T2> {
032    private static final long serialVersionUID = 1L;
033
034    private final int cachedHash;
035
036    /**
037     * Constructs a CachedPair.
038     * @param a The first element.
039     * @param b The second element.
040     */
041    public CachedPair(T1 a, T2 b) {
042        super(a,b);
043        this.cachedHash = super.hashCode();
044    }
045
046    /**
047     * Takes two arrays and zips them together into an array of CachedPairs.
048     * @param <T1> The type contained in the first array.
049     * @param <T2> The type contained in the second array.
050     * @param first An array of values.
051     * @param second Another array of values.
052     * @return The zipped array.
053     */
054    public static <T1,T2> ArrayList<CachedPair<T1,T2>> zipArraysCached(ArrayList<T1> first, ArrayList<T2> second) {
055        if (first.size() == second.size()) {
056            ArrayList<CachedPair<T1,T2>> output = new ArrayList<>(first.size());
057
058            for (int i = 0; i < first.size(); i++) {
059                CachedPair<T1,T2> pair = new CachedPair<>(first.get(i),second.get(i));
060                output.add(i, pair);
061            }
062
063            return output;
064        } else {
065            throw new IllegalArgumentException("Zipping requires arrays of the same length. first.size() = " + first.size() + ", second.size() = " + second.size());
066        }
067    }
068
069    /**
070     * Overridden hashcode.
071     * Uses the cached value calculated on construction.
072     * @return A 32-bit integer.
073     */
074    @Override
075    public int hashCode() {
076        return cachedHash;
077    }
078
079    @Override
080    public boolean equals(Object o) {
081        if (this == o) return true;
082        if (o == null || getClass() != o.getClass()) return false;
083        if (!super.equals(o)) return false;
084        CachedPair<?, ?> that = (CachedPair<?, ?>) o;
085        return cachedHash == that.cachedHash;
086    }
087}