96 lines
2.9 KiB
C++
Raw Normal View History

2022-08-05 02:06:42 -04:00
/*
* 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;
};
}