File: Ref.hpp

package info (click to toggle)
reflect-cpp 0.18.0%2Bds-3
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 12,524 kB
  • sloc: cpp: 44,484; python: 131; makefile: 30; sh: 3
file content (147 lines) | stat: -rw-r--r-- 3,837 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#ifndef RFL_REF_HPP_
#define RFL_REF_HPP_

#include <memory>
#include <stdexcept>

#include "Result.hpp"

namespace rfl {

/// The Ref class behaves very similarly to the shared_ptr, but unlike the
/// unique_ptr, it is 100% guaranteed to be filled at all times (unless the user
/// tries to access it after calling std::move does something else that is
/// clearly bad practice).
template <class T>
class Ref {
 public:
  /// The default way of creating new references is
  /// Ref<T>::make(...) or make_ref<T>(...).
  template <class... Args>
  static Ref<T> make(Args&&... _args) {
    return Ref<T>(std::make_shared<T>(std::forward<Args>(_args)...));
  }

  /// You can generate them from shared_ptrs as well, in which case it will
  /// return an Error, if the shared_ptr is not set.
  static Result<Ref<T>> make(std::shared_ptr<T>&& _ptr) {
    if (!_ptr) {
      return error("std::shared_ptr was a nullptr.");
    }
    return Ref<T>(std::move(_ptr));
  }

  /// You can generate them from shared_ptrs as well, in which case it will
  /// return an Error, if the shared_ptr is not set.
  static Result<Ref<T>> make(const std::shared_ptr<T>& _ptr) {
    if (!_ptr) {
      return error("std::shared_ptr was a nullptr.");
    }
    return Ref<T>(_ptr);
  }

  Ref() : ptr_(std::make_shared<T>()) {}

  Ref(const Ref<T>& _other) = default;

  Ref(Ref<T>&& _other) = default;

  template <class U>
  Ref(const Ref<U>& _other) : ptr_(_other.ptr()) {}

  template <class U>
  Ref(Ref<U>&& _other) noexcept
      : ptr_(std::forward<std::shared_ptr<U>>(_other.ptr())) {}

  ~Ref() = default;

  /// Returns a pointer to the underlying object
  T* get() const { return ptr_.get(); }

  /// Returns the underlying object.
  T& operator*() { return *ptr_; }

  /// Returns the underlying object.
  T& operator*() const { return *ptr_; }

  /// Returns the underlying object.
  T* operator->() { return ptr_.get(); }

  /// Returns the underlying object.
  T* operator->() const { return ptr_.get(); }

  /// Returns the underlying shared_ptr
  std::shared_ptr<T>& ptr() { return ptr_; }

  /// Returns the underlying shared_ptr
  const std::shared_ptr<T>& ptr() const { return ptr_; }

  /// Copy assignment operator.
  template <class U>
  Ref<T>& operator=(const Ref<U>& _other) {
    ptr_ = _other.ptr();
    return *this;
  }

  /// Move assignment operator
  template <class U>
  Ref<T>& operator=(Ref<U>&& _other) noexcept {
    ptr_ = std::forward<std::shared_ptr<U>>(_other.ptr());
    return *this;
  }

  /// Move assignment operator
  Ref<T>& operator=(Ref<T>&& _other) noexcept = default;

  /// Copy assignment operator
  Ref<T>& operator=(const Ref<T>& _other) = default;

 private:
  /// Only make is allowed to use this constructor.
  explicit Ref(std::shared_ptr<T>&& _ptr) : ptr_(std::move(_ptr)) {}

  /// Only make is allowed to use this constructor.
  explicit Ref(const std::shared_ptr<T>& _ptr) : ptr_(_ptr) {}

 private:
  /// The underlying shared_ptr_
  std::shared_ptr<T> ptr_;
};

/// Generates a new Ref<T>.
template <class T, class... Args>
auto make_ref(Args&&... _args) {
  return Ref<T>::make(std::forward<Args>(_args)...);
}

template <class T1, class T2>
inline auto operator<=>(const Ref<T1>& _t1, const Ref<T2>& _t2) {
  return _t1.ptr() <=> _t2.ptr();
}

template <class CharT, class Traits, class T>
inline std::basic_ostream<CharT, Traits>& operator<<(
    std::basic_ostream<CharT, Traits>& _os, const Ref<T>& _b) {
  _os << _b.get();
  return _os;
}

}  // namespace rfl

namespace std {

template <class T>
struct hash<rfl::Ref<T>> {
  size_t operator()(const rfl::Ref<T>& _r) const {
    return hash<shared_ptr<T>>()(_r.ptr());
  }
};

template <class T>
inline void swap(rfl::Ref<T>& _r1, rfl::Ref<T>& _r2) {
  return swap(_r1.ptr(), _r2.ptr());
}

}  // namespace std

#endif  // RFL_REF_HPP_