2024-05-31 22:59:00 -04:00
|
|
|
#ifndef RFL_BOX_HPP_
|
|
|
|
#define RFL_BOX_HPP_
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
#include "Result.hpp"
|
|
|
|
|
|
|
|
namespace rfl {
|
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// The Box class behaves very similarly to the unique_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 Box {
|
|
|
|
public:
|
|
|
|
/// The only way of creating new boxes is
|
|
|
|
/// Box<T>::make(...).
|
|
|
|
template <class... Args>
|
|
|
|
static Box<T> make(Args&&... _args) {
|
|
|
|
return Box<T>(std::make_unique<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 unique_ptrs as well, in which case it will
|
|
|
|
/// return an Error, if the unique_ptr is not set.
|
|
|
|
static Result<Box<T>> make(std::unique_ptr<T>&& _ptr) {
|
2024-06-09 18:55:00 -04:00
|
|
|
if (!_ptr) {
|
|
|
|
return Error("std::unique_ptr was a nullptr.");
|
|
|
|
}
|
2024-06-08 14:10:59 -04:00
|
|
|
return Box<T>(std::move(_ptr));
|
2024-05-31 22:59:00 -04:00
|
|
|
}
|
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
Box() : ptr_(std::make_unique<T>()) {}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
Box(const Box<T>& _other) = delete;
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
Box(Box<T>&& _other) = default;
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
template <class U>
|
2024-06-16 00:13:15 -04:00
|
|
|
Box(Box<U>&& _other) noexcept : ptr_(std::forward<std::unique_ptr<U>>(_other.ptr())) {}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
~Box() = 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
|
|
|
/// Copy assignment operator
|
|
|
|
Box<T>& operator=(const Box<T>& _other) = delete;
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Move assignment operator
|
|
|
|
Box<T>& operator=(Box<T>&& _other) noexcept = default;
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Move assignment operator
|
|
|
|
template <class U>
|
|
|
|
Box<T>& operator=(Box<U>&& _other) noexcept {
|
|
|
|
ptr_ = std::forward<std::unique_ptr<U>>(_other.ptr());
|
|
|
|
return *this;
|
|
|
|
}
|
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 unique_ptr
|
|
|
|
std::unique_ptr<T>& ptr() { return ptr_; }
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Returns the underlying unique_ptr
|
|
|
|
const std::unique_ptr<T>& ptr() const { return ptr_; }
|
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 Box(std::unique_ptr<T>&& _ptr) : ptr_(std::move(_ptr)) {}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
private:
|
|
|
|
/// The underlying unique_ptr_
|
|
|
|
std::unique_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_box(Args&&... _args) {
|
|
|
|
return Box<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 Box<T1>& _b1, const Box<T2>& _b2) {
|
|
|
|
return _b1.ptr() <=> _b2.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 Box<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::Box<T>> {
|
2024-06-16 00:13:15 -04:00
|
|
|
size_t operator()(const rfl::Box<T>& _b) const { return hash<unique_ptr<T>>()(_b.ptr()); }
|
2024-06-08 14:10:59 -04:00
|
|
|
};
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
template <class T>
|
|
|
|
inline void swap(rfl::Box<T>& _b1, rfl::Box<T>& _b2) {
|
|
|
|
return swap(_b1.ptr(), _b2.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
|
|
|
|
|
|
|
#endif
|