Skip to content

Commit 1c1d278

Browse files
committed
Add Option::zip() which returns an Option<Tuple> from 2 Options.
1 parent 10b519c commit 1c1d278

File tree

3 files changed

+67
-2
lines changed

3 files changed

+67
-2
lines changed

option/option.h

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121

2222
// TODO: Clone integration: cloned().
2323

24-
// TODO: Pair/tuple integration: zip().
25-
2624
#pragma once
2725

2826
#include <type_traits>
@@ -51,6 +49,11 @@ template <class T, class E>
5149
class Result;
5250
}
5351

52+
namespace sus::tuple {
53+
template <class T, class... Ts>
54+
class Tuple;
55+
}
56+
5457
namespace sus::option {
5558

5659
using sus::iter::Iterator;
@@ -683,6 +686,25 @@ class Option final {
683686
return Result::with_err(static_cast<ElseFn&&>(f)());
684687
}
685688

689+
/// Zips self with another Option.
690+
///
691+
/// If self is `Some(s)` and other is `Some(o)`, this method returns `Some((s,
692+
/// o))`. Otherwise, `None` is returned.
693+
template <class U, int&..., class Tuple = ::sus::tuple::Tuple<T, U>>
694+
constexpr inline Option<Tuple> zip(Option<U> o) && noexcept {
695+
if (o.is_none()) {
696+
if (t_.set_state(None) == Some) t_.val_.~T();
697+
return Option<Tuple>::none();
698+
} else if (is_none()) {
699+
return Option<Tuple>::none();
700+
} else {
701+
t_.set_state(None);
702+
return Option<Tuple>::some(
703+
Tuple::with(::sus::mem::take_and_destruct(unsafe_fn, mref(t_.val_)),
704+
static_cast<Option<U>&&>(o).unwrap()));
705+
}
706+
}
707+
686708
/// Transposes an #Option of a #Result into a #Result of an #Option.
687709
///
688710
/// `None` will be mapped to `Ok(None)`. `Some(Ok(_))` and `Some(Err(_))` will
@@ -1157,6 +1179,24 @@ class Option<T&> final {
11571179
return Result::with_err(static_cast<ElseFn&&>(f)());
11581180
}
11591181

1182+
/// Zips self with another Option.
1183+
///
1184+
/// If self is `Some(s)` and other is `Some(o)`, this method returns `Some((s,
1185+
/// o))`. Otherwise, `None` is returned.
1186+
template <class U, int&..., class Tuple = ::sus::tuple::Tuple<T&, U>>
1187+
constexpr inline Option<Tuple> zip(Option<U> o) && noexcept {
1188+
if (o.is_none()) {
1189+
t_.ptr_ = nullptr;
1190+
return Option<Tuple>::none();
1191+
} else if (is_none()) {
1192+
return Option<Tuple>::none();
1193+
} else {
1194+
return Option<Tuple>::some(
1195+
Tuple::with(*::sus::mem::replace_ptr(mref(t_.ptr_), nullptr),
1196+
static_cast<Option<U>&&>(o).unwrap()));
1197+
}
1198+
}
1199+
11601200
/// Replaces whatever the Option is currently holding with #Some value `t` and
11611201
/// returns an Option holding what was there previously.
11621202
Option replace(T& t) & noexcept {

option/option_unittest.cc

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "iter/iterator.h"
2121
#include "mem/relocate.h"
2222
#include "num/types.h"
23+
#include "tuple/tuple.h"
2324
#include "result/result.h"
2425
#include "test/behaviour_types.h"
2526
#include "third_party/googletest/googletest/include/gtest/gtest.h"
@@ -1603,4 +1604,25 @@ TEST(Option, Transpose) {
16031604
EXPECT_EQ(sus::move(t3).unwrap_err(), -2_i32);
16041605
}
16051606

1607+
TEST(Option, Zip) {
1608+
EXPECT_EQ(Option<i32>::none().zip(Option<i32>::none()), None);
1609+
EXPECT_EQ(Option<i32>::some(1_i32).zip(Option<i32>::none()), None);
1610+
EXPECT_EQ(Option<i32>::none().zip(Option<i32>::some(1_i32)), None);
1611+
EXPECT_EQ(Option<i32>::some(2_i32).zip(Option<i32>::some(1_i32)), Some);
1612+
1613+
{
1614+
auto o = Option<i32>::some(-2_i32);
1615+
EXPECT_EQ(sus::move(o).zip(Option<u8>::some(3_u8)).unwrap(), (sus::Tuple<i32, u8>::with(-2_i32, 3_u8)));
1616+
EXPECT_EQ(o, None);
1617+
}
1618+
1619+
{
1620+
auto i = -2_i32;
1621+
auto u = 3_u8;
1622+
auto o = Option<const i32&>::some(i);
1623+
EXPECT_EQ(sus::move(o).zip(Option<const u8&>::some(u)).unwrap(), (sus::Tuple<i32, u8>::with(-2_i32, 3_u8)));
1624+
EXPECT_EQ(o, None);
1625+
}
1626+
}
1627+
16061628
} // namespace

tuple/tuple.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ class Tuple final {
113113
}
114114

115115
private:
116+
template <class U, class... Us>
117+
friend class Tuple; // For access to moved_from();
118+
116119
/// Storage for the tuple elements. The first element is the moved-from flag.
117120
using Storage = __private::TupleStorage<2 + sizeof...(Ts), bool, T, Ts...>;
118121
/// A helper type used for accessing the `Storage`.

0 commit comments

Comments
 (0)