GCC Code Coverage Report


Directory: ./
File: UniqueRef.hpp
Date: 2026-03-21 20:51:59
Exec Total Coverage
Lines: 20 20 100.0%
Functions: 20 20 100.0%
Branches: 4 7 57.1%

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