MutexGuard.h revision b20a0ce59f59cb5ec857748e056cc341dbd13b92
1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ANDROIDFW_MUTEXGUARD_H
18#define ANDROIDFW_MUTEXGUARD_H
19
20#include <mutex>
21#include <type_traits>
22
23#include "android-base/macros.h"
24
25namespace android {
26
27template <typename T>
28class ScopedLock;
29
30// Owns the guarded object and protects access to it via a mutex.
31// The guarded object is inaccessible via this class.
32// The mutex is locked and the object accessed via the ScopedLock<T> class.
33//
34// NOTE: The template parameter T should not be a raw pointer, since ownership
35// is ambiguous and error-prone. Instead use an std::unique_ptr<>.
36//
37// Example use:
38//
39//   Guarded<std::string> shared_string("hello");
40//   {
41//     ScopedLock<std::string> locked_string(shared_string);
42//     *locked_string += " world";
43//   }
44//
45template <typename T>
46class Guarded {
47  static_assert(!std::is_pointer<T>::value, "T must not be a raw pointer");
48
49 public:
50  explicit Guarded() : guarded_() {
51  }
52
53  template <typename U = T>
54  explicit Guarded(const T& guarded,
55                   typename std::enable_if<std::is_copy_constructible<U>::value>::type = void())
56      : guarded_(guarded) {
57  }
58
59  template <typename U = T>
60  explicit Guarded(T&& guarded,
61                   typename std::enable_if<std::is_move_constructible<U>::value>::type = void())
62      : guarded_(std::move(guarded)) {
63  }
64
65 private:
66  friend class ScopedLock<T>;
67
68  DISALLOW_COPY_AND_ASSIGN(Guarded);
69
70  std::mutex lock_;
71  T guarded_;
72};
73
74template <typename T>
75class ScopedLock {
76 public:
77  explicit ScopedLock(Guarded<T>& guarded) : lock_(guarded.lock_), guarded_(guarded.guarded_) {
78  }
79
80  T& operator*() {
81    return guarded_;
82  }
83
84  T* operator->() {
85    return &guarded_;
86  }
87
88  T* get() {
89    return &guarded_;
90  }
91
92 private:
93  DISALLOW_COPY_AND_ASSIGN(ScopedLock);
94
95  std::lock_guard<std::mutex> lock_;
96  T& guarded_;
97};
98
99}  // namespace android
100
101#endif  // ANDROIDFW_MUTEXGUARD_H
102