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
|
#ifndef MESSMER_CPP_UTILS_EITHER_H
|
||||||
#define MESSMER_CPP_UTILS_EITHER_H
|
#define MESSMER_CPP_UTILS_EITHER_H
|
||||||
|
|
||||||
#include <type_traits>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
namespace cpputils {
|
namespace cpputils {
|
||||||
|
|
||||||
@ -65,21 +65,50 @@ namespace cpputils {
|
|||||||
return _side == Side::right;
|
return _side == Side::right;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO Also offer a safe version of getting left/right (exceptions? nullptr?)
|
|
||||||
const Left &left() const {
|
const Left &left() const {
|
||||||
return _left;
|
return _left;
|
||||||
}
|
}
|
||||||
|
Left &left() {
|
||||||
|
return const_cast<Left&>(const_cast<const Either<Left, Right>*>(this)->left());
|
||||||
|
}
|
||||||
|
|
||||||
const Right &right() const {
|
const Right &right() const {
|
||||||
return _right;
|
return _right;
|
||||||
}
|
}
|
||||||
|
|
||||||
Left &left() {
|
|
||||||
return const_cast<Left&>(const_cast<const Either<Left, Right>*>(this)->left());
|
|
||||||
}
|
|
||||||
Right &right() {
|
Right &right() {
|
||||||
return const_cast<Right&>(const_cast<const Either<Left, Right>*>(this)->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:
|
private:
|
||||||
union {
|
union {
|
||||||
Left _left;
|
Left _left;
|
||||||
|
@ -1,8 +1,16 @@
|
|||||||
#include <google/gtest/gtest.h>
|
#include <google/gtest/gtest.h>
|
||||||
#include <google/gmock/gmock.h>
|
#include <google/gmock/gmock.h>
|
||||||
|
#include <boost/optional/optional_io.hpp>
|
||||||
#include "../either.h"
|
#include "../either.h"
|
||||||
#include "../macros.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 {
|
class OnlyMoveable {
|
||||||
public:
|
public:
|
||||||
OnlyMoveable(int value_): value(value_) {}
|
OnlyMoveable(int value_): value(value_) {}
|
||||||
@ -12,9 +20,11 @@ private:
|
|||||||
DISALLOW_COPY_AND_ASSIGN(OnlyMoveable);
|
DISALLOW_COPY_AND_ASSIGN(OnlyMoveable);
|
||||||
};
|
};
|
||||||
|
|
||||||
using std::string;
|
template<typename T>
|
||||||
using namespace cpputils;
|
struct StoreWith1ByteFlag {
|
||||||
using ::testing::Test;
|
T val;
|
||||||
|
char flag;
|
||||||
|
};
|
||||||
|
|
||||||
class EitherTest: public Test {
|
class EitherTest: public Test {
|
||||||
public:
|
public:
|
||||||
@ -32,18 +42,39 @@ public:
|
|||||||
void EXPECT_LEFT_IS(const Expected &expected, Either<Left, Right> &value) {
|
void EXPECT_LEFT_IS(const Expected &expected, Either<Left, Right> &value) {
|
||||||
EXPECT_IS_LEFT(value);
|
EXPECT_IS_LEFT(value);
|
||||||
EXPECT_EQ(expected, value.left());
|
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;
|
const Either<Left, Right> &const_value = value;
|
||||||
EXPECT_EQ(expected, const_value.left());
|
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>
|
template<class Left, class Right, class Expected>
|
||||||
void EXPECT_RIGHT_IS(const Expected &expected, Either<Left, Right> &value) {
|
void EXPECT_RIGHT_IS(const Expected &expected, Either<Left, Right> &value) {
|
||||||
EXPECT_IS_RIGHT(value);
|
EXPECT_IS_RIGHT(value);
|
||||||
EXPECT_EQ(expected, value.right());
|
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;
|
const Either<Left, Right> &const_value = value;
|
||||||
EXPECT_EQ(expected, const_value.right());
|
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) {
|
TEST_F(EitherTest, LeftCanBeConstructed) {
|
||||||
Either<int, string> val = 3;
|
Either<int, string> val = 3;
|
||||||
UNUSED(val);
|
UNUSED(val);
|
||||||
@ -142,6 +173,30 @@ TEST_F(EitherTest, RightCanBeMoved) {
|
|||||||
EXPECT_EQ(5, val2.right().value);
|
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) {
|
TEST_F(EitherTest, LeftEquals) {
|
||||||
Either<string, int> val1 = string("mystring");
|
Either<string, int> val1 = string("mystring");
|
||||||
Either<string, int> val2 = string("mystring");
|
Either<string, int> val2 = string("mystring");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user