1 /*************************************************************************
3 * Copyright 2016 Realm Inc.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 **************************************************************************/
19 #ifndef REALM_UTIL_BIND_PTR_HPP
20 #define REALM_UTIL_BIND_PTR_HPP
27 #include <realm/util/features.h>
28 #include <realm/util/assert.hpp>
41 /// A generic intrusive smart pointer that binds itself explicitely to
42 /// the target object.
44 /// This class is agnostic towards what 'binding' means for the target
45 /// object, but a common use is 'reference counting'. See RefCountBase
46 /// for an example of that.
48 /// This smart pointer implementation assumes that the target object
49 /// destructor never throws.
51 class bind_ptr : public bind_ptr_base {
53 constexpr bind_ptr() noexcept
62 explicit bind_ptr(T* p) noexcept
67 explicit bind_ptr(U* p) noexcept
72 bind_ptr(T* p, adopt_tag) noexcept
77 bind_ptr(U* p, adopt_tag) noexcept
83 bind_ptr(const bind_ptr& p) noexcept
88 bind_ptr(const bind_ptr<U>& p) noexcept
94 bind_ptr& operator=(const bind_ptr& p) noexcept
96 bind_ptr(p).swap(*this);
100 bind_ptr& operator=(const bind_ptr<U>& p) noexcept
102 bind_ptr(p).swap(*this);
107 bind_ptr(bind_ptr&& p) noexcept
112 bind_ptr(bind_ptr<U>&& p) noexcept
118 bind_ptr& operator=(bind_ptr&& p) noexcept
120 bind_ptr(std::move(p)).swap(*this);
124 bind_ptr& operator=(bind_ptr<U>&& p) noexcept
126 bind_ptr(std::move(p)).swap(*this);
133 bool operator==(const bind_ptr<U>&) const noexcept;
136 bool operator==(U*) const noexcept;
139 bool operator!=(const bind_ptr<U>&) const noexcept;
142 bool operator!=(U*) const noexcept;
145 bool operator<(const bind_ptr<U>&) const noexcept;
148 bool operator<(U*) const noexcept;
151 bool operator>(const bind_ptr<U>&) const noexcept;
154 bool operator>(U*) const noexcept;
157 bool operator<=(const bind_ptr<U>&) const noexcept;
160 bool operator<=(U*) const noexcept;
163 bool operator>=(const bind_ptr<U>&) const noexcept;
166 bool operator>=(U*) const noexcept;
170 T& operator*() const noexcept
174 T* operator->() const noexcept
179 explicit operator bool() const noexcept
184 T* get() const noexcept
188 void reset() noexcept
190 bind_ptr().swap(*this);
192 void reset(T* p) noexcept
194 bind_ptr(p).swap(*this);
197 void reset(U* p) noexcept
199 bind_ptr(p).swap(*this);
202 T* release() noexcept
209 void swap(bind_ptr& p) noexcept
211 std::swap(m_ptr, p.m_ptr);
213 friend void swap(bind_ptr& a, bind_ptr& b) noexcept
219 struct casting_move_tag {
222 bind_ptr(bind_ptr<U>* p, casting_move_tag) noexcept
223 : m_ptr(static_cast<T*>(p->release()))
230 void bind(T* p) noexcept
236 void unbind() noexcept
243 friend class bind_ptr;
247 template <class C, class T, class U>
248 inline std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& out, const bind_ptr<U>& p)
250 out << static_cast<const void*>(p.get());
257 template <class T, class U>
258 bool operator==(T*, const bind_ptr<U>&) noexcept;
259 template <class T, class U>
260 bool operator!=(T*, const bind_ptr<U>&) noexcept;
261 template <class T, class U>
262 bool operator<(T*, const bind_ptr<U>&) noexcept;
263 template <class T, class U>
264 bool operator>(T*, const bind_ptr<U>&) noexcept;
265 template <class T, class U>
266 bool operator<=(T*, const bind_ptr<U>&) noexcept;
267 template <class T, class U>
268 bool operator>=(T*, const bind_ptr<U>&) noexcept;
272 /// Polymorphic convenience base class for reference counting objects.
274 /// Together with bind_ptr, this class delivers simple instrusive
275 /// reference counting.
280 RefCountBase() noexcept
284 virtual ~RefCountBase() noexcept
286 REALM_ASSERT(m_ref_count == 0);
289 RefCountBase(const RefCountBase&) = delete;
290 RefCountBase(RefCountBase&&) = delete;
292 void operator=(const RefCountBase&) = delete;
293 void operator=(RefCountBase&&) = delete;
296 void bind_ptr() const noexcept
300 void unbind_ptr() const noexcept
302 if (--m_ref_count == 0)
307 mutable unsigned long m_ref_count;
310 friend class bind_ptr;
314 /// Same as RefCountBase, but this one makes the copying of, and the
315 /// destruction of counted references thread-safe.
319 class AtomicRefCountBase {
321 AtomicRefCountBase() noexcept
325 virtual ~AtomicRefCountBase() noexcept
327 REALM_ASSERT(m_ref_count == 0);
330 AtomicRefCountBase(const AtomicRefCountBase&) = delete;
331 AtomicRefCountBase(AtomicRefCountBase&&) = delete;
333 void operator=(const AtomicRefCountBase&) = delete;
334 void operator=(AtomicRefCountBase&&) = delete;
337 // FIXME: Operators ++ and -- as used below use
338 // std::memory_order_seq_cst. This can be optimized.
339 void bind_ptr() const noexcept
343 void unbind_ptr() const noexcept
345 if (--m_ref_count == 0) {
351 mutable std::atomic<unsigned long> m_ref_count;
354 friend class bind_ptr;
362 bool bind_ptr<T>::operator==(const bind_ptr<U>& p) const noexcept
364 return m_ptr == p.m_ptr;
369 bool bind_ptr<T>::operator==(U* p) const noexcept
376 bool bind_ptr<T>::operator!=(const bind_ptr<U>& p) const noexcept
378 return m_ptr != p.m_ptr;
383 bool bind_ptr<T>::operator!=(U* p) const noexcept
390 bool bind_ptr<T>::operator<(const bind_ptr<U>& p) const noexcept
392 return m_ptr < p.m_ptr;
397 bool bind_ptr<T>::operator<(U* p) const noexcept
404 bool bind_ptr<T>::operator>(const bind_ptr<U>& p) const noexcept
406 return m_ptr > p.m_ptr;
411 bool bind_ptr<T>::operator>(U* p) const noexcept
418 bool bind_ptr<T>::operator<=(const bind_ptr<U>& p) const noexcept
420 return m_ptr <= p.m_ptr;
425 bool bind_ptr<T>::operator<=(U* p) const noexcept
432 bool bind_ptr<T>::operator>=(const bind_ptr<U>& p) const noexcept
434 return m_ptr >= p.m_ptr;
439 bool bind_ptr<T>::operator>=(U* p) const noexcept
444 template <class T, class U>
445 bool operator==(T* a, const bind_ptr<U>& b) noexcept
450 template <class T, class U>
451 bool operator!=(T* a, const bind_ptr<U>& b) noexcept
456 template <class T, class U>
457 bool operator<(T* a, const bind_ptr<U>& b) noexcept
462 template <class T, class U>
463 bool operator>(T* a, const bind_ptr<U>& b) noexcept
468 template <class T, class U>
469 bool operator<=(T* a, const bind_ptr<U>& b) noexcept
474 template <class T, class U>
475 bool operator>=(T* a, const bind_ptr<U>& b) noexcept
484 #endif // REALM_UTIL_BIND_PTR_HPP