citra/src/common/synchronized_wrapper.h
2017-02-26 17:22:02 -08:00

85 lines
2 KiB
C++

// Copyright 2015 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <algorithm>
#include <mutex>
namespace Common {
template <typename T>
class SynchronizedWrapper;
/**
* Synchronized reference, that keeps a SynchronizedWrapper's mutex locked during its lifetime. This
* greatly reduces the chance that someone will access the wrapped resource without locking the
* mutex.
*/
template <typename T>
class SynchronizedRef {
public:
SynchronizedRef(SynchronizedWrapper<T>& wrapper) : wrapper(&wrapper) {
wrapper.mutex.lock();
}
SynchronizedRef(SynchronizedRef&) = delete;
SynchronizedRef(SynchronizedRef&& o) : wrapper(o.wrapper) {
o.wrapper = nullptr;
}
~SynchronizedRef() {
if (wrapper)
wrapper->mutex.unlock();
}
SynchronizedRef& operator=(SynchronizedRef&) = delete;
SynchronizedRef& operator=(SynchronizedRef&& o) {
std::swap(wrapper, o.wrapper);
return *this;
}
T& operator*() {
return wrapper->data;
}
const T& operator*() const {
return wrapper->data;
}
T* operator->() {
return &wrapper->data;
}
const T* operator->() const {
return &wrapper->data;
}
private:
SynchronizedWrapper<T>* wrapper;
};
/**
* Wraps an object, only allowing access to it via a locking reference wrapper. Good to ensure no
* one forgets to lock a mutex before acessing an object. To access the wrapped object construct a
* SyncronizedRef on this wrapper. Inspired by Rust's Mutex type
* (http://doc.rust-lang.org/std/sync/struct.Mutex.html).
*/
template <typename T>
class SynchronizedWrapper {
public:
template <typename... Args>
SynchronizedWrapper(Args&&... args) : data(std::forward<Args>(args)...) {}
SynchronizedRef<T> Lock() {
return {*this};
}
private:
template <typename U>
friend class SynchronizedRef;
std::mutex mutex;
T data;
};
} // namespace Common