001/*
002 * Written by Doug Lea with assistance from members of JCP JSR-166
003 * Expert Group and released to the public domain, as explained at
004 * http://creativecommons.org/publicdomain/zero/1.0/
005 */
006
007/*
008 * Source:
009 * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/extra/AtomicDoubleArray.java?revision=1.5
010 * (Modified to adapt to guava coding conventions and
011 * to use AtomicLongArray instead of sun.misc.Unsafe)
012 */
013
014package com.google.common.util.concurrent;
015
016import static com.google.common.base.Preconditions.checkNotNull;
017import static java.lang.Double.doubleToRawLongBits;
018import static java.lang.Double.longBitsToDouble;
019
020import com.google.common.annotations.GwtIncompatible;
021import com.google.common.annotations.J2ktIncompatible;
022import com.google.common.primitives.ImmutableLongArray;
023import com.google.errorprone.annotations.CanIgnoreReturnValue;
024import java.io.IOException;
025import java.io.ObjectInputStream;
026import java.io.ObjectOutputStream;
027import java.io.Serializable;
028import java.util.concurrent.atomic.AtomicLongArray;
029import java.util.function.DoubleBinaryOperator;
030import java.util.function.DoubleUnaryOperator;
031
032/**
033 * A {@code double} array in which elements may be updated atomically. See the {@link
034 * java.util.concurrent.atomic} package specification for description of the properties of atomic
035 * variables.
036 *
037 * <p><a id="bitEquals"></a>This class compares primitive {@code double} values in methods such as
038 * {@link #compareAndSet} by comparing their bitwise representation using {@link
039 * Double#doubleToRawLongBits}, which differs from both the primitive double {@code ==} operator and
040 * from {@link Double#equals}, as if implemented by:
041 *
042 * {@snippet :
043 * static boolean bitEquals(double x, double y) {
044 *   long xBits = Double.doubleToRawLongBits(x);
045 *   long yBits = Double.doubleToRawLongBits(y);
046 *   return xBits == yBits;
047 * }
048 * }
049 *
050 * @author Doug Lea
051 * @author Martin Buchholz
052 * @since 11.0
053 */
054@GwtIncompatible
055@J2ktIncompatible
056public class AtomicDoubleArray implements Serializable {
057  private static final long serialVersionUID = 0L;
058
059  // Making this non-final is the lesser evil according to Effective
060  // Java 2nd Edition Item 76: Write readObject methods defensively.
061  private transient AtomicLongArray longs;
062
063  /**
064   * Creates a new {@code AtomicDoubleArray} of the given length, with all elements initially zero.
065   *
066   * @param length the length of the array
067   */
068  public AtomicDoubleArray(int length) {
069    this.longs = new AtomicLongArray(length);
070  }
071
072  /**
073   * Creates a new {@code AtomicDoubleArray} with the same length as, and all elements copied from,
074   * the given array.
075   *
076   * @param array the array to copy elements from
077   * @throws NullPointerException if array is null
078   */
079  public AtomicDoubleArray(double[] array) {
080    int len = array.length;
081    long[] longArray = new long[len];
082    for (int i = 0; i < len; i++) {
083      longArray[i] = doubleToRawLongBits(array[i]);
084    }
085    this.longs = new AtomicLongArray(longArray);
086  }
087
088  /**
089   * Returns the length of the array.
090   *
091   * @return the length of the array
092   */
093  public final int length() {
094    return longs.length();
095  }
096
097  /**
098   * Returns the current value of the element at index {@code i}, with memory effects as specified
099   * by {@link java.lang.invoke.VarHandle#getVolatile VarHandle.getVolatile}.
100   *
101   * @param i the index
102   * @return the current value
103   */
104  public final double get(int i) {
105    return longBitsToDouble(longs.get(i));
106  }
107
108  /**
109   * Sets the element at index {@code i} to {@code newValue}, with memory effects as specified by
110   * {@link java.lang.invoke.VarHandle#setVolatile VarHandle.setVolatile}.
111   *
112   * @param i the index
113   * @param newValue the new value
114   */
115  public final void set(int i, double newValue) {
116    long next = doubleToRawLongBits(newValue);
117    longs.set(i, next);
118  }
119
120  /**
121   * Sets the element at index {@code i} to {@code newValue}, with memory effects as specified by
122   * {@link java.lang.invoke.VarHandle#setRelease VarHandle.setRelease}.
123   *
124   * @param i the index
125   * @param newValue the new value
126   */
127  public final void lazySet(int i, double newValue) {
128    long next = doubleToRawLongBits(newValue);
129    longs.lazySet(i, next);
130  }
131
132  /**
133   * Atomically sets the element at position {@code i} to the given value and returns the old value.
134   *
135   * @param i the index
136   * @param newValue the new value
137   * @return the previous value
138   */
139  public final double getAndSet(int i, double newValue) {
140    long next = doubleToRawLongBits(newValue);
141    return longBitsToDouble(longs.getAndSet(i, next));
142  }
143
144  /**
145   * Atomically sets the element at position {@code i} to the given updated value if the current
146   * value is <a href="#bitEquals">bitwise equal</a> to the expected value.
147   *
148   * @param i the index
149   * @param expect the expected value
150   * @param update the new value
151   * @return true if successful. False return indicates that the actual value was not equal to the
152   *     expected value.
153   */
154  public final boolean compareAndSet(int i, double expect, double update) {
155    return longs.compareAndSet(i, doubleToRawLongBits(expect), doubleToRawLongBits(update));
156  }
157
158  /**
159   * Atomically sets the element at position {@code i} to the given updated value if the current
160   * value is <a href="#bitEquals">bitwise equal</a> to the expected value.
161   *
162   * <p>May <a
163   * href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html#Spurious">
164   * fail spuriously</a> and does not provide ordering guarantees, so is only rarely an appropriate
165   * alternative to {@code compareAndSet}.
166   *
167   * @param i the index
168   * @param expect the expected value
169   * @param update the new value
170   * @return true if successful
171   */
172  public final boolean weakCompareAndSet(int i, double expect, double update) {
173    return longs.weakCompareAndSet(i, doubleToRawLongBits(expect), doubleToRawLongBits(update));
174  }
175
176  /**
177   * Atomically adds the given value to the element at index {@code i}.
178   *
179   * @param i the index
180   * @param delta the value to add
181   * @return the previous value
182   */
183  @CanIgnoreReturnValue
184  public final double getAndAdd(int i, double delta) {
185    return getAndAccumulate(i, delta, Double::sum);
186  }
187
188  /**
189   * Atomically adds the given value to the element at index {@code i}.
190   *
191   * @param i the index
192   * @param delta the value to add
193   * @return the updated value
194   */
195  @CanIgnoreReturnValue
196  public double addAndGet(int i, double delta) {
197    return accumulateAndGet(i, delta, Double::sum);
198  }
199
200  /**
201   * Atomically updates the element at index {@code i} with the results of applying the given
202   * function to the current and given values.
203   *
204   * @param i the index to update
205   * @param x the update value
206   * @param accumulatorFunction the accumulator function
207   * @return the previous value
208   * @since 31.1
209   */
210  @CanIgnoreReturnValue
211  public final double getAndAccumulate(int i, double x, DoubleBinaryOperator accumulatorFunction) {
212    checkNotNull(accumulatorFunction);
213    return getAndUpdate(i, oldValue -> accumulatorFunction.applyAsDouble(oldValue, x));
214  }
215
216  /**
217   * Atomically updates the element at index {@code i} with the results of applying the given
218   * function to the current and given values.
219   *
220   * @param i the index to update
221   * @param x the update value
222   * @param accumulatorFunction the accumulator function
223   * @return the updated value
224   * @since 31.1
225   */
226  @CanIgnoreReturnValue
227  public final double accumulateAndGet(int i, double x, DoubleBinaryOperator accumulatorFunction) {
228    checkNotNull(accumulatorFunction);
229    return updateAndGet(i, oldValue -> accumulatorFunction.applyAsDouble(oldValue, x));
230  }
231
232  /**
233   * Atomically updates the element at index {@code i} with the results of applying the given
234   * function to the current value.
235   *
236   * @param i the index to update
237   * @param updaterFunction the update function
238   * @return the previous value
239   * @since 31.1
240   */
241  @CanIgnoreReturnValue
242  public final double getAndUpdate(int i, DoubleUnaryOperator updaterFunction) {
243    while (true) {
244      long current = longs.get(i);
245      double currentVal = longBitsToDouble(current);
246      double nextVal = updaterFunction.applyAsDouble(currentVal);
247      long next = doubleToRawLongBits(nextVal);
248      if (longs.compareAndSet(i, current, next)) {
249        return currentVal;
250      }
251    }
252  }
253
254  /**
255   * Atomically updates the element at index {@code i} with the results of applying the given
256   * function to the current value.
257   *
258   * @param i the index to update
259   * @param updaterFunction the update function
260   * @return the updated value
261   * @since 31.1
262   */
263  @CanIgnoreReturnValue
264  public final double updateAndGet(int i, DoubleUnaryOperator updaterFunction) {
265    while (true) {
266      long current = longs.get(i);
267      double currentVal = longBitsToDouble(current);
268      double nextVal = updaterFunction.applyAsDouble(currentVal);
269      long next = doubleToRawLongBits(nextVal);
270      if (longs.compareAndSet(i, current, next)) {
271        return nextVal;
272      }
273    }
274  }
275
276  /**
277   * Returns the String representation of the current values of array.
278   *
279   * @return the String representation of the current values of array
280   */
281  @Override
282  public String toString() {
283    int iMax = length() - 1;
284    if (iMax == -1) {
285      return "[]";
286    }
287
288    // Double.toString(Math.PI).length() == 17
289    StringBuilder b = new StringBuilder((17 + 2) * (iMax + 1));
290    b.append('[');
291    for (int i = 0; ; i++) {
292      b.append(longBitsToDouble(longs.get(i)));
293      if (i == iMax) {
294        return b.append(']').toString();
295      }
296      b.append(',').append(' ');
297    }
298  }
299
300  /**
301   * Saves the state to a stream (that is, serializes it).
302   *
303   * @serialData The length of the array is emitted (int), followed by all of its elements (each a
304   *     {@code double}) in the proper order.
305   */
306  private void writeObject(ObjectOutputStream s) throws IOException {
307    s.defaultWriteObject();
308
309    // Write out array length
310    int length = length();
311    s.writeInt(length);
312
313    // Write out all elements in the proper order.
314    for (int i = 0; i < length; i++) {
315      s.writeDouble(get(i));
316    }
317  }
318
319  /** Reconstitutes the instance from a stream (that is, deserializes it). */
320  private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
321    s.defaultReadObject();
322
323    int length = s.readInt();
324    ImmutableLongArray.Builder builder = ImmutableLongArray.builder();
325    for (int i = 0; i < length; i++) {
326      builder.add(doubleToRawLongBits(s.readDouble()));
327    }
328    this.longs = new AtomicLongArray(builder.build().toArray());
329  }
330}