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    
014    package com.google.common.util.concurrent;
015    
016    import static java.lang.Double.doubleToRawLongBits;
017    import static java.lang.Double.longBitsToDouble;
018    
019    import com.google.common.annotations.Beta;
020    
021    import java.util.concurrent.atomic.AtomicLongArray;
022    
023    /**
024     * A {@code double} array in which elements may be updated atomically.
025     * See the {@link java.util.concurrent.atomic} package specification
026     * for description of the properties of atomic variables.
027     *
028     * <p><a name="bitEquals">This class compares primitive {@code double}
029     * values in methods such as {@link #compareAndSet} by comparing their
030     * bitwise representation using {@link Double#doubleToRawLongBits},
031     * which differs from both the primitive double {@code ==} operator
032     * and from {@link Double#equals}, as if implemented by:
033     *  <pre> {@code
034     * static boolean bitEquals(double x, double y) {
035     *   long xBits = Double.doubleToRawLongBits(x);
036     *   long yBits = Double.doubleToRawLongBits(y);
037     *   return xBits == yBits;
038     * }}</pre>
039     *
040     * @author Doug Lea
041     * @author Martin Buchholz
042     * @since 11.0
043     */
044    @Beta
045    public class AtomicDoubleArray implements java.io.Serializable {
046      private static final long serialVersionUID = 0L;
047    
048      // Making this non-final is the lesser evil according to Effective
049      // Java 2nd Edition Item 76: Write readObject methods defensively.
050      private transient AtomicLongArray longs;
051    
052      /**
053       * Creates a new {@code AtomicDoubleArray} of the given length,
054       * with all elements initially zero.
055       *
056       * @param length the length of the array
057       */
058      public AtomicDoubleArray(int length) {
059        this.longs = new AtomicLongArray(length);
060      }
061    
062      /**
063       * Creates a new {@code AtomicDoubleArray} with the same length
064       * as, and all elements copied from, the given array.
065       *
066       * @param array the array to copy elements from
067       * @throws NullPointerException if array is null
068       */
069      public AtomicDoubleArray(double[] array) {
070        final int len = array.length;
071        long[] longArray = new long[len];
072        for (int i = 0; i < len; i++) {
073          longArray[i] = doubleToRawLongBits(array[i]);
074        }
075        this.longs = new AtomicLongArray(longArray);
076      }
077    
078      /**
079       * Returns the length of the array.
080       *
081       * @return the length of the array
082       */
083      public final int length() {
084        return longs.length();
085      }
086    
087      /**
088       * Gets the current value at position {@code i}.
089       *
090       * @param i the index
091       * @return the current value
092       */
093      public final double get(int i) {
094        return longBitsToDouble(longs.get(i));
095      }
096    
097      /**
098       * Sets the element at position {@code i} to the given value.
099       *
100       * @param i the index
101       * @param newValue the new value
102       */
103      public final void set(int i, double newValue) {
104        long next = doubleToRawLongBits(newValue);
105        longs.set(i, next);
106      }
107    
108      /**
109       * Eventually 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 lazySet(int i, double newValue) {
115        set(i, newValue);
116        // TODO(user): replace with code below when jdk5 support is dropped.
117        // long next = doubleToRawLongBits(newValue);
118        // longs.lazySet(i, next);
119      }
120    
121      /**
122       * Atomically sets the element at position {@code i} to the given value
123       * and returns the old value.
124       *
125       * @param i the index
126       * @param newValue the new value
127       * @return the previous value
128       */
129      public final double getAndSet(int i, double newValue) {
130        long next = doubleToRawLongBits(newValue);
131        return longBitsToDouble(longs.getAndSet(i, next));
132      }
133    
134      /**
135       * Atomically sets the element at position {@code i} to the given
136       * updated value
137       * if the current value is <a href="#bitEquals">bitwise equal</a>
138       * to the expected value.
139       *
140       * @param i the index
141       * @param expect the expected value
142       * @param update the new value
143       * @return true if successful. False return indicates that
144       * the actual value was not equal to the expected value.
145       */
146      public final boolean compareAndSet(int i, double expect, double update) {
147        return longs.compareAndSet(i,
148                                   doubleToRawLongBits(expect),
149                                   doubleToRawLongBits(update));
150      }
151    
152      /**
153       * Atomically sets the element at position {@code i} to the given
154       * updated value
155       * if the current value is <a href="#bitEquals">bitwise equal</a>
156       * to the expected value.
157       *
158       * <p>May <a
159       * href="http://download.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html#Spurious">
160       * fail spuriously</a>
161       * and does not provide ordering guarantees, so is only rarely an
162       * appropriate alternative to {@code compareAndSet}.
163       *
164       * @param i the index
165       * @param expect the expected value
166       * @param update the new value
167       * @return true if successful
168       */
169      public final boolean weakCompareAndSet(int i, double expect, double update) {
170        return longs.weakCompareAndSet(i,
171                                       doubleToRawLongBits(expect),
172                                       doubleToRawLongBits(update));
173      }
174    
175      /**
176       * Atomically adds the given value to the element at index {@code i}.
177       *
178       * @param i the index
179       * @param delta the value to add
180       * @return the previous value
181       */
182      public final double getAndAdd(int i, double delta) {
183        while (true) {
184          long current = longs.get(i);
185          double currentVal = longBitsToDouble(current);
186          double nextVal = currentVal + delta;
187          long next = doubleToRawLongBits(nextVal);
188          if (longs.compareAndSet(i, current, next)) {
189            return currentVal;
190          }
191        }
192      }
193    
194      /**
195       * Atomically adds the given value to the element at index {@code i}.
196       *
197       * @param i the index
198       * @param delta the value to add
199       * @return the updated value
200       */
201      public double addAndGet(int i, double delta) {
202        while (true) {
203          long current = longs.get(i);
204          double currentVal = longBitsToDouble(current);
205          double nextVal = currentVal + delta;
206          long next = doubleToRawLongBits(nextVal);
207          if (longs.compareAndSet(i, current, next)) {
208            return nextVal;
209          }
210        }
211      }
212    
213      /**
214       * Returns the String representation of the current values of array.
215       * @return the String representation of the current values of array
216       */
217      public String toString() {
218        int iMax = length() - 1;
219        if (iMax == -1) {
220          return "[]";
221        }
222    
223        // Double.toString(Math.PI).length() == 17
224        StringBuilder b = new StringBuilder((17 + 2) * (iMax + 1));
225        b.append('[');
226        for (int i = 0;; i++) {
227          b.append(longBitsToDouble(longs.get(i)));
228          if (i == iMax) {
229            return b.append(']').toString();
230          }
231          b.append(',').append(' ');
232        }
233      }
234    
235      /**
236       * Saves the state to a stream (that is, serializes it).
237       *
238       * @serialData The length of the array is emitted (int), followed by all
239       *             of its elements (each a {@code double}) in the proper order.
240       */
241      private void writeObject(java.io.ObjectOutputStream s)
242          throws java.io.IOException {
243        s.defaultWriteObject();
244    
245        // Write out array length
246        int length = length();
247        s.writeInt(length);
248    
249        // Write out all elements in the proper order.
250        for (int i = 0; i < length; i++) {
251          s.writeDouble(get(i));
252        }
253      }
254    
255      /**
256       * Reconstitutes the instance from a stream (that is, deserializes it).
257       */
258      private void readObject(java.io.ObjectInputStream s)
259          throws java.io.IOException, ClassNotFoundException {
260        s.defaultReadObject();
261    
262        // Read in array length and allocate array
263        int length = s.readInt();
264        this.longs = new AtomicLongArray(length);
265    
266        // Read in all elements in the proper order.
267        for (int i = 0; i < length; i++) {
268          set(i, s.readDouble());
269        }
270      }
271    }