File: Box.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 (125 lines) | stat: -rw-r--r-- 3,156 bytes parent folder | download
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
#ifndef RFL_BOX_HPP_
#define RFL_BOX_HPP_

#include <memory>
#include <stdexcept>

#include "Result.hpp"

namespace rfl {

/// 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)...));
  }

  /// 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) {
    if (!_ptr) {
      return error("std::unique_ptr was a nullptr.");
    }
    return Box<T>(std::move(_ptr));
  }

  Box() : ptr_(std::make_unique<T>()) {}

  Box(const Box<T>& _other) = delete;

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

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

  ~Box() = default;

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

  /// Copy assignment operator
  Box<T>& operator=(const Box<T>& _other) = delete;

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

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

  /// 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 unique_ptr
  std::unique_ptr<T>& ptr() { return ptr_; }

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

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

 private:
  /// The underlying unique_ptr_
  std::unique_ptr<T> ptr_;
};

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

template <class T1, class T2>
inline auto operator<=>(const Box<T1>& _b1, const Box<T2>& _b2) {
  return _b1.ptr() <=> _b2.ptr();
}

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

}  // namespace rfl

namespace std {

template <class T>
struct hash<rfl::Box<T>> {
  size_t operator()(const rfl::Box<T>& _b) const {
    return hash<unique_ptr<T>>()(_b.ptr());
  }
};

template <class T>
inline void swap(rfl::Box<T>& _b1, rfl::Box<T>& _b2) {
  return swap(_b1.ptr(), _b2.ptr());
}

}  // namespace std

#endif