ReferenceCounter.java

package neureka.devices;

import java.util.Objects;
import java.util.function.Consumer;

public final class ReferenceCounter
{
    public enum ChangeType { INCREMENT, DECREMENT, FULL_DELETE }
    public static class ChangeEvent {
        private final ChangeType changeType;
        private final int change;
        private final int count;

        public ChangeEvent(ChangeType changeType, int change, int count ) {
            this.changeType = changeType;
            this.change = change;
            this.count = count;
        }

        public ChangeType type() { return changeType; }

        public int change() { return change; }

        public int currentCount() { return count; }
    }

    private int _count = 0;
    private final Consumer<ChangeEvent> _action;


    public ReferenceCounter( Consumer<ChangeEvent> action ) { _action = Objects.requireNonNull(action); }

    public void increment() {
        if ( _count < 0 ) throw new IllegalStateException("Cannot increment a reference counter with a negative count!");
        _count++;
        _action.accept(new ChangeEvent(ChangeType.INCREMENT, 1, _count));
    }

    public void decrement() {
        if ( _count == 0 ) throw new IllegalStateException("Cannot decrement a reference counter with a count of zero!");
        _count--;
        _action.accept(new ChangeEvent(ChangeType.DECREMENT, -1, _count));
    }

    public void fullDelete() {
        if ( _count == 0 ) return; // Cleanup action already performed by decrement()!
        if ( _count < 0 ) throw new IllegalStateException("Cannot decrement a reference counter with a negative count!");
        _action.accept(new ChangeEvent(ChangeType.FULL_DELETE, -_count, 0));
        _count = 0;
    }

    public int count() { return _count; }
}