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 
25 namespace android {
26 
27 template <typename T>
28 class 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 //
45 template <typename T>
46 class Guarded {
47   static_assert(!std::is_pointer<T>::value, "T must not be a raw pointer");
48 
49  public:
Guarded()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())
guarded_(guarded)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())
guarded_(std::move (guarded))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 
74 template <typename T>
75 class ScopedLock {
76  public:
ScopedLock(Guarded<T> & guarded)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 
get()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