001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.units;
006
007import edu.wpi.first.units.collections.LongToObjectHashMap;
008import java.util.Objects;
009
010/**
011 * A combinatory unit type that is equivalent to the product of two other others.
012 *
013 * @param <A> the type of the first unit in the result
014 * @param <B> the type of the second unit in the result
015 */
016public class Mult<A extends Unit<A>, B extends Unit<B>> extends Unit<Mult<A, B>> {
017  private final A m_unitA;
018  private final B m_unitB;
019
020  @SuppressWarnings("rawtypes")
021  private static final LongToObjectHashMap<Mult> cache = new LongToObjectHashMap<>();
022
023  protected Mult(Class<? extends Mult<A, B>> baseType, A a, B b) {
024    super(
025        baseType,
026        a.toBaseUnits(1) * b.toBaseUnits(1),
027        a.name() + "-" + b.name(),
028        a.symbol() + "*" + b.symbol());
029    m_unitA = a;
030    m_unitB = b;
031  }
032
033  /**
034   * Creates a new Mult unit derived from two arbitrary units multiplied together.
035   *
036   * <pre>
037   *   Mult.combine(Volts, Meters) // Volt-Meters
038   * </pre>
039   *
040   * <p>It's recommended to use the convenience function {@link Unit#mult(Unit)} instead of calling
041   * this factory directly.
042   *
043   * @param <A> the type of the first unit
044   * @param <B> the type of the second unit
045   * @param a the first unit
046   * @param b the second unit
047   * @return the combined unit
048   */
049  @SuppressWarnings({"unchecked", "rawtypes"})
050  public static <A extends Unit<A>, B extends Unit<B>> Mult<A, B> combine(A a, B b) {
051    final long key = ((long) a.hashCode()) << 32L | ((long) b.hashCode()) & 0xFFFFFFFFL;
052    if (cache.containsKey(key)) {
053      return cache.get(key);
054    }
055
056    var mult = new Mult<A, B>((Class) Mult.class, a, b);
057    cache.put(key, mult);
058    return mult;
059  }
060
061  public A unitA() {
062    return m_unitA;
063  }
064
065  public B unitB() {
066    return m_unitB;
067  }
068
069  @Override
070  public String toString() {
071    return "(" + m_unitA.toString() + " * " + m_unitB.toString() + ")";
072  }
073
074  @Override
075  public boolean equals(Object o) {
076    if (this == o) {
077      return true;
078    }
079    if (o == null || getClass() != o.getClass()) {
080      return false;
081    }
082    if (!super.equals(o)) {
083      return false;
084    }
085    Mult<?, ?> mult = (Mult<?, ?>) o;
086    return Objects.equals(m_unitA, mult.m_unitA) && Objects.equals(m_unitB, mult.m_unitB);
087  }
088
089  @Override
090  public int hashCode() {
091    return Objects.hash(super.hashCode(), m_unitA, m_unitB);
092  }
093}