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> < 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> < 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 }