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 java.util.Objects; 008 009/** 010 * A specialization of {@link Measure} that allows for mutability. This is intended to be used for 011 * memory use reasons (such as on the memory-restricted roboRIO 1 or 2 or SBC coprocessors) and 012 * should NOT be exposed in the public API for a class that uses it. 013 * 014 * <p>The advantage of using this class is to reuse one instance of a measurement object, as opposed 015 * to instantiating a new immutable instance every time an operation is performed. This will reduce 016 * memory pressure, but comes at the cost of increased code complexity and sensitivity to race 017 * conditions if misused. 018 * 019 * <p>Any unsafe methods are prefixed with {@code mut_*}, such as {@link #mut_plus(Measure)} or 020 * {@link #mut_replace(Measure)}. These methods will change the internal state of the measurement 021 * object, and as such can be dangerous to use. They are primarily intended for use to track 022 * internal state of things like sensors 023 * 024 * @param <U> the type of the unit of measure 025 */ 026public final class MutableMeasure<U extends Unit<U>> implements Measure<U> { 027 private double m_magnitude; 028 private double m_baseUnitMagnitude; 029 private U m_unit; 030 031 private MutableMeasure(double initialMagnitude, double baseUnitMagnitude, U unit) { 032 m_magnitude = initialMagnitude; 033 m_baseUnitMagnitude = baseUnitMagnitude; 034 m_unit = unit; 035 } 036 037 /** 038 * Creates a new mutable measure that is a copy of the given one. 039 * 040 * @param <U> the type of the units of measure 041 * @param measure the measure to create a mutable copy of 042 * @return a new mutable measure with an initial state equal to the given measure 043 */ 044 public static <U extends Unit<U>> MutableMeasure<U> mutable(Measure<U> measure) { 045 return new MutableMeasure<>(measure.magnitude(), measure.baseUnitMagnitude(), measure.unit()); 046 } 047 048 /** 049 * Creates a new mutable measure with a magnitude of 0 in the given unit. 050 * 051 * @param <U> the type of the units of measure 052 * @param unit the unit of measure 053 * @return a new mutable measure 054 */ 055 public static <U extends Unit<U>> MutableMeasure<U> zero(U unit) { 056 return mutable(unit.zero()); 057 } 058 059 /** 060 * Creates a new mutable measure in the given unit with a magnitude equal to the given one in base 061 * units. 062 * 063 * @param <U> the type of the units of measure 064 * @param baseUnitMagnitude the magnitude of the measure, in terms of the base unit of measure 065 * @param unit the unit of measure 066 * @return a new mutable measure 067 */ 068 public static <U extends Unit<U>> MutableMeasure<U> ofBaseUnits( 069 double baseUnitMagnitude, U unit) { 070 return new MutableMeasure<>(unit.fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, unit); 071 } 072 073 /** 074 * Creates a new mutable measure in the given unit with a magnitude in terms of that unit. 075 * 076 * @param <U> the type of the units of measure 077 * @param relativeMagnitude the magnitude of the measure 078 * @param unit the unit of measure 079 * @return a new mutable measure 080 */ 081 public static <U extends Unit<U>> MutableMeasure<U> ofRelativeUnits( 082 double relativeMagnitude, U unit) { 083 return new MutableMeasure<>(relativeMagnitude, unit.toBaseUnits(relativeMagnitude), unit); 084 } 085 086 @Override 087 public double magnitude() { 088 return m_magnitude; 089 } 090 091 @Override 092 public double baseUnitMagnitude() { 093 return m_baseUnitMagnitude; 094 } 095 096 @Override 097 public U unit() { 098 return m_unit; 099 } 100 101 // UNSAFE 102 103 /** 104 * Sets the new magnitude of the measurement. The magnitude must be in terms of the {@link 105 * #unit()}. 106 * 107 * @param magnitude the new magnitude of the measurement 108 */ 109 public void mut_setMagnitude(double magnitude) { 110 m_magnitude = magnitude; 111 m_baseUnitMagnitude = m_unit.toBaseUnits(magnitude); 112 } 113 114 /** 115 * Sets the new magnitude of the measurement. The magnitude must be in terms of the base unit of 116 * the current unit. 117 * 118 * @param baseUnitMagnitude the new magnitude of the measurement 119 */ 120 public void mut_setBaseUnitMagnitude(double baseUnitMagnitude) { 121 m_baseUnitMagnitude = baseUnitMagnitude; 122 m_magnitude = m_unit.fromBaseUnits(baseUnitMagnitude); 123 } 124 125 /** 126 * Overwrites the state of this measure and replaces it with values from the given one. 127 * 128 * @param other the other measure to copy values from 129 * @return this measure 130 */ 131 public MutableMeasure<U> mut_replace(Measure<U> other) { 132 m_magnitude = other.magnitude(); 133 m_baseUnitMagnitude = other.baseUnitMagnitude(); 134 m_unit = other.unit(); 135 return this; 136 } 137 138 /** 139 * Overwrites the state of this measure with new values. 140 * 141 * @param magnitude the new magnitude in terms of the new unit 142 * @param unit the new unit 143 * @return this measure 144 */ 145 public MutableMeasure<U> mut_replace(double magnitude, U unit) { 146 this.m_magnitude = magnitude; 147 this.m_baseUnitMagnitude = unit.toBaseUnits(magnitude); 148 this.m_unit = unit; 149 return this; 150 } 151 152 /** 153 * Increments the current magnitude of the measure by the given value. The value must be in terms 154 * of the current {@link #unit() unit}. 155 * 156 * @param raw the raw value to accumulate by 157 * @return the measure 158 */ 159 public MutableMeasure<U> mut_acc(double raw) { 160 this.m_magnitude += raw; 161 this.m_baseUnitMagnitude += m_unit.toBaseUnits(raw); 162 return this; 163 } 164 165 /** 166 * Increments the current magnitude of the measure by the amount of the given measure. 167 * 168 * @param other the measure whose value should be added to this one 169 * @return the measure 170 */ 171 public MutableMeasure<U> mut_acc(Measure<U> other) { 172 m_baseUnitMagnitude += other.baseUnitMagnitude(); 173 174 // can't naively use m_magnitude += other.in(m_unit) because the units may not 175 // be scalar multiples (eg adding 0C to 100K should result in 373.15K, not 100K) 176 m_magnitude = m_unit.fromBaseUnits(m_baseUnitMagnitude); 177 return this; 178 } 179 180 // Math 181 182 /** 183 * Adds another measurement to this one. This will mutate the object instead of generating a new 184 * measurement object. 185 * 186 * @param other the measurement to add 187 * @return this measure 188 */ 189 public MutableMeasure<U> mut_plus(Measure<U> other) { 190 return mut_plus(other.magnitude(), other.unit()); 191 } 192 193 /** 194 * Adds another measurement to this one. This will mutate the object instead of generating a new 195 * measurement object. This is a denormalized version of {@link #mut_plus(Measure)} to avoid 196 * having to wrap raw numbers in a {@code Measure} object and pay for an object allocation. 197 * 198 * @param magnitude the magnitude of the other measurement. 199 * @param unit the unit of the other measurement 200 * @return this measure 201 */ 202 public MutableMeasure<U> mut_plus(double magnitude, U unit) { 203 mut_setBaseUnitMagnitude(m_baseUnitMagnitude + unit.toBaseUnits(magnitude)); 204 return this; 205 } 206 207 /** 208 * Subtracts another measurement to this one. This will mutate the object instead of generating a 209 * new measurement object. 210 * 211 * @param other the measurement to add 212 * @return this measure 213 */ 214 public MutableMeasure<U> mut_minus(Measure<U> other) { 215 return mut_minus(other.magnitude(), other.unit()); 216 } 217 218 /** 219 * Subtracts another measurement to this one. This will mutate the object instead of generating a 220 * new measurement object. This is a denormalized version of {@link #mut_minus(Measure)} to avoid 221 * having to wrap raw numbers in a {@code Measure} object and pay for an object allocation. 222 * 223 * @param magnitude the magnitude of the other measurement. 224 * @param unit the unit of the other measurement 225 * @return this measure 226 */ 227 public MutableMeasure<U> mut_minus(double magnitude, U unit) { 228 return mut_plus(-magnitude, unit); 229 } 230 231 /** 232 * Multiplies this measurement by some constant value. This will mutate the object instead of 233 * generating a new measurement object. 234 * 235 * @param multiplier the multiplier to scale the measurement by 236 * @return this measure 237 */ 238 public MutableMeasure<U> mut_times(double multiplier) { 239 mut_setBaseUnitMagnitude(m_baseUnitMagnitude * multiplier); 240 return this; 241 } 242 243 /** 244 * Multiplies this measurement by some constant value. This will mutate the object instead of 245 * generating a new measurement object. 246 * 247 * @param multiplier the multiplier to scale the measurement by 248 * @return this measure 249 */ 250 public MutableMeasure<U> mut_times(Measure<? extends Dimensionless> multiplier) { 251 return mut_times(multiplier.baseUnitMagnitude()); 252 } 253 254 /** 255 * Divides this measurement by some constant value. This will mutate the object instead of 256 * generating a new measurement object. 257 * 258 * @param divisor the divisor to scale the measurement by 259 * @return this measure 260 */ 261 public MutableMeasure<U> mut_divide(double divisor) { 262 mut_setBaseUnitMagnitude(m_baseUnitMagnitude / divisor); 263 return this; 264 } 265 266 /** 267 * Divides this measurement by some constant value. This will mutate the object instead of 268 * generating a new measurement object. 269 * 270 * @param divisor the divisor to scale the measurement by 271 * @return this measure 272 */ 273 public MutableMeasure<U> mut_divide(Measure<? extends Dimensionless> divisor) { 274 return mut_divide(divisor.baseUnitMagnitude()); 275 } 276 277 @Override 278 public Measure<U> copy() { 279 return new ImmutableMeasure<>(m_magnitude, m_baseUnitMagnitude, m_unit); 280 } 281 282 @Override 283 public String toString() { 284 return toShortString(); 285 } 286 287 @Override 288 public boolean equals(Object o) { 289 if (this == o) { 290 return true; 291 } 292 if (!(o instanceof Measure)) { 293 return false; 294 } 295 Measure<?> that = (Measure<?>) o; 296 return Objects.equals(m_unit, that.unit()) && this.isEquivalent(that); 297 } 298 299 @Override 300 public int hashCode() { 301 return Objects.hash(m_magnitude, m_unit); 302 } 303}