added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / util / atomic_shared_ptr.hpp
1 ////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright 2016 Realm Inc.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 ////////////////////////////////////////////////////////////////////////////
18
19 #ifndef REALM_ATOMIC_SHARED_PTR_HPP
20 #define REALM_ATOMIC_SHARED_PTR_HPP
21
22 #include <atomic>
23 #include <memory>
24 #include <mutex>
25
26 namespace realm {
27 namespace _impl {
28
29 // Check if std::atomic_load has an overload taking a std::shared_ptr, and set
30 // HasAtomicPtrOps to either true_type or false_type
31
32 template<typename... Ts> struct make_void { typedef void type; };
33 template<typename... Ts> using void_t = typename make_void<Ts...>::type;
34
35 template<typename, typename = void_t<>>
36 struct HasAtomicPtrOps : std::false_type { };
37
38 template<class T>
39 struct HasAtomicPtrOps<T, void_t<decltype(std::atomic_load(std::declval<T*>()))>> : std::true_type { };
40 } // namespace _impl
41
42 namespace util {
43 // A wrapper for std::shared_ptr that enables sharing a shared_ptr instance
44 // (and not just a thing *pointed to* by a shared_ptr) between threads. Is
45 // lock-free iff the underlying shared_ptr implementation supports atomic
46 // operations. Currently the only implemented operation other than copy/move
47 // construction/assignment is exchange().
48 template<typename T, bool = _impl::HasAtomicPtrOps<std::shared_ptr<T>>::value>
49 class AtomicSharedPtr;
50
51 template<typename T>
52 class AtomicSharedPtr<T, true> {
53 public:
54     AtomicSharedPtr() = default;
55     AtomicSharedPtr(std::shared_ptr<T> ptr) : m_ptr(std::move(ptr)) { }
56
57     AtomicSharedPtr(AtomicSharedPtr const& ptr) : m_ptr(std::atomic_load(&ptr.m_ptr)) { }
58     AtomicSharedPtr(AtomicSharedPtr&& ptr) : m_ptr(std::atomic_exchange(&ptr.m_ptr, {})) { }
59
60     AtomicSharedPtr& operator=(AtomicSharedPtr const& ptr)
61     {
62         if (&ptr != this) {
63             std::atomic_store(&m_ptr, std::atomic_load(&ptr.m_ptr));
64         }
65         return *this;
66     }
67
68     AtomicSharedPtr& operator=(AtomicSharedPtr&& ptr)
69     {
70         std::atomic_store(&m_ptr, std::atomic_exchange(&ptr.m_ptr, {}));
71         return *this;
72     }
73
74     std::shared_ptr<T> exchange(std::shared_ptr<T> ptr)
75     {
76         return std::atomic_exchange(&m_ptr, std::move(ptr));
77     }
78
79     std::shared_ptr<T> load() const noexcept
80     {
81         return std::atomic_load(&m_ptr);
82     }
83
84 private:
85     std::shared_ptr<T> m_ptr = nullptr;
86 };
87
88 template<typename T>
89 class AtomicSharedPtr<T, false> {
90 public:
91     AtomicSharedPtr() = default;
92     AtomicSharedPtr(std::shared_ptr<T> ptr) : m_ptr(std::move(ptr)) { }
93
94     AtomicSharedPtr(AtomicSharedPtr const& ptr)
95     {
96         std::lock_guard<std::mutex> lock(ptr.m_mutex);
97         m_ptr = ptr.m_ptr;
98     }
99     AtomicSharedPtr(AtomicSharedPtr&& ptr)
100     {
101         std::lock_guard<std::mutex> lock(ptr.m_mutex);
102         m_ptr = std::move(ptr.m_ptr);
103     }
104
105     AtomicSharedPtr& operator=(AtomicSharedPtr const& ptr)
106     {
107         if (&ptr != this) {
108             // std::lock() ensures that these are locked in a consistent order
109             // to avoid deadlock
110             std::lock(m_mutex, ptr.m_mutex);
111             m_ptr = ptr.m_ptr;
112             m_mutex.unlock();
113             ptr.m_mutex.unlock();
114         }
115         return *this;
116     }
117
118     AtomicSharedPtr& operator=(AtomicSharedPtr&& ptr)
119     {
120         std::lock(m_mutex, ptr.m_mutex);
121         m_ptr = std::move(ptr.m_ptr);
122         m_mutex.unlock();
123         ptr.m_mutex.unlock();
124         return *this;
125     }
126
127     std::shared_ptr<T> exchange(std::shared_ptr<T> ptr)
128     {
129         std::lock_guard<std::mutex> lock(m_mutex);
130         m_ptr.swap(ptr);
131         return ptr;
132     }
133
134     std::shared_ptr<T> load() const noexcept
135     {
136         std::lock_guard<std::mutex> lock(m_mutex);
137         return m_ptr;
138     }
139
140 private:
141     mutable std::mutex m_mutex;
142     std::shared_ptr<T> m_ptr = nullptr;
143 };
144
145 }
146 }
147
148 #endif // REALM_ATOMIC_SHARED_PTR_HPP