View Javadoc
1   //******************************************************************************
2   //
3   // File:    SharedFloatArray.java
4   // Package: edu.rit.pj.reduction
5   // Unit:    Class edu.rit.pj.reduction.SharedFloatArray
6   //
7   // This Java source file is copyright (C) 2007 by Alan Kaminsky. All rights
8   // reserved. For further information, contact the author, Alan Kaminsky, at
9   // ark@cs.rit.edu.
10  //
11  // This Java source file is part of the Parallel Java Library ("PJ"). PJ is free
12  // software; you can redistribute it and/or modify it under the terms of the GNU
13  // General Public License as published by the Free Software Foundation; either
14  // version 3 of the License, or (at your option) any later version.
15  //
16  // PJ is distributed in the hope that it will be useful, but WITHOUT ANY
17  // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
18  // A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19  //
20  // Linking this library statically or dynamically with other modules is making a
21  // combined work based on this library. Thus, the terms and conditions of the GNU
22  // General Public License cover the whole combination.
23  //
24  // As a special exception, the copyright holders of this library give you
25  // permission to link this library with independent modules to produce an
26  // executable, regardless of the license terms of these independent modules, and
27  // to copy and distribute the resulting executable under terms of your choice,
28  // provided that you also meet, for each linked independent module, the terms
29  // and conditions of the license of that module. An independent module is a module
30  // which is not derived from or based on this library. If you modify this library,
31  // you may extend this exception to your version of the library, but you are not
32  // obligated to do so. If you do not wish to do so, delete this exception
33  // statement from your version.
34  //
35  // A copy of the GNU General Public License is provided in the file gpl.txt. You
36  // may also obtain a copy of the GNU General Public License on the World Wide
37  // Web at http://www.gnu.org/licenses/gpl.html.
38  //
39  //******************************************************************************
40  package edu.rit.pj.reduction;
41  
42  import java.util.concurrent.atomic.AtomicIntegerArray;
43  
44  /**
45   * Class SharedFloatArray provides an array reduction variable with elements of
46   * type <code>float</code>.
47   * <P>
48   * Class SharedFloatArray is multiple thread safe. The methods use lock-free
49   * atomic compare-and-set.
50   * <P>
51   * <I>Note:</I> Class SharedFloatArray is implemented using class
52   * java.util.concurrent.atomic.AtomicIntegerArray. Each float array element is
53   * stored as an <code>int</code> whose bit pattern is the same as the float value.
54   *
55   * @author Alan Kaminsky
56   * @version 24-Aug-2007
57   */
58  public class SharedFloatArray {
59  
60  // Hidden data members.
61      private AtomicIntegerArray myArray;
62  
63  // Exported constructors.
64      /**
65       * Construct a new float array reduction variable with the given length.
66       * Each array element is initially 0.
67       *
68       * @param len Length.
69       * @exception NegativeArraySizeException (unchecked exception) Thrown if
70       * <code>len</code> &lt; 0.
71       */
72      public SharedFloatArray(int len) {
73          myArray = new AtomicIntegerArray(len);
74      }
75  
76      /**
77       * Construct a new float array reduction variable whose elements are copied
78       * from the given array.
79       *
80       * @param array Array to copy.
81       * @exception NullPointerException (unchecked exception) Thrown if
82       * <code>array</code> is null.
83       */
84      public SharedFloatArray(float[] array) {
85          int n = array.length;
86          int[] intarray = new int[n];
87          for (int i = 0; i < n; ++i) {
88              intarray[i] = Float.floatToIntBits(array[i]);
89          }
90          myArray = new AtomicIntegerArray(intarray);
91      }
92  
93  // Exported operations.
94      /**
95       * Returns this array reduction variable's length.
96       *
97       * @return Length.
98       */
99      public int length() {
100         return myArray.length();
101     }
102 
103     /**
104      * Returns this array reduction variable's current value at the given index.
105      *
106      * @param i Index.
107      * @return Current value.
108      */
109     public float get(int i) {
110         return Float.intBitsToFloat(myArray.get(i));
111     }
112 
113     /**
114      * Set this array reduction variable at the given index to the given value.
115      *
116      * @param i Index.
117      * @param value New value.
118      */
119     public void set(int i,
120             float value) {
121         myArray.set(i, Float.floatToIntBits(value));
122     }
123 
124     /**
125      * Set this array reduction variable at the given index to the given value
126      * and return the previous value.
127      *
128      * @param i Index.
129      * @param value New value.
130      * @return Previous value.
131      */
132     public float getAndSet(int i,
133             float value) {
134         return Float.intBitsToFloat(myArray.getAndSet(i, Float.floatToIntBits(value)));
135     }
136 
137     /**
138      * Atomically set this array reduction variable at the given index to the
139      * given updated value if the current value equals the expected value.
140      *
141      * @param i Index.
142      * @param expect Expected value.
143      * @param update Updated value.
144      * @return True if the update happened, false otherwise.
145      */
146     public boolean compareAndSet(int i,
147             float expect,
148             float update) {
149         return myArray.compareAndSet(i, Float.floatToIntBits(expect), Float.floatToIntBits(update));
150     }
151 
152     /**
153      * Atomically set this array reduction variable at the given index to the
154      * given updated value if the current value equals the expected value. May
155      * fail spuriously.
156      *
157      * @param i Index.
158      * @param expect Expected value.
159      * @param update Updated value.
160      * @return True if the update happened, false otherwise.
161      */
162     @SuppressWarnings("deprecation")
163     public boolean weakCompareAndSet(int i,
164             float expect,
165             float update) {
166         return myArray.weakCompareAndSet(i, Float.floatToIntBits(expect), Float.floatToIntBits(update));
167     }
168 
169     /**
170      * Add one to this array reduction variable at the given index and return
171      * the previous value.
172      *
173      * @param i Index.
174      * @return Previous value.
175      */
176     public float getAndIncrement(int i) {
177         for (;;) {
178             int oldvalueInt = myArray.get(i);
179             float oldvalue = Float.intBitsToFloat(oldvalueInt);
180             float newvalue = oldvalue + 1.0f;
181             int newvalueInt = Float.floatToIntBits(newvalue);
182             if (myArray.compareAndSet(i, oldvalueInt, newvalueInt)) {
183                 return oldvalue;
184             }
185         }
186     }
187 
188     /**
189      * Subtract one from this array reduction variable at the given index and
190      * return the previous value.
191      *
192      * @param i Index.
193      * @return Previous value.
194      */
195     public float getAndDecrement(int i) {
196         for (;;) {
197             int oldvalueInt = myArray.get(i);
198             float oldvalue = Float.intBitsToFloat(oldvalueInt);
199             float newvalue = oldvalue - 1.0f;
200             int newvalueInt = Float.floatToIntBits(newvalue);
201             if (myArray.compareAndSet(i, oldvalueInt, newvalueInt)) {
202                 return oldvalue;
203             }
204         }
205     }
206 
207     /**
208      * Add the given value to this array reduction variable at the given index
209      * and return the previous value.
210      *
211      * @param i Index.
212      * @param value Value to add.
213      * @return Previous value.
214      */
215     public float getAndAdd(int i,
216             float value) {
217         for (;;) {
218             int oldvalueInt = myArray.get(i);
219             float oldvalue = Float.intBitsToFloat(oldvalueInt);
220             float newvalue = oldvalue + value;
221             int newvalueInt = Float.floatToIntBits(newvalue);
222             if (myArray.compareAndSet(i, oldvalueInt, newvalueInt)) {
223                 return oldvalue;
224             }
225         }
226     }
227 
228     /**
229      * Add one to this array reduction variable at the given index and return
230      * the new value.
231      *
232      * @param i Index.
233      * @return New value.
234      */
235     public float incrementAndGet(int i) {
236         for (;;) {
237             int oldvalueInt = myArray.get(i);
238             float oldvalue = Float.intBitsToFloat(oldvalueInt);
239             float newvalue = oldvalue + 1.0f;
240             int newvalueInt = Float.floatToIntBits(newvalue);
241             if (myArray.compareAndSet(i, oldvalueInt, newvalueInt)) {
242                 return newvalue;
243             }
244         }
245     }
246 
247     /**
248      * Subtract one from this array reduction variable at the given index and
249      * return the new value.
250      *
251      * @param i Index.
252      * @return New value.
253      */
254     public float decrementAndGet(int i) {
255         for (;;) {
256             int oldvalueInt = myArray.get(i);
257             float oldvalue = Float.intBitsToFloat(oldvalueInt);
258             float newvalue = oldvalue - 1.0f;
259             int newvalueInt = Float.floatToIntBits(newvalue);
260             if (myArray.compareAndSet(i, oldvalueInt, newvalueInt)) {
261                 return newvalue;
262             }
263         }
264     }
265 
266     /**
267      * Add the given value to this array reduction variable at the given index
268      * and return the new value.
269      *
270      * @param i Index.
271      * @param value Value to add.
272      * @return New value.
273      */
274     public float addAndGet(int i,
275             float value) {
276         for (;;) {
277             int oldvalueInt = myArray.get(i);
278             float oldvalue = Float.intBitsToFloat(oldvalueInt);
279             float newvalue = oldvalue + value;
280             int newvalueInt = Float.floatToIntBits(newvalue);
281             if (myArray.compareAndSet(i, oldvalueInt, newvalueInt)) {
282                 return newvalue;
283             }
284         }
285     }
286 
287     /**
288      * Combine this array reduction variable at the given index with the given
289      * value using the given operation. (This array <code>[i]</code>) is set to
290      * (this array <code>[i]</code>) <I>op</I> (<code>value</code>), then (this array
291      * <code>[i]</code>) is returned.
292      *
293      * @param i Index.
294      * @param value Value.
295      * @param op Binary operation.
296      * @return (This array <code>[i]</code>) <I>op</I> (<code>value</code>).
297      */
298     public float reduce(int i,
299             float value,
300             FloatOp op) {
301         for (;;) {
302             int oldvalueInt = myArray.get(i);
303             float oldvalue = Float.intBitsToFloat(oldvalueInt);
304             float newvalue = op.op(oldvalue, value);
305             int newvalueInt = Float.floatToIntBits(newvalue);
306             if (myArray.compareAndSet(i, oldvalueInt, newvalueInt)) {
307                 return newvalue;
308             }
309         }
310     }
311 
312     /**
313      * Combine this array reduction variable with the given array using the
314      * given operation. For each index <code>i</code> from 0 to this array's
315      * length-1, (this array <code>[i]</code>) is set to (this array <code>[i]</code>)
316      * <I>op</I> (<code>src[i]</code>).
317      * <P>
318      * The <code>reduce()</code> method is multiple thread safe <I>on a per-element
319      * basis.</I> Each individual array element is updated atomically, but the
320      * array as a whole is not updated atomically.
321      *
322      * @param src Source array.
323      * @param op Binary operation.
324      * @exception NullPointerException (unchecked exception) Thrown if
325      * <code>src</code> is null. Thrown if
326      * <code>op</code> is null.
327      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
328      * array index would be out of bounds.
329      */
330     public void reduce(float[] src,
331             FloatOp op) {
332         reduce(0, src, 0, myArray.length(), op);
333     }
334 
335     /**
336      * Combine a portion of this array reduction variable with a portion of the
337      * given array using the given operation. For each index <code>i</code> from 0
338      * to <code>len</code>-1, (this array <code>[dstoff+i]</code>) is set to (this array
339      * <code>[dstoff+i]</code>) <I>op</I> (<code>src[srcoff+i]</code>).
340      * <P>
341      * The <code>reduce()</code> method is multiple thread safe <I>on a per-element
342      * basis.</I> Each individual array element is updated atomically, but the
343      * array as a whole is not updated atomically.
344      *
345      * @param dstoff Index of first element to update in this array.
346      * @param src Source array.
347      * @param srcoff Index of first element to update from in the source array.
348      * @param len Number of array elements to update.
349      * @param op Binary operation.
350      * @exception NullPointerException (unchecked exception) Thrown if
351      * <code>src</code> is null. Thrown if
352      * <code>op</code> is null.
353      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if
354      * <code>len</code> &lt; 0. Thrown if any array index would be out of bounds.
355      */
356     public void reduce(int dstoff,
357             float[] src,
358             int srcoff,
359             int len,
360             FloatOp op) {
361         if (len < 0
362                 || dstoff < 0 || dstoff + len > myArray.length()
363                 || srcoff < 0 || srcoff + len > src.length) {
364             throw new IndexOutOfBoundsException();
365         }
366         while (len > 0) {
367             updateLoop:
368             for (;;) {
369                 int oldvalueInt = myArray.get(dstoff);
370                 float oldvalue = Float.intBitsToFloat(oldvalueInt);
371                 float newvalue = op.op(oldvalue, src[srcoff]);
372                 int newvalueInt = Float.floatToIntBits(newvalue);
373                 if (myArray.compareAndSet(dstoff, oldvalueInt, newvalueInt)) {
374                     break updateLoop;
375                 }
376             }
377             ++dstoff;
378             ++srcoff;
379             --len;
380         }
381     }
382 
383     /**
384      * Returns a string version of this array reduction variable.
385      *
386      * @return String version.
387      */
388     public String toString() {
389         StringBuilder b = new StringBuilder();
390         b.append('[');
391         int n = myArray.length();
392         for (int i = 0; i < n; ++i) {
393             if (i > 0) {
394                 b.append(", ");
395             }
396             b.append(get(i));
397         }
398         b.append(']');
399         return b.toString();
400     }
401 
402 }