// 
// Decompiled by Procyon v0.6.0
// 

package io.netty.util.internal;

import io.netty.util.IllegalReferenceCountException;
import io.netty.util.ReferenceCounted;

@Deprecated
public abstract class ReferenceCountUpdater<T extends ReferenceCounted>
{
    protected ReferenceCountUpdater() {
    }
    
    protected abstract void safeInitializeRawRefCnt(final T p0, final int p1);
    
    protected abstract int getAndAddRawRefCnt(final T p0, final int p1);
    
    protected abstract int getRawRefCnt(final T p0);
    
    protected abstract int getAcquireRawRefCnt(final T p0);
    
    protected abstract void setReleaseRawRefCnt(final T p0, final int p1);
    
    protected abstract boolean casRawRefCnt(final T p0, final int p1, final int p2);
    
    public final int initialValue() {
        return 2;
    }
    
    public final void setInitialValue(final T instance) {
        this.safeInitializeRawRefCnt(instance, this.initialValue());
    }
    
    private static int realRefCnt(final int rawCnt) {
        return rawCnt >>> 1;
    }
    
    public final int refCnt(final T instance) {
        return realRefCnt(this.getAcquireRawRefCnt(instance));
    }
    
    public final boolean isLiveNonVolatile(final T instance) {
        final int rawCnt = this.getRawRefCnt(instance);
        return rawCnt == 2 || (rawCnt & 0x1) == 0x0;
    }
    
    public final void setRefCnt(final T instance, final int refCnt) {
        final int rawRefCnt = (refCnt > 0) ? (refCnt << 1) : 1;
        this.setReleaseRawRefCnt(instance, rawRefCnt);
    }
    
    public final void resetRefCnt(final T instance) {
        this.setReleaseRawRefCnt(instance, this.initialValue());
    }
    
    public final T retain(final T instance) {
        return this.retain0(instance, 2);
    }
    
    public final T retain(final T instance, final int increment) {
        return this.retain0(instance, ObjectUtil.checkPositive(increment, "increment") << 1);
    }
    
    private T retain0(final T instance, final int increment) {
        final int oldRef = this.getAndAddRawRefCnt(instance, increment);
        if ((oldRef & 0x80000001) != 0x0 || oldRef > Integer.MAX_VALUE - increment) {
            this.getAndAddRawRefCnt(instance, -increment);
            throw new IllegalReferenceCountException(0, increment >>> 1);
        }
        return instance;
    }
    
    public final boolean release(final T instance) {
        return this.release0(instance, 2);
    }
    
    public final boolean release(final T instance, final int decrement) {
        return this.release0(instance, ObjectUtil.checkPositive(decrement, "decrement") << 1);
    }
    
    private boolean release0(final T instance, final int decrement) {
        int curr;
        int next;
        do {
            curr = this.getRawRefCnt(instance);
            if (curr == decrement) {
                next = 1;
            }
            else {
                if (curr < decrement || (curr & 0x1) == 0x1) {
                    throwIllegalRefCountOnRelease(decrement, curr);
                }
                next = curr - decrement;
            }
        } while (!this.casRawRefCnt(instance, curr, next));
        return (next & 0x1) == 0x1;
    }
    
    private static void throwIllegalRefCountOnRelease(final int decrement, final int curr) {
        throw new IllegalReferenceCountException(curr >>> 1, -(decrement >>> 1));
    }
    
    public static <T extends ReferenceCounted> UpdaterType updaterTypeOf(final Class<T> clz, final String fieldName) {
        final long fieldOffset = getUnsafeOffset(clz, fieldName);
        if (fieldOffset >= 0L) {
            return UpdaterType.Unsafe;
        }
        if (PlatformDependent.hasVarHandle()) {
            return UpdaterType.VarHandle;
        }
        return UpdaterType.Atomic;
    }
    
    public static long getUnsafeOffset(final Class<? extends ReferenceCounted> clz, final String fieldName) {
        try {
            if (PlatformDependent.hasUnsafe()) {
                return PlatformDependent.objectFieldOffset(clz.getDeclaredField(fieldName));
            }
        }
        catch (final Throwable t) {}
        return -1L;
    }
    
    public enum UpdaterType
    {
        Unsafe, 
        VarHandle, 
        Atomic;
    }
}
