001/*
002 * JDrupes Builder
003 * Copyright (C) 2026 Michael N. Lipp
004 * 
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
017 */
018
019package org.jdrupes.builder.core;
020
021/// A counter that supports waiting for a specific value. The waiting
022/// thread is woken when the counter hits the target value.
023///
024@SuppressWarnings("PMD.AvoidSynchronizedAtMethodLevel")
025public class AwaitableCounter {
026    private int count;
027
028    /// Initializes a new awaitable counter.
029    ///
030    public AwaitableCounter() {
031        // Make javadoc happy
032    }
033
034    /// Increment the count's value.
035    ///
036    /// @return the counter
037    ///
038    public synchronized AwaitableCounter increment() {
039        count++;
040        return this;
041    }
042
043    /// Decrement the counter's value.
044    ///
045    /// @return the counter
046    ///
047    public synchronized AwaitableCounter decrement() {
048        count--;
049        if (count == 0) {
050            notifyAll();
051        }
052        return this;
053    }
054
055    /// Return the counter's value.
056    ///
057    /// @return the value
058    ///
059    public int value() {
060        return count;
061    }
062
063    /// Create an increment.
064    ///
065    /// @return the count
066    ///
067    public Increment acquire() {
068        return new Increment();
069    }
070
071    /// Wait for the counter to reach the given value.
072    ///
073    /// @param wanted the wanted
074    /// @return the counter
075    /// @throws InterruptedException the interrupted exception
076    ///
077    public synchronized AwaitableCounter await(int wanted)
078            throws InterruptedException {
079        while (count != wanted) {
080            wait();
081        }
082        return this;
083    }
084
085    /// Increment/decrement with an AutoCloseable. This supports
086    /// reliable increment/decrement using try-with-resources.
087    ///
088    public class Increment implements AutoCloseable {
089
090        /// Initializes a new Increment. Increments the counter.
091        ///
092        @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
093        public Increment() {
094            increment();
095        }
096
097        /// Decrements the counter.
098        ///
099        @Override
100        public void close() {
101            decrement();
102        }
103    }
104}