/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright 2018 Danny Robson <danny@nerdcruft.net>
 */

#ifndef CRUFT_UTIL_THREAD_SPINLOCK_HPP
#define CRUFT_UTIL_THREAD_SPINLOCK_HPP

#include <atomic>

namespace cruft::thread {
    /// a CPU intensive, but lower latency, lock.
    ///
    /// std::atomic_flag seems like it might have been a good option on which
    /// to base our implementation, but it appears potentially expensive to
    /// spin over without a cheap read operation.
    ///
    /// satisfies BasicLockable.
    class spinlock {
    public:
        spinlock ();
        spinlock (spinlock &&) noexcept;
        spinlock& operator= (spinlock &&) noexcept;

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

        void lock ();
        void unlock ();

    private:
        static_assert (
            std::atomic<bool>::is_always_lock_free,
            "we require a lock free primitive or the entire point is moot"
        );

        std::atomic<bool> held;
    };
};

#endif