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