Skip to content

Commit 04eb064

Browse files
committed
Add Result type
1 parent bd4eabe commit 04eb064

File tree

10 files changed

+1473
-530
lines changed

10 files changed

+1473
-530
lines changed

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ add_library(subspace STATIC
7676
"num/unsigned_integer.h"
7777
"option/__private/is_option_type.h"
7878
"option/option.h"
79+
"result/result.h"
7980
"tuple/__private/storage.h"
8081
"tuple/tuple.h"
8182
"lib/lib.cc"
@@ -129,6 +130,8 @@ add_executable(subspace_unittests
129130
"num/usize_unittest.cc"
130131
"option/option_unittest.cc"
131132
"option/option_types_unittest.cc"
133+
"result/result_unittest.cc"
134+
"result/result_types_unittest.cc"
132135
"tuple/tuple_unittest.cc"
133136
)
134137
set_target_properties(subspace_unittests PROPERTIES LINKER_LANGUAGE CXX)

mem/move.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ concept MoveableForAssign = (NonConstObject<T> && std::is_move_assignable_v<T>);
5252
//
5353
// TODO: Should this be `as_rvalue()`? Kinda technical. `as_...something...()`?
5454
template <NonConstObject T>
55-
sus_always_inline constexpr std::remove_reference_t<T>&& move(T&& t) noexcept {
55+
[[nodiscard]] sus_always_inline constexpr std::remove_reference_t<T>&& move(T&& t) noexcept {
5656
return static_cast<typename std::remove_reference_t<T>&&>(t);
5757
}
5858

mem/relocate.h

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,16 @@ template <class... T>
100100
struct relocate_one_by_memcpy_helper final
101101
: public std::integral_constant<
102102
bool,
103-
(... && relocatable_tag<T>::value(0))
103+
(... &&
104+
(relocatable_tag<T>::value(0)
104105
#if __has_extension(trivially_relocatable)
105-
|| (... && __is_trivially_relocatable(T))
106+
|| __is_trivially_relocatable(T)
106107
#else
107-
|| (... && (std::is_trivially_move_constructible_v<T> &&
108-
std::is_trivially_destructible_v<T>))
108+
|| (std::is_trivially_move_constructible_v<T> &&
109+
std::is_trivially_destructible_v<T>)
109110
#endif
111+
)
112+
)
110113
> {};
111114
// clang-format on
112115

@@ -143,10 +146,12 @@ struct relocate_array_by_memcpy_helper final
143146
} // namespace __private
144147

145148
template <class T>
146-
concept relocate_array_by_memcpy = __private::relocate_array_by_memcpy_helper<T>::value;
149+
concept relocate_array_by_memcpy =
150+
__private::relocate_array_by_memcpy_helper<T>::value;
147151

148152
template <class... T>
149-
concept relocate_one_by_memcpy = __private::relocate_one_by_memcpy_helper<T...>::value;
153+
concept relocate_one_by_memcpy =
154+
__private::relocate_one_by_memcpy_helper<T...>::value;
150155

151156
} // namespace sus::mem
152157

@@ -172,35 +177,31 @@ concept relocate_one_by_memcpy = __private::relocate_one_by_memcpy_helper<T...>:
172177
///
173178
/// To additionally allow the class to be passed in registers, the class can be
174179
/// marked with the `sus_trivial_abi` attribute.
175-
#define sus_class_trivial_relocatable(unsafe_fn) \
176-
static_assert(std::is_same_v<decltype(unsafe_fn), \
177-
const ::sus::marker::UnsafeFnMarker>, \
178-
""); \
179-
template <class SusOuterClassTypeForTriviallyReloc> \
180-
friend struct ::sus::mem::__private::relocatable_tag; \
180+
#define sus_class_trivial_relocatable(unsafe_fn) \
181+
static_assert(std::is_same_v<decltype(unsafe_fn), \
182+
const ::sus::marker::UnsafeFnMarker>); \
183+
template <class SusOuterClassTypeForTriviallyReloc> \
184+
friend struct ::sus::mem::__private::relocatable_tag; \
181185
static constexpr bool SusUnsafeTrivialRelocate = true
182186

183187
/// Mark a class as trivially relocatable based on a compile-time condition.
184-
#define sus_class_trivial_relocatable_value(unsafe_fn, is_trivially_reloc) \
185-
static_assert(std::is_same_v<decltype(unsafe_fn), \
186-
const ::sus::marker::UnsafeFnMarker>, \
187-
""); \
188-
static_assert( \
189-
std::is_same_v<std::remove_cv_t<decltype(is_trivially_reloc)>, bool>, \
190-
""); \
191-
template <class SusOuterClassTypeForTriviallyReloc> \
192-
friend struct ::sus::mem::__private::relocatable_tag; \
188+
#define sus_class_trivial_relocatable_value(unsafe_fn, is_trivially_reloc) \
189+
static_assert(std::is_same_v<decltype(unsafe_fn), \
190+
const ::sus::marker::UnsafeFnMarker>); \
191+
static_assert( \
192+
std::is_same_v<std::remove_cv_t<decltype(is_trivially_reloc)>, bool>); \
193+
template <class SusOuterClassTypeForTriviallyReloc> \
194+
friend struct ::sus::mem::__private::relocatable_tag; \
193195
static constexpr bool SusUnsafeTrivialRelocate = is_trivially_reloc
194196

