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 * <pre>{@code
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 * }</pre>
049 *
050 * @author Doug Lea
051 * @author Martin Buchholz
052 * @since 11.0
053 */
054@GwtIncompatible
055@J2ktIncompatible
056@ElementTypesAreNonnullByDefault
057public class AtomicDoubleArray implements Serializable {
058  private static final long serialVersionUID = 0L;
059
060  // Making this non-final is the lesser evil according to Effective
061  // Java 2nd Edition Item 76: Write readObject methods defensively.
062  private transient AtomicLongArray longs;
063
064  /**
065   * Creates a new {@code AtomicDoubleArray} of the given length, with all elements initially zero.
066   *
067   * @param length the length of the array
068   */
069  public AtomicDoubleArray(int length) {
070    this.longs = new AtomicLongArray(length);
071  }
072
073  /**
074   * Creates a new {@code AtomicDoubleArray} with the same length as, and all elements copied from,
075   * the given array.
076   *
077   * @param array the array to copy elements from
078   * @throws NullPointerException if array is null
079   */
080  public AtomicDoubleArray(double[] array) {
081    int len = array.length;
082    long[] longArray = new long[len];
083    for (int i = 0; i < len; i++) {
084      longArray[i] = doubleToRawLongBits(array[i]);
085    }
086    this.longs = new AtomicLongArray(longArray);
087  }
088
089  /**
090   * Returns the length of the array.
091   *
092   * @return the length of the array
093   */
094  public final int length() {
095    return longs.length();
096  }
097
098  /**
099   * Gets the current value at position {@code i}.
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   * Atomically sets the element at position {@code i} to the given value.
110   *
111   * @param i the index
112   * @param newValue the new value
113   */
114  public final void set(int i, double newValue) {
115    long next = doubleToRawLongBits(newValue);
116    longs.set(i, next);
117  }
118
119  /**
120   * Eventually sets the element at position {@code i} to the given value.
121   *
122   * @param i the index
123   * @param newValue the new value
124   */
125  public final void lazySet(int i, double newValue) {
126    long next = doubleToRawLongBits(newValue);
127    longs.lazySet(i, next);
128  }
129
130  /**
131   * Atomically sets the element at position {@code i} to the given value and returns the old value.
132   *
133   * @param i the index
134   * @param newValue the new value
135   * @return the previous value
136   */
137  public final double getAndSet(int i, double newValue) {
138    long next = doubleToRawLongBits(newValue);
139    return longBitsToDouble(longs.getAndSet(i, next));
140  }
141
142  /**
143   * Atomically sets the element at position {@code i} to the given updated value if the current
144   * value is <a href="#bitEquals">bitwise equal</a> to the expected value.
145   *
146   * @param i the index
147   * @param expect the expected value
148   * @param update the new value
149   * @return true if successful. False return indicates that the actual value was not equal to the
150   *     expected value.
151   */
152  public final boolean compareAndSet(int i, double expect, double update) {
153    return longs.compareAndSet(i, doubleToRawLongBits(expect), doubleToRawLongBits(update));
154  }
155
156  /**
157   * Atomically sets the element at position {@code i} to the given updated value if the current
158   * value is <a href="#bitEquals">bitwise equal</a> to the expected value.
159   *
160   * <p>May <a
161   * href="http://download.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html#Spurious">
162   * fail spuriously</a> and does not provide ordering guarantees, so is only rarely an appropriate
163   * alternative to {@code compareAndSet}.
164   *
165   * @param i the index
166   * @param expect the expected value
167   * @param update the new value
168   * @return true if successful
169   */
170  public final boolean weakCompareAndSet(int i, double expect, double update) {
171    return longs.weakCompareAndSet(i, doubleToRawLongBits(expect), doubleToRawLongBits(update));
172  }
173
174  /**
175   * Atomically adds the given value to the element at index {@code i}.
176   *
177   * @param i the index
178   * @param delta the value to add
179   * @return the previous value
180   */
181  @CanIgnoreReturnValue
182  public final double getAndAdd(int i, double delta) {
183    return getAndAccumulate(i, delta, Double::sum);
184  }
185
186  /**
187   * Atomically adds the given value to the element at index {@code i}.
188   *
189   * @param i the index
190   * @param delta the value to add
191   * @return the updated value
192   */
193  @CanIgnoreReturnValue
194  public double addAndGet(int i, double delta) {
195    return accumulateAndGet(i, delta, Double::sum);
196  }
197
198  /**
199   * Atomically updates the element at index {@code i} with the results of applying the given
200   * function to the current and given values.
201   *
202   * @param i the index to update
203   * @param x the update value
204   * @param accumulatorFunction the accumulator function
205   * @return the previous value
206   * @since 31.1
207   */
208  @CanIgnoreReturnValue
209  public final double getAndAccumulate(int i, double x, DoubleBinaryOperator accumulatorFunction) {
210    checkNotNull(accumulatorFunction);
211    return getAndUpdate(i, oldValue -> accumulatorFunction.applyAsDouble(oldValue, x));
212  }
213
214  /**
215   * Atomically updates the element at index {@code i} with the results of applying the given
216   * function to the current and given values.
217   *
218   * @param i the index to update
219   * @param x the update value
220   * @param accumulatorFunction the accumulator function
221   * @return the updated value
222   * @since 31.1
223   */
224  @CanIgnoreReturnValue
225  public final double accumulateAndGet(int i, double x, DoubleBinaryOperator accumulatorFunction) {
226    checkNotNull(accumulatorFunction);
227    return updateAndGet(i, oldValue -> accumulatorFunction.applyAsDouble(oldValue, x));
228  }
229
230  /**
231   * Atomically updates the element at index {@code i} with the results of applying the given
232   * function to the current value.
233   *
234   * @param i the index to update
235   * @param updaterFunction the update function
236   * @return the previous value
237   * @since 31.1
238   */
239  @CanIgnoreReturnValue
240  public final double getAndUpdate(int i, DoubleUnaryOperator updaterFunction) {
241    while (true) {
242      long current = longs.get(i);
243      double currentVal = longBitsToDouble(current);
244      double nextVal = updaterFunction.applyAsDouble(currentVal);
245      long next = doubleToRawLongBits(nextVal);
246      if (longs.compareAndSet(i, current, next)) {
247        return currentVal;
248      }
249    }
250  }
251
252  /**
253   * Atomically updates the element at index {@code i} with the results of applying the given
254   * function to the current value.
255   *
256   * @param i the index to update
257   * @param updaterFunction the update function
258   * @return the updated value
259   * @since 31.1
260   */
261  @CanIgnoreReturnValue
262  public final double updateAndGet(int i, DoubleUnaryOperator updaterFunction) {
263    while (true) {
264      long current = longs.get(i);
265      double currentVal = longBitsToDouble(current);
266      double nextVal = updaterFunction.applyAsDouble(currentVal);
267      long next = doubleToRawLongBits(nextVal);
268      if (longs.compareAndSet(i, current, next)) {
269        return nextVal;
270      }
271    }
272  }
273
274  /**
275   * Returns the String representation of the current values of array.
276   *
277   * @return the String representation of the current values of array
278   */
279  @Override
280  public String toString() {
281    int iMax = length() - 1;
282    if (iMax == -1) {
283      return "[]";
284    }
285
286    // Double.toString(Math.PI).length() == 17
287    StringBuilder b = new StringBuilder((17 + 2) * (iMax + 1));
288    b.append('[');
289    for (int i = 0; ; i++) {
290      b.append(longBitsToDouble(longs.get(i)));
291      if (i == iMax) {
292        return b.append(']').toString();
293      }
294      b.append(',').append(' ');
295    }
296  }
297
298  /**
299   * Saves the state to a stream (that is, serializes it).
300   *
301   * @serialData The length of the array is emitted (int), followed by all of its elements (each a
302   *     {@code double}) in the proper order.
303   */
304  private void writeObject(ObjectOutputStream s) throws IOException {
305    s.defaultWriteObject();
306
307    // Write out array length
308    int length = length();
309    s.writeInt(length);
310
311    // Write out all elements in the proper order.
312    for (int i = 0; i < length; i++) {
313      s.writeDouble(get(i));
314    }
315  }
316
317  /** Reconstitutes the instance from a stream (that is, deserializes it). */
318  private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
319    s.defaultReadObject();
320
321    int length = s.readInt();
322    ImmutableLongArray.Builder builder = ImmutableLongArray.builder();
323    for (int i = 0; i < length; i++) {
324      builder.add(doubleToRawLongBits(s.readDouble()));
325    }
326    this.longs = new AtomicLongArray(builder.build().toArray());
327  }
328}