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 a the first unit of the product 030 * @param b the second unit of the product 031 */ 032 protected Mult(A a, B b) { 033 super( 034 a.isBaseUnit() && b.isBaseUnit() ? null : combine(a.getBaseUnit(), b.getBaseUnit()), 035 a.toBaseUnits(1) * b.toBaseUnits(1), 036 a.name() + "-" + b.name(), 037 a.symbol() + "*" + b.symbol()); 038 m_unitA = a; 039 m_unitB = b; 040 } 041 042 Mult( 043 Mult<A, B> baseUnit, 044 UnaryFunction toBaseConverter, 045 UnaryFunction fromBaseConverter, 046 String name, 047 String symbol) { 048 super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol); 049 m_unitA = baseUnit.unitA(); 050 m_unitB = baseUnit.unitB(); 051 } 052 053 /** 054 * Creates a new Mult unit derived from two arbitrary units multiplied together. 055 * 056 * <pre> 057 * Mult.combine(Volts, Meters) // Volt-Meters 058 * </pre> 059 * 060 * <p>It's recommended to use the convenience function {@link Unit#mult(Unit)} instead of calling 061 * this factory directly. 062 * 063 * @param <A> the type of the first unit 064 * @param <B> the type of the second unit 065 * @param a the first unit 066 * @param b the second unit 067 * @return the combined unit 068 */ 069 @SuppressWarnings({"unchecked", "rawtypes"}) 070 public static <A extends Unit<A>, B extends Unit<B>> Mult<A, B> combine(A a, B b) { 071 final long key = ((long) a.hashCode()) << 32L | (((long) b.hashCode()) & 0xFFFFFFFFL); 072 if (cache.containsKey(key)) { 073 return cache.get(key); 074 } 075 076 var mult = new Mult<A, B>(a, b); 077 cache.put(key, mult); 078 return mult; 079 } 080 081 /** 082 * Gets the first unit of the product. 083 * 084 * @return the first unit 085 */ 086 public A unitA() { 087 return m_unitA; 088 } 089 090 /** 091 * Gets the second unit of the product. 092 * 093 * @return the second unit 094 */ 095 public B unitB() { 096 return m_unitB; 097 } 098 099 @Override 100 public String toString() { 101 return "(" + m_unitA.toString() + " * " + m_unitB.toString() + ")"; 102 } 103 104 @Override 105 public boolean equals(Object o) { 106 if (this == o) { 107 return true; 108 } 109 if (o == null || getClass() != o.getClass()) { 110 return false; 111 } 112 if (!super.equals(o)) { 113 return false; 114 } 115 Mult<?, ?> mult = (Mult<?, ?>) o; 116 return Objects.equals(m_unitA, mult.m_unitA) && Objects.equals(m_unitB, mult.m_unitB); 117 } 118 119 @Override 120 public int hashCode() { 121 return Objects.hash(super.hashCode(), m_unitA, m_unitB); 122 } 123}