Skip to content

Commit b7973a6

Browse files
committed
* Implemented comparison
1 parent c94321f commit b7973a6

File tree

4 files changed

+112
-40
lines changed

4 files changed

+112
-40
lines changed

neither/include/either.hpp

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
#ifndef NEITHER_EITHER_HPP
22
#define NEITHER_EITHER_HPP
33

4-
#include <neither/traits.hpp>
5-
#include <neither/maybe.hpp>
64
#include <memory>
75
#include <type_traits>
86

7+
#include <neither/traits.hpp>
8+
#include <neither/maybe.hpp>
9+
910
namespace neither {
1011

1112
template<class T>
@@ -25,7 +26,7 @@ constexpr Left<T> left(T const& x) {
2526

2627
template<class T>
2728
Left<T> left(T&& x) {
28-
return {std::move(x)};
29+
return { std::move(x) };
2930
}
3031

3132
template<class T>
@@ -41,12 +42,9 @@ constexpr Right<T> right(T const& x) {
4142

4243
template<class T>
4344
Right<T> right(T&& x) {
44-
return {std::move(x)};
45+
return { std::move(x) };
4546
}
4647

47-
48-
49-
5048
template<class L, class R>
5149
struct Either {
5250

@@ -104,18 +102,17 @@ struct Either {
104102
}
105103

106104
constexpr auto left() const -> Maybe<L> {
107-
if (!isLeft)
108-
return maybe();
109-
return maybe(leftValue);
105+
return isLeft ?
106+
maybe(leftValue) :
107+
maybe();
110108
}
111109

112110
constexpr auto right() const -> Maybe<R> {
113-
if(isLeft)
114-
return maybe();
115-
return maybe(rightValue);
111+
return isLeft ?
112+
maybe() :
113+
maybe(rightValue);
116114
}
117115

118-
119116
static constexpr auto leftOf( L const& l ) {
120117
return Either<L, R>{ neither::left(l) };
121118
}
@@ -124,7 +121,6 @@ struct Either {
124121
return Either<L, R>{ neither::right(r) };
125122
}
126123

127-
128124
static constexpr auto leftOf( L && l ) {
129125
return Either<L, R>{ neither::left(std::move(l)) };
130126
}
@@ -133,7 +129,6 @@ struct Either {
133129
return Either<L, R>{ neither::right(std::move(r)) };
134130
}
135131

136-
137132
template<
138133
class L2 = L,
139134
class R2 = R>
@@ -142,26 +137,25 @@ struct Either {
142137
isCopyable((L2)leftValue, (R2)rightValue),
143138
std::declval<std::common_type_t<L2, R2>>()
144139
) {
145-
return isLeft? leftValue : rightValue;
140+
return isLeft ? leftValue : rightValue;
146141
}
147142

148-
149143
template<
150144
class L2 = L,
151145
class R2 = R>
152146
auto join()&&
153147
-> std::common_type_t<L2, R2> {
154-
return isLeft? std::move(leftValue) : std::move(rightValue);
148+
return isLeft ? std::move(leftValue) : std::move(rightValue);
155149
}
156150

157151
template<class LeftF, class RightF>
158152
constexpr auto join(LeftF const& leftCase, RightF const& rightCase) const
159153
-> decltype( isLeft? leftCase( leftValue ) : rightCase( rightValue ) ) {
160-
return isLeft? leftCase( leftValue ) : rightCase( rightValue );
154+
return isLeft ? leftCase( leftValue ) : rightCase( rightValue );
161155
}
162156

163157
template<class F, class L2=L, class R2=R>
164-
constexpr auto leftMap(F const& leftCase) const&
158+
constexpr auto leftMap(F const& leftCase) const&
165159
-> Either<decltype(leftCase( isCopyable((L2)leftValue, (R2)rightValue) )), R2> {
166160
using NextEither = Either<decltype(leftCase(leftValue)), R2>;
167161
return isLeft ?
@@ -205,7 +199,7 @@ struct Either {
205199
return NextEither::rightOf(rightValue);
206200
}
207201

208-
template<class RightCase, class L2=L, class R2=R>
202+
template<class RightCase, class L2 = L, class R2 = R>
209203
constexpr auto rightFlatMap(RightCase const& rightCase) const&
210204
-> decltype( ensureEitherLeft(rightCase(isCopyable((R2)rightValue)), isCopyable((L2)leftValue))) {
211205
using NextEither = decltype(rightCase(rightValue));
@@ -217,9 +211,7 @@ struct Either {
217211
return NextEither::leftOf(leftValue);
218212
}
219213

220-
221-
222-
template<class LeftCase, class L2=L, class R2=R>
214+
template<class LeftCase, class L2 = L, class R2 = R>
223215
auto leftFlatMap(LeftCase const& leftCase)&&
224216
-> decltype( ensureEitherRight(leftCase(std::move(leftValue)), std::move(rightValue))) {
225217
using NextEither = decltype(leftCase(std::move(leftValue)));
@@ -246,6 +238,25 @@ struct Either {
246238
constexpr operator bool()const { return !isLeft; }
247239
};
248240

241+
template <typename L, typename R>
242+
bool operator == (Either<L, R> const& a, Either<L, R> const& b) {
243+
if (a.isLeft) {
244+
if (b.isLeft) {
245+
return a.left() == b.left();
246+
}
247+
} else {
248+
if (!b.isLeft) {
249+
return a.right() == b.right();
250+
}
251+
}
252+
return false;
253+
}
254+
255+
template <typename L, typename R>
256+
bool operator != (Either<L, R> const& a, Either<L, R> const& b) {
257+
return !(a == b);
258+
}
259+
249260
}
250261

251262
#endif

neither/include/maybe.hpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ template <class T> struct Maybe {
1515
union {
1616
T value;
1717
};
18+
1819
bool const hasValue = 0;
1920

2021
constexpr Maybe() : hasValue{0} {}
@@ -85,12 +86,28 @@ template <class T> struct Maybe {
8586
return f(std::move(value));
8687
}
8788

88-
constexpr operator bool()const { return hasValue; }
89+
constexpr operator bool() const { return hasValue; }
8990
};
9091

91-
template <class T> auto maybe(T value) -> Maybe<T> { return {value}; }
92+
template <typename T>
93+
auto maybe(T value) -> Maybe<T> { return {value}; }
94+
95+
template <typename T = void>
96+
auto maybe() -> Maybe<T> { return {}; }
97+
98+
template <typename T>
99+
bool operator == (Maybe<T> const& a, Maybe<T> const& b) {
100+
if (a.hasValue) {
101+
return b.hasValue && a.value == b.value;
102+
}
103+
return !b.hasValue;
104+
}
105+
106+
template <typename T>
107+
bool operator != (Maybe<T> const& a, Maybe<T> const& b) {
108+
return !(a == b);
109+
}
92110

93-
template <class T = void> auto maybe() -> Maybe<T> { return {}; }
94111
}
95112

96113
#endif

neither/tests/either.cpp

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
1-
#include <gtest/gtest.h>
21
#include <iostream>
3-
#include <neither/either.hpp>
42
#include <string>
53
#include <memory>
64

5+
#include <gtest/gtest.h>
6+
#include <neither/either.hpp>
7+
78
using namespace neither;
89
using namespace std::literals::string_literals;
10+
911
using IntOrStr = Either<int, std::string>;
1012
using StrOrInt = Either<std::string, int>;
1113
using StrOrStr = Either<std::string, std::string>;
1214

13-
14-
TEST(neither, join_left) {
15+
TEST(neither, either_join_left) {
1516

1617
auto i = IntOrStr::leftOf(21);
1718

@@ -22,7 +23,7 @@ TEST(neither, join_left) {
2223
ASSERT_TRUE(i2 == 42);
2324
}
2425

25-
TEST(neither, join_right) {
26+
TEST(neither, either_join_right) {
2627

2728
auto s = IntOrStr::rightOf("foo");
2829

@@ -35,7 +36,7 @@ TEST(neither, join_right) {
3536
}
3637

3738

38-
TEST(neither, leftFlatMap) {
39+
TEST(neither, either_leftFlatMap) {
3940
auto s = IntOrStr::leftOf(1);
4041

4142
auto s2 = s.rightMap([](auto) -> std::string { return "b"; })
@@ -45,7 +46,7 @@ TEST(neither, leftFlatMap) {
4546
ASSERT_TRUE(s2[0] == 'a');
4647
}
4748

48-
TEST(neither, rightFlatMap) {
49+
TEST(neither, either_rightFlatMap) {
4950
auto s = StrOrStr::rightOf("a");
5051

5152
auto i = s.rightFlatMap([](auto x) { return StrOrInt::rightOf(2); })
@@ -55,7 +56,7 @@ TEST(neither, rightFlatMap) {
5556
ASSERT_TRUE(i == 2);
5657
}
5758

58-
TEST(neither, leftMapMove) {
59+
TEST(neither, either_leftMapMove) {
5960
neither::Either<int, std::string> e = neither::left(1);
6061
e.leftMap([](auto x) {
6162
return x;
@@ -64,7 +65,7 @@ TEST(neither, leftMapMove) {
6465
});
6566
}
6667

67-
TEST(neither, rightMapMove) {
68+
TEST(neither, either_rightMapMove) {
6869
neither::Either<std::string, int> e = neither::right(1);
6970
e.rightMap([](auto x) {
7071
return x;
@@ -73,12 +74,12 @@ TEST(neither, rightMapMove) {
7374
});
7475
}
7576

76-
TEST(neither, constructFromUnique) {
77+
TEST(neither, either_constructFromUnique) {
7778
neither::Either<std::unique_ptr<int>, std::string> e =
7879
neither::left(std::make_unique<int>(1));
7980
}
8081

81-
TEST(neither, flatMapToUnique) {
82+
TEST(neither, either_flatMapToUnique) {
8283
neither::Either<int, int> e = left(1);
8384

8485
auto i = e.leftFlatMap([](auto x) {
@@ -95,7 +96,7 @@ TEST(neither, flatMapToUnique) {
9596
}
9697

9798

98-
TEST(neither, mapToUnique) {
99+
TEST(neither, either_mapToUnique) {
99100
neither::Either<int, int> e = left(1);
100101

101102
auto u = e.leftFlatMap([](auto x) { return
@@ -110,3 +111,25 @@ TEST(neither, mapToUnique) {
110111

111112
ASSERT_TRUE(*u == 1);
112113
}
114+
115+
TEST(neither, either_comparison) {
116+
117+
auto a = IntOrStr::leftOf(123);
118+
auto b = IntOrStr::leftOf(123);
119+
120+
EXPECT_TRUE(a == b);
121+
122+
auto c = IntOrStr::rightOf("abc");
123+
auto d = IntOrStr::rightOf("abc");
124+
auto e = IntOrStr::rightOf("def");
125+
126+
EXPECT_TRUE(c == d);
127+
128+
EXPECT_TRUE(a != c);
129+
EXPECT_TRUE(a != d);
130+
EXPECT_TRUE(b != c);
131+
EXPECT_TRUE(b != d);
132+
133+
EXPECT_TRUE(c != e);
134+
EXPECT_TRUE(d != e);
135+
}

neither/tests/maybe.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,24 @@ TEST(neither, maybe_flatMap_no_value) {
2727
auto x = maybe<int>(42);
2828
ASSERT_TRUE(x.flatMap([](auto x) { return maybe<int>(); }).get(1) == 1);
2929
}
30+
31+
TEST(neither, maybe_comparison) {
32+
33+
auto a = maybe<int>(42);
34+
auto b = maybe<int>(42);
35+
auto c = maybe<int>(17);
36+
auto d = maybe<int>();
37+
auto e = maybe<int>();
38+
39+
EXPECT_TRUE(a == a);
40+
EXPECT_TRUE(a == b);
41+
EXPECT_TRUE(b == a);
42+
43+
EXPECT_TRUE(a != c);
44+
EXPECT_TRUE(b != c);
45+
EXPECT_TRUE(a != d);
46+
EXPECT_TRUE(b != d);
47+
48+
EXPECT_TRUE(d == d);
49+
EXPECT_TRUE(d == e);
50+
}

0 commit comments

Comments
 (0)