#ifndef threading_ExclusiveData_h
#define threading_ExclusiveData_h
#include "mozilla/Maybe.h"
#include "mozilla/Move.h"
#include "mozilla/OperatorNewExtensions.h"
#include "threading/ConditionVariable.h"
#include "threading/Mutex.h"
namespace js {
template <typename T>
class ExclusiveData {
protected:
mutable Mutex lock_;
mutable T value_;
ExclusiveData(const ExclusiveData&) = delete;
ExclusiveData& operator=(const ExclusiveData&) = delete;
void acquire() const { lock_.lock(); }
void release() const { lock_.unlock(); }
public:
template <typename U>
explicit ExclusiveData(const MutexId& id, U&& u)
: lock_(id), value_(std::forward<U>(u)) {}
template <typename... Args>
explicit ExclusiveData(const MutexId& id, Args&&... args)
: lock_(id), value_(std::forward<Args>(args)...) {}
ExclusiveData(ExclusiveData&& rhs)
: lock_(std::move(rhs.lock)), value_(std::move(rhs.value_)) {
MOZ_ASSERT(&rhs != this, "self-move disallowed!");
}
ExclusiveData& operator=(ExclusiveData&& rhs) {
this->~ExclusiveData();
new (mozilla::KnownNotNull, this) ExclusiveData(std::move(rhs));
return *this;
}
class MOZ_STACK_CLASS Guard {
const ExclusiveData* parent_;
Guard(const Guard&) = delete;
Guard& operator=(const Guard&) = delete;
public:
explicit Guard(const ExclusiveData& parent) : parent_(&parent) {
parent_->acquire();
}
Guard(Guard&& rhs) : parent_(rhs.parent_) {
MOZ_ASSERT(&rhs != this, "self-move disallowed!");
rhs.parent_ = nullptr;
}
Guard& operator=(Guard&& rhs) {
this->~Guard();
new (this) Guard(std::move(rhs));
return *this;
}
T& get() const {
MOZ_ASSERT(parent_);
return parent_->value_;
}
operator T&() const { return get(); }
T* operator->() const { return &get(); }
const ExclusiveData<T>* parent() const {
MOZ_ASSERT(parent_);
return parent_;
}
~Guard() {
if (parent_) {
parent_->release();
}
}
};
Guard lock() const { return Guard(*this); }
};
template <class T>
class ExclusiveWaitableData : public ExclusiveData<T> {
typedef ExclusiveData<T> Base;
mutable ConditionVariable condVar_;
public:
template <typename U>
explicit ExclusiveWaitableData(const MutexId& id, U&& u)
: Base(id, std::forward<U>(u)) {}
template <typename... Args>
explicit ExclusiveWaitableData(const MutexId& id, Args&&... args)
: Base(id, std::forward<Args>(args)...) {}
class MOZ_STACK_CLASS Guard : public ExclusiveData<T>::Guard {
typedef typename ExclusiveData<T>::Guard Base;
public:
explicit Guard(const ExclusiveWaitableData& parent) : Base(parent) {}
Guard(Guard&& guard) : Base(std::move(guard)) {}
Guard& operator=(Guard&& rhs) { return Base::operator=(std::move(rhs)); }
void wait() {
auto* parent = static_cast<const ExclusiveWaitableData*>(this->parent());
parent->condVar_.impl_.wait(parent->lock_);
}
void notify_one() {
auto* parent = static_cast<const ExclusiveWaitableData*>(this->parent());
parent->condVar_.notify_one();
}
void notify_all() {
auto* parent = static_cast<const ExclusiveWaitableData*>(this->parent());
parent->condVar_.notify_all();
}
};
Guard lock() const { return Guard(*this); }
};
}
#endif