/* Copyright (c) 2018 vesoft inc. All rights reserved.
 *
 * This source code is licensed under Apache 2.0 License,
 * attached with Common Clause Condition 1.0, found in the LICENSES directory.
 */
#ifndef COMMON_CONCURRENT_LATCH_H_
#define COMMON_CONCURRENT_LATCH_H_

#include "base/Base.h"
#include "cpp/helpers.h"
/**
 * Latch is an one-shot synchronization object.
 * It provides an synchronization point for multiple threads.
 * See shared/concurrent/test/LatchTest.cpp for use scenarios.
 */

namespace nebula {
namespace concurrent {

class Latch final : public nebula::cpp::NonCopyable, public nebula::cpp::NonMovable {
public:
    /**
     * @counter:  initial counter,
     *            typically number of participating threads.
     * Throws `std::invalid_argument' if counter is zero.
     */
    explicit Latch(size_t counter);
    ~Latch() = default;
    /**
     * Decrements the internal counter by one.
     * If the counter reaches 0, all blocking(in `wait')
     * threads will be given the green light.
     * Throws `std::runtime_error' if counter already zeroed.
     */
    void down();
    /**
     * Decrements the internal counter by one.
     * If the counter reaches 0, returns immediately,
     * and all blocking threads will be woken up.
     * Otherwise, the calling thread blocks until being woken up.
     * Throws `std::runtime_error' if counter already zeroed.
     */
    void downWait();
    /**
     * Blocks if internal counter not zero.
     * Otherwise, returns immediately.
     */
    void wait();
    /**
     * Returns true if internal counter already zeroed.
     * Otherwise, returns false.
     */
    bool isReady();

private:
    volatile size_t         counter_{0};
    std::mutex              lock_;
    std::condition_variable cond_;
};

}   // namespace concurrent
}   // namespace nebula

#endif  // COMMON_CONCURRENT_LATCH_H_
