added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / util / atomic_shared_ptr.hpp
diff --git a/iOS/Pods/Realm/include/util/atomic_shared_ptr.hpp b/iOS/Pods/Realm/include/util/atomic_shared_ptr.hpp
new file mode 100644 (file)
index 0000000..b4eb52f
--- /dev/null
@@ -0,0 +1,148 @@
+////////////////////////////////////////////////////////////////////////////
+//
+// Copyright 2016 Realm Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////
+
+#ifndef REALM_ATOMIC_SHARED_PTR_HPP
+#define REALM_ATOMIC_SHARED_PTR_HPP
+
+#include <atomic>
+#include <memory>
+#include <mutex>
+
+namespace realm {
+namespace _impl {
+
+// Check if std::atomic_load has an overload taking a std::shared_ptr, and set
+// HasAtomicPtrOps to either true_type or false_type
+
+template<typename... Ts> struct make_void { typedef void type; };
+template<typename... Ts> using void_t = typename make_void<Ts...>::type;
+
+template<typename, typename = void_t<>>
+struct HasAtomicPtrOps : std::false_type { };
+
+template<class T>
+struct HasAtomicPtrOps<T, void_t<decltype(std::atomic_load(std::declval<T*>()))>> : std::true_type { };
+} // namespace _impl
+
+namespace util {
+// A wrapper for std::shared_ptr that enables sharing a shared_ptr instance
+// (and not just a thing *pointed to* by a shared_ptr) between threads. Is
+// lock-free iff the underlying shared_ptr implementation supports atomic
+// operations. Currently the only implemented operation other than copy/move
+// construction/assignment is exchange().
+template<typename T, bool = _impl::HasAtomicPtrOps<std::shared_ptr<T>>::value>
+class AtomicSharedPtr;
+
+template<typename T>
+class AtomicSharedPtr<T, true> {
+public:
+    AtomicSharedPtr() = default;
+    AtomicSharedPtr(std::shared_ptr<T> ptr) : m_ptr(std::move(ptr)) { }
+
+    AtomicSharedPtr(AtomicSharedPtr const& ptr) : m_ptr(std::atomic_load(&ptr.m_ptr)) { }
+    AtomicSharedPtr(AtomicSharedPtr&& ptr) : m_ptr(std::atomic_exchange(&ptr.m_ptr, {})) { }
+
+    AtomicSharedPtr& operator=(AtomicSharedPtr const& ptr)
+    {
+        if (&ptr != this) {
+            std::atomic_store(&m_ptr, std::atomic_load(&ptr.m_ptr));
+        }
+        return *this;
+    }
+
+    AtomicSharedPtr& operator=(AtomicSharedPtr&& ptr)
+    {
+        std::atomic_store(&m_ptr, std::atomic_exchange(&ptr.m_ptr, {}));
+        return *this;
+    }
+
+    std::shared_ptr<T> exchange(std::shared_ptr<T> ptr)
+    {
+        return std::atomic_exchange(&m_ptr, std::move(ptr));
+    }
+
+    std::shared_ptr<T> load() const noexcept
+    {
+        return std::atomic_load(&m_ptr);
+    }
+
+private:
+    std::shared_ptr<T> m_ptr = nullptr;
+};
+
+template<typename T>
+class AtomicSharedPtr<T, false> {
+public:
+    AtomicSharedPtr() = default;
+    AtomicSharedPtr(std::shared_ptr<T> ptr) : m_ptr(std::move(ptr)) { }
+
+    AtomicSharedPtr(AtomicSharedPtr const& ptr)
+    {
+        std::lock_guard<std::mutex> lock(ptr.m_mutex);
+        m_ptr = ptr.m_ptr;
+    }
+    AtomicSharedPtr(AtomicSharedPtr&& ptr)
+    {
+        std::lock_guard<std::mutex> lock(ptr.m_mutex);
+        m_ptr = std::move(ptr.m_ptr);
+    }
+
+    AtomicSharedPtr& operator=(AtomicSharedPtr const& ptr)
+    {
+        if (&ptr != this) {
+            // std::lock() ensures that these are locked in a consistent order
+            // to avoid deadlock
+            std::lock(m_mutex, ptr.m_mutex);
+            m_ptr = ptr.m_ptr;
+            m_mutex.unlock();
+            ptr.m_mutex.unlock();
+        }
+        return *this;
+    }
+
+    AtomicSharedPtr& operator=(AtomicSharedPtr&& ptr)
+    {
+        std::lock(m_mutex, ptr.m_mutex);
+        m_ptr = std::move(ptr.m_ptr);
+        m_mutex.unlock();
+        ptr.m_mutex.unlock();
+        return *this;
+    }
+
+    std::shared_ptr<T> exchange(std::shared_ptr<T> ptr)
+    {
+        std::lock_guard<std::mutex> lock(m_mutex);
+        m_ptr.swap(ptr);
+        return ptr;
+    }
+
+    std::shared_ptr<T> load() const noexcept
+    {
+        std::lock_guard<std::mutex> lock(m_mutex);
+        return m_ptr;
+    }
+
+private:
+    mutable std::mutex m_mutex;
+    std::shared_ptr<T> m_ptr = nullptr;
+};
+
+}
+}
+
+#endif // REALM_ATOMIC_SHARED_PTR_HPP