| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | #include "compat/gsl14.hpp" | ||
| 3 | #include <memory> | ||
| 4 | |||
| 5 | // Forward declarations. | ||
| 6 | template <typename T> | ||
| 7 | class SharedRef; | ||
| 8 | |||
| 9 | template <typename T> | ||
| 10 | void swap(SharedRef<T>&, SharedRef<T>&) noexcept; | ||
| 11 | |||
| 12 | template <typename T, typename... Args> | ||
| 13 | SharedRef<T> makeSharedRef(Args&&...); | ||
| 14 | |||
| 15 | // Inspired by std::reference_wrapper, but holds a shared_ptr | ||
| 16 | // instead of a raw pointer. | ||
| 17 | // A moved-from object is empty, but can be deleted or assigned to. | ||
| 18 | // See: [A move operation should move and leave its source in a valid state](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-move-semantic) | ||
| 19 | template <typename T> | ||
| 20 | class SharedRef { | ||
| 21 | public: | ||
| 22 | using type = T; | ||
| 23 | SharedRef(T*) noexcept; | ||
| 24 | SharedRef(std::shared_ptr<T>) noexcept; | ||
| 25 | operator T&(); | ||
| 26 | operator const T&() const; | ||
| 27 | T& get(); | ||
| 28 | [[nodiscard]] const T& get() const; | ||
| 29 | operator std::shared_ptr<T>(); | ||
| 30 | operator std::shared_ptr<const T>() const; | ||
| 31 | std::shared_ptr<T> share(); | ||
| 32 | [[nodiscard]] std::shared_ptr<const T> share() const; | ||
| 33 | 10 | SharedRef(const SharedRef&) = default; // copy constructor | |
| 34 | 12 | SharedRef(SharedRef&&) noexcept = default; // move constructor | |
| 35 | 1 | SharedRef& operator=(const SharedRef&) = default; // copy assignment | |
| 36 | 10 | SharedRef& operator=(SharedRef&&) noexcept = default; // move assignment | |
| 37 | 52 | virtual ~SharedRef() noexcept = default; // destructor | |
| 38 | friend void swap<>(SharedRef&, SharedRef&) noexcept; // non-member swap | ||
| 39 | |||
| 40 | // Unfortunately, we cannot overload operator . (dot) | ||
| 41 | // See [Operator Dot](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4477.pdf) | ||
| 42 | // T& operator.(); | ||
| 43 | private: | ||
| 44 | SharedRef() noexcept = delete; // no default constructor | ||
| 45 | |||
| 46 | std::shared_ptr<T> p_; // never null (unless moved from) | ||
| 47 | }; | ||
| 48 | |||
| 49 | template <typename T> | ||
| 50 | 4 | SharedRef<T>::SharedRef(T* p) noexcept : p_{p} { | |
| 51 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | Expects(p != nullptr); |
| 52 | 4 | } | |
| 53 | |||
| 54 | template <typename T> | ||
| 55 | 44 | SharedRef<T>::SharedRef(std::shared_ptr<T> p) noexcept : p_{std::move(p)} { | |
| 56 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 11 times.
|
22 | Expects(p_ != nullptr); |
| 57 | 22 | } | |
| 58 | |||
| 59 | template <typename T> | ||
| 60 | 104 | SharedRef<T>::operator T&() { | |
| 61 | 104 | return *p_; | |
| 62 | } | ||
| 63 | |||
| 64 | template <typename T> | ||
| 65 | 36 | SharedRef<T>::operator const T&() const { | |
| 66 | 36 | return *p_; | |
| 67 | } | ||
| 68 | |||
| 69 | template <typename T> | ||
| 70 | T& SharedRef<T>::get() { | ||
| 71 | return *p_; | ||
| 72 | } | ||
| 73 | |||
| 74 | template <typename T> | ||
| 75 | 6 | const T& SharedRef<T>::get() const { | |
| 76 | 6 | return *p_; | |
| 77 | } | ||
| 78 | |||
| 79 | template <typename T> | ||
| 80 | SharedRef<T>::operator std::shared_ptr<T>() { | ||
| 81 | return p_; | ||
| 82 | } | ||
| 83 | |||
| 84 | template <typename T> | ||
| 85 | SharedRef<T>::operator std::shared_ptr<const T>() const { | ||
| 86 | return p_; | ||
| 87 | } | ||
| 88 | |||
| 89 | template <typename T> | ||
| 90 | std::shared_ptr<T> SharedRef<T>::share() { | ||
| 91 | return p_; | ||
| 92 | } | ||
| 93 | |||
| 94 | template <typename T> | ||
| 95 | std::shared_ptr<const T> SharedRef<T>::share() const { | ||
| 96 | return p_; | ||
| 97 | } | ||
| 98 | |||
| 99 | // non-member swap | ||
| 100 | template <typename T> | ||
| 101 | 2 | void swap(SharedRef<T>& left, SharedRef<T>& right) noexcept { | |
| 102 | using std::swap; // enable Argument Dependent Lookup | ||
| 103 | 2 | swap(left.p_, right.p_); | |
| 104 | 2 | } | |
| 105 | |||
| 106 | template <typename T, typename... Args> | ||
| 107 | 16 | SharedRef<T> makeSharedRef(Args&&... args) { | |
| 108 |
1/2✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
48 | return std::make_shared<T>(std::forward<Args>(args)...); |
| 109 | } | ||
| 110 |