195197
/// Mark a class as trivially relocatable if all of the types passed as
196198
/// arguments are also marked as such.
197-
#define sus_class_maybe_trivial_relocatable_types(unsafe_fn, ...) \
198-
static_assert(std::is_same_v<decltype(unsafe_fn), \
199-
const ::sus::marker::UnsafeFnMarker>, \
200-
""); \
201-
template <class SusOuterClassTypeForTriviallyReloc> \
202-
friend struct ::sus::mem::__private::relocatable_tag; \
203-
static constexpr bool SusUnsafeTrivialRelocate = \
199+
#define sus_class_maybe_trivial_relocatable_types(unsafe_fn, ...) \
200+
static_assert(std::is_same_v<decltype(unsafe_fn), \
201+
const ::sus::marker::UnsafeFnMarker>); \
202+
template <class SusOuterClassTypeForTriviallyReloc> \
203+
friend struct ::sus::mem::__private::relocatable_tag; \
204+
static constexpr bool SusUnsafeTrivialRelocate = \
204205
::sus::mem::relocate_one_by_memcpy<__VA_ARGS__>
205206

206207
/// Mark a class as unconditionally trivially relocatable while also asserting

mem/relocate_unittest.cc

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,67 +19,72 @@ namespace {
1919
using sus::mem::relocate_array_by_memcpy;
2020
using sus::mem::relocate_one_by_memcpy;
2121

22-
static_assert(relocate_one_by_memcpy<int>, "");
23-
static_assert(relocate_array_by_memcpy<int>, "");
24-
static_assert(relocate_one_by_memcpy<char>, "");
25-
static_assert(relocate_array_by_memcpy<char>, "");
22+
static_assert(relocate_one_by_memcpy<int>);
23+
static_assert(relocate_array_by_memcpy<int>);
24+
static_assert(relocate_one_by_memcpy<char>);
25+
static_assert(relocate_array_by_memcpy<char>);
2626

2727
struct A {};
28-
static_assert(relocate_one_by_memcpy<A>, "");
29-
static_assert(relocate_array_by_memcpy<A>, "");
28+
static_assert(relocate_one_by_memcpy<A>);
29+
static_assert(relocate_array_by_memcpy<A>);
3030

3131
// TODO: why it it false here? will it stay false when we can use
3232
// __is_trivially_relocatable()?
33-
static_assert(!relocate_one_by_memcpy<volatile A>, "");
34-
static_assert(!relocate_array_by_memcpy<volatile A>, "");
33+
static_assert(!relocate_one_by_memcpy<volatile A>);
34+
static_assert(!relocate_array_by_memcpy<volatile A>);
3535

3636
struct B {
3737
B(B &&) = default;
3838
~B() = default;
3939
};
40-
static_assert(relocate_one_by_memcpy<B>, "");
41-
static_assert(relocate_array_by_memcpy<B>, "");
40+
static_assert(relocate_one_by_memcpy<B>);
41+
static_assert(relocate_array_by_memcpy<B>);
4242

4343
struct C {
4444
C(C &&) = default;
4545
~C() {}
4646
};
47-
static_assert(!relocate_one_by_memcpy<C>, "");
48-
static_assert(!relocate_array_by_memcpy<C>, "");
47+
static_assert(!relocate_one_by_memcpy<C>);
48+
static_assert(!relocate_array_by_memcpy<C>);
4949

5050
struct D {
5151
D(D &&) {}
5252
~D() = default;
5353
};
54-
static_assert(!relocate_one_by_memcpy<D>, "");
55-
static_assert(!relocate_array_by_memcpy<D>, "");
54+
static_assert(!relocate_one_by_memcpy<D>);
55+
static_assert(!relocate_array_by_memcpy<D>);
5656

5757
struct [[sus_trivial_abi]] T {
5858
T(T &&) {}
5959
~T() {}
6060
};
6161
#if __has_extension(trivially_relocatable)
62-
static_assert(relocate_one_by_memcpy<T>, "");
63-
static_assert(relocate_array_by_memcpy<T>, "");
62+
static_assert(relocate_one_by_memcpy<T>);
63+
static_assert(relocate_array_by_memcpy<T>);
6464
#else
65-
static_assert(!relocate_one_by_memcpy<T>, "");
66-
static_assert(!relocate_array_by_memcpy<T>, "");
65+
static_assert(!relocate_one_by_memcpy<T>);
66+
static_assert(!relocate_array_by_memcpy<T>);
6767
#endif
6868

6969
struct [[sus_trivial_abi]] G {
7070
sus_class_trivial_relocatable_value(unsafe_fn, true);
7171
G(G &&) {}
7272
~G() {}
7373
};
74-
static_assert(relocate_one_by_memcpy<G>, "");
75-
static_assert(relocate_array_by_memcpy<G>, "");
74+
static_assert(relocate_one_by_memcpy<G>);
75+
static_assert(relocate_array_by_memcpy<G>);
7676

7777
struct [[sus_trivial_abi]] H {
7878
sus_class_trivial_relocatable_value(unsafe_fn, false);
7979
H(H &&) {}
8080
~H() {}
8181
};
82-
static_assert(!relocate_one_by_memcpy<H>, "");
83-
static_assert(!relocate_array_by_memcpy<H>, "");
82+
static_assert(!relocate_one_by_memcpy<H>);
83+
static_assert(!relocate_array_by_memcpy<H>);
84+
85+
// A mixture of explicit relocatable tag and trivial move + destroy.
86+
static_assert(relocate_one_by_memcpy<G, int>);
87+
static_assert(relocate_one_by_memcpy<int, G>);
88+
static_assert(relocate_one_by_memcpy<int, G, int>);
8489

8590
} // namespace

