/*
* 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.util.concurrent.atomic.AtomicInteger;
public class AtomicFloat extends Number {
private static final long serialVersionUID = 4712809432683706435L;
private final AtomicInteger value;
/**
* Creates a new {@link AtomicFloat} with initial value {@code 0}.
*/
public AtomicFloat() {
this(0f);
}
/**
* Creates a new {@link AtomicFloat} with the given initial value.
*
* @param initialValue the initial value
*/
public AtomicFloat(float initialValue) {
this.value = new AtomicInteger(Float.floatToRawIntBits(initialValue));
}
/**
* Gets the current value.
*
* @return the current value
*/
public final float get() {
return Float.intBitsToFloat(this.value.get());
}
/**
* Sets to the given value.
*
* @param newValue the new value
*/
public final void set(int newValue) {
this.value.set(Float.floatToRawIntBits(newValue));
}
/**
* Eventually sets to the given value.
*
* @param newValue the new value
*/
public final void lazySet(float newValue) {
this.value.lazySet(Float.floatToRawIntBits(newValue));
}
/**
* Atomically sets to the given value and returns the old value.
*
* @param newValue the new value
* @return the previous value
*/
public final float getAndSet(float newValue) {
return Float.intBitsToFloat(this.value.getAndSet(Float.floatToRawIntBits(newValue)));
}
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @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(float expect, float update) {
return this.value.compareAndSet(Float.floatToRawIntBits(expect), Float.floatToRawIntBits(update));
}
/**
* Atomically sets the value 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 expect the expected value
* @param update the new value
* @return true if successful.
*/
public final boolean weakCompareAndSet(float expect, float update) {
return this.value.weakCompareAndSet(Float.floatToRawIntBits(expect), Float.floatToRawIntBits(update));
}
private float addAndGet(float delta, boolean old) {
while (true) {
int oldIntValue = this.value.get();
float oldValue = Float.intBitsToFloat(oldIntValue);
float newValue = oldValue + delta;
if (this.value.compareAndSet(oldIntValue, Float.floatToRawIntBits(newValue))) {
return old ? oldValue : newValue;
}
}
}
/**
* Atomically increments by one the current value.
*
* @return the previous value
*/
public final float getAndIncrement() {
return this.getAndAdd(1f);
}
/**
* Atomically decrements by one the current value.
*
* @return the previous value
*/
public final float getAndDecrement() {
return this.getAndAdd(-1f);
}
/**
* Atomically adds the given value to the current value.
*
* @param delta the value to add
* @return the previous value
*/
public final float getAndAdd(float delta) {
return this.addAndGet(delta, true);
}
/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final float incrementAndGet() {
return this.addAndGet(1f);
}
/**
* Atomically decrements by one the current value.
*
* @return the updated value
*/
public final float decrementAndGet() {
return this.addAndGet(-1f);
}
/**
* Atomically adds the given value to the current value.
*
* @param delta the value to add
* @return the updated value
*/
public final float addAndGet(float delta) {
return this.addAndGet(delta, false);
}
/**
* Returns the String representation of the current value.
*
* @return the string representation
*/
@Override
public String toString() {
return Float.toString(this.get());
}
@Override
public int intValue() {
return (int) this.get();
}
@Override
public long longValue() {
return (long) this.get();
}
@Override
public float floatValue() {
return this.get();
}
@Override
public double doubleValue() {
return (double) this.get();
}
}