1 //****************************************************************************** 2 // 3 // File: SharedCharacterArray.java 4 // Package: edu.rit.pj.reduction 5 // Unit: Class edu.rit.pj.reduction.SharedCharacterArray 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 SharedCharacterArray provides an array reduction variable with elements 46 * of type <code>char</code>. 47 * <P> 48 * Class SharedCharacterArray is multiple thread safe. The methods use lock-free 49 * atomic compare-and-set. 50 * <P> 51 * <I>Note:</I> Class SharedCharacterArray is implemented using class 52 * java.util.concurrent.atomic.AtomicIntegerArray. Each character array element 53 * is stored as an <code>int</code> whose values are restricted to the range of type 54 * <code>char</code>. 55 * 56 * @author Alan Kaminsky 57 * @version 24-Aug-2007 58 */ 59 public class SharedCharacterArray { 60 61 // Hidden data members. 62 private AtomicIntegerArray myArray; 63 64 // Exported constructors. 65 /** 66 * Construct a new character array reduction variable with the given length. 67 * Each 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 SharedCharacterArray(int len) { 74 myArray = new AtomicIntegerArray(len); 75 } 76 77 /** 78 * Construct a new character array reduction variable whose elements are 79 * copied 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 SharedCharacterArray(char[] 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 char get(int i) { 111 return (char) 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 char 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 char getAndSet(int i, 134 char value) { 135 return (char) 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 char expect, 149 char 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 char expect, 166 char 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 char getAndIncrement(int i) { 178 for (;;) { 179 char oldvalue = (char) myArray.get(i); 180 char newvalue = (char) (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 char getAndDecrement(int i) { 195 for (;;) { 196 char oldvalue = (char) myArray.get(i); 197 char newvalue = (char) (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 char getAndAdd(int i, 213 char value) { 214 for (;;) { 215 char oldvalue = (char) myArray.get(i); 216 char newvalue = (char) (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 char incrementAndGet(int i) { 231 for (;;) { 232 char oldvalue = (char) myArray.get(i); 233 char newvalue = (char) (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 char decrementAndGet(int i) { 248 for (;;) { 249 char oldvalue = (char) myArray.get(i); 250 char newvalue = (char) (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 char addAndGet(int i, 266 char value) { 267 for (;;) { 268 char oldvalue = (char) myArray.get(i); 269 char newvalue = (char) (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 char reduce(int i, 288 char value, 289 CharacterOp op) { 290 for (;;) { 291 char oldvalue = (char) myArray.get(i); 292 char 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(char[] src, 318 CharacterOp 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 char[] src, 345 int srcoff, 346 int len, 347 CharacterOp 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 char oldvalue = (char) myArray.get(dstoff); 357 char 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 StringBuilder b = new StringBuilder(); 375 b.append('['); 376 int n = myArray.length(); 377 for (int i = 0; i < n; ++i) { 378 if (i > 0) { 379 b.append(", "); 380 } 381 b.append(get(i)); 382 } 383 b.append(']'); 384 return b.toString(); 385 } 386 387 }