Baton::ready, a const variant of try_wait
[folly.git] / folly / SynchronizedPtr.h
1 /*
2  * Copyright 2004-present Facebook, Inc.
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 #pragma once
18
19 #include <folly/Synchronized.h>
20
21 /* `SynchronizedPtr` is a variation on the `Synchronized` idea that's useful for
22  * some cases where you want to protect a pointed-to object (or an object within
23  * some pointer-like wrapper). If you would otherwise need to use
24  * `Synchronized<smart_ptr<Synchronized<T>>>` consider using
25  * `SynchronizedPtr<smart_ptr<T>>`as it is a bit easier to use and it works when
26  * you want the `T` object at runtime to actually a subclass of `T`.
27  *
28  * You can access the contained `T` with `.rlock()`, and `.wlock()`, and the
29  * pointer or pointer-like wrapper with `.wlockPointer()`. The corresponding
30  * `with...` methods take a callback, invoke it with a `T const&`, `T&` or
31  * `smart_ptr<T>&` respectively, and return the callback's result.
32  */
33 namespace folly {
34 template <typename LockHolder, typename Element>
35 struct SynchronizedPtrLockedElement {
36   explicit SynchronizedPtrLockedElement(LockHolder&& holder)
37       : holder_(std::move(holder)) {}
38
39   Element& operator*() const {
40     return **holder_;
41   }
42
43   Element* operator->() const {
44     return &**holder_;
45   }
46
47   explicit operator bool() const {
48     return static_cast<bool>(*holder_);
49   }
50
51  private:
52   LockHolder holder_;
53 };
54
55 template <typename PointerType, typename MutexType = SharedMutex>
56 class SynchronizedPtr {
57   using inner_type = Synchronized<PointerType, MutexType>;
58   inner_type inner_;
59
60  public:
61   using pointer_type = PointerType;
62   using element_type = typename std::pointer_traits<pointer_type>::element_type;
63   using const_element_type = typename std::add_const<element_type>::type;
64   using read_locked_element = SynchronizedPtrLockedElement<
65       typename inner_type::ConstLockedPtr,
66       const_element_type>;
67   using write_locked_element = SynchronizedPtrLockedElement<
68       typename inner_type::LockedPtr,
69       element_type>;
70   using write_locked_pointer = typename inner_type::LockedPtr;
71
72   template <typename... Args>
73   explicit SynchronizedPtr(Args... args)
74       : inner_(std::forward<Args>(args)...) {}
75
76   SynchronizedPtr() = default;
77   SynchronizedPtr(SynchronizedPtr const&) = default;
78   SynchronizedPtr(SynchronizedPtr&&) = default;
79   SynchronizedPtr& operator=(SynchronizedPtr const&) = default;
80   SynchronizedPtr& operator=(SynchronizedPtr&&) = default;
81
82   // Methods to provide appropriately locked and const-qualified access to the
83   // element.
84
85   read_locked_element rlock() const {
86     return read_locked_element(inner_.rlock());
87   }
88
89   template <class Function>
90   auto withRLock(Function&& function) const {
91     return function(*rlock());
92   }
93
94   write_locked_element wlock() {
95     return write_locked_element(inner_.wlock());
96   }
97
98   template <class Function>
99   auto withWLock(Function&& function) {
100     return function(*wlock());
101   }
102
103   // Methods to provide write-locked access to the pointer. We deliberately make
104   // it difficult to get a read-locked pointer because that provides read-locked
105   // non-const access to the element, and the purpose of this class is to
106   // discourage that.
107   write_locked_pointer wlockPointer() {
108     return inner_.wlock();
109   }
110
111   template <class Function>
112   auto withWLockPointer(Function&& function) {
113     return function(*wlockPointer());
114   }
115 };
116 } // namespace folly