1 //******************************************************************************
2 //
3 // File: SharedByteArray.java
4 // Package: edu.rit.pj.reduction
5 // Unit: Class edu.rit.pj.reduction.SharedByteArray
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 SharedByteArray provides an array reduction variable with elements of
46 * type <code>byte</code>.
47 * <P>
48 * Class SharedByteArray is multiple thread safe. The methods use lock-free
49 * atomic compare-and-set.
50 * <P>
51 * <I>Note:</I> Class SharedByteArray is implemented using class
52 * java.util.concurrent.atomic.AtomicIntegerArray. Each byte array element is
53 * stored as an <code>int</code> whose values are restricted to the range of type
54 * <code>byte</code>.
55 *
56 * @author Alan Kaminsky
57 * @version 24-Aug-2007
58 */
59 public class SharedByteArray {
60
61 // Hidden data members.
62 private AtomicIntegerArray myArray;
63
64 // Exported constructors.
65 /**
66 * Construct a new byte array reduction variable with the given length. Each
67 * array element is initially 0.
68 *
69 * @param len Length.
70 * @exception NegativeArraySizeException (unchecked exception) Thrown if
71 * <code>len</code> < 0.
72 */
73 public SharedByteArray(int len) {
74 myArray = new AtomicIntegerArray(len);
75 }
76
77 /**
78 * Construct a new byte array reduction variable whose elements are copied
79 * from the given array.
80 *
81 * @param array Array to copy.
82 * @exception NullPointerException (unchecked exception) Thrown if
83 * <code>array</code> is null.
84 */
85 public SharedByteArray(byte[] array) {
86 int n = array.length;
87 int[] intarray = new int[n];
88 for (int i = 0; i < n; ++i) {
89 intarray[i] = array[i];
90 }
91 myArray = new AtomicIntegerArray(intarray);
92 }
93
94 // Exported operations.
95 /**
96 * Returns this array reduction variable's length.
97 *
98 * @return Length.
99 */
100 public int length() {
101 return myArray.length();
102 }
103
104 /**
105 * Returns this array reduction variable's current value at the given index.
106 *
107 * @param i Index.
108 * @return Current value.
109 */
110 public byte get(int i) {
111 return (byte) myArray.get(i);
112 }
113
114 /**
115 * Set this array reduction variable at the given index to the given value.
116 *
117 * @param i Index.
118 * @param value New value.
119 */
120 public void set(int i,
121 byte value) {
122 myArray.set(i, value);
123 }
124
125 /**
126 * Set this array reduction variable at the given index to the given value
127 * and return the previous value.
128 *
129 * @param i Index.
130 * @param value New value.
131 * @return Previous value.
132 */
133 public byte getAndSet(int i,
134 byte value) {
135 return (byte) myArray.getAndSet(i, value);
136 }
137
138 /**
139 * Atomically set this array reduction variable at the given index to the
140 * given updated value if the current value equals the expected value.
141 *
142 * @param i Index.
143 * @param expect Expected value.
144 * @param update Updated value.
145 * @return True if the update happened, false otherwise.
146 */
147 public boolean compareAndSet(int i,
148 byte expect,
149 byte update) {
150 return myArray.compareAndSet(i, expect, update);
151 }
152
153 /**
154 * Atomically set this array reduction variable at the given index to the
155 * given updated value if the current value equals the expected value. May
156 * fail spuriously.
157 *
158 * @param i Index.
159 * @param expect Expected value.
160 * @param update Updated value.
161 * @return True if the update happened, false otherwise.
162 */
163 @SuppressWarnings("deprecation")
164 public boolean weakCompareAndSet(int i,
165 byte expect,
166 byte update) {
167 return myArray.weakCompareAndSet(i, expect, update);
168 }
169
170 /**
171 * Add one to this array reduction variable at the given index and return
172 * the previous value.
173 *
174 * @param i Index.
175 * @return Previous value.
176 */
177 public byte getAndIncrement(int i) {
178 for (;;) {
179 byte oldvalue = (byte) myArray.get(i);
180 byte newvalue = (byte) (oldvalue + 1);
181 if (myArray.compareAndSet(i, oldvalue, newvalue)) {
182 return oldvalue;
183 }
184 }
185 }
186
187 /**
188 * Subtract one from this array reduction variable at the given index and
189 * return the previous value.
190 *
191 * @param i Index.
192 * @return Previous value.
193 */
194 public byte getAndDecrement(int i) {
195 for (;;) {
196 byte oldvalue = (byte) myArray.get(i);
197 byte newvalue = (byte) (oldvalue - 1);
198 if (myArray.compareAndSet(i, oldvalue, newvalue)) {
199 return oldvalue;
200 }
201 }
202 }
203
204 /**
205 * Add the given value to this array reduction variable at the given index
206 * and return the previous value.
207 *
208 * @param i Index.
209 * @param value Value to add.
210 * @return Previous value.
211 */
212 public byte getAndAdd(int i,
213 byte value) {
214 for (;;) {
215 byte oldvalue = (byte) myArray.get(i);
216 byte newvalue = (byte) (oldvalue + value);
217 if (myArray.compareAndSet(i, oldvalue, newvalue)) {
218 return oldvalue;
219 }
220 }
221 }
222
223 /**
224 * Add one to this array reduction variable at the given index and return
225 * the new value.
226 *
227 * @param i Index.
228 * @return New value.
229 */
230 public byte incrementAndGet(int i) {
231 for (;;) {
232 byte oldvalue = (byte) myArray.get(i);
233 byte newvalue = (byte) (oldvalue + 1);
234 if (myArray.compareAndSet(i, oldvalue, newvalue)) {
235 return newvalue;
236 }
237 }
238 }
239
240 /**
241 * Subtract one from this array reduction variable at the given index and
242 * return the new value.
243 *
244 * @param i Index.
245 * @return New value.
246 */
247 public byte decrementAndGet(int i) {
248 for (;;) {
249 byte oldvalue = (byte) myArray.get(i);
250 byte newvalue = (byte) (oldvalue - 1);
251 if (myArray.compareAndSet(i, oldvalue, newvalue)) {
252 return newvalue;
253 }
254 }
255 }
256
257 /**
258 * Add the given value to this array reduction variable at the given index
259 * and return the new value.
260 *
261 * @param i Index.
262 * @param value Value to add.
263 * @return New value.
264 */
265 public byte addAndGet(int i,
266 byte value) {
267 for (;;) {
268 byte oldvalue = (byte) myArray.get(i);
269 byte newvalue = (byte) (oldvalue + value);
270 if (myArray.compareAndSet(i, oldvalue, newvalue)) {
271 return newvalue;
272 }
273 }
274 }
275
276 /**
277 * Combine this array reduction variable at the given index with the given
278 * value using the given operation. (This array <code>[i]</code>) is set to
279 * (this array <code>[i]</code>) <I>op</I> (<code>value</code>), then (this array
280 * <code>[i]</code>) is returned.
281 *
282 * @param i Index.
283 * @param value Value.
284 * @param op Binary operation.
285 * @return (This array <code>[i]</code>) <I>op</I> (<code>value</code>).
286 */
287 public byte reduce(int i,
288 byte value,
289 ByteOp op) {
290 for (;;) {
291 byte oldvalue = (byte) myArray.get(i);
292 byte newvalue = op.op(oldvalue, value);
293 if (myArray.compareAndSet(i, oldvalue, newvalue)) {
294 return newvalue;
295 }
296 }
297 }
298
299 /**
300 * Combine this array reduction variable with the given array using the
301 * given operation. For each index <code>i</code> from 0 to this array's
302 * length-1, (this array <code>[i]</code>) is set to (this array <code>[i]</code>)
303 * <I>op</I> (<code>src[i]</code>).
304 * <P>
305 * The <code>reduce()</code> method is multiple thread safe <I>on a per-element
306 * basis.</I> Each individual array element is updated atomically, but the
307 * array as a whole is not updated atomically.
308 *
309 * @param src Source array.
310 * @param op Binary operation.
311 * @exception NullPointerException (unchecked exception) Thrown if
312 * <code>src</code> is null. Thrown if
313 * <code>op</code> is null.
314 * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
315 * array index would be out of bounds.
316 */
317 public void reduce(byte[] src,
318 ByteOp op) {
319 reduce(0, src, 0, myArray.length(), op);
320 }
321
322 /**
323 * Combine a portion of this array reduction variable with a portion of the
324 * given array using the given operation. For each index <code>i</code> from 0
325 * to <code>len</code>-1, (this array <code>[dstoff+i]</code>) is set to (this array
326 * <code>[dstoff+i]</code>) <I>op</I> (<code>src[srcoff+i]</code>).
327 * <P>
328 * The <code>reduce()</code> method is multiple thread safe <I>on a per-element
329 * basis.</I> Each individual array element is updated atomically, but the
330 * array as a whole is not updated atomically.
331 *
332 * @param dstoff Index of first element to update in this array.
333 * @param src Source array.
334 * @param srcoff Index of first element to update from in the source array.
335 * @param len Number of array elements to update.
336 * @param op Binary operation.
337 * @exception NullPointerException (unchecked exception) Thrown if
338 * <code>src</code> is null. Thrown if
339 * <code>op</code> is null.
340 * @exception IndexOutOfBoundsException (unchecked exception) Thrown if
341 * <code>len</code> < 0. Thrown if any array index would be out of bounds.
342 */
343 public void reduce(int dstoff,
344 byte[] src,
345 int srcoff,
346 int len,
347 ByteOp op) {
348 if (len < 0
349 || dstoff < 0 || dstoff + len > myArray.length()
350 || srcoff < 0 || srcoff + len > src.length) {
351 throw new IndexOutOfBoundsException();
352 }
353 while (len > 0) {
354 updateLoop:
355 for (;;) {
356 byte oldvalue = (byte) myArray.get(dstoff);
357 byte newvalue = op.op(oldvalue, src[srcoff]);
358 if (myArray.compareAndSet(dstoff, oldvalue, newvalue)) {
359 break updateLoop;
360 }
361 }
362 ++dstoff;
363 ++srcoff;
364 --len;
365 }
366 }
367
368 /**
369 * Returns a string version of this array reduction variable.
370 *
371 * @return String version.
372 */
373 public String toString() {
374 return myArray.toString();
375 }
376
377 }