GCC Code Coverage Report


Directory: ./
File: SharedRef.hpp
Date: 2026-03-21 20:51:59
Exec Total Coverage
Lines: 22 22 100.0%
Functions: 23 24 95.8%
Branches: 3 6 50.0%

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