Offer Either::left_opt() and Either::right_opt() and add some test cases
This commit is contained in:
parent
e1c4327338
commit
d5dadc74e7
41
either.h
41
either.h
@ -2,7 +2,7 @@
|
||||
#ifndef MESSMER_CPP_UTILS_EITHER_H
|
||||
#define MESSMER_CPP_UTILS_EITHER_H
|
||||
|
||||
#include <type_traits>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
@ -65,21 +65,50 @@ namespace cpputils {
|
||||
return _side == Side::right;
|
||||
}
|
||||
|
||||
//TODO Also offer a safe version of getting left/right (exceptions? nullptr?)
|
||||
const Left &left() const {
|
||||
return _left;
|
||||
}
|
||||
Left &left() {
|
||||
return const_cast<Left&>(const_cast<const Either<Left, Right>*>(this)->left());
|
||||
}
|
||||
|
||||
const Right &right() const {
|
||||
return _right;
|
||||
}
|
||||
|
||||
Left &left() {
|
||||
return const_cast<Left&>(const_cast<const Either<Left, Right>*>(this)->left());
|
||||
}
|
||||
Right &right() {
|
||||
return const_cast<Right&>(const_cast<const Either<Left, Right>*>(this)->right());
|
||||
}
|
||||
|
||||
boost::optional<const Left&> left_opt() const {
|
||||
if (_side == Side::left) {
|
||||
return _left;
|
||||
} else {
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
boost::optional<Left&> left_opt() {
|
||||
if (_side == Side::left) {
|
||||
return _left;
|
||||
} else {
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
boost::optional<const Right&> right_opt() const {
|
||||
if (_side == Side::right) {
|
||||
return _right;
|
||||
} else {
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
boost::optional<Right&> right_opt() {
|
||||
if (_side == Side::right) {
|
||||
return _right;
|
||||
} else {
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
Left _left;
|
||||
|
@ -1,8 +1,16 @@
|
||||
#include <google/gtest/gtest.h>
|
||||
#include <google/gmock/gmock.h>
|
||||
#include <boost/optional/optional_io.hpp>
|
||||
#include "../either.h"
|
||||
#include "../macros.h"
|
||||
|
||||
//TODO Go through all test cases and think about whether it makes sense to add the same test case but with primitive types.
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using namespace cpputils;
|
||||
using ::testing::Test;
|
||||
|
||||
class OnlyMoveable {
|
||||
public:
|
||||
OnlyMoveable(int value_): value(value_) {}
|
||||
@ -12,9 +20,11 @@ private:
|
||||
DISALLOW_COPY_AND_ASSIGN(OnlyMoveable);
|
||||
};
|
||||
|
||||
using std::string;
|
||||
using namespace cpputils;
|
||||
using ::testing::Test;
|
||||
template<typename T>
|
||||
struct StoreWith1ByteFlag {
|
||||
T val;
|
||||
char flag;
|
||||
};
|
||||
|
||||
class EitherTest: public Test {
|
||||
public:
|
||||
@ -32,18 +42,39 @@ public:
|
||||
void EXPECT_LEFT_IS(const Expected &expected, Either<Left, Right> &value) {
|
||||
EXPECT_IS_LEFT(value);
|
||||
EXPECT_EQ(expected, value.left());
|
||||
EXPECT_EQ(expected, value.left_opt().get());
|
||||
EXPECT_EQ(boost::none, value.right_opt());
|
||||
const Either<Left, Right> &const_value = value;
|
||||
EXPECT_EQ(expected, const_value.left());
|
||||
EXPECT_EQ(expected, const_value.left_opt().get());
|
||||
EXPECT_EQ(boost::none, const_value.right_opt());
|
||||
}
|
||||
template<class Left, class Right, class Expected>
|
||||
void EXPECT_RIGHT_IS(const Expected &expected, Either<Left, Right> &value) {
|
||||
EXPECT_IS_RIGHT(value);
|
||||
EXPECT_EQ(expected, value.right());
|
||||
EXPECT_EQ(expected, value.right_opt().get());
|
||||
EXPECT_EQ(boost::none, value.left_opt());
|
||||
const Either<Left, Right> &const_value = value;
|
||||
EXPECT_EQ(expected, const_value.right());
|
||||
EXPECT_EQ(expected, const_value.right_opt().get());
|
||||
EXPECT_EQ(boost::none, const_value.left_opt());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Left, typename Right>
|
||||
void TestSpaceUsage() {
|
||||
EXPECT_EQ(std::max(sizeof(StoreWith1ByteFlag<Left>), sizeof(StoreWith1ByteFlag<Right>)), sizeof(Either<Left, Right>));
|
||||
}
|
||||
|
||||
TEST_F(EitherTest, SpaceUsage) {
|
||||
TestSpaceUsage<char, int>();
|
||||
TestSpaceUsage<int, short>();
|
||||
TestSpaceUsage<char, short>();
|
||||
TestSpaceUsage<int, string>();
|
||||
TestSpaceUsage<string, vector<string>>();
|
||||
}
|
||||
|
||||
TEST_F(EitherTest, LeftCanBeConstructed) {
|
||||
Either<int, string> val = 3;
|
||||
UNUSED(val);
|
||||
@ -142,6 +173,30 @@ TEST_F(EitherTest, RightCanBeMoved) {
|
||||
EXPECT_EQ(5, val2.right().value);
|
||||
}
|
||||
|
||||
TEST_F(EitherTest, ModifyLeft) {
|
||||
Either<string, int> val = string("mystring1");
|
||||
val.left() = "mystring2";
|
||||
EXPECT_LEFT_IS("mystring2", val);
|
||||
}
|
||||
|
||||
TEST_F(EitherTest, ModifyRight) {
|
||||
Either<int, string> val = string("mystring1");
|
||||
val.right() = "mystring2";
|
||||
EXPECT_RIGHT_IS("mystring2", val);
|
||||
}
|
||||
|
||||
TEST_F(EitherTest, ModifyLeftOpt) {
|
||||
Either<string, int> val = string("mystring1");
|
||||
val.left_opt().get() = "mystring2";
|
||||
EXPECT_LEFT_IS("mystring2", val);
|
||||
}
|
||||
|
||||
TEST_F(EitherTest, ModifyRightOpt) {
|
||||
Either<int, string> val = string("mystring1");
|
||||
val.right_opt().get() = "mystring2";
|
||||
EXPECT_RIGHT_IS("mystring2", val);
|
||||
}
|
||||
|
||||
TEST_F(EitherTest, LeftEquals) {
|
||||
Either<string, int> val1 = string("mystring");
|
||||
Either<string, int> val2 = string("mystring");
|
||||
|
Loading…
Reference in New Issue
Block a user