/*
* This file is part of LanternServer, licensed under the MIT License (MIT).
*
* Copyright (c) LanternPowered <https://www.lanternpowered.org>
* Copyright (c) SpongePowered <https://www.spongepowered.org>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.lanternpowered.server.util.concurrent;
import java.io.Serializable;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicIntegerArray;
public class AtomicFloatArray implements Serializable {
private static final long serialVersionUID = 1128664741971193255L;
private final AtomicIntegerArray backingArray;
/**
* Creates a new {@link AtomicFloatArray} of the given length, with all
* elements initially zero.
*
* @param length the length of the array
*/
public AtomicFloatArray(int length) {
this(new float[length]);
}
/**
* Creates a new {@link AtomicFloatArray} with the same length as, and
* all elements copied from, the given array.
*
* @param array the array to copy elements from
* @throws NullPointerException if array is null
*/
public AtomicFloatArray(float[] array) {
int[] array0 = new int[array.length];
for (int i = 0; i < array.length; i++) {
array0[i] = Float.floatToRawIntBits(array[i]);
}
this.backingArray = new AtomicIntegerArray(array0);
}
/**
* Returns the length of the array.
*
* @return the length of the array
*/
public final int length() {
return this.backingArray.length();
}
/**
* Gets the current value at position {@code index}.
*
* @param index the index
* @return the current value
*/
public final float get(int index) {
return Float.intBitsToFloat(this.backingArray.get(index));
}
/**
* Sets the element at position {@code index} to the given value.
*
* @param index the index
* @param newValue the new value
*/
public final void set(int index, float newValue) {
this.backingArray.set(index, Float.floatToRawIntBits(newValue));
}
/**
* Eventually sets the element at position {@code index} to the given value.
*
* @param index the index
* @param newValue the new value
*/
public final void lazySet(int index, float newValue) {
this.backingArray.lazySet(index, Float.floatToRawIntBits(newValue));
}
/**
* Atomically sets the element at position {@code index} to the given
* value and returns the old value.
*
* @param index the index
* @param newValue the new value
* @return the previous value
*/
public final float getAndSet(int index, float newValue) {
return Float.intBitsToFloat(this.backingArray.getAndSet(index, Float.floatToRawIntBits(newValue)));
}
/**
* Atomically sets the element at position {@code index} to the given
* updated value if the current value {@code ==} the expected value.
*
* @param index the index
* @param expect the expected value
* @param update the new value
* @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int index, float expect, float update) {
return this.backingArray.compareAndSet(index, Float.floatToRawIntBits(expect), Float.floatToRawIntBits(update));
}
/**
* Atomically sets the element at position {@code index} to the given
* updated value if the current value {@code ==} the expected value.
*
* May fail spuriously and does not provide ordering guarantees, so is only rarely an
* appropriate alternative to {@code compareAndSet}.
*
* @param index the index
* @param expect the expected value
* @param update the new value
* @return true if successful.
*/
public final boolean weakCompareAndSet(int index, float expect, float update) {
return this.compareAndSet(index, expect, update);
}
/**
* Atomically increments by one the element at index {@code index}.
*
* @param index the index
* @return the previous value
*/
public final float getAndIncrement(int index) {
return this.getAndAdd(index, 1f);
}
/**
* Atomically decrements by one the element at index {@code index}.
*
* @param index the index
* @return the previous value
*/
public final float getAndDecrement(int index) {
return this.getAndAdd(index, -1f);
}
private float addAndGet(int index, float delta, boolean old) {
boolean success = false;
float newValue = 0;
float oldValue = 0;
while (!success) {
oldValue = this.get(index);
newValue = oldValue + delta;
success = this.compareAndSet(index, oldValue, newValue);
}
return old ? oldValue : newValue;
}
/**
* Atomically adds the given value to the element at index {@code index}.
*
* @param index the index
* @param delta the value to add
* @return the previous value
*/
public final float getAndAdd(int index, float delta) {
return this.addAndGet(index, delta, true);
}
/**
* Atomically increments by one the element at index {@code index}.
*
* @param index the index
* @return the updated value
*/
public final float incrementAndGet(int index) {
return this.addAndGet(index, 1f);
}
/**
* Atomically decrements by one the element at index {@code index}.
*
* @param index the index
* @return the updated value
*/
public final float decrementAndGet(int index) {
return this.addAndGet(index, -1f);
}
/**
* Atomically adds the given value to the element at index {@code index}.
*
* @param index the index
* @param delta the value to add
* @return the updated value
*/
public final float addAndGet(int index, float delta) {
return this.addAndGet(index, delta, false);
}
/**
* Gets an array containing all the values in the array. The returned values are not
* guaranteed to be from the same time instant.
*
* If an array is provided and it is the correct length, then that array will be
* used as the destination array.
*
* @param array the provided array
* @return an array containing the values in the array
*/
public final float[] getArray(float[] array) {
int length = this.length();
if (array == null || array.length != length) {
array = new float[length];
}
for (int i = 0; i < length; i++) {
array[i] = this.get(i);
}
return array;
}
/**
* Gets an array containing all the values in the array.
*
* The returned values are not guaranteed to be from
* the same time instant.
*
* @return the array
*/
public final float[] getArray() {
return this.getArray(null);
}
/**
* Returns the String representation of the current values of array.
*
* The returned values are not guaranteed to be from
* the same time instant.
*
* @return the string representation
*/
@Override
public String toString() {
return Arrays.toString(this.getArray());
}
}