option/option.h

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,19 @@ struct Storage final {
8686
constexpr ~Storage()
8787
requires(!std::is_trivially_destructible_v<T>)
8888
{}
89-
constexpr Storage(const Storage&) = default;
90-
constexpr Storage& operator=(const Storage&) = default;
91-
constexpr Storage(Storage&&) = default;
92-
constexpr Storage& operator=(Storage&&) = default;
89+
90+
constexpr Storage(const Storage&)
91+
requires(std::is_trivially_copy_constructible_v<T>)
92+
= default;
93+
constexpr Storage& operator=(const Storage&)
94+
requires(std::is_trivially_copy_assignable_v<T>)
95+
= default;
96+
constexpr Storage(Storage&&)
97+
requires(std::is_trivially_move_constructible_v<T>)
98+
= default;
99+
constexpr Storage& operator=(Storage&&)
100+
requires(std::is_trivially_move_assignable_v<T>)
101+
= default;
93102

94103
constexpr Storage(State s) : state_(s) {}
95104
constexpr Storage(const std::remove_cvref_t<T>& t) : val_(t), state_(Some) {}
@@ -111,6 +120,7 @@ struct Storage final {
111120
template <class T>
112121
struct Storage<T&> final {
113122
constexpr ~Storage() = default;
123+
114124
constexpr Storage(const Storage&) = default;
115125
constexpr Storage& operator=(const Storage&) = default;
116126
constexpr Storage(Storage&&) = default;
@@ -169,6 +179,8 @@ class Option final {
169179
return Option<T>(::sus::construct::make_default<T>());
170180
}
171181

182+
/// Destructor for the Option.
183+
///
172184
/// If T can be trivially destroyed, we don't need to explicitly destroy it,
173185
/// so we can use the default destructor, which allows Option<T> to also be
174186
/// trivially destroyed.
@@ -191,7 +203,7 @@ class Option final {
191203
requires(std::is_trivially_copy_constructible_v<T>)
192204
= default;
193205

194-
constexpr Option(const Option& o)
206+
constexpr Option(const Option& o) noexcept
195207
requires(!std::is_trivially_copy_constructible_v<T> &&
196208
std::is_copy_constructible_v<T>)
197209
: t_(o.t_.state()) {
@@ -204,9 +216,8 @@ class Option final {
204216
requires(!std::is_copy_constructible_v<T>)
205217
= delete;
206218

207-
/// If T can be trivially move-constructed, we don't need to explicitly
208-
/// construct it, so we can use the default destructor, which allows Option<T>
209-
/// to also be trivially move-constructed.
219+
/// If T can be trivially copy-constructed, Option<T> can also be trivially
220+
/// move-constructed.
210221
constexpr Option(Option&& o)
211222
requires(std::is_trivially_move_constructible_v<T>)
212223
= default;
@@ -1149,10 +1160,8 @@ template <class T, class U>
11491160
constexpr inline bool operator==(const Option<T>& l,
11501161
const Option<U>& r) noexcept {
11511162
switch (l) {
1152-
case Some:
1153-
return r.is_some() && l.unwrap_ref() == r.unwrap_ref();
1154-
case None:
1155-
return r.is_none();
1163+
case Some: return r.is_some() && l.unwrap_ref() == r.unwrap_ref();
1164+
case None: return r.is_none();
11561165
}
11571166
::sus::unreachable_unchecked(unsafe_fn);
11581167
}

0 commit comments

Comments
 (0)