blob: ed9d7e2af4617c73661d4e7403bb63b32863955b [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COBALT_UTIL_PROTECTED_FIELDS_H_
#define COBALT_UTIL_PROTECTED_FIELDS_H_
#include <chrono>
#include <condition_variable>
#include <mutex>
namespace cobalt {
namespace util {
// ProtectedFields is a useful abstraction for having an object that is
// protected by a mutex.
//
// Example usage:
//
// struct SafeField {
// int protected_int;
// };
// ProtectedFields<SafeField> protected_fields;
// protected_fields.lock()->protected_int = 100;
// LOG(INFO) << "Current protected_int: " <<
// protected_fields.const_lock()->protected_int;
//
template <class Fields>
class ProtectedFields {
public:
// ConstLockedFieldsPtr holds a pointer to Fields, as well a
// unique_lock<mutex>.
//
// The semantics of this object is similar to a pointer.
class LockedFieldsPtr {
public:
Fields* operator->() { return fields_; }
Fields& operator*() { return *fields_; }
// Calls the wait() method of a condition variable with a reference to the
// mutex.
void wait_with(std::condition_variable* cv) { return cv->wait(lock_); }
template <class Predicate>
void wait_with(std::condition_variable* cv, Predicate pred) {
return cv->wait(lock_, pred);
}
// Calls the wait_for() method of a condition variable with a reference to
// the mutex.
template <class Rep, class Period>
std::cv_status wait_for_with(
std::condition_variable* cv,
const std::chrono::duration<Rep, Period>& rel_time) {
return cv->wait(lock_, rel_time);
}
template <class Rep, class Period, class Predicate>
bool wait_for_with(std::condition_variable* cv,
const std::chrono::duration<Rep, Period>& rel_time,
Predicate pred) {
return cv->wait_for(lock_, rel_time, pred);
}
// Calls the wait_until() method of a condition variable with a reference to
// the mutex.
template <class Clock, class Duration>
std::cv_status wait_until_with(
std::condition_variable* cv,
const std::chrono::time_point<Clock, Duration>& timeout_time) {
return cv->wait_until(lock_, timeout_time);
}
template <class Clock, class Duration, class Predicate>
bool wait_until_with(
std::condition_variable* cv,
const std::chrono::time_point<Clock, Duration>& timeout_time,
Predicate pred) {
return cv->wait_until(lock_, timeout_time, pred);
}
private:
friend class ProtectedFields;
LockedFieldsPtr(std::mutex* mutex, Fields* fields)
: lock_(*mutex), fields_(fields) {}
std::unique_lock<std::mutex> lock_;
Fields* fields_;
public:
// Disable copy/assign. Only allow move.
LockedFieldsPtr(LockedFieldsPtr&&);
LockedFieldsPtr& operator=(LockedFieldsPtr&&);
LockedFieldsPtr& operator=(const LockedFieldsPtr&) = delete;
LockedFieldsPtr(const LockedFieldsPtr&) = delete;
};
// ConstLockedFieldsPtr holds a const pointer to Fields, as well a
// unique_lock<mutex>.
//
// The semantics of this object is similar to a const pointer.
class ConstLockedFieldsPtr {
public:
const Fields* operator->() { return fields_; }
const Fields& operator*() { return *fields_; }
// Calls the wait() method of a condition variable with a reference to the
// mutex.
void wait_with(std::condition_variable* cv) { return cv->wait(lock_); }
template <class Predicate>
void wait_with(std::condition_variable* cv, Predicate pred) {
return cv->wait(lock_, pred);
}
// Calls the wait_for() method of a condition variable with a reference to
// the mutex.
template <class Rep, class Period>
std::cv_status wait_for_with(
std::condition_variable* cv,
const std::chrono::duration<Rep, Period>& rel_time) {
return cv->wait(lock_, rel_time);
}
template <class Rep, class Period, class Predicate>
bool wait_for_with(std::condition_variable* cv,
const std::chrono::duration<Rep, Period>& rel_time,
Predicate pred) {
return cv->wait_for(lock_, rel_time, pred);
}
// Calls the wait_until() method of a condition variable with a reference to
// the mutex.
template <class Clock, class Duration>
std::cv_status wait_until_with(
std::condition_variable* cv,
const std::chrono::time_point<Clock, Duration>& timeout_time) {
return cv->wait_until(lock_, timeout_time);
}
template <class Clock, class Duration, class Predicate>
bool wait_until_with(
std::condition_variable* cv,
const std::chrono::time_point<Clock, Duration>& timeout_time,
Predicate pred) {
return cv->wait_until(lock_, timeout_time, pred);
}
private:
friend class ProtectedFields;
ConstLockedFieldsPtr(std::mutex* mutex, const Fields* fields)
: lock_(*mutex), fields_(fields) {}
std::unique_lock<std::mutex> lock_;
const Fields* fields_;
public:
// Disable copy/assign. Only allow move.
ConstLockedFieldsPtr(ConstLockedFieldsPtr&&);
ConstLockedFieldsPtr& operator=(ConstLockedFieldsPtr&&);
ConstLockedFieldsPtr& operator=(const ConstLockedFieldsPtr&) = delete;
ConstLockedFieldsPtr(const ConstLockedFieldsPtr&) = delete;
};
LockedFieldsPtr lock() { return LockedFieldsPtr(&mutex_, &fields_); }
ConstLockedFieldsPtr const_lock() const {
return ConstLockedFieldsPtr(&mutex_, &fields_);
}
private:
mutable std::mutex mutex_;
Fields fields_;
public:
ProtectedFields& operator=(const ProtectedFields&) = delete;
ProtectedFields(const ProtectedFields&) = delete;
ProtectedFields() {}
};
} // namespace util
} // namespace cobalt
#endif // COBALT_UTIL_PROTECTED_FIELDS_H_