96 lines
2.9 KiB
C++
96 lines
2.9 KiB
C++
/*
|
|
* Copyright (C) Nemirtingas
|
|
* This file is part of System.
|
|
*
|
|
* System is free software; you can redistribute it
|
|
* and/or modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* System 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 System; if not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <tuple>
|
|
#include <mutex>
|
|
|
|
namespace System {
|
|
|
|
class scoped_lock {
|
|
struct value_holder
|
|
{
|
|
virtual ~value_holder() noexcept {}
|
|
};
|
|
|
|
template<typename... Args>
|
|
struct templated_value_holder : value_holder
|
|
{
|
|
template<std::size_t I = 0, typename... Tp>
|
|
inline typename std::enable_if<I == sizeof...(Tp), void>::type unlock(std::tuple<Tp...>& t) { }
|
|
|
|
template<std::size_t I = 0, typename... Tp>
|
|
inline typename std::enable_if<I < sizeof...(Tp), void>::type unlock(std::tuple<Tp...>& t)
|
|
{
|
|
std::get<I>(t).unlock();
|
|
unlock<I + 1, Tp...>(t);
|
|
}
|
|
|
|
explicit templated_value_holder(Args&... mutexes) : _mutexes(mutexes...) { std::lock(mutexes...); }
|
|
explicit templated_value_holder(std::adopt_lock_t, Args&... mutexes) : _mutexes(mutexes...) {} // construct but don't lock
|
|
|
|
virtual ~templated_value_holder() noexcept { unlock(_mutexes); }
|
|
|
|
std::tuple<Args&...> _mutexes;
|
|
};
|
|
|
|
template<typename Arg>
|
|
struct templated_value_holder<Arg> : value_holder
|
|
{
|
|
explicit templated_value_holder(Arg& mutex) : _mutex(mutex) { _mutex.lock(); }
|
|
explicit templated_value_holder(std::adopt_lock_t, Arg& mutex) : _mutex(mutex) {} // construct but don't lock
|
|
|
|
virtual ~templated_value_holder() noexcept { _mutex.unlock(); }
|
|
|
|
Arg& _mutex;
|
|
};
|
|
|
|
value_holder* _val;
|
|
|
|
public:
|
|
template<typename... Args>
|
|
explicit scoped_lock(Args&... mutexes) : _val(new templated_value_holder<Args&...>(mutexes...)) { }
|
|
|
|
template<typename... Args>
|
|
explicit scoped_lock(std::adopt_lock_t, Args&... mutexes) : _val(new templated_value_holder<Args&...>(std::adopt_lock, mutexes...)) { }
|
|
|
|
explicit scoped_lock(scoped_lock && other):
|
|
_val(other._val)
|
|
{
|
|
other._val = nullptr;
|
|
}
|
|
|
|
scoped_lock() noexcept:
|
|
_val(nullptr)
|
|
{}
|
|
~scoped_lock() noexcept { delete _val; }
|
|
|
|
scoped_lock& operator=(scoped_lock && other)
|
|
{
|
|
_val = other._val;
|
|
other._val = nullptr;
|
|
return *this;
|
|
}
|
|
|
|
scoped_lock(const scoped_lock&) = delete;
|
|
scoped_lock& operator=(const scoped_lock&) = delete;
|
|
};
|
|
|
|
} |