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}