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. Note that 012 * algebraic reduction is not possible in Java's generic type system, so {@code Mult<A, B>} is not 013 * type-compatible with {@code Mult<B, A>}! 014 * 015 * @param <A> the type of the first unit in the result 016 * @param <B> the type of the second unit in the result 017 */ 018public class Mult<A extends Unit<A>, B extends Unit<B>> extends Unit<Mult<A, B>> { 019 private final A m_unitA; 020 private final B m_unitB; 021 022 @SuppressWarnings("rawtypes") 023 private static final LongToObjectHashMap<Mult> cache = new LongToObjectHashMap<>(); 024 025 /** 026 * Creates a new product unit. Consider using {@link #combine} instead of manually calling this 027 * constructor. 028 * 029 * @param baseType the base type representing the unit product 030 * @param a the first unit of the product 031 * @param b the second unit of the product 032 */ 033 protected Mult(Class<? extends Mult<A, B>> baseType, A a, B b) { 034 super( 035 baseType, 036 a.toBaseUnits(1) * b.toBaseUnits(1), 037 a.name() + "-" + b.name(), 038 a.symbol() + "*" + b.symbol()); 039 m_unitA = a; 040 m_unitB = b; 041 } 042 043 /** 044 * Creates a new Mult unit derived from two arbitrary units multiplied together. 045 * 046 * <pre> 047 * Mult.combine(Volts, Meters) // Volt-Meters 048 * </pre> 049 * 050 * <p>It's recommended to use the convenience function {@link Unit#mult(Unit)} instead of calling 051 * this factory directly. 052 * 053 * @param <A> the type of the first unit 054 * @param <B> the type of the second unit 055 * @param a the first unit 056 * @param b the second unit 057 * @return the combined unit 058 */ 059 @SuppressWarnings({"unchecked", "rawtypes"}) 060 public static <A extends Unit<A>, B extends Unit<B>> Mult<A, B> combine(A a, B b) { 061 final long key = ((long) a.hashCode()) << 32L | (((long) b.hashCode()) & 0xFFFFFFFFL); 062 if (cache.containsKey(key)) { 063 return cache.get(key); 064 } 065 066 var mult = new Mult<A, B>((Class) Mult.class, a, b); 067 cache.put(key, mult); 068 return mult; 069 } 070 071 /** 072 * Gets the first unit of the product. 073 * 074 * @return the first unit 075 */ 076 public A unitA() { 077 return m_unitA; 078 } 079 080 /** 081 * Gets the second unit of the product. 082 * 083 * @return the second unit 084 */ 085 public B unitB() { 086 return m_unitB; 087 } 088 089 @Override 090 public String toString() { 091 return "(" + m_unitA.toString() + " * " + m_unitB.toString() + ")"; 092 } 093 094 @Override 095 public boolean equals(Object o) { 096 if (this == o) { 097 return true; 098 } 099 if (o == null || getClass() != o.getClass()) { 100 return false; 101 } 102 if (!super.equals(o)) { 103 return false; 104 } 105 Mult<?, ?> mult = (Mult<?, ?>) o; 106 return Objects.equals(m_unitA, mult.m_unitA) && Objects.equals(m_unitB, mult.m_unitB); 107 } 108 109 @Override 110 public int hashCode() { 111 return Objects.hash(super.hashCode(), m_unitA, m_unitB); 112 } 113}