draconisplusplus/include/rfl/Ref.hpp

144 lines
3.9 KiB
C++
Raw Normal View History

2024-05-31 22:59:00 -04:00
#ifndef RFL_REF_HPP_
#define RFL_REF_HPP_
#include <memory>
#include <stdexcept>
#include "Result.hpp"
namespace rfl {
2024-06-08 14:10:59 -04:00
/// 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)...));
}
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
/// 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));
2024-05-31 22:59:00 -04:00
}
2024-06-08 14:10:59 -04:00
/// 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);
2024-05-31 22:59:00 -04:00
}
2024-06-08 14:10:59 -04:00
Ref() : ptr_(std::make_shared<T>()) {}
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
Ref(const Ref<T>& _other) = default;
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
Ref(Ref<T>&& _other) = default;
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
template <class U>
Ref(const Ref<U>& _other) : ptr_(_other.ptr()) {}
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
template <class U>
Ref(Ref<U>&& _other) noexcept
: ptr_(std::forward<std::shared_ptr<U>>(_other.ptr())) {}
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
~Ref() = default;
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
/// Returns a pointer to the underlying object
T* get() const { return ptr_.get(); }
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
/// Returns the underlying object.
T& operator*() { return *ptr_; }
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
/// Returns the underlying object.
T& operator*() const { return *ptr_; }
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
/// Returns the underlying object.
T* operator->() { return ptr_.get(); }
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
/// Returns the underlying object.
T* operator->() const { return ptr_.get(); }
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
/// Returns the underlying shared_ptr
std::shared_ptr<T>& ptr() { return ptr_; }
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
/// Returns the underlying shared_ptr
const std::shared_ptr<T>& ptr() const { return ptr_; }
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
/// Copy assignment operator.
template <class U>
Ref<T>& operator=(const Ref<U>& _other) {
ptr_ = _other.ptr();
return *this;
}
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
/// Move assignment operator
template <class U>
Ref<T>& operator=(Ref<U>&& _other) noexcept {
ptr_ = std::forward<std::shared_ptr<U>>(_other.ptr());
return *this;
}
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
/// Move assignment operator
Ref<T>& operator=(Ref<T>&& _other) noexcept = default;
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
/// Copy assignment operator
Ref<T>& operator=(const Ref<T>& _other) = default;
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
private:
/// Only make is allowed to use this constructor.
explicit Ref(std::shared_ptr<T>&& _ptr) : ptr_(std::move(_ptr)) {}
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
/// Only make is allowed to use this constructor.
explicit Ref(const std::shared_ptr<T>& _ptr) : ptr_(_ptr) {}
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
private:
/// The underlying shared_ptr_
std::shared_ptr<T> ptr_;
};
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
/// Generates a new Ref<T>.
template <class T, class... Args>
auto make_ref(Args&&... _args) {
return Ref<T>::make(std::forward<Args>(_args)...);
}
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
template <class T1, class T2>
inline auto operator<=>(const Ref<T1>& _t1, const Ref<T2>& _t2) {
return _t1.ptr() <=> _t2.ptr();
}
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
template <class CharT, class Traits, class T>
2024-06-08 15:53:06 -04:00
inline std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& _os, const Ref<T>& _b) {
2024-06-08 14:10:59 -04:00
_os << _b.get();
return _os;
}
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
} // namespace rfl
2024-05-31 22:59:00 -04:00
namespace std {
2024-06-08 14:10:59 -04:00
template <class T>
struct hash<rfl::Ref<T>> {
size_t operator()(const rfl::Ref<T>& _r) const {
return hash<shared_ptr<T>>()(_r.ptr());
}
};
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
template <class T>
inline void swap(rfl::Ref<T>& _r1, rfl::Ref<T>& _r2) {
return swap(_r1.ptr(), _r2.ptr());
}
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
} // namespace std
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
#endif // RFL_REF_HPP_