package org.multiverse.stms.gamma.transactionalobjects; import org.multiverse.api.LockMode; import org.multiverse.api.Txn; import org.multiverse.api.exceptions.LockedException; import org.multiverse.api.functions.DoubleFunction; import org.multiverse.api.predicates.DoublePredicate; import org.multiverse.api.references.TxnDouble; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.Listeners; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.stms.gamma.GammaStmUtils.*; import static org.multiverse.stms.gamma.ThreadLocalGammaObjectPool.getThreadLocalGammaObjectPool; @SuppressWarnings({"OverlyComplexClass"}) public class GammaTxnDouble extends BaseGammaTxnRef implements TxnDouble { public GammaTxnDouble(double value) { this((GammaStm) getGlobalStmInstance(), value); } public GammaTxnDouble(final GammaTxn tx) { this(tx, 0); } public GammaTxnDouble(final GammaTxn tx, final double value) { super(tx.getConfig().stm, TYPE_DOUBLE); arriveAndLock(1, LOCKMODE_EXCLUSIVE); Tranlocal tranlocal = openForConstruction(tx); tranlocal.long_value = doubleAsLong(value); } public GammaTxnDouble(final GammaStm stm) { this(stm, 0); } public GammaTxnDouble(final GammaStm stm, final double value) { super(stm, TYPE_DOUBLE); this.long_value = doubleAsLong(value); //noinspection PointlessArithmeticExpression this.version = VERSION_UNCOMMITTED + 1; } @Override public final double get() { return get(getRequiredThreadLocalGammaTxn()); } @Override public final double get(final Txn tx) { return get(asGammaTxn(tx)); } public final double get(final GammaTxn tx) { return longAsDouble(openForRead(tx, LOCKMODE_NONE).long_value); } @Override public final double getAndLock(final LockMode lockMode) { return getAndLock(getRequiredThreadLocalGammaTxn(), lockMode); } @Override public final double getAndLock(final Txn tx, final LockMode lockMode) { return getAndLock(asGammaTxn(tx), lockMode); } public final double getAndLock(final GammaTxn tx, final LockMode lockMode) { return longAsDouble(getLong(tx, lockMode)); } @Override public final double set(final double value) { return set(getRequiredThreadLocalGammaTxn(), value); } @Override public final double set(final Txn tx, final double value) { return set(asGammaTxn(tx), value); } public final double set(final GammaTxn tx, final double value) { openForWrite(tx, LOCKMODE_NONE).long_value = doubleAsLong(value); return value; } @Override public final double setAndLock(final double value, final LockMode lockMode) { return setAndLock(getRequiredThreadLocalGammaTxn(), doubleAsLong(value), lockMode); } @Override public final double setAndLock(final Txn tx, final double value, final LockMode lockMode) { return setAndLock(asGammaTxn(tx), value, lockMode); } public final double setAndLock(final GammaTxn tx, final double value, final LockMode lockMode) { return longAsDouble(setLong(tx, lockMode, doubleAsLong(value), false)); } @Override public final double getAndSet(final double value) { return getAndSet(getRequiredThreadLocalGammaTxn(), value); } @Override public final double getAndSet(final Txn tx, final double value) { return getAndSet(asGammaTxn(tx), value); } public final double getAndSet(final GammaTxn tx, final double value) { Tranlocal tranlocal = openForWrite(tx, LOCKMODE_NONE); double oldValue = longAsDouble(tranlocal.long_value); tranlocal.long_value = doubleAsLong(value); return oldValue; } @Override public final double getAndSetAndLock(final double value, final LockMode lockMode) { return getAndSetAndLock(getRequiredThreadLocalGammaTxn(), value, lockMode); } @Override public final double getAndSetAndLock(final Txn tx, final double value, final LockMode lockMode) { return getAndSetAndLock(asGammaTxn(tx), value, lockMode); } public final double getAndSetAndLock(final GammaTxn tx, final double value, final LockMode lockMode) { return longAsDouble(setLong(tx, lockMode, doubleAsLong(value), true)); } @Override public final double atomicGet() { return longAsDouble(atomicGetLong()); } @Override public final double atomicWeakGet() { return longAsDouble(long_value); } @Override public final double atomicSet(final double newValue) { return longAsDouble(atomicSetLong(doubleAsLong(newValue), false)); } @Override public final double atomicGetAndSet(final double newValue) { return longAsDouble(atomicSetLong(doubleAsLong(newValue), true)); } @Override public final void commute(final DoubleFunction function) { commute(getRequiredThreadLocalGammaTxn(), function); } @Override public final void commute(final Txn tx, final DoubleFunction function) { commute(asGammaTxn(tx), function); } public final void commute(final GammaTxn tx, final DoubleFunction function) { openForCommute(tx, function); } @Override public final double atomicAlterAndGet(final DoubleFunction function) { return atomicAlter(function, false); } @Override public final double atomicGetAndAlter(final DoubleFunction function) { return atomicAlter(function, true); } private double atomicAlter(final DoubleFunction function, final boolean returnOld) { if (function == null) { throw new NullPointerException("Function can't be null"); } final int arriveStatus = arriveAndExclusiveLockOrBackoff(); if (arriveStatus == FAILURE) { throw new LockedException(); } final double oldValue = longAsDouble(long_value); double newValue; boolean abort = true; try { newValue = function.call(oldValue); abort = false; } finally { if (abort) { departAfterFailureAndUnlock(); } } if (oldValue == newValue) { if ((arriveStatus & MASK_UNREGISTERED) != 0) { unlockByUnregistered(); } else { departAfterReadingAndUnlock(); } return oldValue; } if ((arriveStatus & MASK_CONFLICT) != 0) { stm.globalConflictCounter.signalConflict(); } long_value = doubleAsLong(newValue); //noinspection NonAtomicOperationOnVolatileField version++; final Listeners listeners = ___removeListenersAfterWrite(); departAfterUpdateAndUnlock(); if (listeners != null) { listeners.openAll(getThreadLocalGammaObjectPool()); } return returnOld ? oldValue : newValue; } @Override public final double alterAndGet(final DoubleFunction function) { return alterAndGet(getRequiredThreadLocalGammaTxn(), function); } @Override public final double alterAndGet(final Txn tx, final DoubleFunction function) { return alterAndGet(asGammaTxn(tx), function); } public final double alterAndGet(final GammaTxn tx, final DoubleFunction function) { return alter(tx, function, false); } @Override public final double getAndAlter(final DoubleFunction function) { return getAndAlter(getRequiredThreadLocalGammaTxn(), function); } @Override public final double getAndAlter(final Txn tx, final DoubleFunction function) { return getAndAlter(asGammaTxn(tx), function); } public final double getAndAlter(final GammaTxn tx, final DoubleFunction function) { return alter(tx, function, true); } public final double alter(final GammaTxn tx, final DoubleFunction function, boolean returnOld) { if (tx == null) { throw new NullPointerException(); } if (function == null) { tx.abort(); throw new NullPointerException("Function can't be null"); } final Tranlocal write = openForWrite(tx, LOCKMODE_NONE); boolean abort = true; try { double oldValue = longAsDouble(write.long_value); write.long_value = doubleAsLong(function.call(oldValue)); abort = false; return returnOld ? oldValue : longAsDouble(write.long_value); } finally { if (abort) { tx.abort(); } } } @Override public final boolean atomicCompareAndSet(final double expectedValue, final double newValue) { return atomicCompareAndSetLong(doubleAsLong(expectedValue), doubleAsLong(newValue)); } @Override public final double getAndIncrement(final double amount) { return getAndIncrement(getRequiredThreadLocalGammaTxn(), amount); } @Override public final double getAndIncrement(final Txn tx, final double amount) { return getAndIncrement(asGammaTxn(tx), amount); } public final double getAndIncrement(final GammaTxn tx, final double amount) { Tranlocal tranlocal = openForWrite(tx, LOCKMODE_NONE); double oldValue = longAsDouble(tranlocal.long_value); tranlocal.long_value = doubleAsLong(oldValue + amount); return oldValue; } @Override public final double atomicGetAndIncrement(final double amount) { return atomicIncrement(amount, true); } @Override public final double atomicIncrementAndGet(final double amount) { return atomicIncrement(amount, false); } private double atomicIncrement(final double amount, boolean returnOld) { final int arriveStatus = arriveAndExclusiveLockOrBackoff(); if (arriveStatus == FAILURE) { throw new LockedException(); } final double oldValue = longAsDouble(long_value); if (amount == 0) { if ((arriveStatus & MASK_UNREGISTERED) != 0) { unlockByUnregistered(); } else { departAfterReadingAndUnlock(); } return oldValue; } if ((arriveStatus & MASK_CONFLICT) != 0) { stm.globalConflictCounter.signalConflict(); } final double newValue = oldValue + amount; long_value = doubleAsLong(newValue); //noinspection NonAtomicOperationOnVolatileField version++; final Listeners listeners = ___removeListenersAfterWrite(); departAfterUpdateAndUnlock(); if (listeners != null) { listeners.openAll(getThreadLocalGammaObjectPool()); } return returnOld ? oldValue : newValue; } @Override public final double incrementAndGet(final double amount) { return incrementAndGet(getRequiredThreadLocalGammaTxn(), amount); } @Override public final double incrementAndGet(final Txn tx, final double amount) { return incrementAndGet(asGammaTxn(tx), amount); } public final double incrementAndGet(final GammaTxn tx, final double amount) { Tranlocal tranlocal = openForWrite(tx, LOCKMODE_NONE); double result = longAsDouble(tranlocal.long_value) + amount; tranlocal.long_value = doubleAsLong(result); return result; } @Override public final void await(final double value) { await(getRequiredThreadLocalGammaTxn(), value); } @Override public final void await(final Txn tx, final double value) { await(asGammaTxn(tx), value); } public final void await(final GammaTxn tx, final double value) { if (longAsDouble(openForRead(tx, LOCKMODE_NONE).long_value) != value) { tx.retry(); } } @Override public final void await(final DoublePredicate predicate) { await(getRequiredThreadLocalGammaTxn(), predicate); } @Override public final void await(final Txn tx, final DoublePredicate predicate) { await(asGammaTxn(tx), predicate); } public final void await(final GammaTxn tx, final DoublePredicate predicate) { final Tranlocal tranlocal = openForRead(tx, LOCKMODE_NONE); boolean abort = true; try { if (!predicate.evaluate(longAsDouble(tranlocal.long_value))) { tx.retry(); } abort = false; } finally { if (abort) { tx.abort(); } } } @Override public final String toDebugString() { return String.format("GammaTxnDouble{orec=%s, version=%s, value=%s, hasListeners=%s)", ___toOrecString(), version, longAsDouble(long_value), listeners != null); } @Override public final String toString() { return toString(getRequiredThreadLocalGammaTxn()); } @Override public final String toString(Txn tx) { return toString(asGammaTxn(tx)); } public final String toString(GammaTxn tx) { return Double.toString(get(tx)); } @Override public final String atomicToString() { return Double.toString(atomicGet()); } }