Program Listing for File synchronised.h

↰ Return to documentation for file (/home/docs/checkouts/readthedocs.org/user_builds/canonical-mir-documentation/checkouts/2.30/include/core/mir/synchronised.h)

/*
 * Copyright © Canonical Ltd.
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 2 or 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef MIR_SYNCHRONISED_H_
#define MIR_SYNCHRONISED_H_

#include <mutex>
#include <utility>
#include <type_traits>

namespace mir
{

template<typename T>
class Synchronised
{
public:
    Synchronised() = default;
    Synchronised(T&& initial_value) noexcept(std::is_nothrow_move_constructible_v<T>) : value{std::move(initial_value)}
    {}

    Synchronised(Synchronised const&) = delete;
    Synchronised& operator=(Synchronised const&) = delete;

    template<typename U>
    class LockedImpl
    {
    public:
        LockedImpl(LockedImpl&& from) noexcept : value{from.value}, lock{std::move(from.lock)} { from.value = nullptr; }

        ~LockedImpl() = default;

        auto operator*() const -> U& { return *value; }

        auto operator->() const -> U* { return value; }

        void drop()
        {
            value = nullptr;
            lock.unlock();
        }

        template<typename Cv, typename Predicate>
        void wait(Cv& cv, Predicate stop_waiting)
        { cv.wait(lock, stop_waiting); }

        template<typename Cv, typename Duration, typename Predicate>
        auto wait_for(Cv& cv, Duration const& timeout, Predicate stop_waiting) -> bool
        { return cv.wait_for(lock, timeout, stop_waiting); }

    private:
        friend class Synchronised;
        LockedImpl(std::unique_lock<std::mutex>&& lock, U& value) : value{&value}, lock{std::move(lock)} {}

        U* value;
        std::unique_lock<std::mutex> lock;
    };

    using Locked = LockedImpl<T>;
    auto lock() -> Locked { return LockedImpl<T>{std::unique_lock{mutex}, value}; }

    auto lock_mut() const -> Locked { return LockedImpl<T>{std::unique_lock{mutex}, value}; }

    using LockedView = LockedImpl<T const>;
    auto lock() const -> LockedView { return LockedImpl<T const>{std::unique_lock{mutex}, value}; }

private:
    std::mutex mutable mutex;
    T mutable value;
};

}

#endif //MIR_SYNCHRONISED_H_