/*
* ModeShape (http://www.modeshape.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.modeshape.common.collection.ring;
import static java.util.Arrays.copyOf;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
/**
* Static methods for atomically modifying an array of {@link Pointer} instances.
*
* @author Randall Hauch (rhauch@redhat.com)
*/
public class Pointers {
private Pointers() {
}
public static long getMinimum( Pointer[] pointers,
long minimum ) {
for (int i = 0; i != pointers.length; ++i) {
minimum = Math.min(minimum, pointers[i].get());
}
return minimum;
}
/**
* Atomically add the specified {@link Pointer} instance(s) to an array known to the given updator.
*
* @param holder the object that holds the array; may not be null
* @param updater the updator of the array; may not be null
* @param cursor the cursor that the pointers will follow; may be null if none of the pointers are to be changed
* @param pointersToAdd the pointer(s) to be added to the existing pointers
*/
public static <T> void add( T holder,
AtomicReferenceFieldUpdater<T, Pointer[]> updater,
Cursor cursor,
Pointer... pointersToAdd ) {
long currentPosition = 0L;
Pointer[] updatedPointers;
Pointer[] currentPointers;
do {
currentPointers = updater.get(holder);
updatedPointers = copyOf(currentPointers, currentPointers.length + pointersToAdd.length);
if (cursor != null) currentPosition = cursor.getCurrent();
int index = currentPointers.length;
for (Pointer pointer : pointersToAdd) {
if (cursor != null) pointer.set(currentPosition);
updatedPointers[index++] = pointer;
}
} while (!updater.compareAndSet(holder, currentPointers, updatedPointers));
if (cursor != null) {
// Set all of the new pointers to the current position ...
currentPosition = cursor.getCurrent();
for (Pointer pointer : pointersToAdd) {
pointer.set(currentPosition);
}
}
}
/**
* Atomically remove the specified {@link Pointer} instance from an array known to the given updator.
*
* @param holder the object that holds the array; may not be null
* @param updater the updator of the array; may not be null
* @param pointer the pointer to be removed from the existing pointers
* @return true if the pointer was removed, or false if the array never contained the pointer
*/
public static <T> boolean remove( T holder,
AtomicReferenceFieldUpdater<T, Pointer[]> updater,
Pointer pointer ) {
int numToRemove;
Pointer[] oldPointers;
Pointer[] newPointers;
do {
oldPointers = updater.get(holder);
numToRemove = countMatching(oldPointers, pointer);
if (0 == numToRemove) break;
final int oldSize = oldPointers.length;
newPointers = new Pointer[oldSize - numToRemove];
// Copy all but the 'pointer' into the new array ...
for (int i = 0, pos = 0; i < oldSize; i++) {
final Pointer testPointer = oldPointers[i];
if (pointer != testPointer) {
newPointers[pos++] = testPointer;
}
}
} while (!updater.compareAndSet(holder, oldPointers, newPointers));
return numToRemove != 0;
}
private static <T> int countMatching( final T[] values,
final T toMatch ) {
int numToRemove = 0;
for (T value : values) {
// Use object identity ...
if (value == toMatch) numToRemove++;
}
return numToRemove;
}
}